diff --git a/GPGxx_defines.c b/GPGxx_defines.c new file mode 100644 index 0000000..770a9bb --- /dev/null +++ b/GPGxx_defines.c @@ -0,0 +1,29 @@ +/* + * GPGxx_defines.c + * + * Created on: 27 Jun 2025 + * Author: Christian Lind Vie Madsen + */ +#include "GPGxx_defines.h" + +nmea_field_type gpgll_type[5] = { + + NMEA_FIELD_INT32_T, + NMEA_FIELD_CHAR_T, + NMEA_FIELD_INT32_T, + NMEA_FIELD_CHAR_T, + NMEA_FIELD_UINT32_T, +}; + +nmea_field_desc_t nmea_sentences [1] = { + + { + .nmea_sentence = "$GPGLL", + .nmea_sentence_type = NMEA_MSG_GPGLL, + .field_type = gpgll_type, + .field_type_size = (sizeof(gpgll_type) / sizeof(gpgll_type[0])), + + }, + +}; + diff --git a/GPGxx_defines.h b/GPGxx_defines.h new file mode 100644 index 0000000..bde756a --- /dev/null +++ b/GPGxx_defines.h @@ -0,0 +1,61 @@ +/* + * GPGxx_defines.h + * + * Created on: 27 Jun 2025 + * Author: Christian Lind Vie Madsen + */ + +#ifndef CM_NMEA_DECODER_GPGXX_DEFINES_H_ +#define CM_NMEA_DECODER_GPGXX_DEFINES_H_ +#include + +typedef enum { + + NMEA_FIELD_UINT8_T = 0, + NMEA_FIELD_INT8_T = 1, + NMEA_FIELD_UINT16_T = 2, + NMEA_FIELD_INT16_T = 3, + NMEA_FIELD_UINT32_T = 4, + NMEA_FIELD_INT32_T = 5, + NMEA_FIELD_CHAR_T = 6, + NMEA_FIELD_STRING_T = 7, + NMEA_FIELD_CHECKSUM_T = 8 + +}nmea_field_type; + + +typedef enum { + + NMEA_MSG_GPGLL = 0, + +}nmea_msg_type; + +typedef struct { + int32_t latitude; + char lat_dir; + int32_t longitude; + char lon_dir; + int32_t utc_time; +} __attribute__((packed)) GPGLL_t; + +typedef struct { + + union{ + + GPGLL_t gpgll; + }; + +}__attribute__((packed)) nmea_msg_t; + +typedef struct { + const char *nmea_sentence; + nmea_msg_type nmea_sentence_type; + nmea_field_type *field_type; + uint8_t field_type_size; + +} __attribute__((packed)) nmea_field_desc_t; + +extern nmea_field_desc_t nmea_sentences[1]; + + +#endif /* CM_NMEA_DECODER_GPGXX_DEFINES_H_ */ diff --git a/cm_nmea_decoder.c b/cm_nmea_decoder.c index 3a1983d..68d9280 100644 --- a/cm_nmea_decoder.c +++ b/cm_nmea_decoder.c @@ -8,53 +8,157 @@ #include "cm_nmea_decoder.h" #include #include -#define MAX_NMEA_MSG_TYPES 2 -const char *nmea_msg_types[MAX_NMEA_MSG_TYPES] = {"$GPGLL", "$GPGFF"}; -typedef int (*nmeaDecoder_Evt_fpt)(cm_nmea_msg_t *inst, char *str); -static int findLenToChar(const char *str, const char character){ +static int findFirstChar(const char *str, const char Ch){ + + for(int i = 0; ; i++){ + + if(str[i] == Ch) return i; + if(str[i] == '\0') return -1; + } + + return -1; +} + +static int isPeriodInLine(char *str){ int i = 0; - while((str[i] != character) && (str[i] != '\0')) i++; + while((str[i] != '.') && (str[i] != '\0') && (str[i] != ',')) i++; + + if(str[i] == '\0' || str[i] == ',') return -1; return i; } -static int sGPGLL_decode(cm_nmea_msg_t *inst, char *str){ +static int moveToNextLine(char **str){ - printf("%s \r\n ",str); + // Check if moved to next line or past the string. + while((**str != ',') && (**str != '\0')){ - //Move pointer until we meet a "," or NULL! - while((str != NULL) && (*str != ',')) str++; + // Count pointer up because we didnt came across ',' or end + (*str)++; + + } + + // Throw error code if we found end and not a ',' + if(**str == '\0') return -1; // Move past ',' - if (*str == ',') str++; + (*str)++; - // Find comma - int comma_idx = findLenToChar(str, '.'); + return 1; - // Replace with '\0' - str[comma_idx] = '\0'; +} - // Decode first part of latitude - inst->gpgll_msg.coordinates.lat_deg = atoi(str); +static int decodeIntIntoStruct(uint8_t *inst, char *str, nmea_field_type type){ + + int isPeriod = isPeriodInLine(str); + uint8_t next_val = 0; + + int lineEnd = findFirstChar(str, ','); + if (lineEnd < 0) return -1; // error check + str[lineEnd] = '\0'; + + switch (type) { + case NMEA_FIELD_UINT8_T: + *((uint8_t*)inst) = (uint8_t)atoi(str); + next_val = sizeof(uint8_t); + break; + case NMEA_FIELD_INT8_T: + *((int8_t*)inst) = (int8_t)atoi(str); + next_val = sizeof(int8_t); + break; + case NMEA_FIELD_UINT16_T: + *((uint16_t*)inst) = (uint16_t)(isPeriod != -1 ? atoi(str) * 10000 + atoi(str + isPeriod + 1) : atoi(str)); + next_val = sizeof(uint16_t); + break; + case NMEA_FIELD_INT16_T: + *((int16_t*)inst) = (int16_t)(isPeriod != -1 ? atoi(str) * 10000 + atoi(str + isPeriod + 1) : atoi(str)); + next_val = sizeof(int16_t); + break; + case NMEA_FIELD_UINT32_T: + *((uint32_t*)inst) = (uint32_t)(isPeriod != -1 ? atoi(str) * 10000 + atoi(str + isPeriod + 1) : atoi(str)); + next_val = sizeof(uint32_t); + break; + case NMEA_FIELD_INT32_T: + *((int32_t*)inst) = (int32_t)(isPeriod != -1 ? atoi(str) * 10000 + atoi(str + isPeriod + 1) : atoi(str)); + next_val = sizeof(int32_t); + //printf("val: %d \r\n", *((int32_t*)inst)); + break; + + default: + break; + } + + str[lineEnd] = ','; // Restore + + return next_val; +} + + +static int storeValIntoStruct(uint8_t *inst, char *str, nmea_field_type type){ + + + + if((type >= NMEA_FIELD_UINT8_T) && (type <= NMEA_FIELD_INT32_T)){ + + return decodeIntIntoStruct(inst, str, type); + } + + if(type == NMEA_FIELD_CHAR_T){ + + char *p = (void*)inst; + + *p = *str; + } + + + + + return 1; + + + +} + +static int sNMEA_decode(cm_nmea_msg_t *inst, char *str, int sentence_idx){ + + nmea_field_desc_t *p = &nmea_sentences[sentence_idx]; + + uint8_t *dst = (void*)inst; + + int next_val = 0; + + moveToNextLine(&str); + + printf("%s \r\n", str); + + for(int i = 0; i < p->field_type_size; i++){ + + next_val = storeValIntoStruct(dst, str, p->field_type[i]); + + if(next_val == -1) return next_val; + + dst += next_val; + + + if (i < p->field_type_size - 1 && moveToNextLine(&str) == -1) + return 0; + + } + + printf("lat: %d, lat_dir: %c, lon: %d, lon_dir: %c, utc: %d", inst->msg.gpgll.latitude, inst->msg.gpgll.lat_dir, inst->msg.gpgll.longitude, inst->msg.gpgll.lon_dir, inst->msg.gpgll.utc_time); - printf("deg: %d, str: %s \r\n ",comma_idx,str); return 0; } - -nmeaDecoder_Evt_fpt nmea_decodeFuncs[1] = { - (void *)&sGPGLL_decode, -}; - static int sNMEA_getMsgType(char *str){ - for(int i = 0; i < (MAX_NMEA_MSG_TYPES-1); i++){ + for(int i = 0; i < (sizeof(nmea_sentences) / sizeof(nmea_sentences[0])); i++){ - if(strcmp(nmea_msg_types[i], str)) return i; + if(strncmp(nmea_sentences[i].nmea_sentence, str, 6) == 0) return nmea_sentences[i].nmea_sentence_type; }; return -1; @@ -75,8 +179,9 @@ int cm_nmea_stringDecode(cm_nmea_msg_t *inst, char *str){ // Check if we found a valid NMEA message. if(nmea_msg_idx == -1) return nmea_msg_idx; - // Use the correct function to decode! - if(nmea_msg_idx >= 0) nmea_decodeFuncs[nmea_msg_idx](inst,str); + // Decode message: + sNMEA_decode(inst,str,nmea_msg_idx); + return nmea_msg_idx; diff --git a/cm_nmea_decoder.h b/cm_nmea_decoder.h index 651ef3e..f04ba32 100644 --- a/cm_nmea_decoder.h +++ b/cm_nmea_decoder.h @@ -9,20 +9,47 @@ #define MAIN_CM_NMEA_DECODER_CM_NMEA_DECODER_H_ #include #include +#include "GPGxx_defines.h" -typedef enum { +typedef struct { - NMEA_MSG_GPGLL = 0, + nmea_msg_t msg; -}nmea_msg_type; +}cm_nmea_msg_t; -typedef struct{ - uint8_t lat_deg; // Degrees: 0–90 (latitude) or 0–180 (longitude) - uint32_t lat_min_x10000; // Minutes × 10,000 (e.g., 16.4512 → 164512) - uint8_t lon_deg; // Degrees: 0–90 (latitude) or 0–180 (longitude) - uint32_t lon_min_x10000; // Minutes × 10,000 (e.g., 16.4512 → 164512) + + + + +int cm_nmea_stringDecode(cm_nmea_msg_t *inst, char *str); + +/* + #define OFFSET(struct_type, field) ((size_t)&(((struct_type *)0)->field)) + +FieldDesc gpgll_fields[] = { + { "latitude", FIELD_INT32, OFFSET(GPGLL_t, latitude), 1 }, + { "lat_dir", FIELD_CHAR, OFFSET(GPGLL_t, lat_dir), 0 }, + { "longitude", FIELD_INT32, OFFSET(GPGLL_t, longitude), 1 }, + { "lon_dir", FIELD_CHAR, OFFSET(GPGLL_t, lon_dir), 0 }, + { "utc_time", FIELD_UINT32, OFFSET(GPGLL_t, utc_time), 0 } +}; + + const char *nmea = "$GPGLL,5606.2719,N,01007.2199,E,130808,A,A*56"; + GPGLL_t gpgll = {0}; + + parse_nmea_generic(nmea, &gpgll, gpgll_fields, sizeof(gpgll_fields)/sizeof(gpgll_fields[0])); + + printf("Latitude: %d\n", gpgll.latitude); + printf("Longitude: %d\n", gpgll.longitude); + printf("Time: %u\n", gpgll.utc_time); + + + + typedef struct{ + uint8_t deg; // Degrees: 0–90 (latitude) or 0–180 (longitude) + uint32_t min_x10000; // Minutes × 10,000 (e.g., 16.4512 → 164512) char dir; // 'N', 'S', 'E', or 'W' }cm_nmea_coord; @@ -40,15 +67,6 @@ typedef struct { }cm_nmea_gpgll_msg; -typedef struct { - - union{ - - cm_nmea_gpgll_msg gpgll_msg; - }; - -}cm_nmea_msg_t; - -int cm_nmea_stringDecode(cm_nmea_msg_t *inst, char *str); + * */ #endif /* MAIN_CM_NMEA_DECODER_CM_NMEA_DECODER_H_ */