// // Created by xemon on 01.09.22. // #include "NmeaACPParser.h" #include "AsciiStringAssmeblingUtils.h" #include "AsciiStringParsingUtils.h" #include "time.h" #include //#include "printf.h" double specifAtCommand; //static char *strnstr(const char *haystack, const char *needle, size_t len) //{ // int i; // size_t needle_len; // // if (0 == (needle_len = strnlen(needle, len))) // return (char *)haystack; // // for (i=0; i<=(int)(len-needle_len); i++) // { // if ((haystack[0] == needle[0]) && // (0 == strncmp(haystack, needle, needle_len))) // return (char *)haystack; // // haystack++; // } // return NULL; //} #define Nmea0183ParseShortCharsDecimalNumber(STR, LEN) (uint16_t) iAsciiStringParseUnsignedLongDecimalNumber(STR,((STR)+(LEN))) #define Nmea0183ParseDouble(STR, LEN) dAsciiStringParseDouble(STR,((STR)+(LEN))) #define Nmea0183SkipSpace(STR, STR_END) xAsciiStringSkipSpace(STR,STR_END) #define Nmea0183SkipToChar(STR, STR_END, SYMBOL) xAsciiStringSeekChar(STR,STR_END,SYMBOL) #define Nmea0183ParseNextPortion(BEGIN, DIV, STR_END) iAsciiStringMoveToNextParsingBlock(BEGIN,DIV,STR_END,',') #define Nmea0183ParseHexByte(STR) iAsciiStringParseHexByte(STR) bool NmeaACPParseTime(char *utcString, char const *utcStringEnd, tNmeaTimeAcp *time) { uint32_t len = utcStringEnd - utcString; uint8_t charsLeft = len - 7; if (len > 10 || len < 9) { return false; } if (utcString[6] != '.') { return false; } time->hour = Nmea0183ParseShortCharsDecimalNumber(utcString + 0, 2); time->minute = Nmea0183ParseShortCharsDecimalNumber(utcString + 2, 2); time->second = Nmea0183ParseShortCharsDecimalNumber(utcString + 4, 2); time->millisecond = Nmea0183ParseShortCharsDecimalNumber(utcString + 7, charsLeft); charsLeft = 3 - charsLeft; while (charsLeft) { time->millisecond *= 10; --charsLeft; } return true; } bool NmeaACPParseDate(char *utcString, char const *utcStringEnd, tNmeaDateAcp *date) { uint32_t len = utcStringEnd - utcString; if (len != 6) { return false; } date->day = Nmea0183ParseShortCharsDecimalNumber(utcString + 0, 2); date->month = Nmea0183ParseShortCharsDecimalNumber(utcString + 2, 2); date->year = Nmea0183ParseShortCharsDecimalNumber(utcString + 4, 2); return true; } uint8_t uNmeaACPChecksum(const char *str, size_t len) { char *end = (char *) (str + len); unsigned char result; result = 0; str++; while ((str != end) && (*str != '*') && (*str != '\0')) result ^= *str++; return result; } void vNmeaACPSign(char *str, size_t *strLen) { uint8_t crc = uNmeaACPChecksum(str, *strLen); vAsciiStringAddChar(str, strLen, '*'); vAsciiStringAddByteAsHex(str, strLen, crc); } bool bNmeaACPString(char *nmeaString, size_t len, tNmeaAcp *acp) { if (nmeaString[0] != '$') { return false; } return true; } uint32_t iNmeaTimestampFromAcp(tNmeaAcp *env) { struct tm time; time.tm_hour = env->time.hour; time.tm_min = env->time.minute; time.tm_sec = env->time.second; time.tm_mday = env->date.day; time.tm_mon = env->date.month - 1; time.tm_year = (2000 - 1900) + env->date.year; return mktime(&time); } bool bNmeaACPIsValidString(char *nmeaString, size_t len) { if (specifAtCommand == 1) { char *dataEndPos = strnstr((char *) nmeaString, "*", len); uint8_t checksumCalculated = uNmeaACPChecksum(nmeaString, dataEndPos - nmeaString); ++dataEndPos; uint8_t checksumInString = Nmea0183ParseHexByte(dataEndPos); return checksumCalculated == checksumInString; } else { return 1; } } bool bNmeaACPParse(char *rmcString, size_t len, tNmeaAcp *result) { rmcString = rmcString + 9; len = len - 9; char *end = rmcString + len; char *front = rmcString; char *nextDivider = front - 1; if (Nmea0183ParseNextPortion(&front, &nextDivider, end) > 0) { if (!NmeaACPParseTime(front, nextDivider, &result->time)) { return false; } } else { result->time.second = 0; result->time.minute = 0; result->time.hour = 0; result->time.millisecond = 0; } if (Nmea0183ParseNextPortion(&front, &nextDivider, end) > 0) { result->location.latitude = Nmea0183ParseDouble(front, nextDivider - front); result->location.nsIndicator = front[9]; } else { result->location.latitude = 0; } if (Nmea0183ParseNextPortion(&front, &nextDivider, end) > 0) { result->location.longitude = Nmea0183ParseDouble(front, nextDivider - front); result->location.ewIndicator = front[10]; } else { result->location.longitude = 0; } // снижение точности if (Nmea0183ParseNextPortion(&front, &nextDivider, end) > 0) { result->location.horizontDiluitPrecis = Nmea0183ParseDouble(front, nextDivider - front); } else { result->location.horizontDiluitPrecis = 0; } if (Nmea0183ParseNextPortion(&front, &nextDivider, end) > 0) { result->location.altitude = Nmea0183ParseDouble(front, nextDivider - front); } else { result->location.altitude = 0; } if (Nmea0183ParseNextPortion(&front, &nextDivider, end) > 0) { result->status = Nmea0183ParseDouble(front, nextDivider - front); if (result->status > 2) { result->status = 'A'; } else { result->status = 'V'; } } else { result->status = 0; } if (Nmea0183ParseNextPortion(&front, &nextDivider, end) > 0) { result->course = Nmea0183ParseDouble(front, nextDivider - front); } else { result->course = 0; } if (Nmea0183ParseNextPortion(&front, &nextDivider, end) > 0) { result->kmhVelocity = Nmea0183ParseDouble(front, nextDivider - front); } else { result->kmhVelocity = 0; } if (Nmea0183ParseNextPortion(&front, &nextDivider, end) > 0) { result->knotVelocity = Nmea0183ParseDouble(front, nextDivider - front); } else { result->knotVelocity = 0; } if (Nmea0183ParseNextPortion(&front, &nextDivider, end) > 0) { if (!NmeaACPParseDate(front, nextDivider, &result->date)) { return false; } } else { result->date.year = 0; result->date.month = 0; result->date.day = 0; } if (Nmea0183ParseNextPortion(&front, &nextDivider, end) > 0) { result->magnetic.nsat = *front; } else { result->magnetic.nsat = 0; } return true; }