Shop OBEX P1 Docs P2 Docs Learn Events
Help with ASCII and numbers — Parallax Forums

Help with ASCII and numbers

average joeaverage joe Posts: 795
edited 2012-04-22 13:37 in Propeller 1
I'm working on a object and I need to:
Receive three numbers as an ASCII encoded string, space delimited and terminated with CR + LF, with FullDuplexSerial.
Then I would like to convert to 3 - 8 bit numbers, pack those into a long and pass the long as result.
So, I'm expecting to receive :
"0 0 0" as ASCII or as decimal "48, 32, 48, 32, 48, 13, 10"
to
"255 255 255" or as decimal "50, 53, 53, 32, 50, 53, 53, 32, 50, 53, 53, 13, 10"
I'm trying to figure out an easy way to do this and keep drawing a blank. I started working on it and got this far :
    index := 0 
    tmp := serial.rx

      repeat while tmp <> -1
        buff[index ++] := tmp
        tmp := serial.rx
    index := 0
    repeat while buff[index + 1] <> 10

      repeat while  buff[index]  <> 13

        places := 0
        repeat while buff[index] <> 32
          temp[places ++] := buff[index ++] - 48

      if places == 2
        tmp1 := ((temp[2] *  100) + (temp[1] * 10) + temp[0])   
      elseif places ==1
        tmp1 := ((temp[1] * 10) + temp[0])   
      else
        tmp1 :=  temp[0]   
        
Any help would be greatly appreciated!

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2012-04-21 23:58
    Here a quick and dirty example to read the data (one of many ways of doing this). No conversion is done, the string is stored including a potential CR but without line terminator (LF).
    CON
      _clkmode = XTAL1|PLL16X
      _xinfreq = 5_000_000
    
    CON
      LT = 10
      
    OBJ
      serial: "FullDuplexSerial"
    
    VAR
      byte  incoming[16]
      
    PUB null | n, c
    
      serial.start(31, 30, %0000, 115200)
      waitcnt(clkfreq*3 + cnt)
    
      repeat
        n := 0
        repeat
          if (c := serial.rx) == LT                         ' line terminator
            quit
          incoming[n++] := c
        until n == 16
    
    '   n == 16 NG no line terminator found within max length
    '   n  < 16 OK but may still be missing numbers
    
        if n < 16
          incoming[n] := 0
          serial.str(@incoming{0})
        else
          serial.str(string("invalid format", 13))
      
    DAT
    
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-04-22 00:49
    That sort of thing is included in Kye's string library. I added a few good-ol MBASIC string commands at the end for good measure, so there are several ways of doing things.

    1980's MBASIC was/is one of those languages that had terrible structure, in terms of GOTO and line numbers, but at the same time, string handling that IMHO is still way ahead of Spin.

    in basic
    A$= STR(N) ' where N is your ascii value. 
    

    and that returns a string, the string has a leading space if it is positive or a - sign if negative. In MBASIC you didn't even need to declare A$ if you didn't want to - it was there ready to use with just one line of code and no "extra" supporting code like having to declare arrays (like in Spin). Though as MBASIC evolved into the MBASIC compiler, QBASIC, and then Visual Basic and VB.Net, it ended up borrowing more and more good things from C like the necessity of declaring things before you use them.

    if you want you can then use TRIM to remove any leading spaces.

    Kuroneko's code does the job better. And with way less supporting code (especially all the string routines you will never use).


    {{
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // ASCII0 String Engine
    //
    // Author: Kwabena W. Agyeman
    // Updated: 8/28/2010
    // Designed For: P8X32A
    // Version: 1.2
    //
    // Copyright (c) 2010 Kwabena W. Agyeman
    // See end of file for terms of use.
    //
    // Update History:
    //
    // v1.0 - Original release - 4/10/2009.
    // v1.1 - Made code faster - 8/18/2009.
    // v1.2 - Updated library functions, fixed bugs, and made code more robust against whitespace and capitalization - 7/27/2010.
    //
    // For each included copy of this object only one spin interpreter should access it at a time.
    //
    // Nyamekye,
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }}
    
    VAR
    
      word tokenStringPointer
      byte decimalString[12], hexadecimalString[9], binaryString[33], characterToStringPointer, characterToString[255]
    
    PUB buildString(character) '' 4 Stack longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Builds a string from individual characters. Use "builtString" to get the address of the string.
    '' //
    '' // If the backspace character is put into the string it is automatically evaluated by removing the previous character.
    '' //
    '' // If 254 characters are put into the string all characters excluding backspace that are put into the string are ignored.
    '' //
    '' // Character - The next character to include in the string. Null will be ignored.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      ifnot(characterToStringPointer)
        bytefill(@characterToString, 0, 255)
    
      if(characterToStringPointer and (character == 8))
        characterToString[--characterToStringPointer] := 0
    
      elseif(character and (characterToStringPointer <> 254))
        characterToString[characterToStringPointer++] := character
    
    PUB builtString(resetString) '' 4 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Returns the pointer to the string built from individual characters.
    '' //
    '' // Reset - If true the next call to "buildString" will begin building a new string and the old string will be destroyed.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      characterToStringPointer &= not(resetString)
      return @characterToString
    
    PUB builderNumber '' 3 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Returns the number of characters in the string builder buffer.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      return characterToStringPointer
    
    PUB builderFull '' 3 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Returns true if the string builder buffer is full and false if not.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      return (characterToStringPointer == 254)
    
    PUB stringCompareCS(characters, otherCharacters) '' 5 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Compares two strings case sensitively.
    '' //
    '' // Returns zero if the two strings are equal.
    '' // Returns a positive value if "characters" comes lexicographically after "otherCharacters".
    '' // Returns a negative value if "characters" comes lexicographically before "otherCharacters".
    '' //
    '' // Characters - A pointer to a string of characters.
    '' // OtherCharacters - A pointer to another string of characters.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      repeat
        result := (byte[characters] - byte[otherCharacters++])
      while(byte[characters++] and (not(result)))
    
    PUB stringCompareCI(characters, otherCharacters) '' 9 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Compares two strings case insensitively.
    '' //
    '' // Returns zero if the two strings are equal.
    '' // Returns a positive value if "characters" comes lexicographically after "otherCharacters".
    '' // Returns a negative value if "characters" comes lexicographically before "otherCharacters".
    '' //
    '' // Characters - A pointer to a string of characters.
    '' // OtherCharacters - A pointer to another string of characters.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      repeat
        result := (ignoreCase(byte[characters]) - ignoreCase(byte[otherCharacters++]))
      while(byte[characters++] and (not(result)))
    
    PUB stringCopy(whereToPut, whereToGet) '' 5 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Copies a string from one location to another. This method can corrupt memory.
    '' //
    '' // Returns a pointer to the new string.
    '' //
    '' // WhereToPut - Address of where to put the copied string.
    '' // WhereToGet - Address of where to get the string to copy.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      bytemove(whereToPut, whereToGet, (strsize(whereToGet) + 1))
      return whereToPut
    
    PUB stringConcatenate(whereToPut, whereToGet) '' 5 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Concatenates a string onto the end of another. This method can corrupt memory.
    '' //
    '' // Returns a pointer to the new string.
    '' //
    '' // WhereToPut - Address of the string to concatenate a string to.
    '' // WhereToGet - Address of where to get the string to concatenate.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      bytemove((whereToPut + strsize(whereToPut)), whereToGet, (strsize(whereToGet) + 1))
      return whereToPut
    
    PUB stringToLowerCase(characters) '' 4 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Demotes all upper case characters in the set of ("A","Z") to their lower case equivalents.
    '' //
    '' // Characters - A pointer to a string of characters to convert to lowercase.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      repeat strsize(characters--)
        result := byte[++characters]
        if((result => "A") and (result =< "Z"))
          byte[characters] := (result + 32)
    
    PUB stringToUpperCase(characters) '' 4 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Promotes all lower case characters in the set of ("a","z") to their upper case equivalents.
    '' //
    '' // Characters - A pointer to a string of characters to convert to uppercase.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      repeat strsize(characters--)
        result := byte[++characters]
        if((result => "a") and (result =< "z"))
          byte[characters] := (result - 32)
    
    PUB trimString(characters) '' 8 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Removes white space and new lines arround the outside of string of characters.
    '' //
    '' // Returns a pointer to the trimmed string of characters.
    '' //
    '' // Characters - A pointer to a string of characters to be trimmed.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      result := ignoreSpace(characters)
      characters := (result + ((strsize(result) - 1) #> 0))
    
      repeat
        case byte[characters]
          8 .. 13, 32, 127: byte[characters--] := 0
          other: quit
    
    PUB tokenizeString(characters) '' 8 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Removes white space and new lines arround the inside of a string of characters.
    '' //
    '' // Returns a pointer to the tokenized string of characters, or an empty string when out of tokenized strings of characters.
    '' //
    '' // Characters - A pointer to a string of characters to be tokenized, or null to continue tokenizing a string of characters.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      if(characters)
        tokenStringPointer := characters
    
      result := tokenStringPointer := ignoreSpace(tokenStringPointer)
    
      repeat while(byte[tokenStringPointer])
        case byte[tokenStringPointer++]
          8 .. 13, 32, 127:
            byte[tokenStringPointer - 1] := 0
            quit
    
    PUB findCharacter(stringToSearch, characterToFind) '' 5 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Searches a string of characters for the first occurence of the specified character.
    '' //
    '' // Returns the address of that character if found and zero if not found.
    '' //
    '' // StringToSearch - A pointer to the string of characters to search.
    '' // CharacterToFind - The character to find in the string of characters to search.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      repeat strsize(stringToSearch--)
        if(byte[++stringToSearch] == characterToFind)
          return stringToSearch
    
    PUB replaceCharacter(stringToSearch, characterToReplace, characterToReplaceWith) '' 11 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Replaces the first occurence of the specified character in a string of characters with another character.
    '' //
    '' // Returns the address of the next character after the character replaced on success and zero on failure.
    '' //
    '' // StringToSearch - A pointer to the string of characters to search.
    '' // CharacterToReplace - The character to find in the string of characters to search.
    '' // CharacterToReplaceWith - The character to replace the character found in the string of characters to search.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      result := findCharacter(stringToSearch, characterToReplace)
      if(result)
        byte[result++] := characterToReplaceWith
    
    PUB replaceAllCharacters(stringToSearch, characterToReplace, characterToReplaceWith) '' 17 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Replaces all occurences of the specified character in a string of characters with another character.
    '' //
    '' // StringToSearch - A pointer to the string of characters to search.
    '' // CharacterToReplace - The character to find in the string of characters to search.
    '' // CharacterToReplaceWith - The character to replace the character found in the string of characters to search.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      repeat while(stringToSearch)
        stringToSearch := replaceCharacter(stringToSearch, characterToReplace, characterToReplaceWith)
    
    PUB findString(stringToSearch, stringToFind) | index, size '' 7 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Searches a string of characters for the first occurence of the specified string of characters.
    '' //
    '' // Returns the address of that string of characters if found and zero if not found.
    '' //
    '' // StringToSearch - A pointer to the string of characters to search.
    '' // StringToFind - A pointer to the string of characters to find in the string of characters to search.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      size := strsize(stringToFind)
      if(size--)
    
        repeat strsize(stringToSearch--)
          if(byte[++stringToSearch] == byte[stringToFind])
    
            repeat index from 0 to size
              if(byte[stringToSearch][index] <> byte[stringToFind][index])
                result := true
                quit
    
            ifnot(result~)
              return stringToSearch
    
    PUB replaceString(stringToSearch, stringToReplace, stringToReplaceWith) '' 13 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Replaces the first occurence of the specified string of characters in a string of characters with another string of
    '' // characters. Will not enlarge or shrink a string of characters.
    '' //
    '' // Returns the address of the next character after the string of characters replaced on success and zero on failure.
    '' //
    '' // StringToSearch - A pointer to the string of characters to search.
    '' // StringToReplace - A pointer to the string of characters to find in the string of characters to search.
    '' // StringToReplaceWith - A pointer to the string of characters that will replace the string of characters found in the
    '' //                       string of characters to search.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      result := findString(stringToSearch, stringToReplace)
      if(result)
    
        repeat (strsize(stringToReplaceWith) <# strsize(stringToReplace))
          byte[result++] := byte[stringToReplaceWith++]
    
    PUB replaceAllStrings(stringToSearch, stringToReplace, stringToReplaceWith) '' 19 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Replaces all occurences of the specified string of characters in a string of characters with another string of
    '' // characters. Will not enlarge or shrink a string of characters.
    '' //
    '' // StringToSearch - A pointer to the string of characters to search.
    '' // StringToReplace - A pointer to the string of characters to find in the string of characters to search.
    '' // StringToReplaceWith - A pointer to the string of characters that will replace the string of characters found in the
    '' //                       string of characters to search.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      repeat while(stringToSearch)
        stringToSearch := replaceString(stringToSearch, stringToReplace, stringToReplaceWith)
    
    PUB integerToDecimal(number, length) '' 5 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Converts an integer number to the decimal string of that number padded with zeros.
    '' //
    '' // Returns a pointer to the converted string.
    '' //
    '' // Number - A 32 bit signed integer number to be converted to a string.
    '' // Length - The length of the converted string, "+" or "-" will be concatenated onto the head of converted string.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      length := (10 - ((length <# 10) #> 0))
    
      decimalString := "+"
      if(number < 0)
        decimalString := "-"
    
      if(number == negx)
        bytemove(@decimalString, string("-2147483648KA"), 11)
    
      else
        repeat result from 10 to 1
          decimalString[result] := ((||(number // 10)) + "0")
          number /= 10
    
      decimalString[length] := decimalString
      return @decimalString[length]
    
    PUB integerToHexadecimal(number, length) '' 5 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Converts an integer number to the hexadecimal string of that number padded with zeros.
    '' //
    '' // Returns a pointer to the converted string.
    '' //
    '' // Number - A 32 bit signed integer number to be converted to a string.
    '' // Length - The length of the converted string, negative numbers need a length of 8 for sign extension.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      repeat result from 7 to 0
        hexadecimalString[result] := lookupz((number & $F): "0".."9", "A".."F")
        number >>= 4
    
      return @hexadecimalString[8 - ((length <# 8) #> 0)]
    
    PUB integerToBinary(number, length) '' 5 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Converts an integer number to the binary string of that number padded with zeros.
    '' //
    '' // Returns a pointer to the converted string.
    '' //
    '' // Number - A 32 bit signed integer number to be converted to a string.
    '' // Length - The length of the converted string, negative numbers need a length of 32 for sign extension.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      repeat result from 31 to 0
        binaryString[result] := ((number & 1) + "0")
        number >>= 1
    
      return @binaryString[32 - ((length <# 32) #> 0)]
    
    PUB decimalToInteger(characters) | sign '' 10 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Converts a decimal string into an integer number. Expects a string with only "+-0123456789" characters.
    '' //
    '' // If the string has a "-" sign as its leading character the converted integer returned will be negated.
    '' //
    '' // If the string has a "+" sign as its leading character the converted integer returned will not be negated.
    '' //
    '' // Returns the converted integer. By default the number returned is positive and the "+" sign is unnecessary.
    '' //
    '' // Characters - A pointer to the decimal string to convert. The number returned will be 2's complement compatible.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      characters := checkSign(ignoreSpace(characters), @sign)
    
      repeat (strsize(characters) <# 10)
        ifnot(checkDigit(characters, "0", "9"))
          quit
    
        result := ((result * 10) + (byte[characters++] & $F))
      result *= sign
    
    PUB hexadecimalToInteger(characters) | sign '' 10 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Converts a hexadecimal string into an integer number. Expects a string with only "+-0123456789ABCDEFabdcef" characters.
    '' //
    '' // If the string has a "-" sign as its leading character the converted integer returned will be negated.
    '' //
    '' // If the string has a "+" sign as its leading character the converted integer returned will not be negated.
    '' //
    '' // Returns the converted integer. By default the number returned is positive and the "+" sign is unnecessary.
    '' //
    '' // Characters - A pointer to the hexadecimal string to convert. The number returned will be 2's complement compatible.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      characters := checkSign(ignoreSpace(characters), @sign)
    
      repeat (strsize(characters) <# 8)
        ifnot(checkDigit(characters, "0", "9"))
          ifnot(checkDigit(characters, "A", "F") or checkDigit(characters, "a", "f"))
            quit
    
          result += $90_00_00_00
        result := ((result <- 4) + (byte[characters++] & $F))
      result *= sign
    
    PUB binaryToInteger(characters) | sign '' 10 Stack Longs
    
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '' // Converts a binary string into an integer number. Expects a string with only "+-01" characters.
    '' //
    '' // If the string has a "-" sign as its leading character the converted integer returned will be negated.
    '' //
    '' // If the string has a "+" sign as its leading character the converted integer returned will not be negated.
    '' //
    '' // Returns the converted integer. By default the number returned is positive and the "+" sign is unnecessary.
    '' //
    '' // Characters - A pointer to the binary string to convert. The number returned will be 2's complement compatible.
    '' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
      characters := checkSign(ignoreSpace(characters), @sign)
    
      repeat (strsize(characters) <# 32)
        ifnot(checkDigit(characters, "0", "1"))
          quit
    
        result := ((result << 1) + (byte[characters++] & 1))
      result *= sign
    
    PRI ignoreCase(character) ' 4 Stack Longs
    
      result := character
      if((character => "a") and (character =< "z"))
        result -= 32
    
    PRI ignoreSpace(characters) ' 4 Stack Longs
    
      result := characters
      repeat strsize(characters--)
        case byte[++characters]
          8 .. 13, 32, 127:
          other: return characters
    
    PRI checkSign(characters, signAddress) ' 5 Stack Longs
    
      if(byte[characters] == "-")
        result := -1
    
      if(byte[characters] == "+")
        result := 1
    
      long[signAddress] := (result + ((not(result)) & 1))
      return (characters + (||result))
    
    PRI checkDigit(characters, low, high) ' 5 Stack Longs
    
      result := byte[characters]
      return ((low =< result) and (result =< high))
    
    ' added commands J Moxham Jan 2010
    
    PUB endsWithString(stringToSearch, stringToFind) '' 12 Stack Longs
    
    '' &#9484;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9488;
    '' &#9474; Checks if the string of characters ends with the specified characters.                                                   &#9474;
    '' &#9474;                                                                                                                          &#9474;
    '' &#9474; Returns true if yes and false if no.                                                                                     &#9474;
    '' &#9474;                                                                                                                          &#9474;
    '' &#9474; StringToSearch - A pointer to the string of characters to search.                                                        &#9474;                                                           
    '' &#9474; StringToFind - A pointer to the string of characters to find in the string of characters to search.                      &#9474;                                                                           
    '' &#9492;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9496;
    
      return ((stringToSearch + strsize(stringToSearch) - strsize(stringToFind)) == findString(stringToSearch, stringToFind)) 
    
    PUB Left(Source, Destination,Number)   ' returns the left number of characters
       repeat Number
          byte[Destination] := byte[Source]
          Source++
          Destination++
       byte[Destination] :=0 ' add in the zero terminator
         
                                                                          
    PUB Len(Source) ' returns the length of the string
      return strsize(Source)
    
    PUB Mid(Source,Destination,Start,Number) ' returns strings starting at start with number characters
      Start-- ' so starts at the right position
      Source += Start ' position 1 is the first character
      repeat Number
        byte[Destination] := byte[Source]
        Source++
        Destination++
      byte[Destination] :=0 'add in the zero terminator  
    
    'PUB Add(Source,Number)                                  ' adds ascii number to string at source
    '   byte[Source] :=strsize(Source)                       ' ** use stringconcatentate instead **
    '   byte[Source+1] := 0
    
    PUB Clear(Source)                                       'just set the first byte as zero clears the string
       byte[Source]:=0
       
    
    PUB Copy(Source,Destination) ' reverse order to stringcopy. Can also use to create strings eg copy(string("test"),@lineoftext1)
      bytemove(Destination, Source, (strsize(Source) + 1))
    
    PUB Str(Destination,Number) | n' convert a number to a string representation. Uses Basic syntax, ie leading character is a space if +ve, and is - if negative  
        n := number ' temp store for at the end when add the + or -
        Destination += 10 
        byte[Destination] := 0 ' terminator
        Destination--
        repeat result from 10 to 1
          byte[Destination] := ((||(number // 10)) + "0")
          number /= 10
          Destination--
    
        destination++    ' points to start again
    
        repeat while byte[destination] == "0"  ' while equal to zero remove this leading zero
          repeat result from 0 to 11 ' include the zero terminator as well
            bytemove(destination+result,destination+result+1,1)' shuffle to left
        repeat result from 11 to 1 
          bytemove(destination+result,destination+result-1,1) ' shuffle once to right - leading space or -
        byte[destination] :=" " ' leading space if positive. Can use trim to remove this
        if (n<0)
          byte[destination] := "-"
    
    PUB Stringfill(Destination, Number,AsciiValue)' fill string with a string, eg 3,65 is"AAA" and 2,32 is "  "
        bytefill(destination,AsciiValue,Number) ' same as Basic "string$" function and can also replicate space$ 
        byte[destination+number] :=0 ' zero terminator
    
    PUB Instr(Source,AsciiValue) | j ' find asciivalue in Source. Returns 0 if not found
        j := 0
        repeat result from 0 to strsize(Source)
          if byte[source+result] == AsciiValue
            j := result + 1 ' basic format where 1 is the last first character of a string
        return j    
    
    'PUB Val(Source)' basic string to decimal value only works for integers not floating point, see DecimalToInteger above        
    
    
    
    
    {{
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //                                                  TERMS OF USE: MIT License
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
    // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
    // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
    // Software is furnished to do so, subject to the following conditions:
    //
    // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
    // Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
    // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }}
    
  • average joeaverage joe Posts: 795
    edited 2012-04-22 03:44
    I think I've got it. I'm not decoding the ASCII to decimal yet, just passing a string to debug.
    PRI GetString | n,co,c
      serial.rxflush                                                     'call rxflush
      n := 0
        repeat while (c := serial.rx) <> LT and n <> buffersize - 1                        ' line terminator
          incoming[n++] := c
    '   n == buffersize NG no line terminator found within max length
    '   n  < buffersize OK but may still be missing numbers
    
        if n  < buffersize - 1 
          incoming[n] := 0 
          repeat co from 0 to n  
            byte[bufferAddress][co] := incoming[co] 
          result := n 
          return
        else 
          result := -1   
          return  
    
    This moves the string from serial buffer, to incoming buffer, to the buffer in main memory. Not the most efficient way of doing this I'm sure, but it seems to work. I'm still thinking about the ASCII to DEC conversion. It would be helpful since I have written this object to take decimal values. I will also need to take LONGER strings *not sure how long yet* and deal with those appropriately. I'm still trying to wrap my head around some of the complexities of taking a ASCII text based command set and trying to use decimal input and output. I guess I should have used string communication but it seems like more work to start over.
    Thanks again kuroneko. You've helped me several times.
    I'll look through the string functions again, but not sure they will help right now. A+ for the effort though Doc!
  • kuronekokuroneko Posts: 3,623
    edited 2012-04-22 04:14
    I know there are other ways, but here is a version using a strrtok() implementation (two private methods). The parameters are the string to be tokenized, a string holding all the possible delimiters (\0 is implied) and a private buffer location. The tokenized strings are then fed to the Numbers object for conversion.
    CON
      _clkmode = XTAL1|PLL16X
      _xinfreq = 5_000_000
    
    CON
      LT = 10
      
    OBJ
      serial: "FullDuplexSerial"
          nb: "Numbers"
          
    VAR
      byte  incoming[16]
      
    PUB null | n, c, buffer
    
      serial.start(31, 30, %0000, 115200)
      waitcnt(clkfreq*3 + cnt)
    
      repeat
        n := 0
        repeat
          if (c := serial.rx) == LT                         ' line terminator
            quit
          incoming[n++] := c
        until n == 16
    
    '   n == 16 NG no line terminator found within max length
    '   n  < 16 OK but may still be missing numbers
    
        if n < 16
          incoming[n] := 0                                  ' add terminator
          
    '     First call with string pointer, subsequent ones use 0.
          if c := [COLOR="blue"]strrtok(@incoming{0}, n := string(32, 13), @buffer)[/COLOR]
            repeat
              [COLOR="orange"]serial.dec(nb.FromStr(c, nb#DEC))
              serial.tx(13)[/COLOR]
            while c := [COLOR="blue"]strrtok(0, n, @buffer)[/COLOR]
        else
          serial.str(string("invalid format", 13))
      
    PRI strrtok(str, delimiter, bufp) : token | w
    
      if str
        long[bufp] := str
    
      if token := w := long[bufp]
        repeat while strchr(delimiter, byte[w])             ' find start of token
          ifnot byte[w]
            long[bufp] := w                                 ' update
            return 0                                        ' no more tokens
          w++
        token := w++
        repeat while not strchr(delimiter, byte[w])         ' find end of token
          w++
        if byte[w]
          byte[w++]~                                        ' place terminator
        long[bufp] := w                                     ' update
    
    PRI strchr(str, char)
    
      repeat
        if char == byte[str]
          return str
      while byte[str++]
    
    DAT
    
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2012-04-22 04:47
    "0 0 0" as ASCII or as decimal "48, 32, 48, 32, 48, 13, 10"
    to
    "255 255 255" or as decimal "50, 53, 53, 32, 50, 53, 53, 32, 50, 53, 53, 13, 10"

    I *think* there are enough functions in Kye's modified code to replicate this in something similar to Basic. eg mid$() becomes str.mid() It is one line of code in Basic, where A$ is the input string "0 0 0" and B$ is the output string
    B$ = trim$(str$(mid$(A$,1,1))) + " " + trim$(str$(mid$(A$,3,1))) + " " + trim$(str$(mid$(A$,5,1)))+ chr$(13) + chr$(10)
    

    I'm kind of motivated to take another look at some of the versions of Basic that let you do this sort of thing. There was a version of basic that got translated into C but it was C++, not C89 and it took ages to code all the special differences between C89 and C++. But with the new GCC it might be a much simpler proposition. Strings should not be something you have to think about too much - they should be easy to work with.
  • average joeaverage joe Posts: 795
    edited 2012-04-22 05:37
    Thanks guys. I will look into this as I bugfix the current version. I'm SO close, yet SO far away. lol A preview
    PUB LCD_STRING(index,stringPointer)                                              '' Store "string" @ stringPointer in the string array using index. If stringPointer = -1, recall string from index. Index = 0 - 61. Returns -1 if index is invalid
    if index > 0 and index < 62                                                         'Check for valid index and if valid 
      if stringPointer <> -1                                                              'Check for Store / Recall and if Store 
        LCD_D_S(strcmd,index,stringPointer)                                                     'send "STRING" command to display with "index" and  "string" @ Pointer 
      else                                                                                 'if Recall
        serial.rxflush                                                                   'clear serial buffer     
        LCD_CMD1(strcmd,index)                                                                  'send "STRING" command to display with "index"
         result := GetString                                                                'pass string to buffer in main memory and set result to string size    
    else                                                                                  'if invalid index                                                                
      result := -1                                                                            'set result = -1            
    
    
    PRI GetString | n,co,c
      serial.rxflush                                                     'call rxflush
      n := 0
        repeat while (c := serial.rx) <> LT and n <> buffersize - 1                        ' line terminator
          incoming[n++] := c
    '   n == buffersize NG no line terminator found within max length
    '   n  < buffersize OK but may still be missing numbers
    
        if n  < buffersize - 1
          incoming[n] := 0
          repeat co from 0 to n 
            byte[bufferAddress][co] := incoming[co]
          result := n 
          return
        else
          result := -1  
          return      
    
    
    PRI LCD_D_S(cmd,dec,stringPointer)                                 '' Send a command, 1 decimal and 1 string to display
       serial.dec(cmd)                                                     'send "cmd" command to display
        serial.tx(32)                                                      'send "space" to display
        serial.tx(dec)                                                     'send "index" to display
        serial.tx(32)                                                      'send "space" to display
        serial.str(stringPointer)                                          'send fontName @ Pointer to display
        CR_LF                                                              'send CR + LF to the display  
    
    
    PRI LCD_CMD1(cmd,dec)                                              '' Send a command with 1 decimal parameter to display
        serial.dec(cmd)                                                    'send "cmd" command to display
        serial.tx(32)                                                      'send "space" to display
        serial.dec(dec)                                                    'send dec to display
        CR_LF                                                              'send CR + LF to display                   
    

    *edit*
    I TOTALLY agree that strings should not take a lot of thought. Now that I have 0-terminated strings, I could probably hook into numbers. Still have more work to do first.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2012-04-22 10:23
    Rather than convert to strings then numbers, how about convert on the fly, something like this...
    PUB dec3pack | idx, char
      idx~
      repeat until idx==9
         char := fds.rx
            if char => "0" and char =< "9"
               result := result * 10 + (char - "0")
               idx++
      return     ' three numbers packed
    
    That depends on the rigid 3x3 format you laid out for the incoming ascii. The long returns with the 3 numbers packed as n1*1000000+ n2*1000 + n3.

    Another thing to look at, ParallaxSerialTerminal is essentially FullDuplexSerial with a lot of added Spin functions for things like string input and numeric conversion.
  • Dave HeinDave Hein Posts: 6,347
    edited 2012-04-22 13:37
    With the CLIB object you could do something like this:
    PUB dec3pack | num1, num2, num3, buffer[20]
      c.gets(@buffer)
      c.scanf3(string("%d %d %d"), @num1, @num2, @num3)
      result := (num1 << 16) | (num2 << 8) | num3
    
Sign In or Register to comment.