上传第一版代码
parent
021739e0be
commit
5af266e05b
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
.DS_store
|
|
@ -0,0 +1,95 @@
|
|||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator and
|
||||
subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the
|
||||
purpose of contributing to a commons of creative, cultural and scientific works
|
||||
("Commons") that the public can reliably and without fear of later claims of
|
||||
infringement build upon, modify, incorporate in other works, reuse and
|
||||
redistribute as freely as possible in any form whatsoever and for any purposes,
|
||||
including without limitation commercial purposes. These owners may contribute to
|
||||
the Commons to promote the ideal of a free culture and the further production of
|
||||
creative, cultural and scientific works, or to gain reputation or greater
|
||||
distribution for their Work in part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation of
|
||||
additional consideration or compensation, the person associating CC0 with a Work
|
||||
(the "Affirmer"), to the extent that he or she is an owner of Copyright and
|
||||
Related Rights in the Work, voluntarily elects to apply CC0 to the Work and
|
||||
publicly distribute the Work under its terms, with knowledge of his or her
|
||||
Copyright and Related Rights in the Work and the meaning and intended legal
|
||||
effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and Related
|
||||
Rights"). Copyright and Related Rights include, but are not limited to, the
|
||||
following:
|
||||
|
||||
the right to reproduce, adapt, distribute, perform, display, communicate, and
|
||||
translate a Work; moral rights retained by the original author(s) and/or
|
||||
performer(s); publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work; rights protecting against unfair competition in
|
||||
regards to a Work, subject to the limitations in paragraph 4(a), below; rights
|
||||
protecting the extraction, dissemination, use and reuse of data in a Work;
|
||||
database rights (such as those arising under Directive 96/9/EC of the European
|
||||
Parliament and of the Council of 11 March 1996 on the legal protection of
|
||||
databases, and under any national implementation thereof, including any amended
|
||||
or successor version of such directive); and other similar, equivalent or
|
||||
corresponding rights throughout the world based on applicable law or treaty, and
|
||||
any national implementations thereof. 2. Waiver. To the greatest extent
|
||||
permitted by, but not in contravention of, applicable law, Affirmer hereby
|
||||
overtly, fully, permanently, irrevocably and unconditionally waives, abandons,
|
||||
and surrenders all of Affirmer's Copyright and Related Rights and associated
|
||||
claims and causes of action, whether now known or unknown (including existing as
|
||||
well as future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or treaty
|
||||
(including future time extensions), (iii) in any current or future medium and
|
||||
for any number of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the "Waiver").
|
||||
Affirmer makes the Waiver for the benefit of each member of the public at large
|
||||
and to the detriment of Affirmer's heirs and successors, fully intending that
|
||||
such Waiver shall not be subject to revocation, rescission, cancellation,
|
||||
termination, or any other legal or equitable action to disrupt the quiet
|
||||
enjoyment of the Work by the public as contemplated by Affirmer's express
|
||||
Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be
|
||||
judged legally invalid or ineffective under applicable law, then the Waiver
|
||||
shall be preserved to the maximum extent permitted taking into account
|
||||
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
|
||||
is so judged Affirmer hereby grants to each affected person a royalty-free, non
|
||||
transferable, non sublicensable, non exclusive, irrevocable and unconditional
|
||||
license to exercise Affirmer's Copyright and Related Rights in the Work (i) in
|
||||
all territories worldwide, (ii) for the maximum duration provided by applicable
|
||||
law or treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional purposes
|
||||
(the "License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any reason
|
||||
be judged legally invalid or ineffective under applicable law, such partial
|
||||
invalidity or ineffectiveness shall not invalidate the remainder of the License,
|
||||
and in such case Affirmer hereby affirms that he or she will not (i) exercise
|
||||
any of his or her remaining Copyright and Related Rights in the Work or (ii)
|
||||
assert any associated claims and causes of action with respect to the Work, in
|
||||
either case contrary to Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document. Affirmer offers
|
||||
the Work as-is and makes no representations or warranties of any kind concerning
|
||||
the Work, express, implied, statutory or otherwise, including without limitation
|
||||
warranties of title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or the
|
||||
present or absence of errors, whether or not discoverable, all to the greatest
|
||||
extent permissible under applicable law. Affirmer disclaims responsibility for
|
||||
clearing rights of other persons that may apply to the Work or any use thereof,
|
||||
including without limitation any person's Copyright and Related Rights in the
|
||||
Work. Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the Work. Affirmer
|
||||
understands and acknowledges that Creative Commons is not a party to this
|
||||
document and has no duty or obligation with respect to this CC0 or use of the
|
||||
Work.
|
|
@ -0,0 +1,244 @@
|
|||
# NMEAParser
|
||||
|
||||
An Arduino library to parse NMEA sentences.
|
||||
|
||||
NMEA is a communication standard in the marine equipment industry: GPS, anemometers,... The NMEAParser library allows you to analyze NMEA sentences and associate handlers to each of those that need to be recognized. The library provides the means to associate a handler to each identifier and also provides functions to retrieve the arguments of the sentence in different data formats: character, integer, float, character string.
|
||||
|
||||
## Changelog
|
||||
|
||||
* ```1.1``` : Added joker in type. Remove binaries from ```extra```
|
||||
* ```1.0``` : Initial release
|
||||
|
||||
## Memory footprint
|
||||
|
||||
On an Arduino Uno, an instance of a NMEAParser requires 97 bytes with only one handler. 8 bytes per additional handler are required.
|
||||
|
||||
## Using NMEAParser
|
||||
|
||||
As usual, the library should be included at the beginning of the sketch.
|
||||
|
||||
```C++
|
||||
#include <NMEAParser.h>
|
||||
```
|
||||
|
||||
Then, you must instantiate a parser as follows:
|
||||
|
||||
```C++
|
||||
NMEAParser<4> parser;
|
||||
```
|
||||
|
||||
The ```4``` is the maximum number of handlers desired, ```parser``` is the name of the object that will allow the analysis of NMEA sentences. you can of course use the name you want.
|
||||
|
||||
In ```setup``` you configure your parser as you wish using the following functions.
|
||||
|
||||
### ```void addHandler(<type>, <handler>)```
|
||||
|
||||
where ```<type>``` is a character string and the type of sentence to recongnize, and ```<handler>``` the function to call when a sentence is recognize. ```<type>``` can be a string stored un RAM or a string stored in flash : ```F("ASTRI")```. If ```<type>``` has more than 5 characters, it is trucated.
|
||||
|
||||
For example, suppose you want to recognize the following sounder sentences which give the water depth below keel (DBK) and below surface (DBS):
|
||||
|
||||
```
|
||||
$SDDBK,...
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
```
|
||||
$SDDBS,...
|
||||
```
|
||||
|
||||
You will install two handlers as follows (assuming your parsing object is named ```parser```):
|
||||
|
||||
```C++
|
||||
parser.addHandler("SDDBK", handleDepthBelowKeel);
|
||||
parser.addHanlder("SDDBS", handleDepthBelowSurface);
|
||||
```
|
||||
|
||||
```handleDepthBelowKeel``` and ```handleDepthBelowSurface``` are functions that will be called when sentences are recognized.
|
||||
|
||||
With version 1.1, ```<type>``` may include hyphens. An hyphens matches any character. For instance if you want the handler to match all sentences coming from the sounder, you would write:
|
||||
|
||||
```C++
|
||||
parser.addHandler("SD---", handleSounder);
|
||||
```
|
||||
|
||||
```handleSounder``` function would be called for any sentence with the type beginning with SD.
|
||||
|
||||
### ```void setDefaultHandler(<handler>)```
|
||||
|
||||
When a sentence is succefully parsed but none of the handler correspond to it, ```<handler>``` is called. It is a function corresponding to a ```void f(void)``` prototype. By default, no function is called.
|
||||
|
||||
### ```void setErrorHandler(<handler>)```
|
||||
|
||||
When a sentence is malformed : too long, wrong characters, etc, ```<handler>``` is called. It is a function corresponding to a ```void f(void)``` prototype. By default, no function is called.
|
||||
|
||||
### ```void setHandleCRC(<doCRC>)```
|
||||
|
||||
Specifies whether the CRC is checked or not. By default, the CRC is checked. If you do not want CRC verification, pass ```false``` to ```setHandleCRC```.
|
||||
|
||||
---
|
||||
In the handlers, you will get the arguments of the sentence, the sentence type or the error if any by using the following functions:
|
||||
|
||||
### ```bool getArg(<argnum>, <argval>)```
|
||||
|
||||
is used to get the arguments of the sentence. ```<argnum>``` is the number of the argument, starting at 0 for the argument that follows the identifier. ```<argval``` is a variable where the argument value will be stored if successful. ```getArg``` returns a boolean which is true if successfull, false if not.
|
||||
|
||||
Continuing with the example, [both sentences have the same 6 arguments](https://gpsd.gitlab.io/gpsd/NMEA.html#_dbk_depth_below_keel)
|
||||
|
||||
* Argument 0 is a float number giving the depth in feet.
|
||||
* Argument 1 is a ```f``` for feet.
|
||||
* Argument 2 is a float number giving the depth in meters.
|
||||
* Argument 3 is a ```M``` for Meters.
|
||||
* Argument 4 is a float number giving the depth in fathoms.
|
||||
* At last Argument 5 is a ```F``` for Fathoms.
|
||||
|
||||
Suppose you are interested by the depths in meters and you have two float variables to store theses data:
|
||||
|
||||
```C++
|
||||
float depthBelowKeel;
|
||||
float depthBelowSurface;
|
||||
```
|
||||
|
||||
You would implement ```handleDepthBelowKeel``` and ```handleDepthBelowSurface``` as follow:
|
||||
|
||||
```C++
|
||||
void handleDepthBelowKeel(void)
|
||||
{
|
||||
float depth;
|
||||
if (parser.getArg(2, depth))
|
||||
{
|
||||
depthBelowKeel = depth;
|
||||
}
|
||||
}
|
||||
|
||||
void handleDepthBelowSurface(void)
|
||||
{
|
||||
float depth;
|
||||
if (parser.getArg(2, depth))
|
||||
{
|
||||
depthBelowSurface = depth;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ```bool getType(<type>) / bool getType(<num>, <charType>)```
|
||||
|
||||
3 versions of ```getType``` exist. The first one puts the type of the sentence in ```<type>``` which is a ```char *```. The second one does the same but ```<type>``` is a ```String```. Return ```true``` if a type has been parsed, ```false``` otherwise. The third one puts a character of the type at position ```<num>```
|
||||
|
||||
### ```uint8_t argCount()```
|
||||
|
||||
Return the number of arguments.
|
||||
|
||||
### ```NMEA::ErrorCode error()```
|
||||
|
||||
Return the error. The returned code can be:
|
||||
|
||||
* ```NMEA::NO_ERROR```: no error;
|
||||
* ```NMEA::UNEXPECTED_CHAR```: a char which is not expected in the sentence has been encountered;
|
||||
* ```NMEA::BUFFER_FULL```: the sentence is too long to fit in the buffer;
|
||||
* ```NMEA::TYPE_TOO_LONG```: the sentence type has more than 5 characters;
|
||||
* ```NMEA::CRC_ERROR```: the CRC is wrong;
|
||||
* ```NMEA::INTERNAL_ERROR```: the internal state of the parser is wrong, should not happen by the way.
|
||||
|
||||
### Feeding characters to the parser
|
||||
|
||||
Characters are fed to the parser in ```loop```, assuming we get the characters from ```Serial```, the following way:
|
||||
|
||||
```C++
|
||||
while (Serial.available()) {
|
||||
parser << Serial.read();
|
||||
}
|
||||
```
|
||||
|
||||
This can also be done in ```serialEvent```. ```while``` could be replaced by ```if```.
|
||||
|
||||
## A complete example
|
||||
|
||||
Let's say you want to turn the Arduino's LED on and off. We define a NMEA sentence taking a single argument: 1 to turn on the LED and 0 to turn it off. The sentence can therefore be:
|
||||
|
||||
```
|
||||
$ARLED,1*43
|
||||
```
|
||||
|
||||
to turn the LED on and
|
||||
|
||||
```
|
||||
$ARLED,0*42
|
||||
```
|
||||
|
||||
to turn the LED off. We define a single handler to retrieve the argument and control the LED accordingly:
|
||||
|
||||
```C++
|
||||
void ledHandler()
|
||||
{
|
||||
Serial.print("Got ARLED with ");
|
||||
Serial.print(parser.argCount());
|
||||
Serial.println(" arguments");
|
||||
int ledState;
|
||||
if (parser.getArg(0,ledState)) {
|
||||
digitalWrite(LED_BUILTIN, ledState == 0 ? LOW : HIGH);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We define 2 other handlers for anything else than ```ARLED``` and for errors
|
||||
|
||||
```C++
|
||||
void errorHandler()
|
||||
{
|
||||
Serial.print("*** Error : ");
|
||||
Serial.println(parser.error());
|
||||
}
|
||||
|
||||
void unknownCommand()
|
||||
{
|
||||
Serial.print("*** Unkown command : ");
|
||||
char buf[6];
|
||||
parser.getType(buf);
|
||||
Serial.println(buf);
|
||||
}
|
||||
```
|
||||
|
||||
In ```setup```, the handlers are installed:
|
||||
|
||||
```C++
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
parser.setErrorHandler(errorHandler);
|
||||
parser.addHandler("ARLED", ledHandler);
|
||||
parser.setDefaultHandler(unknownCommand);
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
}
|
||||
```
|
||||
|
||||
At last in loop, we feed the parser with the chars coming from ```Serial```.
|
||||
|
||||
```C++
|
||||
void loop() {
|
||||
if (Serial.available()) {
|
||||
parser << Serial.read();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
# Extra software
|
||||
|
||||
Additional software can be found in the ```extra``` directory.
|
||||
|
||||
## NMEA sentences generator
|
||||
|
||||
The ```gen``` subdirectory contains ```nmeagen```, a NMEA sentence generator program. This program generates well formed sentences with good or bad CRC. It can be used to test the parser. To build ```nmeagen```, run the ```build.sh``` script. ```nmeagen``` takes 1 or 2 arguments. The first argument is the number of sentences to generate. The second optional one is the number of sentences with bad CRC.
|
||||
|
||||
## Test program
|
||||
|
||||
The ```test``` subdirectory contains a test program that compile on Linux or Mac OS X. It takes sentences from the standard input, parse them and print out the type, the arguments and if an error occured.
|
||||
|
||||
---
|
||||
# Additional links
|
||||
|
||||
* [NMEA CRC calculator](https://nmeachecksum.eqth.net)
|
||||
* [NMEA 0183 on Wikipedia](https://fr.wikipedia.org/wiki/NMEA_0183)
|
||||
* [NMEA revealed](https://gpsd.gitlab.io/gpsd/NMEA.html)
|
||||
|
||||
That's all folks !
|
60
1.Software/3rdparty/NMEAParser-master/examples/NMEALedLight/NMEALedLight.ino
vendored
Normal file
60
1.Software/3rdparty/NMEAParser-master/examples/NMEALedLight/NMEALedLight.ino
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* NMEAParser library.
|
||||
*
|
||||
* A NMEA example to switch ON or OFF the built in LED
|
||||
*
|
||||
* Sentences to send are :
|
||||
*
|
||||
* $ARLED,1*43
|
||||
*
|
||||
* to switch the LED on and
|
||||
*
|
||||
* $ARLED,0*42
|
||||
*
|
||||
* to switch the LED off
|
||||
*
|
||||
* Set the serial monitor end of line to <cr><lf>
|
||||
*/
|
||||
#include <NMEAParser.h>
|
||||
|
||||
/* A parser with only one handler */
|
||||
NMEAParser<1> parser;
|
||||
|
||||
void errorHandler()
|
||||
{
|
||||
Serial.print("*** Error : ");
|
||||
Serial.println(parser.error());
|
||||
}
|
||||
|
||||
void unknownCommand()
|
||||
{
|
||||
Serial.print("*** Unkown command : ");
|
||||
char buf[6];
|
||||
parser.getType(buf);
|
||||
Serial.println(buf);
|
||||
}
|
||||
|
||||
void ledHandler()
|
||||
{
|
||||
Serial.print("Got ARLED with ");
|
||||
Serial.print(parser.argCount());
|
||||
Serial.println(" arguments");
|
||||
int ledState;
|
||||
if (parser.getArg(0,ledState)) {
|
||||
digitalWrite(LED_BUILTIN, ledState == 0 ? LOW : HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
parser.setErrorHandler(errorHandler);
|
||||
parser.addHandler("ARLED", ledHandler);
|
||||
parser.setDefaultHandler(unknownCommand);
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (Serial.available()) {
|
||||
parser << Serial.read();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* NMEAParser library.
|
||||
*
|
||||
* A NMEA example to switch ON or OFF the built in LED but with the use
|
||||
* of wild char in the type
|
||||
*
|
||||
* Sentences to send are :
|
||||
*
|
||||
* $ARLE1*2B
|
||||
*
|
||||
* to switch the LED on and
|
||||
*
|
||||
* $ARLE0*2A
|
||||
*
|
||||
* to switch the LED off
|
||||
*
|
||||
* Set the serial monitor end of line to <cr><lf>
|
||||
*/
|
||||
#include <NMEAParser.h>
|
||||
|
||||
/* A parser with only one handler */
|
||||
NMEAParser<1> parser;
|
||||
|
||||
void errorHandler()
|
||||
{
|
||||
Serial.print("*** Error : ");
|
||||
Serial.println(parser.error());
|
||||
}
|
||||
|
||||
void unknownCommand()
|
||||
{
|
||||
Serial.print("*** Unkown command : ");
|
||||
char buf[6];
|
||||
parser.getType(buf);
|
||||
Serial.println(buf);
|
||||
}
|
||||
|
||||
void ledHandler()
|
||||
{
|
||||
Serial.print("Got ARLEx with ");
|
||||
Serial.print(parser.argCount());
|
||||
Serial.println(" arguments");
|
||||
|
||||
char wantedLedState;
|
||||
if (parser.getType(4, wantedLedState)) { // get the 4th character ot the type
|
||||
if (wantedLedState == '0' || wantedLedState == '1') {
|
||||
digitalWrite(LED_BUILTIN, wantedLedState == '0' ? LOW : HIGH);
|
||||
}
|
||||
else {
|
||||
Serial.println("x should be 0 or 1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
parser.setErrorHandler(errorHandler);
|
||||
parser.addHandler("ARLE-", ledHandler);
|
||||
parser.setDefaultHandler(unknownCommand);
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (Serial.available()) {
|
||||
parser << Serial.read();
|
||||
}
|
||||
}
|
77
1.Software/3rdparty/NMEAParser-master/examples/parsingExample/parsingExample.ino
vendored
Normal file
77
1.Software/3rdparty/NMEAParser-master/examples/parsingExample/parsingExample.ino
vendored
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* NMEAParser library.
|
||||
*
|
||||
* Parsing example.
|
||||
*
|
||||
* 2 handlers are added and 2 sentences are parsed
|
||||
*/
|
||||
#include <NMEAParser.h>
|
||||
|
||||
/* A parser is declared with 2 handlers at most */
|
||||
NMEAParser<2> parser;
|
||||
|
||||
const char firstSentence[] = "$DBAXK*54\r\n";
|
||||
const char secondSentence[] = "$EJCHQ,03,O,UUEIE,S,953.11,S,4.172,ASBUX,J*54\r\n";
|
||||
|
||||
void errorHandler()
|
||||
{
|
||||
Serial.print("*** Error : ");
|
||||
Serial.println(parser.error());
|
||||
}
|
||||
|
||||
void firstHandler()
|
||||
{
|
||||
Serial.print("Got DBAXK with ");
|
||||
Serial.print(parser.argCount());
|
||||
Serial.println(" arguments");
|
||||
}
|
||||
|
||||
void secondHandler()
|
||||
{
|
||||
Serial.print("Got $EJCHQ with ");
|
||||
Serial.print(parser.argCount());
|
||||
Serial.println(" arguments");
|
||||
int arg0;
|
||||
char arg1;
|
||||
char arg2[10];
|
||||
char arg3;
|
||||
float arg4;
|
||||
char arg5;
|
||||
float arg6;
|
||||
String arg7;
|
||||
char arg8;
|
||||
if (parser.getArg(0,arg0)) Serial.println(arg0);
|
||||
if (parser.getArg(1,arg1)) Serial.println(arg1);
|
||||
if (parser.getArg(2,arg2)) Serial.println(arg2);
|
||||
if (parser.getArg(3,arg3)) Serial.println(arg3);
|
||||
if (parser.getArg(4,arg4)) Serial.println(arg4);
|
||||
if (parser.getArg(5,arg5)) Serial.println(arg5);
|
||||
if (parser.getArg(6,arg6)) Serial.println(arg6);
|
||||
if (parser.getArg(7,arg7)) Serial.println(arg7);
|
||||
if (parser.getArg(8,arg8)) Serial.println(arg8);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
||||
parser.setErrorHandler(errorHandler);
|
||||
parser.addHandler("DBAXK", firstHandler);
|
||||
parser.addHandler("EJCHQ", secondHandler);
|
||||
|
||||
Serial.print("Parsing : ");
|
||||
Serial.print(firstSentence);
|
||||
for (uint8_t i = 0; i < strlen(firstSentence); i++) {
|
||||
parser << firstSentence[i];
|
||||
}
|
||||
|
||||
Serial.print("Parsing : ");
|
||||
Serial.print(secondSentence);
|
||||
for (uint8_t i = 0; i < strlen(secondSentence); i++) {
|
||||
parser << secondSentence[i];
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
char intToHex(uint8_t v)
|
||||
{
|
||||
if (v < 10) return '0' + v;
|
||||
else if (v < 16) return 'A' + v - 10;
|
||||
else return '-';
|
||||
}
|
||||
|
||||
void generateSentence(bool goodCRC)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
putchar('$');
|
||||
/* generate the id */
|
||||
for (int i = 0; i < 5; i++) {
|
||||
char letter = 'A' + random() % 26;
|
||||
putchar(letter);
|
||||
crc ^= letter;
|
||||
}
|
||||
int numberOfArgs = random() % 10;
|
||||
for (int i = 0; i < numberOfArgs; i++) {
|
||||
putchar(',');
|
||||
crc ^= ',';
|
||||
int kind = random() % 5;
|
||||
switch (kind) {
|
||||
case 0: /* integer */
|
||||
for (int j = 0; j < random() % 5 + 1; j++) {
|
||||
char digit = '0' + random() % 10;
|
||||
putchar(digit);
|
||||
crc ^= digit;
|
||||
}
|
||||
break;
|
||||
case 1: /* char */
|
||||
if (1) {
|
||||
char letter = 'A' + random() % 26;
|
||||
putchar(letter);
|
||||
crc ^= letter;
|
||||
}
|
||||
break;
|
||||
case 2: /* string */
|
||||
for (int i = 0; i < 5; i++) {
|
||||
char letter = 'A' + random() % 26;
|
||||
putchar(letter);
|
||||
crc ^= letter;
|
||||
}
|
||||
break;
|
||||
case 3: /* float */
|
||||
for (int j = 0; j < random() % 5 + 1; j++) {
|
||||
char digit = '0' + random() % 10;
|
||||
putchar(digit);
|
||||
crc ^= digit;
|
||||
}
|
||||
putchar('.');
|
||||
crc ^= '.';
|
||||
for (int j = 0; j < random() % 5 + 1; j++) {
|
||||
char digit = '0' + random() % 10;
|
||||
putchar(digit);
|
||||
crc ^= digit;
|
||||
}
|
||||
case 4: /* nothing */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! goodCRC) crc = ~crc;
|
||||
putchar('*');
|
||||
putchar(intToHex(crc >> 4));
|
||||
putchar(intToHex(crc & 0x0F));
|
||||
putchar('\r');
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 2 || argc > 3) {
|
||||
printf("Usage: nmeagen <n> [<c>] where <n> is the number of sentences\n"
|
||||
" and <c> the number of sentences with a wrong CRC\n");
|
||||
exit(1);
|
||||
}
|
||||
else {
|
||||
int numberOfSentences = strtol(argv[1], NULL, 0);
|
||||
int numberOfWrongCRCSentences = 0;
|
||||
if (argc == 3) {
|
||||
numberOfWrongCRCSentences = strtol(argv[2], NULL, 0);
|
||||
}
|
||||
|
||||
/* Init a the random seed with the epoch */
|
||||
srandom(time(NULL));
|
||||
|
||||
for (int i = 0; i < numberOfSentences; i++) {
|
||||
generateSentence(true);
|
||||
}
|
||||
for (int i = 0; i < numberOfWrongCRCSentences; i++) {
|
||||
generateSentence(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
gcc -o nmeagen NMEASentencesGenerator.c
|
|
@ -0,0 +1,30 @@
|
|||
$FRMIO,G,33,081,I,Q,Q,J,48*2E
|
||||
$APYOG,LDCXT,JSCIE,KUJAU,64,EJMVQ,F,P,AJQLD*12
|
||||
$SUHEG,GAGCE,G,Q*31
|
||||
$KIEHA,E,W,R,SXGMG,64,40,WCIEC,2253,THWNT*6E
|
||||
$WPHGT,FRYBV,5689,C*68
|
||||
$YDXHC,A,J*45
|
||||
$GUIAZ,CWIMW*2B
|
||||
$SOEOE,ZBKFY,HKTHJ,536,504,946,0,705,BIDPI,ACEOK*4B
|
||||
$TEHJW,NNHPF,4,34,DFSFJ,8638,F,B*59
|
||||
$LKGPI,XTUUO*36
|
||||
$ZCHFN,769,0202,12*4E
|
||||
$DQTMV,Y,712,0*2B
|
||||
$MQPEM,H,95,E,M,U,92,N,340,D*47
|
||||
$APUXX,RKPFP,MUQOA,VOCGB,39,6,D,V,U*78
|
||||
$MBLXP,22573,3,AVNFF*3C
|
||||
$LCBXF,V,21,AKCLF,YIASR,PHIUS,VPRJM*11
|
||||
$OFXPI,2,B,14,A*7C
|
||||
$IUKFO,D,MSETP,99,GYBDX*05
|
||||
$UDSFE,QHPNK,D,N,R*55
|
||||
$EDULQ,ISGJX,FDXLJ,O,H,M,B,ROZIU,C*4A
|
||||
$FUONE,P,Y*5E
|
||||
$VLVIU*50
|
||||
$WTBCG,14,819,ATHAO,V,MSUHV,NSCLD*76
|
||||
$WJZLK,3,Q,31*0C
|
||||
$MRFGM,NCVPP,NZCBL,F,U,C,672,LPFAS*56
|
||||
$UFOJW,V,AIUHA,BFBKN*2C
|
||||
$OHOSS,HOIBI,8695,031,B,CVSMD,154,DEUCB*79
|
||||
$MYHGK,ZKTDK,YFJBI,OLBOI,74,KPASB,XBCSE,Q,U*00
|
||||
$ZIENW*4F
|
||||
$ONAYP,N,27,A*6F
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
c++ -o testNMEA testNMEA.cpp
|
|
@ -0,0 +1,63 @@
|
|||
#include "../../src/NMEAParser.h"
|
||||
#include <string.h>
|
||||
|
||||
NMEAParser<4> commandNMEA;
|
||||
int errorCount = 0;
|
||||
|
||||
void error()
|
||||
{
|
||||
printf("=================================================\n");
|
||||
int err = commandNMEA.error();
|
||||
printf("*** ERROR %d ",err);
|
||||
switch (err) {
|
||||
case NMEA::UNEXPECTED_CHAR:
|
||||
printf("(UNEXPECTED CHAR)\n");
|
||||
break;
|
||||
case NMEA::BUFFER_FULL:
|
||||
printf("(BUFFER FULL)\n");
|
||||
break;
|
||||
case NMEA::CRC_ERROR:
|
||||
printf("(CRC ERROR)\n");
|
||||
break;
|
||||
case NMEA::INTERNAL_ERROR:
|
||||
printf("(INTERNAL ERROR)\n");
|
||||
break;
|
||||
default:
|
||||
printf("(?)\n");
|
||||
break;
|
||||
}
|
||||
commandNMEA.printBuffer();
|
||||
printf("=================================================\n");
|
||||
errorCount++;
|
||||
}
|
||||
|
||||
void defaultHandler()
|
||||
{
|
||||
printf("------------\n");
|
||||
char buf[82];
|
||||
if (commandNMEA.getType(buf)) {
|
||||
printf("%s\n", buf);
|
||||
for (int i = 0; i < commandNMEA.argCount(); i++) {
|
||||
if (commandNMEA.getArg(i, buf)) {
|
||||
printf(" %s\n", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("Debut du test\n");
|
||||
|
||||
commandNMEA.setErrorHandler(error);
|
||||
commandNMEA.setDefaultHandler(defaultHandler);
|
||||
|
||||
int count = 0;
|
||||
int v;
|
||||
while ((v = getchar()) != EOF) {
|
||||
commandNMEA << v;
|
||||
if (v == '\n') count++;
|
||||
}
|
||||
printf("*** Processed %d NMEA sentences\n", count);
|
||||
printf("*** Got %d error(s)\n", errorCount);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For NMEAParser
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
NMEAParser KEYWORD1
|
||||
NMEA KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
addHandler KEYWORD2
|
||||
setErrorHandler KEYWORD2
|
||||
setDefaultHandler KEYWORD2
|
||||
argCount KEYWORD2
|
||||
getArg KEYWORD2
|
||||
getType KEYWORD2
|
||||
error KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
NO_ERROR LITERAL1
|
||||
UNEXPECTED_CHAR LITERAL1
|
||||
BUFFER_FULL LITERAL1
|
||||
CRC_ERROR LITERAL1
|
||||
INTERNAL_ERROR LITERAL1
|
|
@ -0,0 +1,9 @@
|
|||
name=NMEAParser
|
||||
version=1.1
|
||||
author=Glinnes Hulden
|
||||
maintainer=Glinnes Hulden
|
||||
sentence=A simple Arduino library to parse NMEA sentences.
|
||||
paragraph=A simple Arduino library to parse NMEA sentences.
|
||||
category=Communication
|
||||
url=https://github.com/Glinnes/NMEAParser
|
||||
architectures=*
|
|
@ -0,0 +1,657 @@
|
|||
/*
|
||||
* NMEA parser library for Arduino
|
||||
*
|
||||
* Simple and compact NMEA parser designed for Arduino
|
||||
*
|
||||
* Author : Glinnes Hulden
|
||||
*
|
||||
* This work is distributed under license CC0.
|
||||
* Check https://creativecommons.org/publicdomain/zero/1.0/deed.en
|
||||
*
|
||||
* No Copyright
|
||||
*
|
||||
* The person who associated a work with this deed has dedicated the work
|
||||
* to the public domain by waiving all of his or her rights to the work
|
||||
* worldwide under copyright law, including all related and neighboring rights,
|
||||
* to the extent allowed by law.
|
||||
*
|
||||
* You can copy, modify, distribute and perform the work, even for commercial
|
||||
* purposes, all without asking permission. See Other Information below.
|
||||
*
|
||||
* Other Information
|
||||
*
|
||||
* In no way are the patent or trademark rights of any person affected by CC0,
|
||||
* nor are the rights that other persons may have in the work or in how the
|
||||
* work is used, such as publicity or privacy rights.
|
||||
* Unless expressly stated otherwise, the person who associated a work with
|
||||
* this deed makes no warranties about the work, and disclaims liability for
|
||||
* all uses of the work, to the fullest extent permitted by applicable law.
|
||||
* When using or citing the work, you should not imply endorsement by the
|
||||
* author or the affirmer.
|
||||
*/
|
||||
|
||||
#ifndef __NMEAParser_h__
|
||||
#define __NMEAParser_h__
|
||||
|
||||
#ifdef __amd64__
|
||||
/* To use on my development platform */
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#else
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
namespace NMEA {
|
||||
/*
|
||||
* Error codes
|
||||
*/
|
||||
typedef enum {
|
||||
NO_ERROR,
|
||||
UNEXPECTED_CHAR,
|
||||
BUFFER_FULL,
|
||||
TYPE_TOO_LONG,
|
||||
CRC_ERROR,
|
||||
INTERNAL_ERROR
|
||||
} ErrorCode;
|
||||
}
|
||||
|
||||
/*
|
||||
* The library consists of a single template: NMEAParser.
|
||||
*/
|
||||
template <size_t S> class NMEAParser {
|
||||
|
||||
private:
|
||||
typedef void (*NMEAErrorHandler)(void);
|
||||
typedef void (*NMEAHandler)(void);
|
||||
typedef struct { char mToken[6]; NMEAHandler mHandler; } NMEAHandlerEntry;
|
||||
typedef enum { INIT, SENT, ARG, CRCH, CRCL, CRLFCR, CRLFLF } State;
|
||||
|
||||
public:
|
||||
/*
|
||||
* maximum sentence size is 82 including the starting '$' and the <cr><lf>
|
||||
* at the end. Since '$', the '*', the 2 characters CRC and the <cr><lf>
|
||||
* are not bufferized, 82 - 6 + 1 = 77 chars are enough.
|
||||
* is enough.
|
||||
*/
|
||||
static const uint8_t kSentenceMaxSize = 77;
|
||||
|
||||
private:
|
||||
/*
|
||||
* buffer to store the NMEA sentence excluding starting '$', the ','
|
||||
* separator, the '*', the CRC and the <cr><lf>. The tail of the buffer
|
||||
* is used to store the index of the arguments.
|
||||
*/
|
||||
char mBuffer[kSentenceMaxSize];
|
||||
|
||||
/*
|
||||
* Current index to store a char of the sentence
|
||||
*/
|
||||
uint8_t mIndex;
|
||||
|
||||
/*
|
||||
* Current index to store the index of an argument
|
||||
*/
|
||||
uint8_t mArgIndex;
|
||||
|
||||
/*
|
||||
* A handler to notify a malformed sentence
|
||||
*/
|
||||
NMEAErrorHandler mErrorHandler;
|
||||
|
||||
/*
|
||||
* A handler for well formed but unrecognized sentences
|
||||
*/
|
||||
NMEAHandler mDefaultHandler;
|
||||
|
||||
/*
|
||||
* An array of NMEA handler : pointers to functions to call when a sentence
|
||||
* is recognized
|
||||
*/
|
||||
NMEAHandlerEntry mHandlers[S];
|
||||
|
||||
/*
|
||||
* The current number of mHandlers
|
||||
*/
|
||||
uint8_t mHandlerCount;
|
||||
|
||||
/*
|
||||
* Parsing automaton variable
|
||||
*/
|
||||
State mState;
|
||||
|
||||
/*
|
||||
* mError
|
||||
*/
|
||||
NMEA::ErrorCode mError;
|
||||
|
||||
/*
|
||||
* True if CRC is handled, false otherwise. Defaults to true
|
||||
*/
|
||||
bool mHandleCRC;
|
||||
|
||||
/*
|
||||
* Variables used to computed and parse the CRC
|
||||
*/
|
||||
uint8_t mComputedCRC;
|
||||
uint8_t mGotCRC;
|
||||
|
||||
/*
|
||||
* NMEAParserStringify is used internally to temporarely replace a char
|
||||
* in the buffer by a '\0' so that libc string functions may be used.
|
||||
* Instantiating a NMEAParserStringify object in a pair of {} defines
|
||||
* a section in which the 'stringification' is done : the constructor
|
||||
* does that according to the arguments and se destructor restore the buffer.
|
||||
*/
|
||||
class NMEAParserStringify {
|
||||
uint8_t mPos;
|
||||
char mTmp;
|
||||
NMEAParser<S> *mParent;
|
||||
public:
|
||||
NMEAParserStringify(NMEAParser<S> *inParent, uint8_t inPos) :
|
||||
mPos(inPos),
|
||||
mParent(inParent)
|
||||
{
|
||||
mTmp = mParent->mBuffer[mPos];
|
||||
mParent->mBuffer[mPos] = '\0';
|
||||
}
|
||||
~NMEAParserStringify()
|
||||
{
|
||||
mParent->mBuffer[mPos] = mTmp;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Call the error handler if defined
|
||||
*/
|
||||
void callErrorHandler(void)
|
||||
{
|
||||
if (mErrorHandler != NULL) {
|
||||
mErrorHandler();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the parser
|
||||
*/
|
||||
void reset() {
|
||||
mState = INIT;
|
||||
mIndex = 0;
|
||||
mArgIndex = kSentenceMaxSize;
|
||||
mError = NMEA::NO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when the parser encounter a char that should not be there
|
||||
*/
|
||||
void unexpectedChar()
|
||||
{
|
||||
mError = NMEA::UNEXPECTED_CHAR;
|
||||
callErrorHandler();
|
||||
reset();
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when the buffer is full because of a malformed sentence
|
||||
*/
|
||||
void bufferFull()
|
||||
{
|
||||
mError = NMEA::BUFFER_FULL;
|
||||
callErrorHandler();
|
||||
reset();
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when the type of the sentence is longer than 5 characters
|
||||
*/
|
||||
void typeTooLong()
|
||||
{
|
||||
mError = NMEA::TYPE_TOO_LONG;
|
||||
callErrorHandler();
|
||||
reset();
|
||||
}
|
||||
/*
|
||||
* Called when the CRC is wrong
|
||||
*/
|
||||
void crcError()
|
||||
{
|
||||
mError = NMEA::CRC_ERROR;
|
||||
callErrorHandler();
|
||||
reset();
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when the state of the parser is not ok
|
||||
*/
|
||||
void internalError()
|
||||
{
|
||||
mError = NMEA::INTERNAL_ERROR;
|
||||
callErrorHandler();
|
||||
reset();
|
||||
}
|
||||
|
||||
/*
|
||||
* retuns true is there is at least one byte left in the buffer
|
||||
*/
|
||||
bool spaceAvail()
|
||||
{
|
||||
return (mIndex < mArgIndex);
|
||||
}
|
||||
|
||||
/*
|
||||
* convert a one hex digit char into an int. Used for the CRC
|
||||
*/
|
||||
static int8_t hexToNum(const char inChar)
|
||||
{
|
||||
if (isdigit(inChar)) return inChar - '0';
|
||||
else if (isupper(inChar) && inChar <= 'F') return inChar - 'A' + 10;
|
||||
else if (islower(inChar) && inChar <= 'f') return inChar - 'a' + 10;
|
||||
else return -1;
|
||||
}
|
||||
|
||||
static bool strnwcmp(const char *s1, const char *s2, uint8_t len)
|
||||
{
|
||||
while (len-- > 0) {
|
||||
if (*s1 != *s2 && *s1 != '-' && *s2 != '-') return false;
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* return the slot number for a handler. -1 if not found
|
||||
*/
|
||||
int8_t getHandler(const char *inToken)
|
||||
{
|
||||
/* Look for the token */
|
||||
for (uint8_t i = 0; i < mHandlerCount; i++) {
|
||||
if (strnwcmp(mHandlers[i].mToken, inToken, 5)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* When all the sentence has been parsed, process it by calling the handler
|
||||
*/
|
||||
void processSentence()
|
||||
{
|
||||
/* Look for the token */
|
||||
uint8_t endPos = startArgPos(0);
|
||||
int8_t slot;
|
||||
{
|
||||
NMEAParserStringify stfy(this, endPos);
|
||||
slot = getHandler(mBuffer);
|
||||
}
|
||||
if (slot != -1) {
|
||||
mHandlers[slot].mHandler();
|
||||
}
|
||||
else {
|
||||
if (mDefaultHandler != NULL) {
|
||||
mDefaultHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if inArgNum corresponds to an actual argument
|
||||
*/
|
||||
bool validArgNum(uint8_t inArgNum)
|
||||
{
|
||||
return inArgNum < (kSentenceMaxSize - mArgIndex);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the start index of the inArgNum th argument
|
||||
*/
|
||||
uint8_t startArgPos(uint8_t inArgNum)
|
||||
{
|
||||
return mBuffer[kSentenceMaxSize - 1 - inArgNum];
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the end index of the inArgNum th argument
|
||||
*/
|
||||
uint8_t endArgPos(uint8_t inArgNum)
|
||||
{
|
||||
return mBuffer[kSentenceMaxSize - 2 - inArgNum];
|
||||
}
|
||||
|
||||
public:
|
||||
/*
|
||||
* Constructor initialize the parser.
|
||||
*/
|
||||
NMEAParser() :
|
||||
mErrorHandler(NULL),
|
||||
mDefaultHandler(NULL),
|
||||
mHandlerCount(0),
|
||||
mError(NMEA::NO_ERROR),
|
||||
mHandleCRC(true),
|
||||
mComputedCRC(0),
|
||||
mGotCRC(0)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a sentence handler
|
||||
*/
|
||||
void addHandler(const char *inToken, NMEAHandler inHandler)
|
||||
{
|
||||
if (mHandlerCount < S) {
|
||||
if (getHandler(inToken) == -1) {
|
||||
strncpy(mHandlers[mHandlerCount].mToken, inToken, 5);
|
||||
mHandlers[mHandlerCount].mToken[5] = '\0';
|
||||
mHandlers[mHandlerCount].mHandler = inHandler;
|
||||
mHandlerCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __AVR__
|
||||
/*
|
||||
* Add a sentence handler. Version with a token stored in flash.
|
||||
*/
|
||||
void addHandler(const __FlashStringHelper *ifsh, NMEAHandler inHandler)
|
||||
{
|
||||
char buf[6];
|
||||
PGM_P p = reinterpret_cast<PGM_P>(ifsh);
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
char c = pgm_read_byte(p++);
|
||||
buf[i] = c;
|
||||
if (c == '\0') break;
|
||||
}
|
||||
addHandler(buf, inHandler);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set the error handler which is called when a sentence is malformed
|
||||
*/
|
||||
void setErrorHandler(NMEAErrorHandler inHandler)
|
||||
{
|
||||
mErrorHandler = inHandler;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the default handler which is called when a sentence is well formed
|
||||
* but has no handler associated to
|
||||
*/
|
||||
void setDefaultHandler(NMEAHandler inHandler)
|
||||
{
|
||||
mDefaultHandler = inHandler;
|
||||
}
|
||||
|
||||
/*
|
||||
* Give a character to the parser
|
||||
*/
|
||||
void operator<<(char inChar)
|
||||
{
|
||||
int8_t tmp;
|
||||
|
||||
switch (mState) {
|
||||
|
||||
/* Waiting for the starting $ character */
|
||||
case INIT:
|
||||
mError = NMEA::NO_ERROR;
|
||||
if (inChar == '$') {
|
||||
mComputedCRC = 0;
|
||||
mState = SENT;
|
||||
}
|
||||
else unexpectedChar();
|
||||
break;
|
||||
|
||||
case SENT:
|
||||
if (isalnum(inChar)) {
|
||||
if (spaceAvail()) {
|
||||
if (mIndex < 5) {
|
||||
mBuffer[mIndex++] = inChar;
|
||||
mComputedCRC ^= inChar;
|
||||
}
|
||||
else {
|
||||
typeTooLong();
|
||||
}
|
||||
}
|
||||
else bufferFull();
|
||||
}
|
||||
else {
|
||||
switch(inChar) {
|
||||
case ',' :
|
||||
mComputedCRC ^= inChar;
|
||||
mBuffer[--mArgIndex] = mIndex;
|
||||
mState = ARG;
|
||||
break;
|
||||
case '*' :
|
||||
mGotCRC = 0;
|
||||
mBuffer[--mArgIndex] = mIndex;
|
||||
mState = CRCH;
|
||||
break;
|
||||
default :
|
||||
unexpectedChar();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ARG:
|
||||
if (spaceAvail()) {
|
||||
switch(inChar) {
|
||||
case ',' :
|
||||
mComputedCRC ^= inChar;
|
||||
mBuffer[--mArgIndex] = mIndex;
|
||||
break;
|
||||
case '*' :
|
||||
mGotCRC = 0;
|
||||
mBuffer[--mArgIndex] = mIndex;
|
||||
mState = CRCH;
|
||||
break;
|
||||
default :
|
||||
mComputedCRC ^= inChar;
|
||||
mBuffer[mIndex++] = inChar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else bufferFull();
|
||||
break;
|
||||
|
||||
case CRCH:
|
||||
tmp = hexToNum(inChar);
|
||||
if (tmp != -1) {
|
||||
mGotCRC |= (uint8_t)tmp << 4;
|
||||
mState = CRCL;
|
||||
}
|
||||
else unexpectedChar();
|
||||
break;
|
||||
|
||||
case CRCL:
|
||||
tmp = hexToNum(inChar);
|
||||
if (tmp != -1) {
|
||||
mGotCRC |= (uint8_t)tmp;
|
||||
mState = CRLFCR;
|
||||
}
|
||||
else unexpectedChar();
|
||||
break;
|
||||
|
||||
case CRLFCR:
|
||||
if (inChar == '\r') {
|
||||
mState = CRLFLF;
|
||||
}
|
||||
else unexpectedChar();
|
||||
break;
|
||||
|
||||
case CRLFLF:
|
||||
if (inChar == '\n') {
|
||||
if (mHandleCRC && (mGotCRC != mComputedCRC)) {
|
||||
crcError();
|
||||
}
|
||||
else {
|
||||
processSentence();
|
||||
}
|
||||
reset();
|
||||
}
|
||||
else unexpectedChar();
|
||||
break;
|
||||
|
||||
default:
|
||||
internalError();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the number of arguments discovered in a well formed sentence.
|
||||
*/
|
||||
uint8_t argCount()
|
||||
{
|
||||
return kSentenceMaxSize - mArgIndex - 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns one of the arguments. Different versions according to data type.
|
||||
*/
|
||||
bool getArg(uint8_t num, char &arg)
|
||||
{
|
||||
if (validArgNum(num)) {
|
||||
uint8_t startPos = startArgPos(num);
|
||||
uint8_t endPos = endArgPos(num);
|
||||
arg = mBuffer[startPos];
|
||||
return (endPos - startPos) == 1;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
bool getArg(uint8_t num, char *arg)
|
||||
{
|
||||
if (validArgNum(num)) {
|
||||
uint8_t startPos = startArgPos(num);
|
||||
uint8_t endPos = endArgPos(num);
|
||||
{
|
||||
NMEAParserStringify stfy(this, endPos);
|
||||
strcpy(arg, &mBuffer[startPos]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
#ifdef ARDUINO
|
||||
bool getArg(uint8_t num, String &arg)
|
||||
{
|
||||
if (validArgNum(num)) {
|
||||
uint8_t startPos = startArgPos(num);
|
||||
uint8_t endPos = endArgPos(num);
|
||||
{
|
||||
NMEAParserStringify stfy(this, endPos);
|
||||
arg = &mBuffer[startPos];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool getArg(uint8_t num, int &arg)
|
||||
{
|
||||
if (validArgNum(num)) {
|
||||
uint8_t startPos = startArgPos(num);
|
||||
uint8_t endPos = endArgPos(num);
|
||||
{
|
||||
NMEAParserStringify stfy(this, endPos);
|
||||
arg = atoi(&mBuffer[startPos]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
bool getArg(uint8_t num, float &arg)
|
||||
{
|
||||
if (validArgNum(num)) {
|
||||
uint8_t startPos = startArgPos(num);
|
||||
uint8_t endPos = endArgPos(num);
|
||||
{
|
||||
NMEAParserStringify stfy(this, endPos);
|
||||
arg = atof(&mBuffer[startPos]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
/*
|
||||
* Returns the type of sentence.
|
||||
*/
|
||||
bool getType(char *arg)
|
||||
{
|
||||
if (mIndex > 0) {
|
||||
uint8_t endPos = startArgPos(0);
|
||||
{
|
||||
NMEAParserStringify stfy(this, endPos);
|
||||
strncpy(arg, mBuffer, 5);
|
||||
arg[5] = '\0';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
#ifdef ARDUINO
|
||||
bool getType(String &arg)
|
||||
{
|
||||
if (mIndex > 0) {
|
||||
uint8_t endPos = startArgPos(0);
|
||||
{
|
||||
NMEAParserStringify stfy(this, endPos);
|
||||
arg = mBuffer;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool getType(uint8_t inIndex, char &outTypeChar)
|
||||
{
|
||||
if (mIndex > 0) {
|
||||
uint8_t endPos = startArgPos(0);
|
||||
if (inIndex < endPos) {
|
||||
outTypeChar = mBuffer[inIndex];
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
NMEA::ErrorCode error() {
|
||||
return mError;
|
||||
}
|
||||
|
||||
void setHandleCRC(bool inHandleCRC)
|
||||
{
|
||||
mHandleCRC = inHandleCRC;
|
||||
}
|
||||
#ifdef __amd64__
|
||||
void printBuffer()
|
||||
{
|
||||
{
|
||||
NMEAParserStringify stfy(this, startArgPos(0));
|
||||
printf("%s\n", mBuffer);
|
||||
}
|
||||
for (uint8_t i = 0; i < argCount(); i++) {
|
||||
uint8_t startPos = startArgPos(i);
|
||||
uint8_t endPos = endArgPos(i);
|
||||
{
|
||||
NMEAParserStringify stfy(this, endPos);
|
||||
printf("%s\n", &mBuffer[startPos]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,17 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# Custom for Visual Studio
|
||||
*.cs diff=csharp
|
||||
|
||||
# Standard to msysgit
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
|
@ -0,0 +1,3 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
custom: ['paypal.me/tilz0R']
|
|
@ -0,0 +1,385 @@
|
|||
#Build Keil files
|
||||
*.rar
|
||||
*.o
|
||||
*.d
|
||||
*.crf
|
||||
*.htm
|
||||
*.dep
|
||||
*.map
|
||||
*.bak
|
||||
*.axf
|
||||
*.lnp
|
||||
*.lst
|
||||
*.ini
|
||||
*.scvd
|
||||
*.iex
|
||||
*.sct
|
||||
*.MajerleT
|
||||
*.tjuln
|
||||
*.tilen
|
||||
*.dbgconf
|
||||
*.uvguix
|
||||
*.uvoptx
|
||||
*.__i
|
||||
*.i
|
||||
!docs/*.txt
|
||||
RTE/
|
||||
|
||||
# IAR Settings
|
||||
**/settings/*.crun
|
||||
**/settings/*.dbgdt
|
||||
**/settings/*.cspy
|
||||
**/settings/*.cspy.*
|
||||
**/settings/*.xcl
|
||||
**/settings/*.dni
|
||||
**/settings/*.wsdt
|
||||
**/settings/*.wspos
|
||||
|
||||
# IAR Debug Exe
|
||||
**/Exe/*.sim
|
||||
|
||||
# IAR Debug Obj
|
||||
**/Obj/*.pbd
|
||||
**/Obj/*.pbd.*
|
||||
**/Obj/*.pbi
|
||||
**/Obj/*.pbi.*
|
||||
|
||||
*.TMP
|
||||
/docs_src/x_Doxyfile.doxy
|
||||
|
||||
.DS_Store
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
_build/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
**/Properties/launchSettings.json
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
*.out
|
||||
*.sim
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
log_file.txt
|
||||
.metadata/
|
||||
.mxproject
|
||||
.settings/
|
||||
project.ioc
|
||||
mx.scratch
|
||||
*.tilen majerle
|
||||
*.exe
|
|
@ -0,0 +1,5 @@
|
|||
" tree-specific vimrc to comply with project coding style
|
||||
" see https://github.com/MaJerle/c-code-style
|
||||
if &ft == "c" || &ft == "cpp"
|
||||
setlocal shiftwidth=4 tabstop=4 softtabstop=4 expandtab autoindent cc=80 foldmethod=indent
|
||||
endif
|
|
@ -0,0 +1,39 @@
|
|||
################################################################################
|
||||
# Lightweight GPS (lwgps) CMake support
|
||||
################################################################################
|
||||
# The lwgps library can be configured with a lwgps_opts.h file.
|
||||
# If such a file is used, the user should set the LWGPS_CONFIG_PATH path variable where
|
||||
# the configuration file is located so that is is included properly.
|
||||
#
|
||||
# Other than that, only two steps are necessary to compile and link against LWGPS:
|
||||
# 1. Use add_subdirectory to add the lwgps folder
|
||||
# 2. Link against lwgps with target_link_libraries
|
||||
################################################################################
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
set(LIB_LWGPS_NAME lwgps)
|
||||
|
||||
add_library(${LIB_LWGPS_NAME})
|
||||
|
||||
add_subdirectory(${LIB_LWGPS_NAME})
|
||||
add_subdirectory(examples)
|
||||
|
||||
# The project CMakeLists can set a LWGPS_CONFIG_PATH path including the lwgps_opts.h file
|
||||
# and add it.
|
||||
if(NOT LWGPS_CONFIG_PATH)
|
||||
message(STATUS "Lightweight GPS configuration path not set.")
|
||||
endif()
|
||||
|
||||
# Extract the absolute path of the provided configuration path
|
||||
if(IS_ABSOLUTE ${LWGPS_CONFIG_PATH})
|
||||
set(LWGPS_CONFIG_PATH_ABSOLUTE ${LWGPS_CONFIG_PATH})
|
||||
else()
|
||||
get_filename_component(LWGPS_CONFIG_PATH_ABSOLUTE
|
||||
${LWGPS_CONFIG_PATH} REALPATH BASE_DIR ${CMAKE_SOURCE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
target_include_directories(${LIB_LWGPS_NAME} PRIVATE
|
||||
${LWGPS_CONFIG_PATH_ABSOLUTE}
|
||||
)
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 Tilen MAJERLE
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,40 @@
|
|||
# Lightweight GPS NMEA parser
|
||||
|
||||
Platform independent GPS NMEA parser for embedded systems.
|
||||
|
||||
<h3>Read first: <a href="http://docs.majerle.eu/projects/lwgps/">Documentation</a></h3>
|
||||
|
||||
## Features
|
||||
|
||||
* Written in ANSI C99
|
||||
* Platform independent, easy to use
|
||||
* Built-in support for 4 GPS statements
|
||||
* ``GPGGA`` or ``GNGGA``: GPS fix data
|
||||
* ``GPGSA`` or ``GNGSA``: GPS active satellites and dillusion of position
|
||||
* ``GPGSV`` or ``GNGSV``: List of satellites in view zone
|
||||
* ``GPRMC`` or ``GNRMC``: Recommended minimum specific GPS/Transit data
|
||||
* Optional ``float`` or ``double`` floating point units
|
||||
* Low-level layer is separated from application layer, thus allows you to add custom communication with GPS device
|
||||
* Works with operating systems
|
||||
* Works with different communication interfaces
|
||||
* User friendly MIT license
|
||||
|
||||
## Contribute
|
||||
|
||||
Fresh contributions are always welcome. Simple instructions to proceed::
|
||||
|
||||
1. Fork Github repository
|
||||
2. Respect [C style & coding rules](https://github.com/MaJerle/c-code-style) used by the library
|
||||
3. Create a pull request to develop branch with new features or bug fixes
|
||||
|
||||
Alternatively you may:
|
||||
|
||||
1. Report a bug
|
||||
2. Ask for a feature request
|
||||
|
||||
## Test
|
||||
|
||||
To build the code and run basic tests on your host::
|
||||
|
||||
cd examples
|
||||
make test
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.28803.452
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwgps_dev", "lwgps_dev.vcxproj", "{C7C465FB-17B3-4226-BBD5-E79C1B3796C6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C7C465FB-17B3-4226-BBD5-E79C1B3796C6}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{C7C465FB-17B3-4226-BBD5-E79C1B3796C6}.Debug|x64.Build.0 = Debug|Win32
|
||||
{C7C465FB-17B3-4226-BBD5-E79C1B3796C6}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{C7C465FB-17B3-4226-BBD5-E79C1B3796C6}.Debug|x86.Build.0 = Debug|Win32
|
||||
{C7C465FB-17B3-4226-BBD5-E79C1B3796C6}.Release|x64.ActiveCfg = Release|x64
|
||||
{C7C465FB-17B3-4226-BBD5-E79C1B3796C6}.Release|x64.Build.0 = Release|x64
|
||||
{C7C465FB-17B3-4226-BBD5-E79C1B3796C6}.Release|x86.ActiveCfg = Release|Win32
|
||||
{C7C465FB-17B3-4226-BBD5-E79C1B3796C6}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C58E98E3-45C5-48F1-A7AF-BCFEC103DD09}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,149 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{C7C465FB-17B3-4226-BBD5-E79C1B3796C6}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>LwGPS</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>.;..\..\lwgps\src\include;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\examples\test_code.c" />
|
||||
<ClCompile Include="..\..\lwgps\src\lwgps\lwgps.c" />
|
||||
<ClCompile Include="main.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
23
1.Software/3rdparty/lwgps-develop/dev/VisualStudio/lwgps_dev.vcxproj.filters
vendored
Normal file
23
1.Software/3rdparty/lwgps-develop/dev/VisualStudio/lwgps_dev.vcxproj.filters
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\LwGPS">
|
||||
<UniqueIdentifier>{d2afbed4-545f-40e7-bf68-d835c5948bcc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\lwgps\src\lwgps\lwgps.c">
|
||||
<Filter>Source Files\LwGPS</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\examples\test_code.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* \file lwgps_opts_template.h
|
||||
* \brief LwGPS configuration file
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Tilen MAJERLE
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
|
||||
* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* This file is part of LwGPS - Lightweight GPS NMEA parser library.
|
||||
*
|
||||
* Author: Tilen MAJERLE <tilen@majerle.eu>
|
||||
* Version: $2.1.0$
|
||||
*/
|
||||
#ifndef LWGPS_HDR_OPTS_H
|
||||
#define LWGPS_HDR_OPTS_H
|
||||
|
||||
/* Rename this file to "lwgps_opts.h" for your application */
|
||||
|
||||
/*
|
||||
* Open "include/lwgps/lwgps_opt.h" and
|
||||
* copy & replace here settings you want to change values
|
||||
*/
|
||||
|
||||
#endif /* LWGPS_HDR_OPTS_H */
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* This example uses direct processing function,
|
||||
* to process dummy NMEA data from GPS receiver
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "lwgps/lwgps.h"
|
||||
|
||||
/* External function */
|
||||
extern void run_tests();
|
||||
|
||||
int
|
||||
main() {
|
||||
lwgps_float_t distance, bearing;
|
||||
run_tests();
|
||||
|
||||
/* Calculate distance and bearing */
|
||||
lwgps_distance_bearing(40.6, -73.7, 48.3, 11.7, &distance, &bearing);
|
||||
|
||||
printf("Distance: %lf meters\r\n", (double)distance);
|
||||
printf("Bearing: %lf degrees\r\n", (double)bearing);
|
||||
|
||||
lwgps_distance_bearing(48.3, 11.7, 40.6, -73.7, &distance, &bearing);
|
||||
printf("Distance: %lf meters\r\n", (double)distance);
|
||||
printf("Bearing: %lf degrees\r\n", (double)bearing);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* JFK: 40.642569, -73.783790 */
|
||||
/* Munich: 48.353962, 11.775114 */
|
|
@ -0,0 +1,20 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
@ -0,0 +1,6 @@
|
|||
.. _api_lwgps:
|
||||
|
||||
LwGPS
|
||||
=====
|
||||
|
||||
.. doxygengroup:: LWGPS
|
|
@ -0,0 +1,12 @@
|
|||
.. _api_lwgps_opt:
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
This is the default configuration of the middleware.
|
||||
When any of the settings shall be modified, it shall be done in dedicated application config ``lwgps_opts.h`` file.
|
||||
|
||||
.. note::
|
||||
Check :ref:`getting_started` to create configuration file.
|
||||
|
||||
.. doxygengroup:: LWGPS_OPT
|
|
@ -0,0 +1,13 @@
|
|||
.. _api_reference:
|
||||
|
||||
API reference
|
||||
=============
|
||||
|
||||
List of all the modules:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:glob:
|
||||
|
||||
*
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
from sphinx.builders.html import StandaloneHTMLBuilder
|
||||
import subprocess, os
|
||||
|
||||
# Run doxygen first
|
||||
# read_the_docs_build = os.environ.get('READTHEDOCS', None) == 'True'
|
||||
# if read_the_docs_build:
|
||||
subprocess.call('doxygen doxyfile.doxy', shell=True)
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'LwGPS'
|
||||
copyright = '2020, Tilen MAJERLE'
|
||||
author = 'Tilen MAJERLE'
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
version = 'v2.1.0'
|
||||
|
||||
# Try to get branch at which this is running
|
||||
# and try to determine which version to display in sphinx
|
||||
git_branch = ''
|
||||
res = os.popen('git branch').read().strip()
|
||||
for line in res.split("\n"):
|
||||
if line[0] == '*':
|
||||
git_branch = line[1:].strip()
|
||||
|
||||
# Decision for display version
|
||||
try:
|
||||
if git_branch.index('develop') >= 0:
|
||||
version = "latest-develop"
|
||||
except Exception:
|
||||
print("Exception for index check")
|
||||
|
||||
# For debugging purpose
|
||||
print("GIT BRANCH: " + git_branch)
|
||||
print("VERSION: " + version)
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.autosectionlabel',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinx.ext.mathjax',
|
||||
'sphinx.ext.ifconfig',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx_sitemap',
|
||||
|
||||
'breathe',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['templates']
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
highlight_language = 'c'
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_theme_options = {
|
||||
'canonical_url': '',
|
||||
'analytics_id': '', # Provided by Google in your dashboard
|
||||
'display_version': True,
|
||||
'prev_next_buttons_location': 'bottom',
|
||||
'style_external_links': False,
|
||||
|
||||
'logo_only': False,
|
||||
|
||||
# Toc options
|
||||
'collapse_navigation': True,
|
||||
'sticky_navigation': True,
|
||||
'navigation_depth': 4,
|
||||
'includehidden': True,
|
||||
'titles_only': False
|
||||
}
|
||||
html_logo = 'static/images/logo.svg'
|
||||
github_url = 'https://github.com/MaJerle/lwgps'
|
||||
html_baseurl = 'https://docs.majerle.eu/projects/lwgps/'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['static']
|
||||
html_css_files = [
|
||||
'css/common.css',
|
||||
'css/custom.css',
|
||||
]
|
||||
html_js_files = [
|
||||
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css'
|
||||
]
|
||||
|
||||
master_doc = 'index'
|
||||
|
||||
#
|
||||
# Breathe configuration
|
||||
#
|
||||
#
|
||||
#
|
||||
breathe_projects = {
|
||||
"lwgps": "_build/xml/"
|
||||
}
|
||||
breathe_default_project = "lwgps"
|
||||
breathe_default_members = ('members', 'undoc-members')
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,47 @@
|
|||
.. _examples:
|
||||
|
||||
Examples and demos
|
||||
==================
|
||||
|
||||
There are several basic examples provided with the library.
|
||||
|
||||
Parse block of data
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In this example, block of data is prepared as big string array and sent to processing function in single shot.
|
||||
Application can then check if GPS signal has been detected as valid and use other data accordingly.
|
||||
|
||||
.. literalinclude:: ../../examples/example.c
|
||||
:language: c
|
||||
:linenos:
|
||||
:caption: Minimum example code
|
||||
|
||||
Parse received data from interrupt/DMA
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Second example is a typical use case with interrupts on embedded systems.
|
||||
For each received character, application uses ``ringbuff`` as intermediate buffer.
|
||||
Data are later processed outside interrupt context.
|
||||
|
||||
.. note::
|
||||
For the sake of this example, application *implements* interrupts as function call in *while loop*.
|
||||
|
||||
.. literalinclude:: ../../examples/example_buff.c
|
||||
:language: c
|
||||
:linenos:
|
||||
:caption: Example of buffer
|
||||
|
||||
Distance and bearing
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Library provides calculation of distance and bearing between ``2`` coordinates on earth.
|
||||
This is useful if used with autonomnous devices to understand in which direction
|
||||
device has to move to reach end point while knowing start coordinate.
|
||||
|
||||
.. literalinclude:: ../../examples/example_dist_bear.c
|
||||
:language: c
|
||||
:linenos:
|
||||
:caption: Distance and bearing calculation
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
|
@ -0,0 +1,100 @@
|
|||
.. _getting_started:
|
||||
|
||||
Getting started
|
||||
===============
|
||||
|
||||
.. _download_library:
|
||||
|
||||
Download library
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Library is primarly hosted on `Github <https://github.com/MaJerle/lwgps>`_.
|
||||
|
||||
* Download latest release from `releases area <https://github.com/MaJerle/lwgps/releases>`_ on Github
|
||||
* Clone `develop` branch for latest development
|
||||
|
||||
Download from releases
|
||||
**********************
|
||||
|
||||
All releases are available on Github `releases area <https://github.com/MaJerle/lwgps/releases>`_.
|
||||
|
||||
Clone from Github
|
||||
*****************
|
||||
|
||||
First-time clone
|
||||
""""""""""""""""
|
||||
|
||||
* Download and install ``git`` if not already
|
||||
* Open console and navigate to path in the system to clone repository to. Use command ``cd your_path``
|
||||
* Clone repository with one of available ``3`` options
|
||||
|
||||
* Run ``git clone --recurse-submodules https://github.com/MaJerle/lwgps`` command to clone entire repository, including submodules
|
||||
* Run ``git clone --recurse-submodules --branch develop https://github.com/MaJerle/lwgps`` to clone `development` branch, including submodules
|
||||
* Run ``git clone --recurse-submodules --branch master https://github.com/MaJerle/lwgps`` to clone `latest stable` branch, including submodules
|
||||
|
||||
* Navigate to ``examples`` directory and run favourite example
|
||||
|
||||
Update cloned to latest version
|
||||
"""""""""""""""""""""""""""""""
|
||||
|
||||
* Open console and navigate to path in the system where your resources repository is. Use command ``cd your_path``
|
||||
* Run ``git pull origin master --recurse-submodules`` command to pull latest changes and to fetch latest changes from submodules
|
||||
* Run ``git submodule foreach git pull origin master`` to update & merge all submodules
|
||||
|
||||
.. note::
|
||||
This is preferred option to use when you want to evaluate library and run prepared examples.
|
||||
Repository consists of multiple submodules which can be automatically downloaded when cloning and pulling changes from root repository.
|
||||
|
||||
|
||||
Add library to project - Generic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
At this point it is assumed that you have successfully download library, either cloned it or from releases page.
|
||||
|
||||
* Copy ``lwgps`` folder to your project
|
||||
* Add ``lwgps/src/include`` folder to `include path` of your toolchain
|
||||
* Add source files from ``lwgps/src/`` folder to toolchain build
|
||||
* Copy ``lwgps/src/include/lwgps/lwgps_opts_template.h`` to project folder and rename it to ``lwgps_opts.h``
|
||||
* Build the project
|
||||
|
||||
Add library to project - CMake
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Including the library with CMake is very easy.
|
||||
|
||||
* Add the ``lwgps`` folder with ``add_subdirectory``
|
||||
* Copy ``lwgps/src/include/lwgps/lwgps_opts_template.h`` to the project folder and rename it
|
||||
to ``lwgps_opts.h``
|
||||
* Set the ``LWGPS_CONFIG_PATH`` path variable containing the ``lwgps_opts.h`` file
|
||||
in the project ``CMakeLists.txt``
|
||||
* Link your project against the ``lwgps`` library with ``target_link_libraries``
|
||||
* The include directory should be set automatically by CMake
|
||||
|
||||
Configuration file
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Library comes with template config file, which can be modified according to needs.
|
||||
This file shall be named ``lwgps_opts.h`` and its default template looks like the one below.
|
||||
|
||||
.. note::
|
||||
Default configuration template file location: ``lwgps/src/include/lwgps/lwgps_opts_template.h``.
|
||||
File must be renamed to ``lwgps_opts.h`` first and then copied to the project directory (or simply renamed in-place) where compiler
|
||||
include paths have access to it by using ``#include "lwgps_opts.h"``.
|
||||
|
||||
.. tip::
|
||||
Check :ref:`api_lwgps_opt` section for possible configuration settings
|
||||
|
||||
.. literalinclude:: ../../lwgps/src/include/lwgps/lwgps_opts_template.h
|
||||
:language: c
|
||||
:linenos:
|
||||
:caption: Template options file
|
||||
|
||||
Minimal example code
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Run below example to test and verify library
|
||||
|
||||
.. literalinclude:: ../../examples/example.c
|
||||
:language: c
|
||||
:linenos:
|
||||
:caption: Test verification code
|
|
@ -0,0 +1,71 @@
|
|||
LwGPS |version| documentation
|
||||
=============================
|
||||
|
||||
Welcome to the documentation for version |version|.
|
||||
|
||||
LwGPS is lightweight, platform independent library to parse NMEA statements from GPS receivers. It is highly optimized for embedded systems.
|
||||
|
||||
.. image:: static/images/logo.svg
|
||||
:align: center
|
||||
|
||||
.. rst-class:: center
|
||||
.. rst-class:: index_links
|
||||
|
||||
:ref:`download_library` :ref:`getting_started` `Open Github <https://github.com/MaJerle/lwgps>`_ `Donate <https://paypal.me/tilz0R>`_
|
||||
|
||||
Features
|
||||
^^^^^^^^
|
||||
|
||||
* Written in ANSI C99
|
||||
* Platform independent, easy to use
|
||||
* Built-in support for 4 GPS statements
|
||||
|
||||
* ``GPGGA`` or ``GNGGA``: GPS fix data
|
||||
* ``GPGSA`` or ``GNGSA``: GPS active satellites and dillusion of position
|
||||
* ``GPGSV`` or ``GNGSV``: List of satellites in view zone
|
||||
* ``GPRMC`` or ``GNRMC``: Recommended minimum specific GPS/Transit data
|
||||
|
||||
* Optional ``float`` or ``double`` floating point units
|
||||
* Low-level layer is separated from application layer, thus allows you to add custom communication with GPS device
|
||||
* Works with operating systems
|
||||
* Works with different communication interfaces
|
||||
* User friendly MIT license
|
||||
|
||||
Requirements
|
||||
^^^^^^^^^^^^
|
||||
|
||||
* C compiler
|
||||
* Driver for receiving data from GPS receiver
|
||||
* Few *kB* of non-volatile memory
|
||||
|
||||
Contribute
|
||||
^^^^^^^^^^
|
||||
|
||||
Fresh contributions are always welcome. Simple instructions to proceed:
|
||||
|
||||
#. Fork Github repository
|
||||
#. Respect `C style & coding rules <https://github.com/MaJerle/c-code-style>`_ used by the library
|
||||
#. Create a pull request to ``develop`` branch with new features or bug fixes
|
||||
|
||||
Alternatively you may:
|
||||
|
||||
#. Report a bug
|
||||
#. Ask for a feature request
|
||||
|
||||
License
|
||||
^^^^^^^
|
||||
|
||||
.. literalinclude:: ../LICENSE
|
||||
|
||||
Table of contents
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
self
|
||||
get-started/index
|
||||
user-manual/index
|
||||
api-reference/index
|
||||
examples/index
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
|
@ -0,0 +1,8 @@
|
|||
breathe>=4.9.1
|
||||
colorama
|
||||
docutils>=0.14
|
||||
sphinx>=2.0.1
|
||||
sphinx_rtd_theme
|
||||
sphinx-tabs
|
||||
sphinxcontrib-svg2pdfconverter
|
||||
sphinx-sitemap
|
|
@ -0,0 +1,64 @@
|
|||
/* Center aligned text */
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Paragraph with main links on index page */
|
||||
.index-links {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.index-links a {
|
||||
display: inline-block;
|
||||
border: 1px solid #0E4263;
|
||||
padding: 5px 20px;
|
||||
margin: 2px 5px;
|
||||
background: #2980B9;
|
||||
border-radius: 4px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.index-links a:hover, .index-links a:active {
|
||||
background: #0E4263;
|
||||
}
|
||||
|
||||
/* Table header p w/0 margin */
|
||||
.index-links a table thead th {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table thead th p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.table-nowrap td {
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
/* Breathe output changes */
|
||||
.breathe-sectiondef.container {
|
||||
background: #f9f9f9;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid #efefef;
|
||||
}
|
||||
.breathe-sectiondef.container .breathe-sectiondef-title {
|
||||
background: #2980b9;
|
||||
color: #FFFFFF;
|
||||
padding: 4px;
|
||||
margin: -10px -10px 0 -10px;
|
||||
}
|
||||
.breathe-sectiondef.container .function,
|
||||
.breathe-sectiondef.container .member,
|
||||
.breathe-sectiondef.container .class,
|
||||
.breathe-sectiondef.container .type {
|
||||
border-bottom: 1px solid #efefef;
|
||||
}
|
||||
.breathe-sectiondef.container .function:last-child,
|
||||
.breathe-sectiondef.container .member:last-child,
|
||||
.breathe-sectiondef.container .class:last-child,
|
||||
.breathe-sectiondef.container .type:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=common.css.map */
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 30 KiB |
|
@ -0,0 +1 @@
|
|||
<mxfile modified="2019-03-17T18:59:38.494Z" host="www.draw.io" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/7.8.7 Chrome/58.0.3029.110 Electron/1.7.5 Safari/537.36" version="10.4.9" etag="K-7s2_uXvQkXh2xx6gpu" type="device"><diagram id="7c61e978-b8e5-555b-ca9a-a1ec85429089" name="Page-1">7Ztfb5swFMU/TR4n2RgIPC5d1z5s0rR06rMDJlgBHDlOk+zTz4BpSM2kaupyq6vmITXXf8C/wwPn0MzYTX2803xbfle5qGYByY8z9mUWBDQkzP5pK6e+ktB5X1hrmbtB58JS/hauSFx1L3OxuxholKqM3F4WM9U0IjMXNa61OlwOK1R1edYtXwuvsMx45VcfZW5KV6Vxeu64F3JdulMngdvfimebtVb7xp1vFrCi+/TdNR/WchvdlTxXh1GJ3c7YjVbK9K36eCOqlu2ArZ/39S+9z9etRWNeMyHoJzzxau+2vnxwV2ZOA41uP6KdQWZscSilEcstz9reg9Xf1kpTV/aI2mbFV6JaPGO4UZXStqtRjR2/KFRjnNw0cMfDEMuKMWI/tu7vw23tSWgjjqOS29edULUw+mSHuF4W9TPcLRikDvnhLChzpXIkZehq3N1C6+eFzxhtw5Gcpso8qiuChGoMRzX0qVIkVFM4qrFPNUBClQZwWOc+VoYFawSHNfGxhliwJnBYUx9rhASrvV3BsA6Ps2OuMRauISBX6nOdY+E6B+Q6YQd+IOHKCCBX3xDgsVkJgeM6YQmwGK2QAnKNfK5YrFYYAnJFbLbCOSBXxG4rIoBcEdutiAFyRey3ohiO65CqY/RbUQrIFbHfigNAroj9VhwBcvX91uJkhK2oxn79+vzTui9SiafutWU3gKykGfrpp0epxXlEXNlrW6y0ba3b1oOsZbNuz7frkbTblvVWacMtr8BeH7l/tF+Gb0Q7JOPdcqpoxxl/QSSSv3jjxtiU4v9Lct8Kfkh+ffd/Xc19m7osrSKtDLIW7xN6IatqVM8jkeShre+MVhsx6kmsh4njN5LpFS/Dhzx3rFLyFir5phdN+JVAPjxMmF4s4VcC+fAwYXqxhF8JYFg79ZIRS/iVAoa1w7oYw68UMKxlE6YXS/iVAoa1zDe9aMIvSgDTWjbxb4dY0i9KAONaNvGaEUv8RQlgXssmDByW/IsSwMCW+Z7rIw25vh28ahrCfD/4TXUq9WFIK8pOtS0iGyO03m87wa0IJJdFIbqNt5rtNoO0K9HrLI4i2xurx7tU7mWkwkVSZFORSpwlYlW8Ub79CitFwwmt/yFTsYfnn4R0faPf3bDbPw==</diagram></mxfile>
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 8.8 KiB |
|
@ -0,0 +1 @@
|
|||
<mxfile modified="2019-03-17T18:28:51.770Z" host="www.draw.io" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/7.8.7 Chrome/58.0.3029.110 Electron/1.7.5 Safari/537.36" etag="Lw4IH-C7q6o9UbXhWxg1" version="10.4.9" type="device"><diagram id="oLfy0yLwNNLmw2rXhwVB" name="Page-1">7VpNc9owEP01HMnYkmXsYyBpy6Fpm5CU9tIRtjCaGIsRopD++sq2DJZlkuCYkHaSQ0a7+rL2vd2VNunAwXzzkePF7DMLSdwBVrjpwIsOAD2/J3+niodcgaCfKyJOw1xl7xQ39A9R45RyRUOy1MYJxmJBF7oyYElCAqHpMOdsrQ+bsljfdIEjYihuAhyb2u80FDOltV1/1/GJ0GimtvaAOu8cF4OtXLGc4ZCtSyp42YEDzpjIW/PNgMSp6Qqz5PM+7OndfhgniXjOhC+Mrn6Ovv2KRugD/0a7v4bTUVet8hvHK3Xgz4Nbqfhy3QFuLNftT7hsRWnr9qbfSfdw8Xwhxay3uxWzIbL/9vx6pA4sHgorrmdUkJsFDlJ5LXkix87EPJaSLZt4ucixm9INkZ/bn9I4HrCY8Ww6nHoBCQKpXwrO7kmpZ+IhB1nZzlVrFEcjXJBNSaWs85GwORH8QQ4pei2FlGIq8JS8LgFfjJmVMN8qsSJbtF17h4dsKEgOgMcz4DFMS5LwPOW5lBKWEN2wZEPFuNT+IdvWmfStJibOewovAI8ZfclWPCBP846EmveZ0JRMj2osX+g4ibGgv3WfrUND7fCVUfnFO+Q9pCEPLaQvkZ9HzSr7WGWhrbPvW0hgHhFhLJSRY3vs5nyxTX82CMPZKglTL7tIQX3CM0/iiNKhdEe0TUcEj7ChdTcsNmvuh4n8jHHmfKgQfzQ28QGOmPPtGYx5I55YdSDgVzBt6onAfV1PBH5LoVsxpgjejQiTzr7YqOmZ8KCEA6hUYchzgvxpqWT7Zz3kucByPd9FyAY6ISxwBm0LOo68sqXDvHaIZnvgVYkGzdh0NxiYtzeDfTIYC51y+wm0j3I4plEidYEkC5Gd/TTIU3l7PlcdcxqG6Ya1eUbPRC0kDtvX87jdMxNHHePAsRIHfEY+fjQKHDU5vNWY7zWM+Q56YqFjuyJ4R/tgtCFq6a796mjDljK8/jjrvT/Oqo8zHWcHtnQlNJh3bMIggzB29/vw+tJM1heXd8NBjd4g2KGFlRhPSNzHwX2UJd+CSYqcp3ntuRU/tsyk7dbQy20haUcArybjcLwZXlm3V5zeB5NJ97+FycCkBrm9MEHnjcHkvsNUA5NTzYqnhqn3wixpJrbHiimZsHvqZlLx1m2Kh/HwbVJnyYP/yS5dfktXbGhXK6VHu3TVsumlBfF/gU2nIgnstUWS6kLIP/NKP/6rUualhbhTUmZXIUnXVoYinEqbEJ4mKppEnXL55O2y68nHeeNX/knZVfMXl9FYyl+HVwbNzIpb+/WzF10ebKRHd1DU00oUcZBJkTbqZ/XWNSsq1/+NdaFzNOtKcfePBTnVd/+cAS//Ag==</diagram></mxfile>
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1 @@
|
|||
<mxfile modified="2019-03-17T18:24:31.030Z" host="www.draw.io" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/7.8.7 Chrome/58.0.3029.110 Electron/1.7.5 Safari/537.36" version="10.4.9" etag="GRhl1qzylYBum7KQYHDi" type="device"><diagram id="85174833-9250-f023-2320-fd733ea284ef" name="Page-1">7Vxdd6I6FP01PraLBMLHY9V2pg8zd1Y7HWceKUTNGgQH01Hvr78BgkKigsiHt8WXkgMEOHvvk5ND6EAdLTafQns5/xK42BtAxd0M1PEAQqApKvsTWbaJxQRGYpiFxOUH7Q3P5F+cGBE3vhEXr3LH0SDwKFnmjU7g+9ihOZsdhsE6f9g08PIXXdozLBmeHduTrRPi0jl/CKTs7Z8xmc3TKwOF73m1nd+zMHjz+fUGUJ3Gv2T3wk774sev5rYbrDMm9X6gjsIgoMnWYjPCXuTa1GvJeQ9H9u7uO8Q+LXOCNRk++KOvD5//jP3J2Jj88TXnBqT9/LW9N5w+SHy7dJu6CPvuXeRp1vIDnxmHc7rwWAuwTbwh9CfbVm4Rb/2KWmx7SjxvFHhBGPeiTk0HOw6zr2gY/MaZPa8m0pDCzx5v+OlxY8sbyTkpQMx3w+QusSuhu/cH2HmZkRcHC0zDLTtkvYc5RXmeQTi1hdizKfmb797mbJvtuttd4VtA2IWhwoUBLU5wLgtgqvkuVsFb6GB+Vha3oo4QyndE7XCGqdQR28g89t4U0+IMiiBdYsiX0Qsz/PM0gLrHvDZ8DdnWLNp6eWbAMAfq9mLJmvHem10zPoTtf7l7+i6xbD0nFD8vbSdqr1msyfPMXi0T+U/JBruV6MWfA4cUb84lDT9BwAIanCwZTu0CRJZUO+MhAuUQOxseoyYBg6x8byGq5OLqOmU3HAuikIldCRqYSh57S9BhaUGr6HRHTQvaLGZMPK5FMoujb4E0O1Ei1MT4KksRnmBD7ULUlXc+kpZRqNnpkIu0WwOZOlR009IRAjDPEAPeqkBRNc2E8WFmRf0icUCGrepXl1O2H6ORPBZL7GNio3nKHSfQMcrZHpn5zOYwbmC2cxiJmLB0+o7vWBDXjS54MGjkw0oTUUCTo4B+gHGwsSigNTIcG/1wLA7HRh55TYS0rJxVkO9I1dodjnUkMQbcTB6f7mVFj+9/PI4O2CWGnZtLe/Yr9oa7CW1KJc7OTsZ3VciSwIFU+5Cy9caULc+DepyY7sC14VQivT0ZgeWgyVwRbjOpWdT8lcboqLFPteJWmmtVBaRMeE6iUmFc6So8q7owyRHz7tLh2RKmXYbQUdPh2foAdOqKJZpWE0ukjqB1a2Z+VqucMeQM/ftP1v72+FXijpyUX1mKDZAgQBNJAT71fisptgEl7z69G+/u0p6uvGvJ3j0v3rU5S+ms0qAJqInl3dK1BKEjKS1qOFJZao/22WhXr/yibiu/1qXFiQ+BtjDxrK5tsc7ftrblwkKPdnEArkvbYkdNoy2XJ06h7Xj2akWcDwi4iJNZ19AtdtQ04HW9+E1fESWV5vTd0+G3R1dWggaKcU1cqj5UFJGyYS4Bpc8MSsAt1rQq54FGt3kgUPrUoALcVYtTkrrFjhqH+7zcoIf7MnUX8aZxuEtkBjQktj87WufKYO+SEDuUBFFtjLkgQqJGPtT69l8F5dYAAeU4OS4qngFw6XLaD6G0oqlS5cCqtqy0dIVRD/cpuIWFk9WzZHEFZssFFQD6aun5cFcfR8XF1m1nyaCfFJWA26hrDixOilpXdz8pqqDuymO3qO6W66UA9AXTcoiLQFUumIrUabvIBfqKKXNCt0v0rbpGiyJWNk6mEssM38ck27y6SXaJJXn/gw+YBL92/gETSK/WJ0DnDIe1JUBtFy/gpbNZGbz3t0JVQqm2FaptV4VhP5stsWy96GOgql8V1Qc3a+7/aURy+P4fc6j3/wE=</diagram></mxfile>
|
|
@ -0,0 +1 @@
|
|||
<mxfile host="Electron" modified="2020-12-05T00:17:49.072Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/12.3.2 Chrome/78.0.3904.113 Electron/7.1.2 Safari/537.36" etag="J3RPSOEyywhlMJWRwdgH" version="12.3.2" type="device" pages="1"><diagram id="Wsjaadh77UIxB9X1bxos" name="Page-1">jZJNb8MgDIZ/TY6VkpB067Vd10nrqkk59IyCG1AhRJSMdL9+ZDH5UDVpJ/BjY+B9HZGd6g6GNvxDM5BRGrMuIi9RmibxU+aXntwHssnzAVRGMCyaQCG+IZxE2goGt0Wh1Vpa0SxhqesaSrtg1BjtlmUXLZe3NrSCB1CUVD7Ss2CWD/Q5jyf+BqLi4eYkxoyioRjBjVOm3QyRfUR2Rms77FS3A9mLF3QZzr3+kR0fZqC2/zlwWrEMNsodT6rdZpv3izwnK+zyRWWLHz66w2eBL7b3IIPRbc2g75REZOu4sFA0tOyzzhvvGbdKYvpmjb6Ocq09uejaorekj0ctYh88fiS8CoyFbobwYwfQCqy5+xLMkgynCqcsDbGbPEvWaASf+RV8pDgm1dh6UtJvUMwQTqb95majT/Y/</diagram></mxfile>
|
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="166px" height="56px" viewBox="-0.5 -0.5 166 56" content="<mxfile host="Electron" modified="2020-12-05T00:17:54.452Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/12.3.2 Chrome/78.0.3904.113 Electron/7.1.2 Safari/537.36" etag="QrTFHCUJlsVW3_ulGR16" version="12.3.2" type="device" pages="1"><diagram id="Wsjaadh77UIxB9X1bxos" name="Page-1">jZJNb8MgDIZ/TY6VkpB067Vd10nrqkk59IyCG1AhRJSMdL9+ZDH5UDVpJ/BjY+B9HZGd6g6GNvxDM5BRGrMuIi9RmibxU+aXntwHssnzAVRGMCyaQCG+IZxE2goGt0Wh1Vpa0SxhqesaSrtg1BjtlmUXLZe3NrSCB1CUVD7Ss2CWD/Q5jyf+BqLi4eYkxoyioRjBjVOm3QyRfUR2Rms77FS3A9mLF3QZzr3+kR0fZqC2/zlwWrEMNsodT6rdZpv3izwnK+zyRWWLHz66w2eBL7b3IIPRbc2g75REZOu4sFA0tOyzzhvvGbdKYvpmjb6Ocq09uejaorekj0ctYh88fiS8CoyFbobwYwfQCqy5+xLMkgynCqcsDbGbPEvWaASf+RV8pDgm1dh6UtJvUMwQTqb95majT/Y/</diagram></mxfile>"><defs/><g><rect x="3" y="3" width="160" height="50" rx="7.5" ry="7.5" fill="#ffffff" stroke="#000000" stroke-width="6" pointer-events="all"/><g transform="translate(21.5,6.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="122" height="41" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 36px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 123px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;white-space:normal;">LwGPS</div></div></foreignObject><text x="61" y="39" fill="#000000" text-anchor="middle" font-size="36px" font-family="Helvetica">LwGPS</text></switch></g></g></svg>
|
After Width: | Height: | Size: 2.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
|
@ -0,0 +1,15 @@
|
|||
.. _float_double:
|
||||
|
||||
Float/double precision
|
||||
======================
|
||||
|
||||
With configuration of ``GSM_CFG_DOUBLE``, it is possible to enable ``double`` floating point precision.
|
||||
All floating point variables are then configured in *double precision*.
|
||||
|
||||
When configuration is set to ``0``, floating point variables are configured in *single precision* format.
|
||||
|
||||
.. note::
|
||||
Single precision uses less memory in application. As a drawback, application may be a subject of data loss at latter digits.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
|
@ -0,0 +1,38 @@
|
|||
.. _how_it_works:
|
||||
|
||||
How it works
|
||||
============
|
||||
|
||||
LwGPS parses raw data formatted as NMEA 0183 statements from GPS receivers. It supports up to ``4`` different statements:
|
||||
|
||||
* ``GPGGA`` or ``GNGGA``: GPS fix data
|
||||
* ``GPGSA`` or ``GNGSA``: GPS active satellites and dillusion of position
|
||||
* ``GPGSV`` or ``GNGSV``: List of satellites in view zone
|
||||
* ``GPRMC`` or ``GNRMC``: Recommended minimum specific GPS/Transit data
|
||||
|
||||
.. tip::
|
||||
By changing different configuration options, it is possible to disable some statements.
|
||||
Check :ref:`api_lwgps_opt` for more information.
|
||||
|
||||
Application must assure to properly receive data from GPS receiver.
|
||||
Usually GPS receivers communicate with host embedded system with UART protocol and output directly formatted NMEA 0183 statements.
|
||||
|
||||
.. note::
|
||||
Application must take care of properly receive data from GPS.
|
||||
|
||||
Application must use :cpp:func:`lwgps_process` function for data processing. Function will:
|
||||
|
||||
* Detect statement type, such as *GPGGA* or *GPGSV*
|
||||
* Parse all the terms of specific statement
|
||||
* Check valid CRC after each statement
|
||||
|
||||
Programmer's model is as following:
|
||||
|
||||
* Application receives data from GPS receiver
|
||||
* Application sends data to :cpp:func:`lwgps_process` function
|
||||
* Application uses processed data to display altitude, latitude, longitude, and other parameters
|
||||
|
||||
Check :ref:`examples` for typical example
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
|
@ -0,0 +1,12 @@
|
|||
.. _um:
|
||||
|
||||
User manual
|
||||
===========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
how-it-works
|
||||
float-double
|
||||
thread-safety
|
||||
tests
|
|
@ -0,0 +1,14 @@
|
|||
.. _tests:
|
||||
|
||||
Tests during development
|
||||
========================
|
||||
|
||||
During the development, test check is performed to validate raw NMEA input data vs expected result.
|
||||
|
||||
.. literalinclude:: ../../examples/test_code.c
|
||||
:language: c
|
||||
:linenos:
|
||||
:caption: Test code for development
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
|
@ -0,0 +1,16 @@
|
|||
.. _thread_safety:
|
||||
|
||||
Thread safety
|
||||
=============
|
||||
|
||||
Library tends to be as simple as possible.
|
||||
No specific features have been implemented for thread safety.
|
||||
|
||||
When library is using multi-thread environment and if multi threads tend to access to shared resources,
|
||||
user must resolve it with care, using mutual exclusion.
|
||||
|
||||
.. tip::
|
||||
When single thread is dedicated for GPS processing, no special mutual exclusion is necessary.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
|
@ -0,0 +1,40 @@
|
|||
# gps-nmea-parser examples and tests Makefile
|
||||
# (c) 2020 Sirio, Balmelli Analog & Digital
|
||||
|
||||
TARGETS := \
|
||||
example.exe \
|
||||
example_stat.exe \
|
||||
test_code.exe \
|
||||
test_time.exe
|
||||
|
||||
.PHONY: all clean test
|
||||
all: $(TARGETS)
|
||||
|
||||
clean:
|
||||
@rm -fv $(TARGETS)
|
||||
|
||||
test: $(TARGETS)
|
||||
@for tgt in $(TARGETS); do \
|
||||
echo "\n--- $$tgt ---"; \
|
||||
./$$tgt; \
|
||||
done
|
||||
|
||||
CFLAGS += -Wall \
|
||||
-DDEBUG=1 \
|
||||
-I../lwgps/src/include \
|
||||
-I./
|
||||
|
||||
example.exe: example.c
|
||||
|
||||
example_stat.exe: CFLAGS += -DLWGPS_CFG_STATUS=1
|
||||
example_stat.exe: example_stat.c
|
||||
|
||||
test_code.exe: ../lwgps/src/lwgps/lwgps.c test_code.c ../dev/VisualStudio/main.c
|
||||
|
||||
test_time.exe: CFLAGS += \
|
||||
-DLWGPS_CFG_STATEMENT_PUBX=1 \
|
||||
-DLWGPS_CFG_STATEMENT_PUBX_TIME=1
|
||||
test_time.exe: ../lwgps/src/lwgps/lwgps.c test_time.c ../dev/VisualStudio/main.c
|
||||
|
||||
$(TARGETS) : ../lwgps/src/lwgps/lwgps.c
|
||||
$(CC) -o $@ $(CFLAGS) $^
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* This example uses direct processing function
|
||||
* to process dummy NMEA data from GPS receiver
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "lwgps/lwgps.h"
|
||||
|
||||
/* GPS handle */
|
||||
lwgps_t hgps;
|
||||
|
||||
/**
|
||||
* \brief Dummy data from GPS receiver
|
||||
*/
|
||||
const char
|
||||
gps_rx_data[] = ""
|
||||
"$GPRMC,183729,A,3907.356,N,12102.482,W,000.0,360.0,080301,015.5,E*6F\r\n"
|
||||
"$GPRMB,A,,,,,,,,,,,,V*71\r\n"
|
||||
"$GPGGA,183730,3907.356,N,12102.482,W,1,05,1.6,646.4,M,-24.1,M,,*75\r\n"
|
||||
"$GPGSA,A,3,02,,,07,,09,24,26,,,,,1.6,1.6,1.0*3D\r\n"
|
||||
"$GPGSV,2,1,08,02,43,088,38,04,42,145,00,05,11,291,00,07,60,043,35*71\r\n"
|
||||
"$GPGSV,2,2,08,08,02,145,00,09,46,303,47,24,16,178,32,26,18,231,43*77\r\n"
|
||||
"$PGRME,22.0,M,52.9,M,51.0,M*14\r\n"
|
||||
"$GPGLL,3907.360,N,12102.481,W,183730,A*33\r\n"
|
||||
"$PGRMZ,2062,f,3*2D\r\n"
|
||||
"$PGRMM,WGS84*06\r\n"
|
||||
"$GPBOD,,T,,M,,*47\r\n"
|
||||
"$GPRTE,1,1,c,0*07\r\n"
|
||||
"$GPRMC,183731,A,3907.482,N,12102.436,W,000.0,360.0,080301,015.5,E*67\r\n"
|
||||
"$GPRMB,A,,,,,,,,,,,,V*71\r\n";
|
||||
|
||||
int
|
||||
main() {
|
||||
/* Init GPS */
|
||||
lwgps_init(&hgps);
|
||||
|
||||
/* Process all input data */
|
||||
lwgps_process(&hgps, gps_rx_data, strlen(gps_rx_data));
|
||||
|
||||
/* Print messages */
|
||||
printf("Valid status: %d\r\n", hgps.is_valid);
|
||||
printf("Latitude: %f degrees\r\n", hgps.latitude);
|
||||
printf("Longitude: %f degrees\r\n", hgps.longitude);
|
||||
printf("Altitude: %f meters\r\n", hgps.altitude);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
#include "lwgps/lwgps.h"
|
||||
#include "lwrb/lwrb.h"
|
||||
#include <string.h>
|
||||
|
||||
/* GPS handle */
|
||||
lwgps_t hgps;
|
||||
|
||||
/* GPS buffer */
|
||||
lwrb_t hgps_buff;
|
||||
uint8_t hgps_buff_data[12];
|
||||
|
||||
/**
|
||||
* \brief Dummy data from GPS receiver
|
||||
* \note This data are used to fake UART receive event on microcontroller
|
||||
*/
|
||||
const char
|
||||
gps_rx_data[] = ""
|
||||
"$GPRMC,183729,A,3907.356,N,12102.482,W,000.0,360.0,080301,015.5,E*6F\r\n"
|
||||
"$GPRMB,A,,,,,,,,,,,,V*71\r\n"
|
||||
"$GPGGA,183730,3907.356,N,12102.482,W,1,05,1.6,646.4,M,-24.1,M,,*75\r\n"
|
||||
"$GPGSA,A,3,02,,,07,,09,24,26,,,,,1.6,1.6,1.0*3D\r\n"
|
||||
"$GPGSV,2,1,08,02,43,088,38,04,42,145,00,05,11,291,00,07,60,043,35*71\r\n"
|
||||
"$GPGSV,2,2,08,08,02,145,00,09,46,303,47,24,16,178,32,26,18,231,43*77\r\n"
|
||||
"$PGRME,22.0,M,52.9,M,51.0,M*14\r\n"
|
||||
"$GPGLL,3907.360,N,12102.481,W,183730,A*33\r\n"
|
||||
"$PGRMZ,2062,f,3*2D\r\n"
|
||||
"$PGRMM,WGS84*06\r\n"
|
||||
"$GPBOD,,T,,M,,*47\r\n"
|
||||
"$GPRTE,1,1,c,0*07\r\n"
|
||||
"$GPRMC,183731,A,3907.482,N,12102.436,W,000.0,360.0,080301,015.5,E*67\r\n"
|
||||
"$GPRMB,A,,,,,,,,,,,,V*71\r\n";
|
||||
static size_t write_ptr;
|
||||
static void uart_irqhandler(void);
|
||||
|
||||
int
|
||||
main() {
|
||||
uint8_t rx;
|
||||
|
||||
/* Init GPS */
|
||||
lwgps_init(&hgps);
|
||||
|
||||
/* Create buffer for received data */
|
||||
lwrb_init(&hgps_buff, hgps_buff_data, sizeof(hgps_buff_data));
|
||||
|
||||
while (1) {
|
||||
/* Add new character to buffer */
|
||||
/* Fake UART interrupt handler on host microcontroller */
|
||||
uart_irqhandler();
|
||||
|
||||
/* Process all input data */
|
||||
/* Read from buffer byte-by-byte and call processing function */
|
||||
if (lwrb_get_full(&hgps_buff)) { /* Check if anything in buffer now */
|
||||
while (lwrb_read(&hgps_buff, &rx, 1) == 1) {
|
||||
lwgps_process(&hgps, &rx, 1); /* Process byte-by-byte */
|
||||
}
|
||||
} else {
|
||||
/* Print all data after successful processing */
|
||||
printf("Latitude: %f degrees\r\n", hgps.latitude);
|
||||
printf("Longitude: %f degrees\r\n", hgps.longitude);
|
||||
printf("Altitude: %f meters\r\n", hgps.altitude);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Interrupt handler routing for UART received character
|
||||
* \note This is not real MCU, it is software method, called from main
|
||||
*/
|
||||
static void
|
||||
uart_irqhandler(void) {
|
||||
/* Make interrupt handler as fast as possible */
|
||||
/* Only write to received buffer and process later */
|
||||
if (write_ptr < strlen(gps_rx_data)) {
|
||||
/* Write to buffer only */
|
||||
lwrb_write(&hgps_buff, &gps_rx_data[write_ptr], 1);
|
||||
++write_ptr;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#include "lwgps/lwgps.h"
|
||||
|
||||
/* Distance and bearing results */
|
||||
lwgps_float_t dist, bear;
|
||||
|
||||
/* New York coordinates */
|
||||
lwgps_float_t lat1 = 40.685721;
|
||||
lwgps_float_t lon1 = -73.820465;
|
||||
|
||||
/* Munich coordinates */
|
||||
lwgps_float_t lat2 = 48.150906;
|
||||
lwgps_float_t lon2 = 11.554176;
|
||||
|
||||
/* Go from New York to Munich */
|
||||
/* Calculate distance and bearing related to north */
|
||||
lwgps_distance_bearing(lat1, lon1, lat2, lon2, &dist, &bear);
|
||||
printf("Distance: %f meters\r\n", (float)dist);
|
||||
printf("Initial bearing: %f degrees\r\n", (float)bear);
|
||||
|
||||
/* Go from Munich to New York */
|
||||
/* Calculate distance and bearing related to north */
|
||||
lwgps_distance_bearing(lat2, lon2, lat1, lon1, &dist, &bear);
|
||||
printf("Distance: %f meters\r\n", (float)dist);
|
||||
printf("Initial bearing: %f degrees\r\n", (float)bear);
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* This example tests the callback functionality of lwgps_process()
|
||||
* when the LWGPS_CFG_STATUS flag is set.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "lwgps/lwgps.h"
|
||||
|
||||
#if !LWGPS_CFG_STATUS
|
||||
#error "this test must be compiled with -DLWGPS_CFG_STATUS=1"
|
||||
#endif /* !LWGPS_CFG_STATUS */
|
||||
|
||||
/* GPS handle */
|
||||
lwgps_t hgps;
|
||||
|
||||
/**
|
||||
* \brief Dummy data from GPS receiver
|
||||
*/
|
||||
const char
|
||||
gps_rx_data[] = ""
|
||||
"$GPRMC,183729,A,3907.356,N,12102.482,W,000.0,360.0,080301,015.5,E*6F\r\n"
|
||||
"$GPRMB,A,,,,,,,,,,,,V*71\r\n"
|
||||
"$GPGGA,183730,3907.356,N,12102.482,W,1,05,1.6,646.4,M,-24.1,M,,*75\r\n"
|
||||
"$GPGSA,A,3,02,,,07,,09,24,26,,,,,1.6,1.6,1.0*3D\r\n"
|
||||
"$GPGSV,2,1,08,02,43,088,38,04,42,145,00,05,11,291,00,07,60,043,35*71\r\n"
|
||||
"$GPGSV,2,2,08,08,02,145,00,09,46,303,47,24,16,178,32,26,18,231,43*77\r\n"
|
||||
"$PGRME,22.0,M,52.9,M,51.0,M*14\r\n"
|
||||
"$GPGLL,3907.360,N,12102.481,W,183730,A*33\r\n"
|
||||
"$PGRMZ,2062,f,3*2D\r\n"
|
||||
"$PGRMM,WGS84*06\r\n"
|
||||
"$GPBOD,,T,,M,,*47\r\n"
|
||||
"$GPRTE,1,1,c,0*07\r\n"
|
||||
"$GPRMC,183731,A,3907.482,N,12102.436,W,000.0,360.0,080301,015.5,E*67\r\n"
|
||||
"$GPRMB,A,,,,,,,,,,,,V*71\r\n";
|
||||
|
||||
const lwgps_statement_t expected[] = {
|
||||
STAT_RMC,
|
||||
STAT_UNKNOWN,
|
||||
STAT_GGA,
|
||||
STAT_GSA,
|
||||
STAT_GSV,
|
||||
STAT_GSV,
|
||||
STAT_UNKNOWN,
|
||||
STAT_UNKNOWN,
|
||||
STAT_UNKNOWN,
|
||||
STAT_CHECKSUM_FAIL,
|
||||
STAT_UNKNOWN,
|
||||
STAT_UNKNOWN,
|
||||
STAT_RMC,
|
||||
STAT_UNKNOWN
|
||||
};
|
||||
|
||||
static int err_cnt;
|
||||
|
||||
void
|
||||
callback(lwgps_statement_t res) {
|
||||
static int i;
|
||||
|
||||
if (res != expected[i]) {
|
||||
printf("failed i %d, expected res %d but received %d\n",
|
||||
i, expected[i], res);
|
||||
++err_cnt;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
int
|
||||
main() {
|
||||
/* Init GPS */
|
||||
lwgps_init(&hgps);
|
||||
|
||||
/* Process all input data */
|
||||
lwgps_process(&hgps, gps_rx_data, strlen(gps_rx_data), callback);
|
||||
|
||||
return err_cnt;
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* This example uses direct processing function,
|
||||
* to process dummy NMEA data from GPS receiver
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "lwgps/lwgps.h"
|
||||
#include "test_common.h"
|
||||
|
||||
/* GPS handle */
|
||||
lwgps_t hgps;
|
||||
|
||||
/**
|
||||
* \brief Dummy data from GPS receiver
|
||||
*/
|
||||
const char
|
||||
gps_rx_data[] = ""
|
||||
"$GPRMC,183729,A,3907.356,N,12102.482,W,000.0,360.0,080301,015.5,E*6F\r\n"
|
||||
"$GPGGA,183730,3907.356,N,12102.482,W,1,05,1.6,646.4,M,-24.1,M,,*75\r\n"
|
||||
"$GPGSA,A,3,02,,,07,,09,24,26,,,,,1.6,1.6,1.0*3D\r\n"
|
||||
"$GPGSV,2,1,08,02,43,088,38,04,42,145,00,05,11,291,00,07,60,043,35*71\r\n"
|
||||
"$GPGSV,2,2,08,08,02,145,00,09,46,303,47,24,16,178,32,26,18,231,43*77\r\n"
|
||||
"";
|
||||
|
||||
/**
|
||||
* \brief Run the test of raw input data
|
||||
*/
|
||||
void
|
||||
run_tests() {
|
||||
lwgps_init(&hgps); /* Init GPS */
|
||||
|
||||
/* Process all input data */
|
||||
lwgps_process(&hgps, gps_rx_data, strlen(gps_rx_data));
|
||||
|
||||
/* Run the test */
|
||||
RUN_TEST(!INT_IS_EQUAL(hgps.is_valid, 0));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.fix, 1));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.fix_mode, 3));
|
||||
RUN_TEST(FLT_IS_EQUAL(hgps.latitude, 39.1226000000));
|
||||
RUN_TEST(FLT_IS_EQUAL(hgps.longitude, -121.0413666666));
|
||||
RUN_TEST(FLT_IS_EQUAL(hgps.altitude, 646.4000000000));
|
||||
RUN_TEST(FLT_IS_EQUAL(hgps.course, 360.0000000000));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.dop_p, 1.6000000000));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.dop_h, 1.6000000000));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.dop_v, 1.0000000000));
|
||||
RUN_TEST(FLT_IS_EQUAL(hgps.speed, 0.0000000000));
|
||||
RUN_TEST(FLT_IS_EQUAL(hgps.geo_sep, -24.100000000));
|
||||
RUN_TEST(FLT_IS_EQUAL(hgps.variation, 15.500000000));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.sats_in_view, 8));
|
||||
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.sats_in_use, 5));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.satellites_ids[0], 2));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.satellites_ids[1], 0));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.satellites_ids[2], 0));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.satellites_ids[3], 7));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.satellites_ids[4], 0));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.satellites_ids[5], 9));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.satellites_ids[6], 24));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.satellites_ids[7], 26));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.satellites_ids[8], 0));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.satellites_ids[9], 0));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.satellites_ids[10], 0));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.satellites_ids[11], 0));
|
||||
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.date, 8));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.month, 3));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.year, 1));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.hours, 18));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.minutes, 37));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.seconds, 30));
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef TEST_COMMON_HDR_H
|
||||
#define TEST_COMMON_HDR_H
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define RUN_TEST(x) do { \
|
||||
if ((x)) { \
|
||||
printf("Test passed on line %u with condition " # x "\r\n", (unsigned)__LINE__); \
|
||||
} else { \
|
||||
printf("Test FAILED on line %u with condition " # x "\r\n", (unsigned)__LINE__ ); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
#define FLT_IS_EQUAL(x, y) (fabs((double)(x) - (double)(y)) < 0.00001)
|
||||
#define INT_IS_EQUAL(x, y) ((int)((x) == (y)))
|
||||
|
||||
#endif /* TEST_COMMON_HDR_H */
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* This example uses direct processing function,
|
||||
* to process dummy PUBX TIME packets from GPS receiver
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "lwgps/lwgps.h"
|
||||
#include "test_common.h"
|
||||
|
||||
#if !LWGPS_CFG_STATEMENT_PUBX_TIME
|
||||
#error "this test must be compiled with -DLWGPS_CFG_STATEMENT_PUBX_TIME=1"
|
||||
#endif /* !LWGPS_CFG_STATEMENT_PUBX_TIME */
|
||||
|
||||
/* GPS handle */
|
||||
lwgps_t hgps;
|
||||
|
||||
/**
|
||||
* \brief Dummy data from GPS receiver
|
||||
*/
|
||||
const char
|
||||
gps_rx_data_A[] = ""
|
||||
"$PUBX,04*37\r\n"
|
||||
"$PUBX,04,073731.00,091202,113851.00,1196,15D,1930035,-2660.664,43*71\r\n"
|
||||
"";
|
||||
const char
|
||||
gps_rx_data_B[] = ""
|
||||
"$PUBX,04,200714.00,230320,158834.00,2098,18,536057,257.043,16*12\r\b"
|
||||
"";
|
||||
|
||||
|
||||
/**
|
||||
* \brief Run the test of raw input data
|
||||
*/
|
||||
void
|
||||
run_tests() {
|
||||
lwgps_init(&hgps);
|
||||
|
||||
/* Process and test block A */
|
||||
lwgps_process(&hgps, gps_rx_data_A, strlen(gps_rx_data_A));
|
||||
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.hours, 7));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.minutes, 37));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.seconds, 31));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.date, 9));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.month, 12));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.year, 2));
|
||||
RUN_TEST(FLT_IS_EQUAL(hgps.utc_tow, 113851.00));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.utc_wk, 1196));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.leap_sec, 15));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.clk_bias, 1930035));
|
||||
RUN_TEST(FLT_IS_EQUAL(hgps.clk_drift, -2660.664));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.tp_gran, 43));
|
||||
|
||||
/* Process and test block B */
|
||||
lwgps_process(&hgps, gps_rx_data_B, strlen(gps_rx_data_B));
|
||||
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.hours, 20));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.minutes, 7));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.seconds, 14));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.date, 23));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.month, 3));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.year, 20));
|
||||
RUN_TEST(FLT_IS_EQUAL(hgps.utc_tow, 158834.00));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.utc_wk, 2098));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.leap_sec, 18));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.clk_bias, 536057));
|
||||
RUN_TEST(FLT_IS_EQUAL(hgps.clk_drift, 257.043));
|
||||
RUN_TEST(INT_IS_EQUAL(hgps.tp_gran, 16));
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(src)
|
|
@ -0,0 +1,3 @@
|
|||
add_subdirectory(include)
|
||||
add_subdirectory(lwgps)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
target_include_directories(${LIB_LWGPS_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
target_include_directories(${LIB_LWGPS_NAME} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
|
@ -0,0 +1,3 @@
|
|||
target_sources(${LIB_LWGPS_NAME} PRIVATE
|
||||
lwgps.c
|
||||
)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue