This commit is contained in:
cfif 2024-12-04 13:10:49 +03:00
commit e35d7b3356
3 changed files with 306 additions and 0 deletions

63
Inc/NmeaACPParser.h Normal file
View File

@ -0,0 +1,63 @@
//
// Created by xemon on 01.09.22.
//
#ifndef NMEA_ACP_PARSER_H
#define NMEA_ACP_PARSER_H
#include "stdint.h"
#include "stddef.h"
#include "stdbool.h"
typedef struct {
uint8_t hour;
uint8_t minute;
uint8_t second;
uint16_t millisecond;
} tNmeaTimeAcp;
typedef struct {
uint8_t day;
uint8_t month;
uint8_t year;
} tNmeaDateAcp;
typedef struct {
double latitude;
char nsIndicator;
double longitude;
double horizontDiluitPrecis;
double altitude;
char ewIndicator;
} tNmeaLocationAcp;
typedef struct {
double declination;
double nsat;
double mode;
} tNmeaMagneticAcp;
typedef struct {
char status;
tNmeaDateAcp date;
tNmeaTimeAcp time;
tNmeaLocationAcp location;
tNmeaMagneticAcp magnetic;
double knotVelocity;
double kmhVelocity;
double course;
} tNmeaAcp;
uint32_t iNmeaTimestampFromAcp(tNmeaAcp *env);
void vNmeaACPSign(char *str, size_t *strLen);
bool bNmeaACPParse(char *acprmcString, size_t len, tNmeaAcp *result);
bool bNmeaACPString(char *nmeaString, size_t len, tNmeaAcp *acp);
bool bNmeaACPIsValidString(char *nmeaString, size_t len);
#endif //NMEA_0183_PARSER_NMEA_0183_PARSER_H

233
Src/NmeaACPParser.c Normal file
View File

@ -0,0 +1,233 @@
//
// Created by xemon on 01.09.22.
//
#include "NmeaACPParser.h"
#include "AsciiStringAssmeblingUtils.h"
#include "AsciiStringParsingUtils.h"
#include "time.h"
#include <string.h>
//#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;
}

10
modular.json Normal file
View File

@ -0,0 +1,10 @@
{
"cmake": {
"inc_dirs": [
"Inc"
],
"srcs": [
"Src/**.c"
]
}
}