Skip to content

Commit a0d4607

Browse files
committed
v5.0.0
* HAL: Changed GPS module to get native GPS time (monotonic, no leap second). **WARNING**: The native GPS time is not given in standard NMEA messages, so we get it from a proprietary message of the GPS module used on gateway reference design, u-blox 7. If you are not using the same GPS module, you may have to update the lgw_parse_ubx() function. * HAL: Added lgw_cnt2gps() and lgw_gps2cnt() functions for SX1301<->GPS time conversion. * HAL: Changed serial port configuration for GPS to properly handle binary messages (UBX). * HAL: Added a lgw_gps_disable() function to restore serial configuration as it was before HAL initialization. * HAL: Fixed packet time on air calculation using the actual packet preamble size. * HAL: Adjusted TX_START_DELAY based on the board reference design to ensure that a packet is sent exactly at 1500µs after the TX trigger (TIMESTAMP or PPS), with a tolerance of +/- 1µs. This is mandatory to comply with LoRaWAN specification for Class-B beaconing precise timing. **WARNING**: This release provides tx start delay values to be used for Semtech reference designs AP1 and AP2. The HAL automatically detects the board version by detecting a FPGA or not. If you are using a different reference design or a different FPGA binary version than the one provided with this release, the value to be used for TX start delay may be different.
1 parent a0040a5 commit a0d4607

File tree

12 files changed

+704
-185
lines changed

12 files changed

+704
-185
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
4.1.3
1+
5.0.0

libloragw/inc/loragw_gps.h

Lines changed: 76 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
A limited set of module brands/models are supported.
1313
1414
License: Revised BSD License, see LICENSE.TXT file include in the project
15-
Maintainer: Sylvain Miermont
15+
Maintainer: Michael Coracin
1616
*/
1717

1818

@@ -22,11 +22,11 @@ Maintainer: Sylvain Miermont
2222
/* -------------------------------------------------------------------------- */
2323
/* --- DEPENDANCIES --------------------------------------------------------- */
2424

25-
/* fix an issue between POSIX and C99 */
2625
#define _GNU_SOURCE
2726
#include <stdint.h> /* C99 types */
2827
#include <time.h> /* time library */
2928
#include <termios.h> /* speed_t */
29+
#include <unistd.h> /* ssize_t */
3030

3131
#include "config.h" /* library configuration options (dynamically generated) */
3232

@@ -40,7 +40,8 @@ Maintainer: Sylvain Miermont
4040
struct tref {
4141
time_t systime; /*!> system time when solution was calculated */
4242
uint32_t count_us; /*!> reference concentrator internal timestamp */
43-
struct timespec utc; /*!> reference UTC time (from GPS) */
43+
struct timespec utc; /*!> reference UTC time (from GPS/NMEA) */
44+
struct timespec gps; /*!> reference GPS time (since 01.Jan.1980) */
4445
double xtal_err; /*!> raw clock error (eg. <1 'slow' XTAL) */
4546
};
4647

@@ -62,6 +63,7 @@ enum gps_msg {
6263
UNKNOWN, /*!> neutral value */
6364
IGNORED, /*!> frame was not parsed by the system */
6465
INVALID, /*!> system try to parse frame but failed */
66+
INCOMPLETE, /*!> frame parsed was missing bytes */
6567
/* NMEA messages of interest */
6668
NMEA_RMC, /*!> Recommended Minimum data (time + date) */
6769
NMEA_GGA, /*!> Global positioning system fix data (pos + alt) */
@@ -77,8 +79,8 @@ enum gps_msg {
7779
NMEA_TXT, /*!> Text Transmission */
7880
NMEA_VTG, /*!> Course over ground and Ground speed */
7981
/* uBlox proprietary NMEA messages of interest */
80-
UBX_POSITION, /*!> */
81-
UBX_TIME /*!> */
82+
UBX_NAV_TIMEGPS, /*!> GPS Time Solution */
83+
UBX_NAV_TIMEUTC /*!> UTC Time Solution */
8284
};
8385

8486
/* -------------------------------------------------------------------------- */
@@ -87,6 +89,10 @@ enum gps_msg {
8789
#define LGW_GPS_SUCCESS 0
8890
#define LGW_GPS_ERROR -1
8991

92+
#define LGW_GPS_MIN_MSG_SIZE (8)
93+
#define LGW_GPS_UBX_SYNC_CHAR (0xB5)
94+
#define LGW_GPS_NMEA_SYNC_CHAR (0x24)
95+
9096
/* -------------------------------------------------------------------------- */
9197
/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
9298

@@ -101,6 +107,14 @@ enum gps_msg {
101107
*/
102108
int lgw_gps_enable(char* tty_path, char* gps_familly, speed_t target_brate, int* fd_ptr);
103109

110+
/**
111+
@brief Restore GPS serial configuration and close serial device
112+
113+
@param fd file descriptor on GPS tty
114+
@return success if the function was able to complete
115+
*/
116+
int lgw_gps_disable(int fd);
117+
104118
/**
105119
@brief Parse messages coming from the GPS system (or other GNSS)
106120
@@ -113,35 +127,52 @@ lgw_gps_get function.
113127
If the lgw_parse_nmea and lgw_gps_get are used in different threads, a mutex
114128
lock must be acquired before calling either function.
115129
*/
116-
enum gps_msg lgw_parse_nmea(char* serial_buff, int buff_size);
130+
enum gps_msg lgw_parse_nmea(const char* serial_buff, int buff_size);
131+
132+
/**
133+
@brief Parse Ublox proprietary messages coming from the GPS system
134+
135+
@param serial_buff pointer to the string to be parsed
136+
@param buff_size maximum string lengths for UBX parsing (incl. null char)
137+
@param msg_size number of bytes parsed as UBX message if found
138+
@return type of frame parsed
139+
140+
The RAW UBX sentences are parsed to a global set of variables shared with the
141+
lgw_gps_get function.
142+
If the lgw_parse_ubx and lgw_gps_get are used in different threads, a mutex
143+
lock must be acquired before calling either function.
144+
*/
145+
enum gps_msg lgw_parse_ubx(const char* serial_buff, size_t buff_size, size_t *msg_size);
117146

118147
/**
119148
@brief Get the GPS solution (space & time) for the concentrator
120149
121150
@param utc pointer to store UTC time, with ns precision (NULL to ignore)
151+
@param gps_time pointer to store GPS time, with ns precision (NULL to ignore)
122152
@param loc pointer to store coordinates (NULL to ignore)
123153
@param err pointer to store coordinates standard deviation (NULL to ignore)
124154
@return success if the chosen elements could be returned
125155
126-
This function read the global variables generated by the NMEA parsing function
127-
lgw_parse_nmea. It returns time and location data in a format that is
128-
exploitable by other functions in that library sub-module.
129-
If the lgw_parse_nmea and lgw_gps_get are used in different threads, a mutex
130-
lock must be acquired before calling either function.
156+
This function read the global variables generated by the NMEA/UBX parsing
157+
functions lgw_parse_nmea/lgw_parse_ubx. It returns time and location data in a
158+
format that is exploitable by other functions in that library sub-module.
159+
If the lgw_parse_nmea/lgw_parse_ubx and lgw_gps_get are used in different
160+
threads, a mutex lock must be acquired before calling either function.
131161
*/
132-
int lgw_gps_get(struct timespec* utc, struct coord_s* loc, struct coord_s* err);
162+
int lgw_gps_get(struct timespec *utc, struct timespec *gps_time, struct coord_s *loc, struct coord_s *err);
133163

134164
/**
135-
@brief Take a timestamp and UTC time and refresh reference for time conversion
136-
137-
@param ref pointer to time reference structure
138-
@param old_ref previous time reference (NULL for initial fix)
165+
@brief Get time and position information from the serial GPS last message received
139166
@param utc UTC time, with ns precision (leap seconds are ignored)
167+
@param gps_time timestamp of last time pulse from the GPS module converted to the UNIX epoch
168+
(leap seconds are ignored)
169+
@param loc location information
170+
@param err location error estimate if supported
140171
@return success if timestamp was read and time reference could be refreshed
141172
142173
Set systime to 0 in ref to trigger initial synchronization.
143174
*/
144-
int lgw_gps_sync(struct tref* ref, uint32_t count_us, struct timespec utc);
175+
int lgw_gps_sync(struct tref *ref, uint32_t count_us, struct timespec utc, struct timespec gps_time);
145176

146177
/**
147178
@brief Convert concentrator timestamp counter value to UTC time
@@ -171,6 +202,34 @@ transform an absolute UTC time into a matching internal concentrator timestamp.
171202
*/
172203
int lgw_utc2cnt(struct tref ref,struct timespec utc, uint32_t* count_us);
173204

205+
/**
206+
@brief Convert concentrator timestamp counter value to GPS time
207+
208+
@param ref time reference structure required for time conversion
209+
@param count_us internal timestamp counter of the LoRa concentrator
210+
@param gps_time pointer to store GPS time, with ns precision (leap seconds ignored)
211+
@return success if the function was able to convert timestamp to GPS time
212+
213+
This function is typically used when a packet is received to transform the
214+
internal counter-based timestamp in an absolute timestamp with an accuracy in
215+
the order of a millisecond.
216+
*/
217+
int lgw_cnt2gps(struct tref ref, uint32_t count_us, struct timespec* gps_time);
218+
219+
/**
220+
@brief Convert GPS time to concentrator timestamp counter value
221+
222+
@param ref time reference structure required for time conversion
223+
@param gps_time GPS time, with ns precision (leap seconds are ignored)
224+
@param count_us pointer to store internal timestamp counter of LoRa concentrator
225+
@return success if the function was able to convert GPS time to timestamp
226+
227+
This function is typically used when a packet must be sent at an accurate time
228+
(eg. to send a piggy-back response after receiving a packet from a node) to
229+
transform an absolute GPS time into a matching internal concentrator timestamp.
230+
*/
231+
int lgw_gps2cnt(struct tref ref, struct timespec gps_time, uint32_t* count_us);
232+
174233
#endif
175234

176235
/* --- EOF ------------------------------------------------------------------ */

libloragw/inc/loragw_hal.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,10 +359,24 @@ int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data);
359359
@param pkt_data structure containing the data and metadata for the packet to send
360360
@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
361361
362-
/!\ When sending a packet, there is a 1.5 ms delay for the analog circuitry to start and be stable (TX_START_DELAY).
363-
In 'timestamp' mode, this is transparent: the modem is started 1.5ms before the user-set timestamp value is reached, the preamble of the packet start right when the internal timestamp counter reach target value.
364-
In 'immediate' mode, the packet is emitted as soon as possible: transferring the packet (and its parameters) from the host to the concentrator takes some time, then there is the TX_START_DELAY, then the packet is emitted.
365-
In 'triggered' mode (aka PPS/GPS mode), the packet, typically a beacon, is emitted 1.5ms after a rising edge of the trigger signal. Because there is no way to anticipate the triggering event and start the analog circuitry beforehand, that delay must be taken into account in the protocol.
362+
/!\ When sending a packet, there is a delay (approx 1.5ms) for the analog
363+
circuitry to start and be stable. This delay is adjusted by the HAL depending
364+
on the board version (lgw_i_tx_start_delay_us).
365+
366+
In 'timestamp' mode, this is transparent: the modem is started
367+
lgw_i_tx_start_delay_us microseconds before the user-set timestamp value is
368+
reached, the preamble of the packet start right when the internal timestamp
369+
counter reach target value.
370+
371+
In 'immediate' mode, the packet is emitted as soon as possible: transferring the
372+
packet (and its parameters) from the host to the concentrator takes some time,
373+
then there is the lgw_i_tx_start_delay_us, then the packet is emitted.
374+
375+
In 'triggered' mode (aka PPS/GPS mode), the packet, typically a beacon, is
376+
emitted lgw_i_tx_start_delay_us microsenconds after a rising edge of the
377+
trigger signal. Because there is no way to anticipate the triggering event and
378+
start the analog circuitry beforehand, that delay must be taken into account in
379+
the protocol.
366380
*/
367381
int lgw_send(struct lgw_pkt_tx_s pkt_data);
368382

libloragw/inc/loragw_reg.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ struct lgw_reg_s {
4141
int32_t dflt; /*!< register default value */
4242
};
4343

44+
enum lgw_brd_version_e {
45+
LGW_BRD_VERSION_1_0, /*!< Gateway v1.0 (no FPGA) */
46+
LGW_BRD_VERSION_1_5, /*!< Gateway v1.5 (with FPGA) */
47+
LGW_BRD_VERSION_UNKNOWN /*!< Unknown */
48+
};
49+
4450
/* -------------------------------------------------------------------------- */
4551
/* --- INTERNAL SHARED FUNCTIONS -------------------------------------------- */
4652

@@ -408,6 +414,12 @@ int lgw_connect(bool spi_only, uint32_t tx_notch_freq);
408414
*/
409415
int lgw_disconnect(void);
410416

417+
/**
418+
@brief Get LoRa concentrator board version
419+
@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
420+
*/
421+
int lgw_brd_version(enum lgw_brd_version_e * brd_version);
422+
411423
/**
412424
@brief Use the soft-reset register to put the concentrator in initial state
413425
@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)

libloragw/readme.md

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,24 @@ use the LoRa concentrator:
5353
For an standard application, include only this module.
5454
The use of this module is detailed on the usage section.
5555

56-
/!\ When sending a packet, there is a 1.5 ms delay for the analog circuitry to
57-
start and be stable (TX_START_DELAY).
56+
/!\ When sending a packet, there is a delay (approx 1.5ms) for the analog
57+
circuitry to start and be stable. This delay is adjusted by the HAL depending
58+
on the board version (lgw_i_tx_start_delay_us).
5859

59-
In 'timestamp' mode, this is transparent: the modem is started 1.5ms before the
60-
user-set timestamp value is reached, the preamble of the packet start right when
61-
the internal timestamp counter reach target value.
60+
In 'timestamp' mode, this is transparent: the modem is started
61+
lgw_i_tx_start_delay_us microseconds before the user-set timestamp value is
62+
reached, the preamble of the packet start right when the internal timestamp
63+
counter reach target value.
6264

6365
In 'immediate' mode, the packet is emitted as soon as possible: transferring the
6466
packet (and its parameters) from the host to the concentrator takes some time,
65-
then there is the TX_START_DELAY, then the packet is emitted.
67+
then there is the lgw_i_tx_start_delay_us, then the packet is emitted.
6668

67-
In 'triggered' mode (aka PPS/GPS mode), the packet, typically a beacon, is
68-
emitted 1.5ms after a rising edge of the trigger signal. Because there is no
69-
way to anticipate the triggering event and start the analog circuitry
70-
beforehand, that delay must be taken into account in the protocol.
69+
In 'triggered' mode (aka PPS/GPS mode), the packet, typically a beacon, is
70+
emitted lgw_i_tx_start_delay_us microsenconds after a rising edge of the
71+
trigger signal. Because there is no way to anticipate the triggering event and
72+
start the analog circuitry beforehand, that delay must be taken into account in
73+
the protocol.
7174

7275
### 2.2. loragw_reg ###
7376

@@ -143,25 +146,28 @@ The internal concentrator counter is used to timestamp incoming packets and to
143146
triggers outgoing packets with a microsecond accuracy.
144147
In some cases, it might be useful to be able to transform that internal
145148
timestamp (that is independent for each concentrator running in a typical
146-
networked system) into an absolute UTC time.
149+
networked system) into an absolute GPS time.
147150

148151
In a typical implementation a GPS specific thread will be called, doing the
149152
following things after opening the serial port:
150153

151154
* blocking reads on the serial port (using system read() function)
152-
* parse NMEA sentences (using lgw_parse_nmea)
155+
* parse UBX messages (using lgw_parse_ubx) to get actual native GPS time
156+
* parse NMEA sentences (using lgw_parse_nmea) to get location and UTC time
157+
Note: the RMC sentence gives UTC time, not native GPS time.
153158

154-
And each time an RMC sentence has been received:
159+
And each time an NAV-TIMEGPS UBX message has been received:
155160

156161
* get the concentrator timestamp (using lgw_get_trigcnt, mutex needed to
157162
protect access to the concentrator)
158-
* get the UTC time contained in the NMEA sentence (using lgw_gps_get)
163+
* get the GPS time contained in the UBX message (using lgw_gps_get)
159164
* call the lgw_gps_sync function (use mutex to protect the time reference that
160165
should be a global shared variable).
161166

162167
Then, in other threads, you can simply used that continuously adjusted time
163-
reference to convert internal timestamps to UTC time (using lgw_cnt2utc) or
164-
the other way around (using lgw_utc2cnt).
168+
reference to convert internal timestamps to GPS time (using lgw_cnt2gps) or
169+
the other way around (using lgw_gps2cnt). Inernal concentrator timestamp can
170+
also be converted to/from UTC time using lgw_cnt2utc/lgw_utc2cnt functions.
165171

166172
### 2.6. loragw_radio ###
167173

@@ -352,20 +358,13 @@ sudo to run all your programs (eg. `sudo ./test_loragw_gps`).
352358

353359
In the current revision, the library only reads data from the serial port,
354360
expecting to receive NMEA frames that are generally sent by GPS receivers as
355-
soon as they are powered up.
356-
357-
The GPS receiver **MUST** send RMC NMEA sentences (starting with "$G<any
358-
character>RMC") shortly after sending a PPS pulse on to allow internal
359-
concentrator timestamps to be converted to absolute UTC time.
360-
If the GPS receiver sends a GGA sentence, the gateway 3D position will also be
361-
available.
362-
363-
The PPS pulse must be sent to the pin 22 of connector CONN400 on the Semtech
364-
FPGA-based nano-concentrator board. Ground is available on pins 2 and 12 of
365-
the same connector.
366-
The pin is loaded by an FPGA internal pull-down, and the signal level coming
367-
in the FPGA must be 3.3V.
368-
Timing is captured on the rising edge of the PPS signal.
361+
soon as they are powered up, and UBX messages which are proprietary to u-blox
362+
modules.
363+
364+
The GPS receiver **MUST** send UBX messages shortly after sending a PPS pulse
365+
on to allow internal concentrator timestamps to be converted to absolute GPS time.
366+
If the GPS receiver sends a GGA NMEA sentence, the gateway 3D position will
367+
also be available.
369368

370369
5. Usage
371370
--------

libloragw/src/loragw_fpga.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ const struct lgw_reg_s fpga_regs[LGW_FPGA_TOTALREGS] = {
9494
};
9595

9696
/* -------------------------------------------------------------------------- */
97-
/* --- PRIVATE VARIABLES ---------------------------------------------------- */
97+
/* --- INTERNAL SHARED VARIABLES -------------------------------------------- */
9898

9999
extern void *lgw_spi_target; /*! generic pointer to the SPI device */
100100
extern uint8_t lgw_spi_mux_mode; /*! current SPI mux mode used */

0 commit comments

Comments
 (0)