Shop OBEX P1 Docs P2 Docs Learn Events
combining strings with SPIN — Parallax Forums

combining strings with SPIN

TCTC Posts: 1,019
edited 2016-09-18 14:04 in Propeller 1
Hello all,

I have been trying for a couple hours to combine different strings and values, and make one string.

I used code from FullDuplexSerial to try and help, but it did not.

lets say I have in the DAT section,

sen_num  byte    "SENSOR_", 0
file_format  byte    ".CSV", 0


And I have a decimal value of 5 (not ASCII "5")

What I want in one variable is

"SENSOR_5.CSV"


Here is the code I have made, that doe not work. Is there something I am doing wrong?

PUB

  New_File(@sen_num, 5, @file_format)



PUB New_File(string_pointer, number, format) | string_temp, c, i

  repeat strsize(string_pointer)
    c := byte[string_pointer++]
    if c <> 0
        byte[string_temp++] := c

  i := 1_000_000_000                                    'Initialize divisor

  repeat 10                                             'Loop for 10 digits
    if number => i                                                               
      byte[string_temp++] := (number / i + "0")      'If non-zero digit, output digit; adjust for max negative
      number //= i                                      'and digit from value
      result~~                                          'flag non-zero found
    elseif result or i == 1
      byte[string_temp++] := "0"                                           'If zero digit (or only digit) output it
    i /= 10                                             'Update divisor

  repeat strsize(format)
    c := byte[format++]
    if c <> 0 
        byte[string_temp++] := c

  com.str(@string_temp)
  com.tx(13)


Thanks for any help
TC

Comments

  • The second last line should be com.str(string_pointer).
  • You also need to add a terminating null before doing com.str(string_pointer). You should add "byte[string_temp] := 0". So the last three lines will look like
      byte[string_temp] := 0
      com.str(string_pointer)
      com.tx(13)
    
  • TCTC Posts: 1,019
    edited 2016-09-18 15:32
    Dave Hein wrote: »
    You also need to add a terminating null before doing com.str(string_pointer). You should add "byte[string_temp] := 0". So the last three lines will look like
      byte[string_temp] := 0
      com.str(string_pointer)
      com.tx(13)
    

    Thanks Dave, But I am not displaying this on the serial terminal. This is to make a new file on a SD-card(file name). That is why I need it to be a variable. I only have the last 2 lines to check my code. But I will try adding a 0 to it. That might be where I am screwing up.

  • TCTC Posts: 1,019
    OK, this is a strange one from me. I do the changes
      byte[string_temp] := 0
    
      com.str(string("File Name --   "))
      com.str(string_temp)
      com.tx(13)
    

    and the prop will reboot when it hits
    byte[string_temp] := 0
    

    If I comment only that line, the prop will not reboot. There is nowhere in my code that tells the prop to reboot.
  • TC wrote: »

    and the prop will reboot when it hits
    byte[string_temp] := 0
    

    If I comment only that line, the prop will not reboot. There is nowhere in my code that tells the prop to reboot.

    Can you post the entire code? My guess is "string_temp" has been set to zero so you're writing zero to the first byte of RAM which messes up the Prop's clock settings. I've cause resets this way many times myself.

  • TCTC Posts: 1,019
    Duane Degn wrote: »

    Can you post the entire code? My guess is "string_temp" has been set to zero so you're writing zero to the first byte of RAM which messes up the Prop's clock settings. I've cause resets this way many times myself.

    I can, but it is really not that great. I still have a lot to do, I try to organised it when I can. Sorry about all the hacks. I'm working on 2 bugs now, one is this problem. The other one I am going to try to figure out if I can fix it first, before I ask for help.

  • TCTC Posts: 1,019
    OK, I cant even get this simple code working
      repeat strsize(string_pointer) +1 'the "+1" is only there to see the null-terminator
        c := byte[string_pointer++]
    
            byte[out_string++] := c
            com.tx(13)
            com.dec(c)   'I get correct value on "c"
            com.tx(13)
    
    
    
      com.tx(13)
      com.tx(13)
      com.str(string("out string --   "))
      com.str(out_string)
      com.tx(13)
      com.tx(13)
    

    I have tried different ways of doing " com.str(out_string) ". I have added the PRE-increment and POST-increment, i have tried the address symbol. And it will only show a few spaces and a "+".

    I am at wits end..... Please tell me what am I missing.
  • You appear to treat "temp_string" as both a buffer and a pointer. I turned it into a buffer and added a local pointer.

    Change the method "New_File" from:
    pub New_File(string_pointer, number, format) | string_temp, c, i
    
      repeat strsize(string_pointer)
        c := byte[string_pointer++]
        if c <> 0
            byte[string_temp++] := c
    
      
      if number <> -1
        i := 1_000_000_000                                    'Initialize divisor
         
        repeat 10                                             'Loop for 10 digits
          if number => i                                                               
            byte[string_temp++] := (number / i + "0")      'If non-zero digit, output digit; adjust for max negative
            number //= i                                      'and digit from value
            result~~                                          'flag non-zero found
          elseif result or i == 1
            byte[string_temp++] := "0"                                           'If zero digit (or only digit) output it
          i /= 10                                             'Update divisor
    
      repeat strsize(format)
        c := byte[format++]
        if c <> 0 
            byte[string_temp++] := c
    
      byte[string_temp] := 0
    
    '  com.str(string("File Name --   "))
    '  com.str(string_temp)
    '  com.tx(13)
    
      Check_Master_File '***** TEMP for checking *****
    
      return true
    

    To:
    pub New_File(string_pointer, number, format) | string_temp[3], local_pointer, c, i
    
      local_pointer := @string_temp
      repeat strsize(string_pointer)
        c := byte[string_pointer++]
        if c ' same as if c <> 0
            byte[local_pointer++] := c
    
      
      if number < 0 ' don't add number characters if number is -1
      
        i := 1_000_000_000                                    'Initialize divisor
         
        repeat 10                                             'Loop for 10 digits
          if number => i                                                               
            byte[local_pointer++] := (number / i + "0")      'If non-zero digit, output digit; adjust for max negative
            number //= i                                      'and digit from value
            result~~                                          'flag non-zero found
          elseif result or i == 1
            byte[local_pointer++] := "0"                                           'If zero digit (or only digit) output it
          i /= 10                                             'Update divisor
    
      repeat strsize(format)
        c := byte[format++]
        if c 
            byte[local_pointer++] := c     
    
      byte[local_pointer] := 0
    
    '  com.str(string("File Name --   "))
    '  com.str(@string_temp)
    '  com.tx(13)
    
      Check_Master_File '***** TEMP for checking *****
    
      return true
    

    You should be able to uncomment the section below without crashing your program:
    '  com.str(string("File Name --   "))
    '  com.str(@string_temp)
    '  com.tx(13)
    

    Rather than just checking or -1, the method will ignore any negative number since negative numbers will not work correctly in your algorithm.
  • TCTC Posts: 1,019
    Duane Degn wrote: »
    pub New_File(string_pointer, number, format) | string_temp[3], local_pointer, c, i
    
      local_pointer := @string_temp
      repeat strsize(string_pointer)
        c := byte[string_pointer++]
        if c ' same as if c <> 0
            byte[local_pointer++] := c
    
      
      if number < 0 ' don't add number characters if number is -1
      
        i := 1_000_000_000                                    'Initialize divisor
         
        repeat 10                                             'Loop for 10 digits
          if number => i                                                               
            byte[local_pointer++] := (number / i + "0")      'If non-zero digit, output digit; adjust for max negative
            number //= i                                      'and digit from value
            result~~                                          'flag non-zero found
          elseif result or i == 1
            byte[local_pointer++] := "0"                                           'If zero digit (or only digit) output it
          i /= 10                                             'Update divisor
    
      repeat strsize(format)
        c := byte[format++]
        if c 
            byte[local_pointer++] := c     
    
      byte[local_pointer] := 0
    
    '  com.str(string("File Name --   "))
    '  com.str(@string_temp)
    '  com.tx(13)
    
      Check_Master_File '***** TEMP for checking *****
    
      return true
    

    Duane.... YOU ARE AMAZING!! I've been trying for a couple hours to figure out what I was doing wrong. Thank you so much.
    Rather than just checking or -1, the method will ignore any negative number since negative numbers will not work correctly in your algorithm.

    I had to change it to
    ifnot number == -1
       "RUN CODE"
    

    Your way worked, but it would still place a "0" in line. I wanted it so that if I place a "-1", it would skip loading a number. Trying to combine code where I can, and make things a little more efficient.

    Again. Thank you so much.
    TC


  • TCTC Posts: 1,019
    You taught me a couple things,

    1) look out using a variable as a buffer AND a pointer. Could be a problem later
    2) I did not know why others did
    if c ' same as if c <> 0
    
    but now I know.

    Thank you
  • TC wrote: »
    ifnot number == -1
       "RUN CODE"
    

    Your way worked, but it would still place a "0" in line. I wanted it so that if I place a "-1", it would skip loading a number.

    Sorry, I had the inequality sign backwards and I forgot the "or equal" part.

    It should have been:
    if number => 0
    

    I think using your "ifnot" with my original "< 0" would also work.
    ifnot number < 0
    

    This way it would skip any negative number not just negative one. A negative number would not be processed correctly by the algorithm.

    TC wrote: »
    Thank you so much.

    You're very welcome.

  • JonnyMacJonnyMac Posts: 9,104
    edited 2016-09-18 22:22
    I do this kind of thing all the time -- and there's no need to concatenate strings given the result you're after. Setup your dat section like this
    dat
    
      FileName      byte    "sensor_0.csv", 0
    

    Now it's a simple matter of changing that character.
      FileName[7] := sensornum + "0"
    

    Okay, so you say you want to change the extension of the file name? That's easy too -- here's a little method that lets you set the sensor number and file type
    pub set_filename(sn, ftype)
     
      FileName[7] := sn + "0"
    
      if (ftype == 0)
        bytemove(@Filename[8], string(".csv"), 5)
      elseif (ftype == 1)
        bytemove(@Filename[8], string(".wav"), 5)
      else
        bytemove(@Filename[8], string(".err"), 5)
    

    We use 5 with bytemove so that we copy the string (period plus three characters) AND the terminating zero -- this is necessary for string methods.

    Here's an actual bit of code I wrote for my friend, Bob, who uses the AP-16+ (which I co-designed and coded) in fun little toys. His latest project will randomize one of a hundred files within one of eight groups. Press the group button, get a random file. Here's his dat section
    dat
    
      FileName      byte    "PCFA_000.WAV", 0                       ' 100..199 .. 800..899
    

    And here's the code that updates FileName before playing the file.
    pub make_filename(grp, fn)      
                                                                      
    '' Updates embedded string with file number
    '' -- gn is the group #                    
    '' -- fn is the file number (00..99)
    
      FileName[5] := "0" + grp
      FileName[6] := "0" + fn  / 10
      FileName[7] := "0" + fn // 10
    
  • You can make it simpler if you can guarantee that the filename won't be zero or negative ... seems like that should be a fair assumption. I had a similar idea for creating filenames for a SD card, and here's what gist of I came up with:
    DAT
      filename              byte      "LOG-xxxx.txt"
      
    PUB Record(counter) | t, i, m, div, value
    
      div := 1000                                                                                                  
      value := word[counter]                                                                                
    '...
      i := 4                                                                                                       
      repeat 4                                                                                                     
        if value => div                                                                                            
          filename[i++] := (value / div + "0")                                                                     
          value //= div                                                                 
        else                                                                            
          filename[i++] := "0"                                                          
        div /= 10                                                                       
    '...
      \sd.popen(@filename,"w")
    
    It doesn't combine strings, rather it overwrites part of the existing string. I fixed the length to four digits as I doubt I'll exceed 10000 recordings.
  • JonnyMac wrote:
    We use 5 with bytemove so that we copy the string (period plus three characters) AND the terminating zero -- this is necessary for string methods.

    If the period and terminator already exist in the target string, it's enough just to bytemove the three-character extension ... right?

    -Phil
  • TCTC Posts: 1,019
    JonnyMac wrote: »
    I do this kind of thing all the time -- and there's no need to concatenate strings given the result you're after. Setup your dat section like this
    dat
    
      FileName      byte    "sensor_0.csv", 0
    

    Now it's a simple matter of changing that character.
      FileName[7] := sensornum + "0"
    

    Okay, so you say you want to change the extension of the file name? That's easy too -- here's a little method that lets you set the sensor number and file type
    pub set_filename(sn, ftype)
     
      FileName[7] := sn + "0"
    
      if (ftype == 0)
        bytemove(@Filename[8], string(".csv"), 5)
      elseif (ftype == 1)
        bytemove(@Filename[8], string(".wav"), 5)
      else
        bytemove(@Filename[8], string(".err"), 5)
    

    We use 5 with bytemove so that we copy the string (period plus three characters) AND the terminating zero -- this is necessary for string methods.

    Here's an actual bit of code I wrote for my friend, Bob, who uses the AP-16+ (which I co-designed and coded) in fun little toys. His latest project will randomize one of a hundred files within one of eight groups. Press the group button, get a random file. Here's his dat section
    dat
    
      FileName      byte    "PCFA_000.WAV", 0                       ' 100..199 .. 800..899
    

    And here's the code that updates FileName before playing the file.
    pub make_filename(grp, fn)      
                                                                      
    '' Updates embedded string with file number
    '' -- gn is the group #                    
    '' -- fn is the file number (00..99)
    
      FileName[5] := "0" + grp
      FileName[6] := "0" + fn  / 10
      FileName[7] := "0" + fn // 10
    

    That is great Jon, I will give it a shot. It is definitely a lot smaller in size, and easier to read.

  • JonnyMacJonnyMac Posts: 9,104
    edited 2016-09-18 23:32
    If the period and terminator already exist in the target string, it's enough just to bytemove the three-character extension ... right?
    You're absolutely right, Phil. I tend to be a overly verbose.

    TC: Given the dat section I suggested, this line would work:
      bytemove(@Filename[9], string("csv"), 3)
    

  • Cluso99Cluso99 Posts: 18,069
    Kye wrote a very nice and well documented string/hex/etc handler.
    ASCII0_STREngine.spin
    It is probably in the OBEX.
Sign In or Register to comment.