Menu

Problem with String Variables - comparisons and string re-assignment not working as expected

Help
2017-12-15
2017-12-24
  • George Alvarez

    George Alvarez - 2017-12-15

    Hi everybody, Windows 7 and Great Cow BASIC (0.98.01 2017-10-27).

    I wonder if there is something about string variables that I'm missing. Not a microprocessor guy, so while I've read the forums and come to learn that strings are an array of single strings, I'm not sure what all the implications of that are. I'm having unexpected problems and I don't understand why.

    Snippets of code are below. I'll post the whole thing if you need it, but I'm sure I'm not missing anything I've left out:

    ; ----- Configuration
      #chip mega328p,16
      #option explicit
      #include <glcd.h>
    
    ...     ' meaning, I'm skipping some code
    
    ; ----- Menu Variables
     Dim v_text as string * 20
      Dim v_x,v_y,v_mult,v_spac,level,item,item_len,cum_item_len,v_i,v_h,v_height as Byte
      Dim v_x1,v_x1,v_x2,v_y1,v_y2,menu_len,v_max_menu,v_inot as Byte
    
      Dim menu as String * 8      '<---------------
    
      Dim menu_text as String * 16
      Dim v_menu_err as String * 32
      v_mult = 6
      v_spac = 7
      v_height = 21
    
     menu = "1"                  '<---------------
    
      item = 1
      v_x = 0
      v_y = 0
      item_len = 0
    
      ...
    
      ; ----- Initialize the display
    '  GLCDCLS
    '  CenterBanner("NNS")
    '  Wait 5 s
    '  GLCDCLS
      GoSub Intro  ' Prints the introduction screen
    
     menu = "start"          '<-------------
    
      WAIT 50 ms
     ' GLCDCLS
    ' displays and waits for a button push
    
    ...
    
     'track button presses - required to manage serial display only
      old_state = 0
    
      do forever
         'determine the state of the switch
         current_state = switch_event
    
         'if the current state is not the same as the saved state then print current state
         if current_state <> old_state then
    
            if current_state = BUTTON_RELEASED then
              Select Case stable_count
    
                Case 1 to 19
    
                  if menu = "start" then               '<-------------
                     HSerPrint "first menu is "
                     HSerPrint menu 
                     HSerPrintCRLF              
                     menu = "1"
                     item = 1
                     HSerPrint "then menu is "
                     HSerPrint menu
                     GoSub First             '<-------------
                   else
                     v_button = 1
                     item = item + 1
                     GoSub Menu_two
                     stable_count = 0
                   end if
    
    ...
    
    Sub First()
    
      HSerPrintCRLF
      HSerPrint "Here in First"
      HSerPrintCRLF
      HSerPrint len(menu)
      menu = "1"
      GoSub PrintMenuHdr
    
    End Sub
    
    Sub PrintMenuHdr()
    
    ; ----- item always = 1 if you get here
      item = 1
      HSerPrintCRLF
      HSerPrint "Here in PMH() - menu is "
      HSerPrint menu
    
      FilledBox(0,20,128,32,0) 'erases the submenu area
      'Wait 5 s 'debugging only
    ; ----- define the menu header text
      If menu = "1" Then           '<-------------- this doesn't work
        menu_text = "MAIN"
        HSerPrintCRLF
        HSerPrint "in IF stmt"
        HSerPrintCRLF
      HSerPrint "Menu text is "
      HSerPrint menu_text
      End if
    
      ...
    

    The text MAIN does not print on the LCD. I get L@MH instead.

    Here is the output from the terminal:

    first menu is start
    then menu is 1
    Here in First
    1
    1
    Here in PMH() - menu is 1

    The comparison where I want to define the value of menu_text doesn't think "1" = "1", and it skips that entire IF statement, and assigns that funky value that exists nowhere in myscript.

    I can solve my immediate problem simply by comparing a byte variable to an integer instead:

    ' If menu = "1" Then             '<-------------- this doesn't work
    if v_button = 0 then
    

    That works, and the code drops through the IF statements and everything looks good and works as expected. So I have a solution to my immediate and practical problem.

    But I'm wondering what it is about strings that I don't understand. One byte per letter, right? My DIM size is sufficient? Is "start" a reserved word? What's going on here?

    I'm at a loss.

     

    Last edit: George Alvarez 2017-12-15
    • Anobium

      Anobium - 2017-12-15

      You have what connected the microcontroller? A GLCD? or an LCD? and a serial Terminal?

      <include glcd.h=""> would tell me you have GLCD but then you dont seem to specifiy which type.
      You write of incorrect output on the LCD but you are addressing the Serial connection with HSerPrint.</include>

      Attach the whole code else we cannot really understand.

       
  • George Alvarez

    George Alvarez - 2017-12-15

    Hi, yes, a (G)LCD, also, terminal supplied with SynWrite attached. I've attached the code to this post.

    The serial connection doesn't seem to impact the lcd output. What appears to impact the output is the use of strings to make decisions.

    Entire code is attached. By the way, this is the same code that creates the crashing problem reported here.

     

    Last edit: George Alvarez 2017-12-15
  • Anobium

    Anobium - 2017-12-16

    @George. Ping me. This code is highly complex and you need to implement a state engine or something a tad easier to debug. The code is doing what you ask it to.

    I have this working on the bench here. I get some menus come up. There use of strings was/is interesting to debug.

    But, what is ButtonPressed doing? An interrupt that is not managed? When you are writing to the GLCD the button be pressed, or any PinChange0 event will interrupt the transmission to the GLCD or the Terminal this will mess up.

    But, re the strings. Those comparisions will be working as expected menu = "1". This will be slow, slow, slow... Select Menu Case "1:1:11:3" will be even slower. Consider using set of numbers rather than strings.I get the following on the terminal.

    1
    Here in PMH() - menu is 1
    in IF stmt
    Menu text is MAINfirst menu is start
    then menu is 1
    Here in First
    1
    1
    Here in PMH() - menu is 1
    in IF stmt
    Menu text is MAINfirst menu is start
    then menu is 1
    Here in First
    1
    1
    Here in PMH() - menu is 1
    in IF stmt
    Menu text is MAINfirst menu is start
    then menu is 1
    Here in First
    1
    1
    Here in PMH() - menu is 1
    in IF stmt
    Menu text is MAIN
    

    and, the GLCD.

    MAIN
    
       key Website  QUIT
    

    So, back to you. I am not sure I understand the issue. Now I have it on the bench - can you restate the question.

    See https://www.dropbox.com/s/y8k3g4kzdkcm7l6/Nashvilla.wmv?dl=0. This is using a different GLCD as this was attached to my board. So, the layout is dfferent.

     

    Last edit: Anobium 2017-12-16
  • George Alvarez

    George Alvarez - 2017-12-16

    Hi,

    Thanks for the offer of a one-on-one. Three questions to start out:

    1) how do I ping you?
    2) what time zone are you in? I'm in Eastern US, UTC - 5
    3) is any day/local time better or worse for you

    My issue is that mine is not doing what it is supposed to do, that is to say it is not doing what yours does. For whatever reason, the assignment of strings to the menu variable is not working reliably, and I don't understand the issue. I also have that same display hooked up too, except mine is the one with the strip of yellow at the top. Other than where the text displays, I wouldn't think that makes a difference, as long as we're using the same driver. I'm running both the big one and little one at the same time. It hasn't been a problem.

    I've modified the code since I posted, so just to make sure, I reloaded the code from here in the forum, so that we're running the exact same thing.

    What is my question?

    To begin with, notice the difference in terminal output between you and me. I get this:


    first menu is start
    then menu is 1
    Here in First
    1
    1
    Here in PMH() - menu is 1


    and you get this:


    first menu is start
    then menu is 1
    Here in First
    1
    1
    Here in PMH() - menu is 1
    in IF stmt
    Menu text is MAIN


    We don't get the same results.

    Here's what happens in the program:

    The Intro displays
    On 122, menu is set to "start"
    User presses a button, short click
    On 155 menu is compared to "start" and sent to First()

    So far, we're both in sync.

    In First, I print a few more statements to terminal
    I set a redundant menu = "1", probably from earlier testing
    The next step is PrintMenuHeader()
    I print a couple more statements to terminal.
    The filledbox statement erases what I call the submenu.

    This is the last point where the behavior we see is that same. After that, it diverges. I wonder why.

    On 344, I again compare the variable menu to the value "1"
    If it is the same (which it should be) then I change the value of menu to "MAIN"
    I print a few more statements to the terminal for proof
    A series of if statements get evaluated, the one on 355 should execute
    Then, on 373, the LCD should display the word MAIN.

    Yours does, and mine does not. Mine displays L@HN. Mine also displays the wrong submenu. I see the one where the length of the submenu = 5.

    It appears to me that the comparison where I evaluate the value of menu_text doesn't think "1" = "1", and so it skips that entire IF statement (for me, but not for you), and in my case, it assigns that funky value that exists nowhere in myscript. We're running the exact same code, and I don't understand why we'd get two different results.

    I made a couple of changes to the script to see if I could chase down what was happening, then I reloaded the version from here in the forum again. Having done that, now the program doesn't act the way I just described. Now it is acting very erratically. A movie will show you why I can't describe it well. Take a look: Video

    Maybe the memory is badly fragmented because of the way I've written my code? Have I mucked up the microcontroller somehow?

    Thanks

     

    Last edit: George Alvarez 2017-12-17
  • George Alvarez

    George Alvarez - 2017-12-16

    After running a far simpler script, my unit is behaving better, but not perfectly. I started to see these problems as the program memory approached 16K. The Nano is 32K, so I wouldn't think that is a problem and maybe it is just coincidental. I'll try to dream up a numeric scheme to keep track of my menu and see how that works.

    The previous post has a youtube video link, I'm guessing that's why it needs to be moderated.

     

    Last edit: George Alvarez 2017-12-16
  • George Alvarez

    George Alvarez - 2017-12-16

    Also, can I address this with you?

    But, what is ButtonPressed doing? An interrupt that is not managed? When you are writing to the GLCD the button be pressed, or any PinChange0 event will interrupt the transmission to the GLCD or the Terminal this will mess up.

    I act on BUTTON_RELEASED. Given that, what I understand you to mean is that I need to change the code to Ignore the PinChange0 event immediately after I detect a BUTTON_RELEASED and then I also need to re-enable it after I'm done doing whatever I do, then after that, I can return to the endless loop.

    If I don't do it in this way, button presses (and maybe random button bounces) could disrupt the output to the LCD and Terminal.

    Is that what you mean?

     

    Last edit: George Alvarez 2017-12-16
  • George Alvarez

    George Alvarez - 2017-12-17

    Hi Anobium,

    I've come up with a new method to display the menu using numbers. Hopefully, I will make all the adaptations tomorrow, and then I'll figure out a way to recognize my choice using numbers, and this will take care of all my problems. Having had the experience of working through some bugs in this script to get it working, I think that my problem is that at least one variable is poorly defined in the script I sent you earlier. I haven't found it yet. The only thing that gives me pause is that it works on your setup, so I don't know. But poor variable definition in this latest effort caused some similar-looking problems.

    Anyway, here's the beginnings of the new menu display script, it will give you an idea of how I'm going to do it. The one thing that would make this script much better is if I could somehow pass the name of an array into a Subroutine, and the Subroutine could recognize that I'm referencing an array so that I can work on it like an array. I tried a couple of methods, but each of them failed. I don't know that it can be done, but if you know how, I'd love to hear about it. Once I make the menu changes to my program, I'll report back to you, so just hang tight for now on my string problem. It might take a day or two.

    I would also appreciate it if you could give me a little clarity on the button issue you raised. The post before this one states what I understood, but I don't know if I got it right.

    Thanks for the generous offer to help. I'm learning a lot in a very short time.

     

    Last edit: George Alvarez 2017-12-17
  • Anobium

    Anobium - 2017-12-17

    George - I have helped you. Hope the attached is a lot easier for you.

    Each set of the menu options has an array. Using some things you may not be aware of ... I pass these arrays to the menu handler. Then, in this in menu handler as one clever line that then calculates the case for you then everything drops into place.

    The menu handler has no output (print etc) is call one method for this - then, you can extend this with ease. This approach will handle up to 10 items per menu - not enough? then, 16 is easy = change to Hex decimal addresing. :-)

    You need to add a state engine. The state engine with trach which menu you are looking at. Starting at menu, then, 1 etc etc.

    Pleasure.

     
  • Anobium

    Anobium - 2017-12-17

    And, then, I went and got a coffee. And, it was bugging me. Why the array? See attached.

    And, I flipped to hexidecimal also.

     
  • George Alvarez

    George Alvarez - 2017-12-17

    :-D I just realized, the concatenated strings WERE my state engine! :-D I guess what you're saying is that I need a better one. A MUCH better one.

    I'll admit, I'm going to have to study your latest one a little. I get the general gist of it, but there are a few subtleties that escape me at the moment.

    That little twist in the case statement is clever indeed. It is an elegant version of what I was attempting to do with the integers. My method had some shortcomings, but I didn't know what to do about them.

    I notice that the output of the submenu starts at 0x?1... the first item of each level is always skipped, so I have to work through why you've done that.

    I'm also thrown by lines 74 and 205 of your code, as they seem to be two Subs that have the same names. I notice that the one on line 74 doesn't appear to be recognized as a Sub structure by SynWrite. It lacks the collapsing graphical connector between Sub and End Sub. The difference seems to be the variable type of the in parameters, and the code appears to be smart enough to know which one you're calling based on that alone. Again, I'll have to look closely, hopefully I can get it.

    Thanks for all your help. I'll let you know when I've done something with this.

     
  • Anobium

    Anobium - 2017-12-17

    :-)

    Let us start with the easy one. Line 74 and 205. This was an error by me. Not intended at all. (but, this is called overloaded methods and I DID NOT intended to use overloaded methods).

    Re the missing first item - a bug.

    Start again with the attached!

     

    Last edit: Anobium 2017-12-17
  • George Alvarez

    George Alvarez - 2017-12-23

    Hi Anobium,

    Been a rough week, took a while to get things done. I just finished up the number-based menu state engine, and now things are working pretty much the way I want them to work.

    I finally figured out the problem I was having, where I would try to GLCDPrint the word MAIN, and it would come out as L@HN. As it turns out, it was caused by a stupid error I was making with the FilledBox command:

    FilledBox(0,20,128,32,0) 'erases the submenu area
    

    The extra pixel caused an overflow, and it happened to land in the word MAIN. Once I changed it to this:

    FilledBox(0,20,127,31,0) 'erases the submenu area
    

    all was well.

    Similarly, sometimes I was inadvertently writing a value into the 0 index of an array, which will also wreak havoc in strange ways. So I've worked out all those bugs now, and I'm almost finished with my little project.

    Thanks very much for your help, I learned a lot and it gave me some ideas that allowed me to reduce the size of my code by about 5K.

    Merry Christmas!

    George

     
  • Anobium

    Anobium - 2017-12-23

    You to hear of the success. Try using adding the contstant below. This will enable the GLCD library to protect the overrun issue you hit.

    #define GLCD_PROTECTOVERRUN 'prevent screen overdrawing

    Merry Christmas!

     
  • George Alvarez

    George Alvarez - 2017-12-24

    Here's another little gotcha I ran into tonight:

    Dim v_disp_idx_cnt
    

    will yield this on a compile:

    myscript.gcb (523): Error: Invalid variable name: (V_DISP_IDX_CNT)
    myscript.gcb (523): Error: Variable (V_DISP_IDX_CNT) was not explicitly declared

    if you enclose the variable in parentheses!

    One must be very, very careful, mustn't one?

     
    • Anobium

      Anobium - 2017-12-24

      Not sure about this. Can you post a very short example?

       
  • George Alvarez

    George Alvarez - 2017-12-24

    I could if I had version control! Unfortunately, I'm not able to reproduce the problem. I think it may have had something to do with another strange one, below. I've since cured it, and now I can't reproduce the problem I had with the parens. Let me describe that to you:

    I included this in my code to debug some positioning problems, and I began to get wacky text in one of my menu items:

              HSerPrintCRLF
              HSerPrint "1. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
              HSerPrintCRLF
              HSerPrint "Level, item = "
              HSerPrint level
              HSerPrint ", "
              HSerPrint item
              HSerPrintCRLF
              HSerPrint "v_i : v_box_x1_ra(v_i) = v_sub_textpos_x_ra(v_i) - v_box_offset(1)" 
              HSerPrint v_i
              HSerPrint " : "
              HSerPrint v_box_x1_ra(v_i)
              HSerPrint " = "
              HSerPrint v_sub_textpos_x_ra(v_i)
              HSerPrint " - "
              HSerPrint v_box_offset(1)
              HSerPrintCRLF
              HSerPrint "~~~~~~~~~~~~~~~~~~~~~"
    

    Because of my previous experience with MAIN vs. L@HN, I thought I might be injecting too many elements in an array or something like that to cause my problem. So I modified the above to include the following, and it made the problem worse, almost all of my text turned wacky:

    **          HSerPrintCRLF
              HSerPrint " ~~~~~~~~~~~ Line 559 - content between stars is text in variable ~~~~~~~~~~~~"
              HSerPrintCRLF
              HSerPrint v_menu_text
              HSerPrintCRLF
              HSerPrint "~~~~~ Goes bad here.  Execution of line 550 destroys variable ~~~~~~~~~~~~~~~~"**
    

    Here's an example of what I mean by "wacky":

    Supposed to be : Key

    Turned into : ra(v_i) - v_box_offset(1) --> À¿<0><0><0><0><0><0><0><0><0>(<0><0><0><0><0><0><0><0><0><0><0><0><0>&9<0><0><0>&9<0><0><0><0><0><0><0><0><0><0><0>

    Commenting all of these HSerPrint statements did nothing to cure this behavior. It finally dawned on me to pull the commented HSerPrint statements out completely, and the text returned to normal immediately.

    Anyway, the other thing that seems to have been cured is that I don't have problems with unnecessary parens any more.

     

    Last edit: George Alvarez 2017-12-24
  • Anobium

    Anobium - 2017-12-24

    If you can save these issues then we can help you resolve.

    Good luck. And, watch the pesky strings!

     
  • George Alvarez

    George Alvarez - 2017-12-24

    Seems to be working better now. I decided to become very disciplined with the code, made some changes for things I did because I was being lazy, and it paid off. I am trying to make fewer assumptions about what I can do than I made when I got started with this product.

    I will begin to keep versions of my code.

    By the way, I use another product like this where the option to save versions is given to the user. Under options, you set the number of versions you'd like to keep (5 for example) and it will save the new one, and copy the one before that to ver_1, the one before that to ver_2, etc. That way you always have the last 5 versions saved, just in case.

    Maybe that would be a good feature for SynWrite. Maybe it's in there, I haven't looked for it.

     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.