Skip to content

Commit be5c8ac

Browse files
author
Sylvain Miermont
committed
v1.7.0
- Added TX “start delay” compensation for timestamp mode (fix time window alignment issue at low SF and/or high BW) - Added adaptive narrowband/wideband TX filtering for LoRa - Added a command-line option to set CR in util_tx_test - Added notes for TX “start delay” in immediate and triggered mode /!\ warning: due to start delay compensation being implemented, TX that were previously 1.5ms late will be sent on time. At low datarate, this is not an issue. At high LoRa data rate (and FSK) you might have to adjust your timing.
1 parent 23127d9 commit be5c8ac

File tree

8 files changed

+290
-217
lines changed

8 files changed

+290
-217
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.6.0
1+
1.7.0

libloragw/inc/loragw_hal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,11 @@ int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data);
343343
@brief Schedule a packet to be send immediately or after a delay depending on tx_mode
344344
@param pkt_data structure containing the data and metadata for the packet to send
345345
@return LGW_HAL_ERROR id the operation failed, LGW_HAL_SUCCESS else
346+
347+
/!\ When sending a packet, there is a 1.5 ms delay for the analog circuitry to start and be stable (TX_START_DELAY).
348+
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.
349+
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.
350+
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.
346351
*/
347352
int lgw_send(struct lgw_pkt_tx_s pkt_data);
348353

libloragw/readme.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,22 @@ use the LoRa concentrator:
4848
For an standard application, include only this module.
4949
The use of this module is detailed on the usage section.
5050

51+
/!\ When sending a packet, there is a 1.5 ms delay for the analog circuitry to
52+
start and be stable (TX_START_DELAY).
53+
54+
In 'timestamp' mode, this is transparent: the modem is started 1.5ms before the
55+
user-set timestamp value is reached, the preamble of the packet start right when
56+
the internal timestamp counter reach target value.
57+
58+
In 'immediate' mode, the packet is emitted as soon as possible: transferring the
59+
packet (and its parameters) from the host to the concentrator takes some time,
60+
then there is the TX_START_DELAY, then the packet is emitted.
61+
62+
In 'triggered' mode (aka PPS/GPS mode), the packet, typically a beacon, is
63+
emitted 1.5ms after a rising edge of the trigger signal. Because there is no
64+
way to anticipate the triggering event and start the analog circuitry
65+
beforehand, that delay must be taken into account in the protocol.
66+
5167
### 2.2. loragw_reg ###
5268

5369
This module is used to access to the LoRa concentrator registers by name instead

libloragw/src/agc_fw.var

Lines changed: 180 additions & 180 deletions
Large diffs are not rendered by default.

libloragw/src/loragw_hal.c

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,7 +1252,7 @@ int lgw_start(void) {
12521252
wait_ms(1);
12531253

12541254
lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
1255-
if (read_val != 0x20) {
1255+
if (read_val != 0x10) {
12561256
DEBUG_PRINTF("ERROR: AGC FIRMWARE INITIALIZATION FAILURE, STATUS 0x%02X\n", (uint8_t)read_val);
12571257
return LGW_HAL_ERROR;
12581258
}
@@ -1287,6 +1287,12 @@ int lgw_start(void) {
12871287
}
12881288
#endif
12891289

1290+
/* Load Tx freq MSBs (always 3 if f > 768 for SX1257 or f > 384 for SX1255 */
1291+
lgw_reg_w(LGW_RADIO_SELECT, AGC_CMD_WAIT);
1292+
wait_ms(1);
1293+
lgw_reg_w(LGW_RADIO_SELECT, 3);
1294+
wait_ms(1);
1295+
12901296
/* Load chan_select firmware option */
12911297
lgw_reg_w(LGW_RADIO_SELECT, AGC_CMD_WAIT);
12921298
wait_ms(1);
@@ -1552,6 +1558,7 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) {
15521558
int payload_offset = 0; /* start of the payload content in the databuffer */
15531559
uint8_t pow_index = 0; /* 4-bit value to set the firmware TX power */
15541560
uint8_t target_mix_gain = 0; /* used to select the proper I/Q offset correction */
1561+
uint32_t count_trig; /* timestamp value in trigger mode corrected for TX start delay */
15551562

15561563
/* check if the concentrator is running */
15571564
if (lgw_is_started == false) {
@@ -1657,10 +1664,15 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) {
16571664
buff[2] = 0xFF & part_frac; /* Least Significant Byte */
16581665

16591666
/* metadata 3 to 6, timestamp trigger value */
1660-
buff[3] = 0xFF & (pkt_data.count_us >> 24);
1661-
buff[4] = 0xFF & (pkt_data.count_us >> 16);
1662-
buff[5] = 0xFF & (pkt_data.count_us >> 8);
1663-
buff[6] = 0xFF & pkt_data.count_us;
1667+
/* TX state machine must be triggered at T0 - TX_START_DELAY for packet to start being emitted at T0 */
1668+
if (pkt_data.tx_mode == TIMESTAMPED)
1669+
{
1670+
count_trig = pkt_data.count_us - TX_START_DELAY;
1671+
buff[3] = 0xFF & (count_trig >> 24);
1672+
buff[4] = 0xFF & (count_trig >> 16);
1673+
buff[5] = 0xFF & (count_trig >> 8);
1674+
buff[6] = 0xFF & count_trig;
1675+
}
16641676

16651677
/* parameters depending on modulation */
16661678
if (pkt_data.modulation == MOD_LORA) {
@@ -1726,11 +1738,11 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) {
17261738
buff[14] = 0;
17271739
buff[15] = 0;
17281740

1729-
/* LSB of RF frequency is now used in AGC firmware to implement large/narrow filtering in SX1257/55 */
1741+
/* MSB of RF frequency is now used in AGC firmware to implement large/narrow filtering in SX1257/55 */
17301742
if (pkt_data.bandwidth == BW_500KHZ) {
1731-
buff[2] |= 0x01; /* Enlarge filter for 500kHz BW */
1743+
buff[0] |= 0x80; /* Enlarge filter for 500kHz BW */
17321744
} else {
1733-
buff[2] &= 0xFE;
1745+
buff[0] &= 0x7F;
17341746
}
17351747

17361748
} else if (pkt_data.modulation == MOD_FSK) {
@@ -1769,8 +1781,8 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) {
17691781
++transfer_size; /* one more byte to transfer to the TX modem */
17701782
++payload_offset; /* start the payload with one more byte of offset */
17711783

1772-
/* LSB of RF frequency is now used in AGC firmware to implement large/narrow filtering in SX1257/55*/
1773-
buff[2] &= 0xFE; /* Always use narrow band for FSK (force LSB to 0) */
1784+
/* MSB of RF frequency is now used in AGC firmware to implement large/narrow filtering in SX1257/55 */
1785+
buff[0] &= 0x7F; /* Always use narrow band for FSK (force MSB to 0) */
17741786

17751787
} else {
17761788
DEBUG_MSG("ERROR: INVALID TX MODULATION..\n");

readme.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,17 @@ gateways as receivers.
5656
3. Changelog
5757
-------------
5858

59+
### v1.7.0 ###
60+
61+
* Added TX “start delay” compensation for timestamp mode (fix time window alignment issue at low SF and/or high BW)
62+
* Added adaptive narrowband/wideband TX filtering for LoRa
63+
* Added a command-line option to set CR in util_tx_test
64+
* Added notes for TX “start delay” in immediate and triggered mode
65+
66+
/!\ warning: due to start delay compensation being implemented, TX that were
67+
previously 1.5ms late will be sent on time. At low datarate, this is not an
68+
issue. At high LoRa data rate (and FSK) you might have to adjust your timing.
69+
5970
### v1.6.0 ###
6071

6172
* Fixed bug with 250kHz and 500 kHz TX filtering

util_tx_test/readme.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,30 +41,38 @@ Press Ctrl+C to stop the application before that.
4141
Use the -f option followed by a real number (decimal point and scientific
4242
'E notation' are OK) to specify the modulation central frequency.
4343

44+
Use the -b option to set LoRa modulation bandwidth in kHz (accepted values: 125,
45+
250 or 500).
46+
4447
Use the -s option to specify the Spreading Factor of LoRa modulation (values 7
4548
to 12 are valid).
4649

47-
Use the -b option to set LoRa modulation bandwidth in kHz (accepted values: 125,
48-
250 or 500).
50+
Use the -c option to specify the Coding Rate of LoRa modulation ( 1 = 4/5, 2 =
51+
4/6, 3 = 4/7, 4 = 4/8 ).
4952

5053
Use the -p option to set the concentrator TX power in dBm. Not all values are
5154
supported by hardware (typically 14 et 20 dBm are supported, other values might
5255
not give expected power). Check with a RF power meter before connecting any
5356
sensitive equipment.
5457

58+
Use the -r option to set LoRa preamble size. A minimum preamble length of 6
59+
symbols is enforced.
60+
61+
Use the -z option to set the payload size in bytes.
62+
5563
Use the -t option to specify the number of milliseconds of pause between
5664
packets. Using zero will result in a quasi-continuous emission.
5765

58-
Use the -x option to specify how many packets should be sent.
66+
Use the -x option to specify how many packets should be sent. The value -1 cause
67+
the program to send packet indefinitely, until stopped (using Ctrl-C).
5968

6069
Use the -i option to invert the LoRa modulation polarity.
6170

62-
The packets are 20 bytes long, and protected by the smallest supported ECC.
63-
6471
The payload content is:
6572
[T][E][S][T][packet counter MSB][packet counter LSB] followed by ASCII padding.
66-
All LoRa data is whitened, so the padding has no influence whatsoever on the
67-
packet error rate.
73+
74+
All LoRa data is scrambled and whitened, so the padding has no influence
75+
whatsoever on the packet error rate.
6876

6977
4. License
7078
-----------

util_tx_test/src/util_tx_test.c

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,18 @@ static void sig_handler(int sigio) {
7979
/* describe command line options */
8080
void usage(void) {
8181
printf("*** Library version information ***\n%s\n\n", lgw_version_info());
82-
printf( "Available options:\n");
83-
printf( " -h print this help\n");
84-
printf( " -f <float> target frequency in MHz\n");
85-
printf( " -s <uint> Spreading Factor\n");
86-
printf( " -b <uint> Modulation bandwidth in kHz\n");
87-
printf( " -p <int> RF power (dBm)\n");
88-
printf( " -r <uint> LoRa preamble length (symbols)\n");
89-
printf( " -z <uint> payload size (bytes)\n");
90-
printf( " -t <uint> pause between packets (ms)\n");
91-
printf( " -x <int> numbers of times the sequence is repeated (-1 for continuous)\n");
92-
printf( " -i send packet using inverted modulation polarity \n");
82+
printf("Available options:\n");
83+
printf(" -h print this help\n");
84+
printf(" -f <float> target frequency in MHz\n");
85+
printf(" -b <uint> LoRa bandwidth in kHz [125, 250, 500]\n");
86+
printf(" -s <uint> LoRa Spreading Factor [7-12]\n");
87+
printf(" -c <uint> LoRa Coding Rate [1-4]\n");
88+
printf(" -p <int> RF power (dBm)\n");
89+
printf(" -r <uint> LoRa preamble length (symbols)\n");
90+
printf(" -z <uint> payload size (bytes, <256)\n");
91+
printf(" -t <uint> pause between packets (ms)\n");
92+
printf(" -x <int> nb of times the sequence is repeated (-1 loop until stopped)\n");
93+
printf(" -i send packet using inverted modulation polarity\n");
9394
}
9495

9596
/* -------------------------------------------------------------------------- */
@@ -109,6 +110,7 @@ int main(int argc, char **argv)
109110
/* application parameters */
110111
uint32_t f_target = lowfreq[RF_CHAIN]/2 + upfreq[RF_CHAIN]/2; /* target frequency */
111112
int sf = 10; /* SF10 by default */
113+
int cr = 1; /* CR1 aka 4/5 by default */
112114
int bw = 125; /* 125kHz bandwidth by default */
113115
int pow = 14; /* 14 dBm by default */
114116
int preamb = 8; /* 8 symbol preamble by default */
@@ -127,7 +129,7 @@ int main(int argc, char **argv)
127129
uint16_t cycle_count = 0;
128130

129131
/* parse command line options */
130-
while ((i = getopt (argc, argv, "hf:s:b:p:r:z:t:x:i")) != -1) {
132+
while ((i = getopt (argc, argv, "hf:b:s:c:p:r:z:t:x:i")) != -1) {
131133
switch (i) {
132134
case 'h':
133135
usage();
@@ -145,6 +147,17 @@ int main(int argc, char **argv)
145147
}
146148
break;
147149

150+
case 'b': /* -b <int> Modulation bandwidth in kHz */
151+
i = sscanf(optarg, "%i", &xi);
152+
if ((i != 1) || ((xi != 125)&&(xi != 250)&&(xi != 500))) {
153+
MSG("ERROR: invalid LoRa bandwidth\n");
154+
usage();
155+
return EXIT_FAILURE;
156+
} else {
157+
bw = xi;
158+
}
159+
break;
160+
148161
case 's': /* -s <int> Spreading Factor */
149162
i = sscanf(optarg, "%i", &xi);
150163
if ((i != 1) || (xi < 7) || (xi > 12)) {
@@ -156,14 +169,14 @@ int main(int argc, char **argv)
156169
}
157170
break;
158171

159-
case 'b': /* -b <int> Modulation bandwidth in kHz */
172+
case 'c': /* -c <int> Coding Rate */
160173
i = sscanf(optarg, "%i", &xi);
161-
if ((i != 1) || ((xi != 125)&&(xi != 250)&&(xi != 500))) {
162-
MSG("ERROR: invalid LoRa bandwidth\n");
174+
if ((i != 1) || (xi < 1) || (xi > 4)) {
175+
MSG("ERROR: invalid coding rate\n");
163176
usage();
164177
return EXIT_FAILURE;
165178
} else {
166-
bw = xi;
179+
cr = xi;
167180
}
168181
break;
169182

@@ -240,7 +253,7 @@ int main(int argc, char **argv)
240253
MSG("ERROR: frequency out of authorized band (accounting for modulation bandwidth)\n");
241254
return EXIT_FAILURE;
242255
}
243-
printf("Sending %i packets on %u Hz (BW %i kHz, SF %i, %i bytes payload, %i symbols preamble) at %i dBm, with %i ms between each\n", repeat, f_target, bw, sf, pl_size, preamb, pow, delay);
256+
printf("Sending %i packets on %u Hz (BW %i kHz, SF %i, CR %i, %i bytes payload, %i symbols preamble) at %i dBm, with %i ms between each\n", repeat, f_target, bw, sf, cr, pl_size, preamb, pow, delay);
244257

245258
/* configure signal handling */
246259
sigemptyset(&sigact.sa_mask);
@@ -286,11 +299,19 @@ int main(int argc, char **argv)
286299
MSG("ERROR: invalid 'sf' variable\n");
287300
return EXIT_FAILURE;
288301
}
289-
txpkt.coderate = CR_LORA_4_5;
302+
switch (cr) {
303+
case 1: txpkt.coderate = CR_LORA_4_5; break;
304+
case 2: txpkt.coderate = CR_LORA_4_6; break;
305+
case 3: txpkt.coderate = CR_LORA_4_7; break;
306+
case 4: txpkt.coderate = CR_LORA_4_8; break;
307+
default:
308+
MSG("ERROR: invalid 'cr' variable\n");
309+
return EXIT_FAILURE;
310+
}
290311
txpkt.invert_pol = invert;
291312
txpkt.preamble = preamb;
292313
txpkt.size = pl_size;
293-
strcpy((char *)txpkt.payload, "TEST**abcdefghijklmnopqrstuvwxyz0123456789" ); /* abc.. is for padding */
314+
strcpy((char *)txpkt.payload, "TEST**abcdefghijklmnopqrstuvwxyz#0123456789#ABCDEFGHIJKLMNOPQRSTUVWXYZ#0123456789#abcdefghijklmnopqrstuvwxyz#0123456789#ABCDEFGHIJKLMNOPQRSTUVWXYZ#0123456789#abcdefghijklmnopqrstuvwxyz#0123456789#ABCDEFGHIJKLMNOPQRSTUVWXYZ#0123456789#abcdefghijklmnopqrs#" ); /* abc.. is for padding */
294315

295316
/* main loop */
296317
cycle_count = 0;

0 commit comments

Comments
 (0)