Shop OBEX P1 Docs P2 Docs Learn Events
If loop — Parallax Forums

If loop

In the snippet, when I type in "ledoff", the led goes off. Then I type in "ledon" to turn the led on, nothing happens. It seems like the elseif is not being invoked. I tried using the case method, I had no success. I am not sure what I am doing wrong with the if / elseif loop. Need some help.

Thanks
Ray

    repeat
        term.fstr0(string("What do you need."))
        get_str(BUF_SIZE-2)
        term.fstr1(string("%s"),@buffer)
        term.fstr0(string("\r"))

        if (buffer := "ledoff")
           pinl(38)
        elseif (buffer := "ledon")
           pinh(38)

Comments

  • JonnyMacJonnyMac Posts: 9,723
    edited 2026-03-07 19:57

    You're not showing the code for get_str() -- you should allow others to be able to run your code.

    A few errors:
    1. The := operator is for assignments; the == operator is for testing equality
    2. There is no string type in Spin so you cannot use ==, anyway.
    3. You need @ to point to a string buffer

    Spin has as built-in function called strcomp() that lets us check for matching strings. Give this a try.

      repeat
        term.fstr0(string("What do you need."))
        get_str(BUF_SIZE-2)
        term.fstr1(string("%s"),@buffer)
        term.fstr0(string("\r"))
    
        if (strcomp(@buffer, @"ledoff"))
          pinl(38)
        elseif (strcomp(@buffer, @"ledoff"))
          pinh(38)
    

    TIP: If you use an IO pin in more than one place you should give it a name so that editing your programs will be easier. I know you're just getting started, but this good habit will save you a lot of trouble later.

  • RsadeikaRsadeika Posts: 3,901

    OK, that did the trick. Since I plan to add other choices, would using case be a better option. I would need an example of how I would implement that in my code.

    In this program I used get_str(), how would that be used if the code were placed in the jm_fullduplexserial object.

    I am thinking that for other people just getting started maybe this program would be beneficial.

    '' test_term.spin2
    ''
    
    CON
        CLK_FREQ = 200_000_000
        MS_001 = CLK_FREQ / 1_000
        US_001 = CLK_FREQ / 1_000_000
    
        _clkfreq = CLK_FREQ
    
    
    con {terminal}
    
        BR_TERM = 115_200
        BUF_SIZE = 32
    
    
    
    obj
    
        term : "jm_fullduplexserial"
    
    var
    
        byte buffer[BUF_SIZE]
    
    
    PUB main()
    
       setup()
       term.rxflush()
       term.rx()
    
       term.tx(term.CLS)
       ''waitms(1000)
    
    
        term.fstr0(string("Enter your name: "))
        get_str(BUF_SIZE-2)
        term.fstr1(string("%s"),@buffer)
        term.fstr1(string("\r\rHello,%s,good luck\r"),@buffer)
        waitms(500)
    
        repeat
            term.fstr0(string("What do you need."))
            get_str(BUF_SIZE-2)
            term.fstr1(string("%s"),@buffer)
            term.fstr0(string("\r"))
    
            if (strcomp(@buffer, @"ledoff"))
               pinl(38)
            elseif (strcomp(@buffer, @"ledon"))
               pinh(38)
    
    
       ''repeat
        ''waitct(0)
    
    
       repeat
    
    
    pub setup()
        term.tstart(BR_TERM)
    
    pub get_str(maxlen) : len | k
        bytefill(@buffer, 0, BUF_SIZE)
        term.rxflush()
        repeat
            k := term.rx()
            case k
                31..127 :
                    if(len < maxlen)
                        buffer[len++] := k
                term.BKSP :
                        if (len > 0)
                            buffer[--len] := 0
             term.CR :
                buffer[len] := 0
                return
    
    
    
    
    
  • JonnyMacJonnyMac Posts: 9,723
    edited 2026-03-08 17:39

    I am thinking that for other people just getting started maybe this program would be beneficial.

    In my opinion, string processing is not a beginner topic with the Propeller, but if want to do it I'll share my experience (as I'm sure others will, too). What I share comes from real-world (i.e., commercial) projects. Some of the tricks I'll show I used in a P2-based coprocessor system for a medical device. The main computer sends string commands to the P2 which turns those into IO signals and low-level things that the PC can't directly control (servos, LED brightness, etc.).

    Since I plan to add other choices, would using case be a better option.

    You can't use case directly with strcomp(). What you can do, though -- and this is what I do in programs that use single string commands -- is convert the string to an index value that can be used with case. This may be a little advanced, so I'll explain it piece-by-piece.

    Step 1. Move your command strings to a list. It is very important that each string have just ONE terminating zero -- except the last which needs one extra zero for the search/indexing method.

      s_Commands            byte
      s_LedOff              byte    "ledoff", 0
      s_LedOn               byte    "ledon",  0
      s_Flash               byte    "flash",  0
      s_Help                byte    "help",   0
      EndOfList             byte    0
    

    Technically, you don't need to give each string a name, but I like to do it for flexibility.

    The next step is to take the string provided by a user and compare it to items in the command list. This uses another string function in Spin called strsize() which returns the length of a string (count of characters up to, but not including, the terminating 0).

    pub str_to_idx(p_str, p_list) : idx | len
    
      repeat 
        len := strsize(p_list)
        if (len > 0)                                                ' more strings?
          if (strcomp(p_str, p_list))                               ' match?
            return idx                                              '  return list index
          else
            p_list += len + 1                                       ' skip unmatched string
            ++idx                                                   ' update index
        else
          return -1                                                 ' string not in list
    

    This is a little tricky -- but only a little. Once you understand it you'll appreciate what it saves you when searching through a list of 20 strings versus a giant stack of if-elseif clauses. Note, too, that it's atomic which means you can use it with different lists within the same program, and they can be of any length.

    Okay, here's how it works. We pass a pointer to our string (input command from user) and a pointer to our command list. There is an unconstrained loop inside this code so that we can process the whole list without having to know how many items it has. To do that we use strsize() at the top of the list. If that is greater than zero there are still strings to process; if not we return -1 to tell the caller that string was not found. Let's assume we have a string. We use strcomp() with the list pointer. If there is a match we return the current index. Remember, the return variable (idx) is automatically set to 0 when we call this method so we don't have to initialize it manually. Let's say that the string isn't a match. We jump over it by adding the length of the current string plus one to the list pointer. Again, the plus one gets us past the current string. We also update the index when skipping a unmatched string.

    Now we can use case to process the string index.

    pub process_command(cmd)
    
      case cmd
        0     : pinlow(LED)
        1     : pinhigh(LED)
        2     : flash_led()
        3     : term.str(@s_HelpMenu)
        other : term.fstr0("\rInvalid command  \r")
    

    Remember that the position of the command string in the list determines its list index. When I build systems using this code I put frequently-used commands at the top of the list.

    Okay, take a breath and dive in. The attached program works. If you read this through a couple times and experiment with the code it will begin to make sense (again, this is not a beginner topic). I love using string commands. Long term, you'll want to get into a string parser where you can enter a complex string, break it into it's constituent parts, and then operate on them. That's a lot of fun.

  • RsadeikaRsadeika Posts: 3,901

    Thanks Jon. I just started to look at your command demo object. I am now using Spin Tools exclusively, when I ran your program, in the Spin Tools terminal, all I see is bunch of strange looking chars. I will see if I can figure out what is going on.

    Ray

  • JonnyMacJonnyMac Posts: 9,723
    edited 2026-03-08 18:00

    Check the baud rate on the terminal. I default to 230_400 because that's the default of FlexProp (which I don't really use, but test projects with when I'm going to do a public presentation). With P2 smart pins we can actually have much higher rates. DEBUG commands, for example, use 2M baud.

  • JonnyMacJonnyMac Posts: 9,723
    edited 2026-03-08 21:34

    Note, too, that it's atomic which means you can use it with different lists within the same program, and they can be of any length.

    I sometimes get frustrated when someone in the forums drops a theory but doesn't demonstrate that theory with actual code -- like I did with that comment above. In order to not be one of those "say but don't show" types, I wrote the attached program while watching the F1 race last night. My laser tag colleague (JoshW) and I are working on a specification for a new product; in our discussions about features multi-lingual support came up. The attached demo is a simple way for multi-lingual support.

    As you can see in the program there is an English section:

    dat { english }
    
    ' Commands must be clean; no leading or trailing space padding
    ' -- only one 0 after each command string
    ' -- additional 0 to signify end of list
    
      s_EnglishCmds         byte
                            byte    "off",     0
                            byte    "on",      0
                            byte    "flash",   0
                            byte    "english", 0
                            byte    "spanish", 0
                            byte    "help",    0
      EndofEnglishCmds      byte    0
    
      s_EnglishHelp         byte    13, 13
                            byte    "Commands:",  13
                            byte    "-- off",     13
                            byte    "-- on",      13
                            byte    "-- flash",   13
                            byte    "-- english", 13
                            byte    "-- spanish", 13
                            byte    "-- help",    13
                            byte    0
    
      s_EnglishBadCmd       byte    13, "-- Invalid command", 0
    

    ... and a matching Spanish section (translation by ChatGPT and Google Translate):

    dat { spanish }
    
      s_SpanishCmds         byte
                            byte    "apagado",   0
                            byte    "encendido", 0
                            byte    "destello",  0
                            byte    "ingles",    0
                            byte    "espanol",   0
                            byte    "ayuda",     0
      EndofSpanishCmds      byte    0
    
      s_SpanishHelp         byte    13, 13
                            byte    "Comandos:",    13
                            byte    "-- apagado",   13
                            byte    "-- encendido", 13
                            byte    "-- destello",  13
                            byte    "-- ingles",    13
                            byte    "-- espanol",   13
                            byte    "-- ayuda",     13
                            byte    0
    
      s_SpanishBadCmd       byte    13, "-- Comando invalido", 0
    

    There is a global variable for the language that drives language-dependent process, e.g., which command list to use or which help string to display.

    One of the nice features of the terminal in Spin Tools is that it has a line input mode; this lets you edit a line before pressing Enter which sends it to the Propeller. You need to enable line input in the Preferences dialog.

    There is no need to change the get_str() method as that will work with the Spin Tools terminal in either mode, or with PST which only does character mode. What's nice about the Spin Tools line input mode is that it has a history list. This can be helpful when testing. Show the terminal history by clicking on the down arrow, select an item, then press Enter. Easy-peasy. Note that this input line at the top of the Spin Tools terminal (STT) is only visible when in Line Input mode is enabled (it's white -- the yellow in this image is my highlight).

    Finally, the multi-lingual demo only has one output line, but in the real world (e.g., our upcoming laser tag project) we'd have more than that. No problem: we simply create a list of output strings like we created a list of command strings and then use this method -- it is a mirror for the str_to_idx() method. We have an extra parameter here for the string to show if the index is outside the bounds of the list.

    pub idx_to_str(idx, p_list, p_error) : p_str | len
    
    '' Return pointer to idx'th string in p_list
    '' -- p_error is pointer to string for bad index
    
      repeat
        len := strsize(p_list)
        if (len > 0)
          if (idx == 0)                                             ' at target?
            return p_list                                           '  return string pointer
          else
            p_list += len + 1                                       ' skip this string
            --idx                                                   ' update index
        else
          return p_error                                            ' bad index, shoe error string
    

    I've attached a simple demo that shows this in action.

  • RsadeikaRsadeika Posts: 3,901

    Thanks Jon. This will take me quite a while to really figure out what is going on with the code. Some of this is a little different from what I am used to.

    I am using the Edge 32 mb board with uSD slot. I have two LED lights 38 and 39. I wonder if their is some code for a small editor code to make use of storing info on an sd card. For that matter maybe using a small editor for use with the 32 mb. No, I am not leaning towards an OS for the P2, just some system tools for dealing with the P2.

    Just some thoughts about what I might try next.

    Ray

  • JonnyMacJonnyMac Posts: 9,723

    I'm not a fan of the idea -- that some support -- of doing development directly on the P2. Microcontrollers have limited resources, anyway, so my opinion is using them to do development is not a wise use of those resources. But that's me.

    I have two LED lights 38 and 39.

    This illustrates the value of CONstant definitions in code (any code, any language). In your case you could easily update the board LED definitions like this:

      LED_39   = 39  { O }                                          ' Edge-32M LEDs
      LED_38   = 38  { O }
    
    
    con { app io pins }
    
      LED      = LED_38
    

    This will take me quite a while to really figure out what is going on with the code.

    Go slowly. It will get easier if you spend a little time each day. I'm lucky that my job causes me to write Propeller code most days, but I still pop into the forums to learn new things -- often by helping others.

    Some of this is a little different from what I am used to.

    Be careful not to let what you know get in the way of learning way you want to know. Spin is its own language; if you accept it for what it is your learning will be easier. To me, there is value in learning different languages because a change in perspective can sometimes be helpful.

  • RsadeikaRsadeika Posts: 3,901

    I have some rpi 3 around the house doing some work. I wonder if I could get the P2, less a direct connection, make contact with the rpi 3. Not sure what kind of capabilities the P2 and WiFi have, if any. I noticed that Parallax sells a Bluetooth device, not sure if their is any P2 support for that.

    Ray

  • JonnyMacJonnyMac Posts: 9,723

    I've used simple Bluetooth for coms between an Android phone and a P1 -- this is where being able to process strings is helpful because you can develop and test from the keyboard, then use Bluetooth (or any other wireless serial connection) later. At the moment I am exploring LoRa for Propeller coms.

  • RsadeikaRsadeika Posts: 3,901

    I just checked the adafruit site and they sell some kind of LoRa device for the rpi. Not sure who would be developing a LoRa for the P2, but that sounds like a more useful way to go with the P2, in terms of expanded functionality. I think that with the P2 WiFi you get very limited functionality.

    Ray

  • JonnyMacJonnyMac Posts: 9,723
    edited 2026-03-10 00:24

    I just started experimenting with these:
    -- https://www.amazon.com/REYAX-RYLR998-Interface-Antenna-Transceiver/dp/B099RM1XMG/

    The message mechanism is text, so your experiments with text processing could end up with a command that looks like this

    AT+SEND=25,5,LEDON

    This message is for device 25 and is 5 characters long. It's pretty easy to build a method that takes the message target address and string to build an AT message for the LoRa module.

    Taking my own medicine, I'm moving slowly. I've started with a program that lets me talk to the LoRa through the keyboard/terminal to adjust settings and send messages. I have verified that the messages are transmitted by using a second unit connected to the PC through USB adapter and another terminal.

  • RaymanRayman Posts: 16,126

    @JonnyMac that Lora is cool. Didn’t know about that one…

  • RaymanRayman Posts: 16,126

    Darn it…. Somebody already thought of using Lora for walkie talkie…

    Still walk in the Park for P2…

  • RossHRossH Posts: 5,717

    @JonnyMac said:
    I'm not a fan of the idea -- that some support -- of doing development directly on the P2. Microcontrollers have limited resources, anyway, so my opinion is using them to do development is not a wise use of those resources. But that's me.

    Back in the Propeller 1 days I would have agreed with you, because self-hosted development was never practical on the Propeller 1. And of course everyone wanted full-blown Unix, which was just a pipe dream on the Propeller 1, and probably (I have learned "never say never" when it comes to the Propeller) remains so even on the Propeller 2. However, if you have slightly more realistic expectations about self-hosted development, then a Propeller 2 with PSRAM has more than enough resources, and - to be honest - I now can't imagine doing without it.

    Using a compiled language like C or Spin is now possible but I agree it is still not very practical because the speed of the PSRAM is too slow for executing a big language compiler (but @rogloh is working on a new external memory driver that may help with that). However, PASM development is already practical, and so is Lua (and Forth of course, if you are fluent enough in Polish to both read and write it backwards :) ). And I mostly now only use C to launch and support Lua anyway.

    I tend now to play with large applications distributed on multiple Propellers, and I routinely have 2 or 3 connected to my PC when testing new code. Having to extract and reinsert all the SD cards each time I wanted to make even just a one line source code change is daunting - I had to do it for a while, but I would not want to have to go back to that again. I have worn out several SD card readers, and now I worry about wearing out the sockets on the P2 boards themselves. Even downloading is too time consuming, because the programs can be hundreds of kilobytes or even megabytes in size, and make one silly mistake and you have to do it all over again. So self-hosted development is the answer - at least in Lua, if not yet in C.

    So while I still do the C work (which implements all the "legwork") on a PC, for all the Lua work (which implement all the "smarts") I now mainly use the Propeller itself - editing, compiling and testing. I don't use Lua on my PC at all.

    As a result, my turnaround time for trying out new ideas, or implementing new functionality, is much faster than it used to be, and I am now back to enjoying working with the Propeller again, rather than being a slave to its demands.

    Ross.

  • RaymanRayman Posts: 16,126

    I love the idea of self hosted development. Even if maybe a rare case to really need it…

    We have a spin compiler for P1. Not for P2? Opening I guess.

    C compiler is of course the best even if takes a while.

    Think we have a Python compiler too for P2.

    Lua sounds good, maybe something like Python.

  • RaymanRayman Posts: 16,126

    Kind of funny that the first post error happens in C++ too with people using = instead of ==. Also not flagged as error but definitely not what you probably want to do…

Sign In or Register to comment.