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
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.
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 returnIn 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.).
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.
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 listThis 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.
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
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.
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", 0There 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 stringI've attached a simple demo that shows this in action.
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
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.
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_38Go 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.
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.
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
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.
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
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,LEDONThis 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.
@JonnyMac that Lora is cool. Didn’t know about that one…
Darn it…. Somebody already thought of using Lora for walkie talkie…
Still walk in the Park for P2…
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.
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.
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…