Using P2 Spin to create an array of text strings
DiverBob
Posts: 1,108
Using P2 Spin, I have a buffer defined in a var as a long, outbuf[400] that contains a long string. I would like to store up to 6 of outbuf[400] values referenced via another array, movebuf[6]. I haven’t run across any obvious examples in my search for code. My initial test of just storing the strings into movebuf didn’t work out although my code could be at fault (it was getting late and I was tired!), thought I’d ask the coding experts for ideas before I hit it again today.
Bob
Comments
I'm sure there are better ways of doing this but this is one way I'm using in my current project.
I have a method which will let me find a specific text string in a list.
I use the above method to fill an array with the start of each of the strings.
Here's an example call to FillStringPointers().
Here's the data used in the above.
After FillStringPointers() is called, the array zMenuIndex will contain the address of each string listed under zMenuLine.
The address of each string could have been entered into the zMenuIndex but this would add an extra element to the program I didn't want to when writing the above code.
A text string could be accessed using:
The above command would send "Set Units" to the UART.
Edit: In case it's not obvious, here's the constant defined.
An alternative technique of storing text arrays is to use the same number of bytes for each string. This will end up having wasted space since there will be a lot of empty bytes.
Here's an example of this technique.
Here the address of a specific string can be found by multiplying by the largest string allowed.
For example:
The above command would send the text "KG/" to the UART.
Using the fixed length technique require more RAM but has the benefit of allowing the text to be altered by the program. The altered text just as to fix in the limited area. This is 11 bytes in the example above. You need to leave a terminating zero.
Thats an interesting approach to the problem, I need to walk through your code and make sure I understand what you are doing.
My case is a bit different as it appears you are using pre-defined strings in the DAT, my output strings are constantly changing and created on the fly. This has given me a couple of ideas to try out too!
This is for my hexapod where I create a string of number’s separated by commas on the fly that is then used by the corresponding hexapod leg for movement. Right now I create one movement string and the string sequence is sent off to its leg for action. Then it starts creating the movement string for the next leg. As each string is created via a very math intensive process, and I need to create 6 separate strings, I thought about doing all the math for each leg upfront, creating an array to temporarily contain the movement strings. After all 6 strings are created I could quickly index through the array sending the strings out more quickly rather than having the lull between string creation due to the math.
Maybe I'm looking at things too simplistically, but I would start here.
Now you can create a few help routines that simplify your coding interface.
Am I out of whack?
Are the values being sent integers? If so, saving the values to send as strings seems like an extra (and unnecessary) complication.
I'd save the values you want to send as integers and then create the strings on the fly with "Serial.Dec()" type methods.
Jon's strategy is pretty much the same as my second strategy but Jon's is a lot easier to read. I just copied a section from a project I'm currently working on. Jon was extra nice and wrote easy to read code.
Jon's code is always easy to read! The string consists of a series of integer like this: "$2,900,0,900,1" where the "$" is the start character followed by the robot leg the string affects, the commas separate integers representing angle data to the robot leg controllers. The string is built on the fly based on the desired movement. Duane, I like the code example you sent as it gave me other ideas to try out also.
Thanks, guys, for the kind words about my coding style. To me, writing code appeals to my technical and artistic sides.
Seeing the construction of Bob's string reminded me about a project I did for the P1 several years ago called jm_hfcp.spin (human friendly control protocol). Like Bob's strings, it uses plain text to send commands and values from point A to point B (and back if needed). Over coffee I thought I'd explore porting that to the P2, and see if Bob would share how he's building his strings. Keeping it simple, I made these to methods.
I tested with this:
...which produced the string Bob described in his comment. Since the P2 makes inline assembly possible, I thought I'd convert putdec() to see if there's a benefit.
The inline assembly version will trim 30%-50% of the time required to convert a non-zero value, so it might be worth using. I did it an an exercise. Note, though, the it won't work with NEGX -- to me this is an unlikely value in a control program, so I didn't burden the conversion code with handling it.
In acting, take 1 is usually a warm-up, and things get better with take 2. After a few hours of day-job work, I took a lunch break and went back to my jm_hfcp code. The dec() method in that object does correctly deal with negx so I ported it to the P2, adding early exit for 0.
It's a bit slower than the code above for having to deal with the negx fix-it flag. I ported it t inline PASM and it's a big speed boost over the Spin2 version. This is what I'll have in my P2 version of HFCP. This early exits on 0, and handles negx correctly.
Here is the method I'm using for creating my strings. Based on the notes, you made the suggestions that went into creating this on the P1 a while back!
Thanks for the additional suggestions, I like your newest string builder, especially the PASM version. I can use the 2 versions to help me in learning PASM which is a task I've been putting off for a while. I especially need to convert the math heavy Spin code over to in-line PASM as it could really use the speed increase.
This gives me something to study on the plane tomorrow as my wife and I head out of this land of ice and snow to much warmer climates for a break!
Thank you Jon for all your input, I have quite a bit of code inspired or written by you in my robot!
Bob
JonnyMac, your example code for putting strings into an array got me thinking and searching the Spin commands, so I came up with this as another possible solution. The debug output shows the expected values at the correct locations.
You indicated speed was so I was thinking that having each of the routines return pointer to the next available character in the buffer might help versus always having to use strsize() to find the length of the buffer. The code you showed might be changed to this:
...using these methods
I love having inline PASM to experiment with, and to add speed updates in many places. That said, there are elements of the Spin2 interpreter that are amazingly efficient, so it's always best to do an emperical test. I do it with this simple code.
Sometimes this test will reveal that the manual PASM isn't worth the effort, but the only way to know is to write the code and test.
Decided to try a couple more number-to-string conversions in PASM2 while watching the Daytona 500. These produce fixed-width strings.
Thanks Jon for all the input. Unfortunately I’m well away from my stuff in snowy Michigan and enjoying the warm sands of Maui for a bit before I can get back to my computer and try these out. I appreciate all you have done to help me and others out over the years.