Announcement

Collapse
No announcement yet.

String Parsing

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • String Parsing

    I am using a gen4-uLCD-50DT and have a serial connection to a micro controller. I am reading in a comma delimited string on COM0 and can successfully save this in a variable. How to I go about parsing the string? I found a 'str_Find()' method and a usage example here (based on this thread), but it does not work. I need a method to search and extract substrings without resorting to something crude. Can someone help?

  • #2
    Hi,

    I have here an example that might help you in your project.

    Code:
    var char;
    var combuf[100];  // buffer for up to 200 bytes
    var strBuff[100];
     
    func main()
                    com_Init(combuf, 77, 0 );
                    var strPtr, ctr;
                    strPtr := str_Ptr(strBuff);  
                    repeat
                    
                    if (com_Count())
                                    char := serin();
                                    if (char != '\n')
                                                    print([CHR]char);
                                                    if (char == ',') char := 0;
                                                    str_PutByte(strPtr+ctr++, char);
                                                    str_PutByte(strPtr+ctr, 0);
                                    else
                                                    var len, ptr, buf[10];
                                                    print("\n");
                                                    ptr := strPtr;
                                                    while (str_Length(ptr) != 0)
                                                                    to (buf); str_Printf(&ptr, "%s");
                                                                    print([STR]buf, "\n");
                                                                    mem_Set(buf, 0, 20);
                                                    wend
                                                    ctr := 0;
                                                    mem_Set(strBuff, 0, 200);
                                    endif  
                    endif
                    forever
    endfunc
    With this example, if the character received is not equal to line feed it will continue to store at the strBuff while any comma character (set as a delimiter) will be replaced by a null character. Upon receiving a line feed (0x0A), all strings separated with comma will be printed individually.

    Say for an instance the whole character string received is this
    aaa,bbb,ccc,d,e,fff

    The data were extracted will be like this
    aaa
    bbb
    ccc
    d
    e
    fff

    Please see the details of the commands in the reference manual. (https://www.4dsystems.com.au/product...ions_R_2_0.pdf)

    Best Regards,

    Pearl
    Pearl

    Comment


    • #3
      Thanks, this is great. Here is what I came up with.

      Code:
      #platform "Gen4-uLCD-50DT"
      
      
      var buffer[100];
      var inputString[100] ;
      var string[100];
      
      var substring[10];
      var delimiter[1];
      var charToCompare[1];
      
      
      func main()
          var serialInputChar;
          var pointer;
          var i;
      
          gfx_ScreenMode(LANDSCAPE) ;
      
      
          com_SetBaud(COM0,11520);
          com_Init(buffer, 100, 0);
      
      
          pointer := str_Ptr(inputString) ;
      
          to(delimiter); putch(",");
      
          repeat
      
              i := 0;
      
              serialInputChar := serin();
      
              if (serialInputChar > 0)
                  str_PutByte(pointer, serialInputChar);
                  pointer++ ;
              endif
      
      
      
              if (serialInputChar == '\n')
                  str_PutByte(pointer, 0);
                  to(string); print("\nInput string = ", [STR] inputString, "\n") ;
                  print([STR]string);
      
                  var serialInputStringPointer;
                  serialInputStringPointer := str_Ptr(string);
      
                  while(i < strlen(string))
      
                      to(charToCompare); putch(str_GetByte(serialInputStringPointer + i));
      
                      var charPointer;
                      charPointer := str_Ptr(charToCompare);
                      var n;
                      if(n := str_Match(&charPointer, ","))
                          //reject the character and skip to next
                          i++;
      
      
                      else
                          to(substring); putstr(charToCompare);
                          print([STR]substring);
                          //print("\n");
                          i++;
      
                      endif
      
                  wend
      
                  pointer := str_Ptr(inputString) ;
                  serialInputChar := 0 ;
      
              endif
      
          forever
      
      endfunc
      What this does is print to the screen the text received on the comm port unaltered, and then parses out the commas. So...

      if I receive: this,is,a,test,string

      this will be displayed: thisisateststring

      I will incorporate your suggestions, as I will need to move each word in the comma delimited string to an array of string.

      Thanks,

      Mike

      Comment


      • #4
        Out of curiosity, in your code you use the variable ctr. Why is this initialized at the end of the second if block? How can this be used reliably when you don't know its initial value?

        Comment


        • Kimberly
          Kimberly commented
          Editing a comment
          Hello,

          In 4DGL, the default value of the local variable when not initialized is equal to zero which makes the variable ctr have an initial value of zero.

          In the second if condition, rather than initializing ctr at the end, it is being reset. The variable ctr is used to indicate where in the buffer the string pointer will be raised and where the character value will be stored. Having ctr incremented each time a character that is not '\n' is placed in the buffer, it is needed to be reverted back to zero when line feed is received.

          I hope this helps.

          Best Regards,
          Kimberly

      • #5
        Not to complain, but dealing with strings is difficult. I need to have an array of strings...for example a 10 element array to hold 10 strings. I read somewhere on the forum that the compiler would accept something like this:
        Code:
        var example[3];
        
        example[0] := "this is a string";
        example[1] := "this is another string";
        example[2] := "and this is yet another string";
        So, what I want to do is assign the string in buffer (see code below), to the element of an array (stringArray), then later in the code I could then iterate over each element of the stringArray to print the contents or do what ever else....however, I can not tell from reading the plethora of documentation if this will work (I am not able to run the code right now, and I am tired of bit-banging my way through this).

        Code:
        stringArray[10];
        
        while (str_Length(pointer) != 0)
                    
         to (buffer); str_Printf(&pointer, "%s");
                        
         stringArray[i] := buffer; // should this be 'stringArray[i] := *buffer;'  ??  Is this the correct way to do the assignment?
                                        
         print([STR]stringArray[i], "\n"); will this print the string in the element stringArray[i]?  
                           
         //reset the buffer
         mem_Set(buffer, 0, 20);
                        
         i++;
                        
        wend
        Can I then do this?

        Code:
        var one, two, ...., ten;
        
        //assign the contents of the stringArray to individual 'insructions'
        one := stringArray[0];
        two := stringArray[1];
        three := stringArray[2];
        four := stringArray[3];
        five := stringArray[4];
        six := stringArray[5];
        seven := stringArray[6];
        eight := stringArray[7];
        nine := stringArray[8];
        ten := stringArray[9];
        Thank you,

        Mike

        Comment


        • #6
          Hello Mike,

          As stated in the 4DGL Reference Manual, arrays can only have one dimension which means that each element of an array cannot hold a string. In the first block of code you provided, what actually happens is that the strings' addresses are being stored in the example array.

          Similarly, you can do this for dynamic strings:

          Code:
          var stringArray[10];   
          var str0[20], str1[20], str2[20]; 
          
          stringArray[0] := str0;
          stringArray[1] := str1;
          stringArray[2] := str2;
          For the proper implementation, kindly refer to the project file I attached below.

          Best Regards,
          Kimberly
          Attached Files

          Comment


          • #7
            Thank you.

            Comment


            • #8
              I am very puzzled by the behavior I am observing with the Visi application I am developing.

              I wrote the attached prototype code 'serialparsetest', and when I downloaded it to my GEN4-uLCD-50DT it works. I connect it to a raspberry pi
              which sends the string "0,0,0,0,33.33,", waits 5 seconds, and send "1,1,1,1,22.22,". This repeats indefinitly. On the display, it prints
              Code:
              0
              0
              0
              0
              33.33
              0
              0
              0
              0
              33.33
              
              1
              1
              1
              1
              22.22
              1
              1
              1
              1
              22.22
              This is what I expected.

              However, when I integrate this code into my larger 'ControlHMI' application (see attached), I experience inconsistant behavior.
              1) after I download the application, form navigation works, and I can change screens....however the 4Dbuttons 'stick'
              2) when I connect the display to my raspberry pi, form navigation does not work. I can not change screens.

              I commented out all calls to serialReceive() and serialTransmit() and then form navigation worked, but still observed 'sticky'
              pushbuttons...which leads me to believe the function is not returning. I then uncommented the initial serialReceive() in main(),
              and this allowed for limited form navigation...but it appeared no data was being read in, as my LEDs did not change state.

              Could someone offer me a fresh set of eyes? What am I missing?
              Attached Files
              Last edited by mojoman; 28th August 2018, 05:06 AM.

              Comment


              • #9
                I have updated my code (see attached zip file) with the following changes:
                - moved main() to bottom of the file so it is the last function
                - change "return 0;" in serialReceive() and serialTransmit() to "return;"
                - changed the variable used by the angular meter to an integer,

                In the attached, and for and after my testing, all calls to serialReceive() are commented out except in main() and Form2().

                Here are my observations from testing:
                1) When all instances of serialReceive() are commented out, serialTransmit() functions correctly, and the 4DButtons do not 'stick'. Form navigation works.
                2) When serialReceive() is uncommented in main() only, form navigation works, data can transmit, but buttons 'stick'
                3) When serialReceive() is uncommented in Form2(), no data transmits, buttons do not respond, and no data appears to be received,
                4) to test if data is being received, I reinserted print commands to display data received as both strings and integer values. Data is being received, formatted correctly, and displayed.

                So what is wrong with how I implemented serialReceive()???? It appears my data is received and assigned to the global variables I created, so why are my LEDs not changing state, form navigation hanging up, and buttons not responding??
                Attached Files

                Comment


                • #10
                  Hello Mike,

                  I noticed that there is an issue with how you convert the strings to integers in the serialReceive() function.

                  When using Floating point Functions, you have to keep in mind that floats need to be 32 bits. In 4DGL, this can be achieved by using an array with 2 elements (var being 16 bits). Note: You may refer to the "Floating point Functions" section in the Diablo16 Internal Functions manual.

                  Converting the string to float this way will cause an issue if it is not defined properly:
                  Code:
                  flt_VAL(stateFeedbackAsFloat[0], str_Ptr(garageDoorState));
                  garageDoorST := flt_FTOI(stateFeedbackAsFloat[0]);
                  What you can do is implement the same technique as storing the strings' addresses into an array, creating five individual arrays with a size of 2 and setting the value of each element of the stateFeedbackAsFloat as the address of each individual array.
                  Code:
                  var stateFeedbackAsFloat[5];
                  var flt0[2], flt1[2],flt2[2],flt3[2],flt4[2];
                  
                  stateFeedbackAsFloat[0] := flt0;
                  stateFeedbackAsFloat[1] := flt1;
                  stateFeedbackAsFloat[2] := flt2;
                  stateFeedbackAsFloat[3] := flt3;
                  stateFeedbackAsFloat[4] := flt4;
                  For reference, you may check the sample project I attached below.

                  I hope this helps!

                  Best Regards,
                  Kimberly
                  Attached Files

                  Comment


                  • #11
                    Kimberly,

                    I cleaned up the float to integer conversion. To be honest, I don't even need floating point values. Almost all data is binary except one data point, and where it is used I do believe I require to pass it an integer only anyways.

                    After I made the changes, I am reading data in, but again, form navigation freezes and ceases to work, incoming data is not updating my LED's, and data transmission stops. Where am I going wrong? I wrote tracer code, and I am entering and exiting the serial read function from the Forms, I can display the values I am reading in (as integers), so what gives?

                    Also, is there no function for convert a string to integer? I haven't found anything.

                    Thanks,

                    Mike

                    Comment


                    • #12
                      disregard the last post....I found the error...I referenced the wrong variable in main() for the float array.

                      BTW....will there be the capability to create multi file programs so everything isn't in one huge, long, hard to read file?

                      Comment


                      • #13
                        Good day Mike,

                        For a multi-file program, you need to create a system file that you can link with your main program.

                        It may be created this way:

                        New file > Choose your display > Create System File (Found at the upper right corner of the "Choose Your Environment" window).

                        Inside the file, you can write the functions that you can call. Make sure to save the file inside the same directory as your project. Include this in your main program so you will be able to use the functions you created.

                        In global:
                        Code:
                        #inherit "(filename).inc"
                        You can read more about the "#inherit" in the 4DGL Programmer reference manual under the Pre-Processor Directives section.

                        I hope this helps!

                        Best Regards,
                        Kimberly

                        Comment

                        Working...
                        X