Shop OBEX P1 Docs P2 Docs Learn Events
GOSUB without RETURN - is that bad? — Parallax Forums

GOSUB without RETURN - is that bad?

YanroyYanroy Posts: 96
edited 2005-07-14 14:42 in BASIC Stamp
Hi,

I'm using a BS2sx in the design of a custom robot controller (the robot it's for was originally designed around an Innovation FIRST robot controller, and this is to be a drop-in replacement to provide more processing power, memory, and autonomous features).· The control system consists of a human working on a laptop, communication with an iPAQ pocket PC over 802.11b wireless LAN, the iPAQ the talks via RS232 to the BS2sx.· Because the iPAQ only has one serial port and there are several RS232 devices that need to be connected to it (in addition to the stamp, a GPS and potentially a datalogger), I have multiplexed the iPAQ's RS232 lines between these devices.· The stamp controls the multiplexer.· The iPAQ orders the stamp, via RS232, to connect it to a different device - but then it can never tell the stamp to switch back again, since it's out of communication with the stamp.· To solve this problem, I have the stamp constantly listening for a pulse on the iPAQ's headphone jack.· This will cause the stamp to restore communication between the iPAQ and the stamp.· This odd communication scheme has resulted in some odd stamp code, which is the reason for my post.

Hopefully that's enough background for this to make some kind of sense.· When there's an error in the communication between iPAQ and stamp, the stamp needs to execute an emergency stop as a safety measure to disable the robot.· The error handling code is usually jumped into my the SERIN statement's implicit GOTO·to the error label parameter.· This presents a problem because to recover from the error, I need the stamp to re-initialize after the emergency stop.· If I used a RETURN, it would jump back into the main loop and the only way out is to treat the error like a communication timeout, which results in the same set of actions being taken again before reinitializing.· I currently use a GOTO to go back to the initialization to avoid the repetition (and confusing debug messages to the user).· This means that there's never any RETURN after the GOSUB that went into the serial communication subroutine.· I haven't yet had a problem with this, but something tells me it could come back to bite me in a serious way.· I'd appreciate it if someone could tell me what's going on when I don't RETURN from a subroutine (eventually some queue or stack must fill up with addresses?).· Also, if you can think of a way to solve this problem that won't involve a massive change to the program, I'd like that input as well.

Sorry for the long post.· Thanks a lot for any help you can give me.· The code is attached - the problem is after the MasterCommErr and CheckSumErr labels.

Comments

  • Paul BakerPaul Baker Posts: 6,351
    edited 2005-07-12 19:07
    As a general practice, it is bad form to not have a corresponding RETURN with·a GOSUB.

    Now will this cause problems in your situation? I am not sure,·but here's an explanation.

    When a GOSUB is executed, one of the things done before jumping to the subroutine is the address of the instruction immeadiatly following the GOSUB is placed on a stack. When·a RETURN is executed, that address is removed from the stack and the program continues executing from that address.

    Now why don't I have a specific answer to your question? Because it depends on how that stack is implemented on whether your situation will cause problems. The little microchip on your stamp has a hardware stack in it, when it fills up the oldest data on the stack is lost, meaning you'll never know where to return to. But in your situation, it is likely that that lost return address was·generated prior to the last error condition, so you had no intention of returning to that address anyways. So·if parallax's PBASIC engine uses the·hardware stack on the microcontroller you shouldn't have a problem (other than you are doing a programming no no). But if·the PBASIC engine uses a software stack your likely looking·at a disaster waiting to happen. This is because when most·software stacks fill up, they return an error condition rather than adding the data item, so the stack become useless until you remove some of the data on the stack (by executing a RETURN). A software stack can be implemented to behave like a hardware stack, but·it isn't that common. So the answer depends on how Parallax designed the PBASIC engine, something I cannot answer for you.

    Rather than worrying about the behavior of the PBASIC engine in a situation it wasn't designed to be in, I strongly suggest modifying your code to be inline with standard programming practice. To illustrate this I have picked an example out of your code:
        IF CheckSum <> 0 THEN GOTO CheckSumErr
     
        ...
     
    CheckSumErr:
        DEBUG "CS", CR  ' Check Sum: invalid checksum for data from iPAQ
        GOSUB AllStop
        NoCommTimer = 0
        GOTO Init
    RETURN
    
    

    As you know, the GOTO Init is the problem.·To convert this to acceptable form, create a variable (say ReturnValue) and write your code this way:

    IF CheckSum <> 0 THEN 
        GOSUB CheckSumErr
        IF ReturnValue = -1 THEN GOTO Init
    ENDIF
     
        ...
     
    CheckSumErr:
        DEBUG "CS", CR  ' Check Sum: invalid checksum for data from iPAQ
        GOSUB AllStop
        NoCommTimer = 0
        ReturnValue = -1
    RETURN
    

    Now this is a generalized solution, it allows you to set the ReturnValue and check it's condition upon RETURN, in this instance the value -1 represents an error (0 typically means success). But in your instance you already know you are in an error condition, so you actually don't need the variable ReturnValue, you can simply write your code this way:

    IF CheckSum <> 0 THEN 
        GOSUB CheckSumErr
        GOTO Init
    ENDIF
     
        ...
     
    CheckSumErr:
        DEBUG "CS", CR  ' Check Sum: invalid checksum for data from iPAQ
        GOSUB AllStop
        NoCommTimer = 0
    RETURN
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ·Everyone can see the beauty in a rose, not everyone can see the beauty in a cockroach.

    Post Edited (Paul Baker) : 7/12/2005 7:29:02 PM GMT
  • Paul BakerPaul Baker Posts: 6,351
    edited 2005-07-12 19:15
    Wait I just noticed you used GOTO CheckSumErr, but end the code with a RETURN, if you intent is to treat CheckSumErr as a subroutine, it should be GOSUB CheckSumErr. I have modified my code examples above to·replace the GOTO CheckSumErr with GOSUB CheckSumErr.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ·Everyone can see the beauty in a rose, not everyone can see the beauty in a cockroach.

    Post Edited (Paul Baker) : 7/12/2005 7:23:20 PM GMT
  • YanroyYanroy Posts: 96
    edited 2005-07-12 19:38
    Those extra return statements were never being used... I included them because I figured someday I'd find a way to remove the GOTO and I'd have forgotten that I'm still inside a subroutine and have weird bugs because I'm not returning when I should be.· The solution you've presented in your posts doesn't seem to quite address the problem.· In the main loop, I could use some kind of return value that is passed up all the way from the error handler...· that would address the checksum issue, though it would slow down my time-critical main loop.· In order for it to help with the SERIN, I'd also have to pass the return value up two levels to the main loop.· Life would be so much easier if subroutines could legitimately return a value... even PIC assembly can manage that; you'd think PBASIC could.

    Thanks for your help.
  • Paul BakerPaul Baker Posts: 6,351
    edited 2005-07-12 20:02
    SX/B v.1.3 supports return values from a GOSUB. I know it requires investing in the SX platform, but you'll get the same great customer service as with your BS, something that is fairly hit or miss with other platforms supporting return values from subroutines.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ·Everyone can see the beauty in a rose, not everyone can see the beauty in a cockroach.
  • Ryan ClarkeRyan Clarke Posts: 738
    edited 2005-07-12 20:06
    Paul is correct, you do want to make sure you leave the stack clean- and a GOSUB without a return = dirty stack...

    It is a good idea to try and structure your code to be 'clean'- this will help time and time again...trust me.

    Ryan
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2005-07-12 20:10
    Your statement that PIC assembly returns values is not correct (without macros, anyway); inside the microcontroller like PIC (or SX -- both are used as cores in BASIC Stamps), all variables are "global."· Sure, a subroutine can put a value into the W register and it can be moved to a target variable by the calling statement -- but this is manual coding, and that's how SX/B does it.· If PBASIC isn't working for you (I think it will when you learn to work with it instead of complain about it) then there are plenty of alternatives.

    If you decide to stick with PBASIC, it's a simple matter of using one of the RAM variables as your return value.· Your subroutine can put a value into this variable and your caller can check it.· Or, with the SX and later, you could use the Scratchpad to hold temporary values.
    Yanroy said...
    Those extra return statements were never being used... I included them because I figured someday I'd find a way to remove the GOTO and I'd have forgotten that I'm still inside a subroutine and have weird bugs because I'm not returning when I should be.· The solution you've presented in your posts doesn't seem to quite address the problem.· In the main loop, I could use some kind of return value that is passed up all the way from the error handler...· that would address the checksum issue, though it would slow down my time-critical main loop.· In order for it to help with the SERIN, I'd also have to pass the return value up two levels to the main loop.· Life would be so much easier if subroutines could legitimately return a value... even PIC assembly can manage that; you'd think PBASIC could.

    Thanks for your help.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax

    Post Edited (Jon Williams (Parallax)) : 7/12/2005 8:14:02 PM GMT
  • Nightrider7731Nightrider7731 Posts: 46
    edited 2005-07-13 17:43
    Is there a way to clear the stack of an unknown quantity of GOSUBs without throwing an error?· I've been working on an app with two main code blocks.· Each block has·an equal·quantity of GOSUBs and RETURN pairs, and each block calls each other (with GOTOs) under given situations.· I'm confident that I've closed out each GOSUB with a RETURN before I call the GOTO, but it has required a lot more coding than I would like and the increase chance of missing something.· It would be nice if I could execute the GOTO statement and then make a call to clear out any remaining GOSUBS on the stack before continuing the block.
  • Tom WalkerTom Walker Posts: 509
    edited 2005-07-13 20:00
    At the risk of shounding harsh, there should never be a function needed to "clear out the GOSUBS". With good coding, there should never be an instance in which the stack should remain "dirty". I realize that it's somewhat of a lost art, but a good flowchart might help the code design. If you haven't spun through the "Elements of PBASIC Style" and the WAM texts, these might be a good step to take.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Truly Understand the Fundamentals and the Path will be so much easier...
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2005-07-13 20:08
    Hello,

    ·· Following proper programming guidelines can also save you a lot of headaches down the road.· I had a colleague who worked on some code for a controller once that had some hardware added to it at a few points.· At some point everything stopped working properly, but they couldn't find the problem.· What happened was there was a bug in one of the original routines that didn't cause a problem for a long time, and so was ignored.· But when the program got larger it certainly became a problem, and three programmers missed it, because they all assumed that it had to be something in only the added/modified code.· They never checked any of the original routines.· Fortunately for them I am more thorough, but it still took me several hours to isolate at their cost.· In the end it was discovered that the original programmer knew there was a potential problem, but it didn't seem to hurt anything, so he left it.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
    csavage@parallax.com
  • YanroyYanroy Posts: 96
    edited 2005-07-14 14:08
    As I understand it, the reason exceptions were added to C++ was to combat this very problem.· I guess the closest thing to this in PBASIC is the return-variable idea you guys have suggested.· I'll do it that way and hope the speed loss isn't noticeable.· Thanks for your help.

    It seems I may have inadvertently insulted Mr. Williams (or perhaps just PBASIC, and thus parallax).· Allow me to offer this explanation, though you may not like it.· I've been using stamps for more than 7 years now.· I initially bought one after becoming involved in the FIRST robotics competition and learning it was the core of the robot controller.· After a year or two of playing with that BS2, I started a project that would have required 6 of them and decided to go the route of PIC chips purely for cost reasons.· Since then, I use the stamps exclusively for proof-of-concept and temporary circuits, since they allow such rapid and easy development, and·I·use PIC chips for most other things·because of the higher execution speed and lower cost.· The project that spawned this post was a prototype I made for a summer job I had in high school (before I knew PIC chips existed) and now I've been asked to come back and adapt it and the robot it controls to a new mission.· If I've allowed my frustration to show through into my posts, I apologize.· Stamps serve a very vital role, I just don't believe this particular application is one of them.

    Post Edited (Yanroy) : 7/14/2005 2:24:58 PM GMT
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2005-07-14 14:42
    I wasn't insulted -- I just refuse to allow ignorance of our products to be promoted as a product problem. The code you posted demostrates that you haven't fully learned how to take advantage of PBASIC (perhaps it's an old program and you'd do it differently starting from scratch). Even so, PBASIC on the BASIC Stamp may not be best for this specific application.

    We understand the cost issue and have worked very hard the last year to address that: we lowered the cost of SX development tools and chips, we introduced a FREE BASIC compiler for the SX (SX/B), and just recently we introduced SX48 and SX52 proto boards -- fully populated -- for $10. Where else are you going to find a deal like that?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
Sign In or Register to comment.