Shop OBEX P1 Docs P2 Docs Learn Events
GPS in C — Parallax Forums

GPS in C

pilot0315pilot0315 Posts: 834
edited 2016-01-12 20:27 in Learn with BlocklyProp
I have been trying to isolate a single gps sentance. strncmp not working.
«1

Comments

  • plus the array does not work it dumps the entire sentance in the first element of the array
  • I took the parsing code from here and modified it:

    https://github.com/parallaxinc/propsideworkspace/tree/master/Learn/Simple Libraries/Sensor/libgps

    If you run "Libgps.c" as your main program it dumps a bunch of useful info. I simplified this and boiled it down to a single file that's easy to work with. I can post it later when I'm off work if you like.
  • Thanks.
    I have been trying to use this code and took the first part from it. For some reason I can't get the strncmp to work so I can isolate just the gprmc.
  • pilot0315, a snippet of your code looks like this:
                 for(int index = 0;  index <= 6; index++);
                 
                   gpsraw = fdserial_rxChar(GPS);
                   RMC[index] = gpsraw;
                   
                 // if(strncmp(RMC, "GPRMC", 5) == 0)  
                   print("%c",RMC[1]);
    
    Your for loop is doing nothing because it is terminated by a ";" character. Also, you need to use braces if you want to execute more than one statement in the for loop. So I think what you what is something like this:
                 for(int index = 0;  index <= 6; index++)
                 {
                   gpsraw = fdserial_rxChar(GPS);
                   RMC[index] = gpsraw;
                 } 
                 if(strncmp(RMC, "GPRMC", 5) == 0)  
                   print("%c",RMC[1]);
    
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    When it comes to community support on customer code, you forum members rock! Thanks Jason and Dave. This is an issue Tech Support could not offer assistance with. :chip:
  • Thanks for the attempt to help.
    The loop does not parse out the characters into the sucessive elements of RMC[index]. It stuffs the entire sentance into element RMC[0].

    When I run the if statement nothing shows on the screen.
    When I // the if statement it displays all of the sentances.
    I also referenced the same code that was suggested during this process.

    I used the following snip from Daniel's code who wrote it for the PAM-7Q GPS Module. I modified the variables to the names that I am using and it does not work as well.


    //read in characters from the GPS
    idx = 0;
    do
    {
    ch = fdserial_rxChar(gps_ser);
    inBuff[idx++] = ch;
    }while(ch != 13);
    inBuff[idx] = 0; //null terminate

    //got the full sentence, do a little prep work to get ready for parsing.
    //modifies inBuff!
    PrepBuff();

    if(strncmp(inBuff, "GPRMC", 5) == 0)
    ParseRMC();
    if(strncmp(inBuff, "GPGGA", 5) == 0)
    ParseGGA();
    }




    {
    for(int index = 0; index <= 6; index++);

    {


    gpsraw = fdserial_rxChar(GPS);
    RMC[index] = gpsraw;


    // pause(250);
    }

    // if(strncmp(RMC, "GPRMC", 5) == 0)
    print("%c",RMC[0]);
    }
  • Here is the snibbet with the code written by Daniel. It does not run with the if statements and without all I get is a single random character then line feed. No isolated sentances. I am just trying to at first isolate the GPRMC sentance then struggle with the rest. Thanks to everybody. This C language is a pain to learn.

    void getdata2()


    {
    //read in characters from the GPS
    int idx = 0;
    do
    {
    gpsraw = fdserial_rxChar(GPS);
    RMC[idx++] = gpsraw;
    }while(gpsraw != 13);
    RMC[idx] = 0; //null terminate

    //got the full sentence, do a little prep work to get ready for parsing.
    //modifies inBuff!
    // PrepBuff();

    if(strncmp(RMC, "GPRMC", 5) == 0)
    print_data();
    if(strncmp(RMC, "GPGGA", 5) == 0)
    print_data();
    }

  • PublisonPublison Posts: 12,366
    edited 2016-01-13 19:23
    When including code use the "C" when responding. That will keep the code intact and look better.
    955 x 514 - 111K
  • As I said before, the semicolon at the end of the for statement causes the for loop to do nothing. A semicolon by itself if a null statement. Remove the semicolon at the end of the for statement. In other words, do this
                      for(int index = 0;  index <= 6; index++)
    
    and not this
                      for(int index = 0;  index <= 6; index++) ;
    
    Another thing is that the "%c" format string causes a single ASCII character to be printed. So the statement
                         print("%c",RMC[0]);
    
    will only print the single character contained in RMC[0]. If you want to print the 7 characters in RMC[0] to RMC[6] you need to change this to
                         print("%c",RMC[index]);
    
  • I did that and it does not work . it dumps into [0], nothing in [1], or any of the others. if I index it and attempt to print a selected cell of the array nothing is there
  • pilot0315, try the following code and see if it works. If you define DEBUG at the beginning of the file you can type in test strings from the console to see what happens. Note, I changed the test for 13 to also test for 10 in case a linefeed is sent instead of a carriage return. I tested it with DEBUG defined, and it works as expected.
    /*
      Blank Simple Project.c
      http://learn.parallax.com/propeller-c-tutorials 
    */
    #undef DEBUG
    
    #ifdef DEBUG
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define print printf
    #else
    #include "simpletools.h"                      // Include simple tools
    #include "fdserial.h"
    #endif
    
    char RMC[80]; //gps string 
    
    char gpsraw;
    void getdata(); //receive data from gps
    void getdata2(); //receive data from gps
    
    void print_data(); 
    void init();
    
    int index;
    char rmc_test[6] = {"x"};
    
    #ifdef DEBUG
    #define fdserial_rxChar(x) getchar()
    #else
    int rx_pin = 26;
    int tx_pin = 27;
    int mode_ = 0;
    int Baud_rate = 9600;
    
    fdserial *GPS;  //MASK FOR THE FDSERIAL INPUT
    #endif
    
    int main()                                    // Main function
    {
        init();
        while(1)
        {
            // getdata();
            getdata2();
            // print_data();
        } 
    }        
    
    void init()
    {
    #ifndef DEBUG
        GPS = fdserial_open(rx_pin,tx_pin,mode_ ,Baud_rate);
    #endif
    }
    
    
    void getdata()
    {
        for(int index = 0;  index <= 6; index++)
        {
            gpsraw = fdserial_rxChar(GPS);
            RMC[index] = gpsraw;
            // pause(250);
        }
        // if(strncmp(RMC, "GPRMC", 5) == 0)  
            print("%c",RMC[0]);
    }            
    
    void getdata2()
    {
        //read in characters from the GPS
        int idx = 0;
        do
        {
            gpsraw = fdserial_rxChar(GPS);
            RMC[idx++] = gpsraw;      
        } while(gpsraw != 13 && gpsraw != 10);
        RMC[idx] = 0;      //null terminate
    
        printf("RMC = %s\n", RMC);
    
        //got the full sentence, do a little prep work to get ready for parsing.
        //modifies inBuff!
        // PrepBuff();
    
        if(strncmp(RMC, "GPRMC", 5) == 0)
            print_data();
        if(strncmp(RMC, "GPGGA", 5) == 0)
            print_data();
    }
                
    void print_data()            
    {
        for(int index = 0;  index <= 6; index++)
            print("%c",RMC[index]);
    }        
    
  • This doesn't fix your existing code, but shows a different approach to handling the GPS data.

    I wrote this not long ago as test code for the PAM-7Q GPS module that Parallax sells. It should work for others, but it hasn't been tested on anything but that hardware.

    The code skips all input until it finds a '$' character, then looks for a 'G'. If it doesn't find one, it goes back to waiting for the '$'.

    After finding the $G sequence, it grabs the next four characters and compares them against 'PRMC' or 'PGGA' - (meaning it's found either a $GPRMC or $GPGGA string). If either of those are found, the appropriate parsing function is called.

    I don't use the standard string library stuff because I was trying to keep the compiled size down, and the code ends up being quite readable this way. I was looking for very specific values in the strings, like lat & long, sat count, and so on.
  • Thanks I will look at this.
  • Thanks Jason.

    I have been struggling to get the data to go from a buffer to an array. The array does not work. I will upload another bit of code tomorrow and explain the problem.

    I did this in spin without a problem.
  • btw,

    If I don't put the semicolon after the for loop statement nothing works.
  • pilot315, did you try the code I posted? It is basically your code with some fixes in it. It works OK for me. Does it work for you?
  • Yes I did it works but I am still having the problem of isolating only the gprmc sentance. Your code puts out the same thing that my code puts out.
    I can't just print out just a single selected setance instead of all of the sentances. It still appears that in my code the string does not get "tokenized" into the selected array via the buffer



  • Here's a version that only prints out lines that start with GPRMC.
    c
    c
    2K
  • thanks I will look at it
  • I ran your code and it did't run. I am new to C and havenot graduated to the # preprocessor directives yet.
    Thanks for the help though.
  • The strncmp(array, findarray, number) is only looking at the first 5 characters in the array.
    Since the array starts with the Dollar sign it will not match.
    This will work though: "strncmp(RMC, "$GPRMC", 6)"

    Mike
  • I have tried 5, 6 and many other combinations. and it strncmp does ot work.
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    To help identify the issue, please specify in what manner it is not working. What exactly is happening versus what you're expecting? =)
  • It works now. tried again to changed the 5 to a six and it works.
    Added "$" to the string. Thanks to all of you
  • pilot0315 wrote: »
    I have tried 5, 6 and many other combinations. and it strncmp does ot work.

    Are you still missing the $ at the beginning of the string? The data in RMC starts with a $ character, so you'd need to change your code that looks for the 5 characters "GPRMC" to look for the 6 characters "$GPRMC".
  • Hey Dave, can you give me an explanation of all of these preprocessor directives. I thank you for uour help. I am gonna print this and try to follow the preprocessor stuff as I am new in C. This has been a good lesson.
    Thanks to all
  • The preprocessor directives I used in my code were #include, #define, #undef, #ifdef, #else and #endif. You are probably familiar with #include, which is used to include the text from another file. This is normally used with header files with the .h extension.

    #define is used to define a symbol, that can be used to replace code or provide a compile-time flag for conditional compilation.

    #undef undefines a symbol.

    #ifdef tests whether a symbol has been define, and will include the following lines.

    #endif terminates an #ifdef section.

    #else can be used within an #ifdef section to include text when the #ifdef test fails.
  • JasonDorieJasonDorie Posts: 1,930
    edited 2016-01-19 23:30
    In Dave's specific case, he's checking to see if the symbol "DEBUG" is defined, and altering the code that gets compiled based on that.

    In fact, because the top of his code specifically does this:

    #undef DEBUG // forcibly un-define the DEBUG symbol if it's defined elsewhere

    ...the other code is only going to compile the "DEBUG not defined" parts.

    For example,
    #ifdef DEBUG   // this part is compiled if the symbol "DEBUG" is defined
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #define print printf
    
    #else  // this part is compiled if "DEBUG" is NOT defined
    
      #include "simpletools.h"                      // Include simple tools
      #include "fdserial.h"
    #endif
    

    So, since his code specifically un-defines that symbol, it's only going to use the 2nd part (simpletools and fdserial) and not the first part (stdio, stdlib, etc).
  • Great thanks for the explanation. I am looking in the books about this
  • JasonDorieJasonDorie Posts: 1,930
    edited 2016-01-20 02:12
    C/C++ is powerful, but it can be a pain in the butt for a beginner. Happy to help. :)

    Slightly more detail:

    All the lines that start with # are pre-processor commands (directives). The pre-processor does a rough parse of the source file looking for these. Directives can do things like text-based substitutions, #include a whole other file, or remove chunks of your code. The result is just a text file, and that is what's passed to the actual compiler.

    If you #define something, you can use it as a text-swapper in your code:
    #define BOO   print("This is what gets substituted.")
    
    void main(void)
    {
      BOO ;
    }
    

    That code would actually compile. The #define tells the pre-processor to look for instances of the text "BOO" and substitute the other text (the print command). They're often referred to as macros, and should be used sparingly . They're generally not type-safe and can be hard to debug.

    In Dave's code, they're used more appropriately to control the code. You'll occasionally see stuff in multi-platform code that looks like:
    #ifdef WINDOWS
      FileHandle = WinCreateFile("filename" .. . . );
    #endif
    #ifdef OSX
      FileHandle = OsxOpenFile("filename" .. . . );
    #endif
    

    It's usually done slightly differently, but it gets the point across. To compile on one platform or another, you just #define the platform value, and compilers often have things like that built in.
Sign In or Register to comment.