LwGPS 2.0.0 documentation¶
Welcome to the documentation for version 2.0.0.
LwGPS is lightweight, platform independent library to parse NMEA statements from GPS receivers. It is highly optimized for embedded systems.
Download library · Getting started · Open Github
Features¶
Written in ANSI C99
Platform independent, easy to use
Built-in support for 4 GPS statements
GPGGA
orGNGGA
: GPS fix dataGPGSA
orGNGSA
: GPS active satellites and dillusion of positionGPGSV
orGNGSV
: List of satellites in view zoneGPRMC
orGNRMC
: Recommended minimum specific GPS/Transit data
Optional
float
ordouble
floating point unitsLow-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 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¶
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.
Table of contents¶
Getting started¶
Download library¶
Library is primarly hosted on Github.
Download latest release from releases area on Github
Clone develop branch for latest development
Download from releases¶
All releases are available on Github releases area.
Clone from Github¶
First-time clone¶
Download and install
git
if not alreadyOpen console and navigate to path in the system to clone repository to. Use command
cd your_path
Clone repository with one of available
3
optionsRun
git clone --recurse-submodules https://github.com/MaJerle/lwgps
command to clone entire repository, including submodulesRun
git clone --recurse-submodules --branch develop https://github.com/MaJerle/lwgps
to clone development branch, including submodulesRun
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 submodulesRun
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¶
At this point it is assumed that you have successfully download library, either cloned it or from releases page.
Copy
lwgps
folder to your projectAdd
lwgps/src/include
folder to include path of your toolchainAdd source files from
lwgps/src/
folder to toolchain buildBuild the project
Minimal example code¶
Run below example to test and verify library
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | /**
* This example uses direct processing function
* to process dummy NMEA data from GPS receiver
*/
#include "lwgps/lwgps.h"
#include <string.h>
#include <stdio.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;
}
|
User manual¶
How it works¶
GPS NMEA Parser parses raw data formatted as NMEA 0183 statements from GPS receivers. It supports up to 4
different statements:
GPGGA
orGNGGA
: GPS fix dataGPGSA
orGNGSA
: GPS active satellites and dillusion of positionGPGSV
orGNGSV
: List of satellites in view zoneGPRMC
orGNRMC
: Recommended minimum specific GPS/Transit data
Tip
By changing different configuration options, it is possible to disable some statements. Check GPS Configuration 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 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
lwgps_process()
functionApplication uses processed data to display altitude, latitude, longitude, and other parameters
Check Examples and demos for typical example
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.
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.
Tests during development¶
During the development, test check is performed to validate raw NMEA input data vs expected result.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 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));
}
|
API reference¶
List of all the modules:
GPS NMEA Parser¶
-
group
LWGPS
Lightweight GPS NMEA parser.
Defines
-
lwgps_is_valid
(_gh)¶ Check if current GPS data contain valid signal.
- Note
LWGPS_CFG_STATEMENT_GPRMC must be enabled and
GPRMC
statement must be sent from GPS receiver- Return
1
on success,0
otherwise- Parameters
[in] _gh
: GPS handle
Typedefs
-
typedef double
lwgps_float_t
¶ GPS float definition, can be either
float
ordouble
- Note
Check for LWGPS_CFG_DOUBLE configuration
-
typedef void (*
lwgps_process_fn
)(lwgps_statement_t res)¶ Signature for caller-suplied callback function from gps_process.
- Parameters
[in] res
: statement type of recently parsed statement
Enums
-
enum
lwgps_statement_t
¶ ENUM of possible GPS statements parsed.
Values:
-
enumerator
STAT_UNKNOWN
= 0¶ Unknown NMEA statement
-
enumerator
STAT_GGA
= 1¶ GPGGA statement
-
enumerator
STAT_GSA
= 2¶ GPGSA statement
-
enumerator
STAT_GSV
= 3¶ GPGSV statement
-
enumerator
STAT_RMC
= 4¶ GPRMC statement
-
enumerator
STAT_UBX
= 5¶ UBX statement (uBlox specific)
-
enumerator
STAT_UBX_TIME
= 6¶ UBX TIME statement (uBlox specific)
-
enumerator
STAT_CHECKSUM_FAIL
= UINT8_MAX¶ Special case, used when checksum fails
-
enumerator
-
enum
lwgps_speed_t
¶ List of optional speed transformation from GPS values (in knots)
Values:
-
enumerator
lwgps_speed_kps
¶ Kilometers per second
-
enumerator
lwgps_speed_kph
¶ Kilometers per hour
-
enumerator
lwgps_speed_mps
¶ Meters per second
-
enumerator
lwgps_speed_mpm
¶ Meters per minute
-
enumerator
lwgps_speed_mips
¶ Miles per second
-
enumerator
lwgps_speed_mph
¶ Miles per hour
-
enumerator
lwgps_speed_fps
¶ Foots per second
-
enumerator
lwgps_speed_fpm
¶ Foots per minute
-
enumerator
lwgps_speed_mpk
¶ Minutes per kilometer
-
enumerator
lwgps_speed_spk
¶ Seconds per kilometer
-
enumerator
lwgps_speed_sp100m
¶ Seconds per 100 meters
-
enumerator
lwgps_speed_mipm
¶ Minutes per mile
-
enumerator
lwgps_speed_spm
¶ Seconds per mile
-
enumerator
lwgps_speed_sp100y
¶ Seconds per 100 yards
-
enumerator
lwgps_speed_smph
¶ Sea miles per hour
-
enumerator
Functions
-
uint8_t
lwgps_init
(lwgps_t *gh)¶ Init GPS handle.
- Return
1
on success,0
otherwise- Parameters
[in] gh
: GPS handle structure
-
uint8_t
lwgps_process
(lwgps_t *gh, const void *data, size_t len, lwgps_process_fn evt_fn)¶ Process NMEA data from GPS receiver.
- Return
1
on success,0
otherwise- Parameters
[in] gh
: GPS handle structure[in] data
: Received data[in] len
: Number of bytes to process[in] evt_fn
: Event function to notify application layer
-
uint8_t
lwgps_distance_bearing
(lwgps_float_t las, lwgps_float_t los, lwgps_float_t lae, lwgps_float_t loe, lwgps_float_t *d, lwgps_float_t *b)¶ Calculate distance and bearing between
2
latitude and longitude coordinates.- Return
1
on success,0
otherwise- Parameters
[in] las
: Latitude start coordinate, in units of degrees[in] los
: Longitude start coordinate, in units of degrees[in] lae
: Latitude end coordinate, in units of degrees[in] loe
: Longitude end coordinate, in units of degrees[out] d
: Pointer to output distance in units of meters[out] b
: Pointer to output bearing between start and end coordinate in relation to north in units of degrees
-
lwgps_float_t
lwgps_to_speed
(lwgps_float_t sik, lwgps_speed_t ts)¶ Convert NMEA GPS speed (in knots = nautical mile per hour) to different speed format.
- Return
Speed calculated from knots
- Parameters
[in] sik
: Speed in knots, received from GPS NMEA statement[in] ts
: Target speed to convert to from knots
-
struct
lwgps_sat_t
¶ - #include <lwgps.h>
Satellite descriptor.
-
struct
lwgps_t
¶ - #include <lwgps.h>
GPS main structure.
Public Members
-
lwgps_float_t
latitude
¶ Latitude in units of degrees
-
lwgps_float_t
longitude
¶ Longitude in units of degrees
-
lwgps_float_t
altitude
¶ Altitude in units of meters
-
lwgps_float_t
geo_sep
¶ Geoid separation in units of meters
-
uint8_t
sats_in_use
¶ Number of satellites in use
-
uint8_t
fix
¶ Fix status.
0
= invalid,1
= GPS fix,2
= DGPS fix,3
= PPS fix
-
uint8_t
hours
¶ Hours in UTC
-
uint8_t
minutes
¶ Minutes in UTC
-
uint8_t
seconds
¶ Seconds in UTC
-
lwgps_float_t
dop_h
¶ Dolution of precision, horizontal
-
lwgps_float_t
dop_v
¶ Dolution of precision, vertical
-
lwgps_float_t
dop_p
¶ Dolution of precision, position
-
uint8_t
fix_mode
¶ Fix mode.
1
= NO fix,2
= 2D fix,3
= 3D fix
-
uint8_t
satellites_ids
[12]¶ List of satellite IDs in use. Valid range is
0
tosats_in_use
-
uint8_t
sats_in_view
¶ Number of satellites in view
-
lwgps_sat_t
sats_in_view_desc
[12]¶
-
uint8_t
is_valid
¶ GPS valid status
-
lwgps_float_t
speed
¶ Ground speed in knots
-
lwgps_float_t
course
¶ Ground coarse
-
lwgps_float_t
variation
¶ Magnetic variation
-
uint8_t
date
¶ Fix date
-
uint8_t
month
¶ Fix month
-
uint8_t
year
¶ Fix year
-
lwgps_float_t
utc_tow
¶ UTC TimeOfWeek, eg 113851.00
-
uint16_t
utc_wk
¶ UTC week number, continues beyond 1023
-
uint8_t
leap_sec
¶ UTC leap seconds; UTC + leap_sec = TAI
-
uint32_t
clk_bias
¶ Receiver clock bias, eg 1930035
-
lwgps_float_t
clk_drift
¶ Receiver clock drift, eg -2660.664
-
uint32_t
tp_gran
¶ Time pulse granularity, eg 43
-
lwgps_float_t
-
GPS Configuration¶
This is the default configuration of the middleware.
When any of the settings shall be modified, it shall be done in library header file, lwgps/src/include/lwgps/lwgps.h
-
group
LWGPS_CONFIG
Default configuration setup.
Defines
-
LWGPS_CFG_DOUBLE
¶ Enables
1
or disables0
double precision
for floating point values such as latitude, longitude, altitude.double
is used as variable type when enabled,float
when disabled.
-
LWGPS_CFG_STATUS
¶ Enables
1
or disables0
status reporting callback by lwgps_process.- Note
This is an extension, so not enabled by default.
-
LWGPS_CFG_STATEMENT_GPGGA
¶ Enables
1
or disables0
GGA
statement parsing.- Note
This statement must be enabled to parse:
Latitude, Longitude, Altitude
Number of satellites in use, fix (no fix, GPS, DGPS), UTC time
-
LWGPS_CFG_STATEMENT_GPGSA
¶ Enables
1
or disables0
GSA
statement parsing.- Note
This statement must be enabled to parse:
Position/Vertical/Horizontal dilution of precision
Fix mode (no fix, 2D, 3D fix)
IDs of satellites in use
-
LWGPS_CFG_STATEMENT_GPRMC
¶ Enables
1
or disables0
RMC
statement parsing.- Note
This statement must be enabled to parse:
Validity of GPS signal
Ground speed in knots and coarse in degrees
Magnetic variation
UTC date
-
LWGPS_CFG_STATEMENT_GPGSV
¶ Enables
1
or disables0
GSV
statement parsing.- Note
This statement must be enabled to parse:
Number of satellites in view
Optional details of each satellite in view. See LWGPS_CFG_STATEMENT_GPGSV_SAT_DET
-
LWGPS_CFG_STATEMENT_GPGSV_SAT_DET
¶ Enables
1
or disables0
detailed parsing of each satellite in view forGSV
statement.- Note
When this feature is disabled, only number of “satellites in view” is parsed
-
LWGPS_CFG_STATEMENT_PUBX
¶ Enables
1
or disables0
parsing and generation of PUBX (uBlox) messages.PUBX are a nonstandard ublox-specific extensions, so disabled by default.
-
LWGPS_CFG_STATEMENT_PUBX_TIME
¶ Enables
1
or disables0
parsing and generation of PUBX (uBlox) TIME messages.This is a nonstandard ublox-specific extension, so disabled by default.
- Note
TIME messages can be used to obtain:
UTC time of week
UTC week number
Leap seconds (allows conversion to eg. TAI)
This configure option requires LWGPS_CFG_STATEMENT_PUBX
-
Examples and demos¶
There are 2
very 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | /**
* This example uses direct processing function
* to process dummy NMEA data from GPS receiver
*/
#include "lwgps/lwgps.h"
#include <string.h>
#include <stdio.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;
}
|
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 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;
}
}
|