1+ #include "hardware/uart.h"
2+ #include "pico/stdlib.h"
3+
4+ #include <stdio.h>
5+ #include <stdlib.h>
6+ #include <string.h>
7+ #include <stdbool.h>
8+
9+
10+ #define UART_ID uart1
11+ #define BAUD_RATE 9600
12+ #define UART_TX_PIN 4
13+ #define UART_RX_PIN 5
14+ #define MAX_NMEA_LENGTH 256
15+
16+ typedef struct
17+ {
18+ float latitude ;
19+ float longitude ;
20+ bool is_valid ;
21+ } GPSData ;
22+
23+
24+ void uart_gps_init ()
25+ {
26+ uart_init (UART_ID , BAUD_RATE );
27+
28+ gpio_set_function (UART_TX_PIN , GPIO_FUNC_UART );
29+ gpio_set_function (UART_RX_PIN , GPIO_FUNC_UART );
30+
31+ uart_set_hw_flow (UART_ID , false, false);
32+ uart_set_format (UART_ID , 8 , 1 , UART_PARITY_NONE );
33+ uart_set_fifo_enabled (UART_ID , true);
34+ }
35+
36+ bool validate_nmea_checksum (char * nmea_string )
37+ {
38+ int len = strlen (nmea_string );
39+ printf ("Checksum Validation - String Length: %d\n" , len );
40+ printf ("Full NMEA String: %s" , nmea_string );
41+
42+ if (len < 7 )
43+ {
44+ printf ("Invalid: Too short (< 7 chars)\n" );
45+ return false;
46+ }
47+
48+ char * checksum_ptr = strchr (nmea_string , '*' );
49+ if (!checksum_ptr )
50+ {
51+ printf ("Invalid: No checksum marker (*) found\n" );
52+ return false;
53+ }
54+
55+ uint8_t calculated_checksum = 0 ;
56+ for (char * p = nmea_string + 1 ; p < checksum_ptr ; p ++ )
57+ {
58+ calculated_checksum ^= * p ;
59+ }
60+
61+ char hex_checksum [3 ];
62+ snprintf (hex_checksum , sizeof (hex_checksum ), "%02X" , calculated_checksum );
63+
64+ printf ("Calculated Checksum: %s\n" , hex_checksum );
65+ printf ("Received Checksum: %s\n" , checksum_ptr + 1 );
66+
67+ bool is_valid = strncmp (hex_checksum , checksum_ptr + 1 , 2 ) == 0 ;
68+ printf ("Checksum Validation: %s\n" , is_valid ? "VALID" : "INVALID" );
69+
70+ return is_valid ;
71+ }
72+
73+ void convert_nmea_to_decimal (char * nmea_coord , float * decimal_coord )
74+ {
75+ float degrees = atof (nmea_coord ) / 100.0 ;
76+ int int_degrees = (int )degrees ;
77+ float minutes = (degrees - int_degrees ) * 100.0 ;
78+
79+ * decimal_coord = int_degrees + (minutes / 60.0 );
80+ }
81+
82+ bool parse_nmea_gps (char * nmea_string , GPSData * gps_data )
83+ {
84+ if (!validate_nmea_checksum (nmea_string ))
85+ {
86+ printf ("Invalid NMEA Checksum\n" );
87+ return false;
88+ }
89+
90+ // Ignore all NMEA strings that are not of type GPRMC
91+ if (strncmp (nmea_string , "$GPRMC" , 6 ) != 0 )
92+ {
93+ return false;
94+ }
95+
96+ char * token ;
97+ char * tokens [12 ] = {0 };
98+ int token_count = 0 ;
99+
100+ // Tokenize the string
101+ token = strtok (nmea_string , "," );
102+ while (token != NULL && token_count < 12 )
103+ {
104+ tokens [token_count ++ ] = token ;
105+
106+ token = strtok (NULL , "," );
107+ }
108+
109+ // Check if we have enough tokens and data is valid
110+ if (token_count >= 12 && strcmp (tokens [2 ], "A" ) == 0 )
111+ {
112+ if (strlen (tokens [3 ]) > 0 )
113+ {
114+ convert_nmea_to_decimal (tokens [3 ], & gps_data -> latitude );
115+ if (tokens [4 ][0 ] == 'S' )
116+ gps_data -> latitude = - gps_data -> latitude ;
117+ }
118+
119+ if (strlen (tokens [5 ]) > 0 )
120+ {
121+ convert_nmea_to_decimal (tokens [5 ], & gps_data -> longitude );
122+ if (tokens [6 ][0 ] == 'W' )
123+ gps_data -> longitude = - gps_data -> longitude ;
124+ }
125+
126+ gps_data -> is_valid = true;
127+ return true;
128+ }
129+ }
130+
131+ void process_gps_data (GPSData * gps_data )
132+ {
133+ char nmea_buffer [MAX_NMEA_LENGTH ];
134+ int chars_read = 0 ;
135+
136+ while (uart_is_readable (UART_ID ) && chars_read < MAX_NMEA_LENGTH - 1 )
137+ {
138+ char received_char = uart_getc (UART_ID );
139+ nmea_buffer [chars_read ] = received_char ;
140+
141+ // NMEA strings are terminated by a newline character
142+ if ((int )received_char == 10 )
143+ {
144+ nmea_buffer [chars_read + 1 ] = '\0' ;
145+
146+ if (parse_nmea_gps (nmea_buffer , gps_data ))
147+ {
148+ printf ("Valid GPS Data Received\n" );
149+ }
150+
151+ chars_read = 0 ;
152+ break ;
153+ }
154+ else
155+ {
156+ chars_read ++ ;
157+ }
158+ }
159+ }
0 commit comments