|
@@ -25,9 +25,6 @@
|
25
|
25
|
#include "influx.h"
|
26
|
26
|
#include "lora.h"
|
27
|
27
|
|
28
|
|
-// define LORA_TEST_TX to periodically transmit a test message
|
29
|
|
-//#define LORA_TEST_TX
|
30
|
|
-
|
31
|
28
|
//#define DEBUG_LORA_RX_HEXDUMP
|
32
|
29
|
|
33
|
30
|
#ifdef FEATURE_SML
|
|
@@ -38,13 +35,6 @@
|
38
|
35
|
#define LORA_LED_BRIGHTNESS 25 // in percent, 50% brightness is plenty for this LED
|
39
|
36
|
#endif // FEATURE_SML
|
40
|
37
|
|
41
|
|
-#ifdef LORA_TEST_TX
|
42
|
|
-// Pause between transmited packets in seconds.
|
43
|
|
-// Set to zero to only transmit a packet when pressing the user button
|
44
|
|
-// Will not exceed 1% duty cycle, even if you set a lower value.
|
45
|
|
-#define PAUSE 10
|
46
|
|
-#endif // LORA_TEST_TX
|
47
|
|
-
|
48
|
38
|
// Frequency in MHz. Keep the decimal point to designate float.
|
49
|
39
|
// Check your own rules and regulations to see what is legal where you are.
|
50
|
40
|
#define FREQUENCY 866.3 // for Europe
|
|
@@ -100,10 +90,6 @@ static struct sml_cache cache[LORA_SML_NUM_MESSAGES];
|
100
|
90
|
|
101
|
91
|
#endif // FEATURE_SML
|
102
|
92
|
|
103
|
|
-#ifdef LORA_TEST_TX
|
104
|
|
-static unsigned long test_counter = 0;
|
105
|
|
-#endif // LORA_TEST_TX
|
106
|
|
-
|
107
|
93
|
void lora_oled_init(void) {
|
108
|
94
|
heltec_setup();
|
109
|
95
|
}
|
|
@@ -126,17 +112,45 @@ double lora_get_mangled_bat(void) {
|
126
|
112
|
return *((double *)data);
|
127
|
113
|
}
|
128
|
114
|
|
|
115
|
+// adapted from "Hacker's Delight"
|
|
116
|
+static uint32_t calc_checksum(const uint8_t *data, size_t len) {
|
|
117
|
+ uint32_t c = 0xFFFFFFFF;
|
|
118
|
+ for (size_t i = 0; i < len; i++) {
|
|
119
|
+ c ^= data[i];
|
|
120
|
+ for (size_t j = 0; j < 8; j++) {
|
|
121
|
+ uint32_t mask = -(c & 1);
|
|
122
|
+ c = (c >> 1) ^ (0xEDB88320 & mask);
|
|
123
|
+ }
|
|
124
|
+ }
|
|
125
|
+
|
|
126
|
+ return ~c;
|
|
127
|
+}
|
|
128
|
+
|
129
|
129
|
static void lora_rx(void) {
|
130
|
130
|
rx_flag = true;
|
131
|
131
|
}
|
132
|
132
|
|
133
|
|
-static bool lora_tx(uint8_t *data, size_t len) {
|
|
133
|
+static bool lora_tx(enum lora_sml_type type, double value) {
|
134
|
134
|
bool tx_legal = millis() > (last_tx + minimum_pause);
|
135
|
135
|
if (!tx_legal) {
|
136
|
136
|
//debug.printf("Legal limit, wait %i sec.\n", (int)((minimum_pause - (millis() - last_tx)) / 1000) + 1);
|
137
|
137
|
return false;
|
138
|
138
|
}
|
139
|
139
|
|
|
140
|
+ struct lora_sml_msg msg;
|
|
141
|
+ msg.type = type;
|
|
142
|
+ msg.value = value;
|
|
143
|
+ msg.checksum = calc_checksum((uint8_t *)&msg, offsetof(struct lora_sml_msg, checksum));
|
|
144
|
+
|
|
145
|
+ uint8_t *data = (uint8_t *)&msg;
|
|
146
|
+ const size_t len = sizeof(struct lora_sml_msg);
|
|
147
|
+
|
|
148
|
+#ifdef LORA_XOR_KEY
|
|
149
|
+ for (size_t i = 0; i < len; i++) {
|
|
150
|
+ data[i] ^= LORA_XOR_KEY[i];
|
|
151
|
+ }
|
|
152
|
+#endif
|
|
153
|
+
|
140
|
154
|
debug.printf("TX [%d] (%lu) ", data[0], len);
|
141
|
155
|
radio.clearDio1Action();
|
142
|
156
|
|
|
@@ -174,11 +188,7 @@ static bool lora_tx(uint8_t *data, size_t len) {
|
174
|
188
|
|
175
|
189
|
#ifdef FEATURE_SML
|
176
|
190
|
static bool lora_sml_cache_send(enum lora_sml_type msg) {
|
177
|
|
- const size_t len = sizeof(double) + 1;
|
178
|
|
- uint8_t data[len];
|
179
|
|
- data[0] = (uint8_t)msg;
|
180
|
|
- memcpy(data + 1, &cache[msg].value, sizeof(double));
|
181
|
|
- return lora_tx(data, len);
|
|
191
|
+ return lora_tx(msg, cache[msg].value);
|
182
|
192
|
}
|
183
|
193
|
|
184
|
194
|
static void lora_sml_handle_cache(void) {
|
|
@@ -313,16 +323,22 @@ void lora_run(void) {
|
313
|
323
|
rx_flag = false;
|
314
|
324
|
|
315
|
325
|
bool success = true;
|
316
|
|
- uint8_t data[sizeof(double) + 1];
|
|
326
|
+ uint8_t data[sizeof(struct lora_sml_msg)];
|
317
|
327
|
RADIOLIB_CHECK(radio.readData(data, sizeof(data)));
|
318
|
328
|
if (success) {
|
|
329
|
+#ifdef LORA_XOR_KEY
|
|
330
|
+ for (size_t i = 0; i < sizeof(data); i++) {
|
|
331
|
+ data[i] ^= LORA_XOR_KEY[i];
|
|
332
|
+ }
|
|
333
|
+#endif
|
|
334
|
+
|
319
|
335
|
debug.printf("RX [%i]\n", data[0]);
|
320
|
336
|
debug.printf(" RSSI: %.2f dBm\n", radio.getRSSI());
|
321
|
337
|
debug.printf(" SNR: %.2f dB\n", radio.getSNR());
|
322
|
338
|
|
323
|
339
|
#if defined(DEBUG_LORA_RX_HEXDUMP) || (!defined(ENABLE_INFLUXDB_LOGGING))
|
324
|
340
|
for (int i = 0; i < sizeof(data); i++) {
|
325
|
|
- debug.printf("%02X", data[i]);
|
|
341
|
+ debug.printf(" %02X", data[i]);
|
326
|
342
|
if (i < (sizeof(data) - 1)) {
|
327
|
343
|
debug.print(" ");
|
328
|
344
|
} else {
|
|
@@ -331,63 +347,70 @@ void lora_run(void) {
|
331
|
347
|
}
|
332
|
348
|
#endif
|
333
|
349
|
|
334
|
|
-#ifdef ENABLE_INFLUXDB_LOGGING
|
335
|
|
- if (data[0] == LORA_SML_BAT_V) {
|
336
|
|
- float vbat = NAN;
|
337
|
|
- int percent = -1;
|
338
|
|
- memcpy(&vbat, data + 1, sizeof(float));
|
339
|
|
- memcpy(&percent, data + 1 + sizeof(float), sizeof(int));
|
340
|
|
- debug.printf(" Vbat: %.2f (%d%%)\n", vbat, percent);
|
341
|
|
-
|
342
|
|
- writeSensorDatum("environment", "sml", SENSOR_LOCATION, "vbat", vbat);
|
343
|
|
- writeSensorDatum("environment", "sml", SENSOR_LOCATION, "percent", percent);
|
|
350
|
+ struct lora_sml_msg *msg = (struct lora_sml_msg *)data;
|
|
351
|
+ uint32_t checksum = calc_checksum(data, offsetof(struct lora_sml_msg, checksum));
|
|
352
|
+ if (checksum != msg->checksum) {
|
|
353
|
+ debug.printf(" CRC: 0x%08X != 0x%08X\n", msg->checksum, checksum);
|
344
|
354
|
} else {
|
345
|
|
- double val = NAN;
|
346
|
|
- memcpy(&val, data + 1, sizeof(double));
|
347
|
|
- debug.printf(" Value: %.2f\n", val);
|
348
|
|
-
|
349
|
|
- String key;
|
350
|
|
- switch (data[0]) {
|
351
|
|
- case LORA_SML_HELLO:
|
352
|
|
- key = "hello";
|
353
|
|
- break;
|
354
|
|
-
|
355
|
|
- case LORA_SML_SUM_WH:
|
356
|
|
- key = "Sum_Wh";
|
357
|
|
- break;
|
358
|
|
-
|
359
|
|
- case LORA_SML_T1_WH:
|
360
|
|
- key = "T1_Wh";
|
361
|
|
- break;
|
362
|
|
-
|
363
|
|
- case LORA_SML_T2_WH:
|
364
|
|
- key = "T2_Wh";
|
365
|
|
- break;
|
366
|
|
-
|
367
|
|
- case LORA_SML_SUM_W:
|
368
|
|
- key = "Sum_W";
|
369
|
|
- break;
|
370
|
|
-
|
371
|
|
- case LORA_SML_L1_W:
|
372
|
|
- key = "L1_W";
|
373
|
|
- break;
|
374
|
|
-
|
375
|
|
- case LORA_SML_L2_W:
|
376
|
|
- key = "L2_W";
|
377
|
|
- break;
|
378
|
|
-
|
379
|
|
- case LORA_SML_L3_W:
|
380
|
|
- key = "L3_W";
|
381
|
|
- break;
|
382
|
|
-
|
383
|
|
- default:
|
384
|
|
- key = "unknown";
|
385
|
|
- break;
|
386
|
|
- }
|
|
355
|
+ debug.printf(" CRC: OK 0x%08X\n", checksum);
|
387
|
356
|
|
388
|
|
- writeSensorDatum("environment", "sml", SENSOR_LOCATION, key, val);
|
389
|
|
- }
|
|
357
|
+#ifdef ENABLE_INFLUXDB_LOGGING
|
|
358
|
+ if (data[0] == LORA_SML_BAT_V) {
|
|
359
|
+ // extract mangled float and int from double
|
|
360
|
+ float vbat = NAN;
|
|
361
|
+ int percent = -1;
|
|
362
|
+ memcpy(&vbat, data + offsetof(struct lora_sml_msg, value), sizeof(float));
|
|
363
|
+ memcpy(&percent, data + offsetof(struct lora_sml_msg, value) + sizeof(float), sizeof(int));
|
|
364
|
+ debug.printf(" Vbat: %.2f (%d%%)\n", vbat, percent);
|
|
365
|
+
|
|
366
|
+ writeSensorDatum("environment", "sml", SENSOR_LOCATION, "vbat", vbat);
|
|
367
|
+ writeSensorDatum("environment", "sml", SENSOR_LOCATION, "percent", percent);
|
|
368
|
+ } else {
|
|
369
|
+ debug.printf(" Value: %.2f\n", msg->value);
|
|
370
|
+
|
|
371
|
+ String key;
|
|
372
|
+ switch (data[0]) {
|
|
373
|
+ case LORA_SML_HELLO:
|
|
374
|
+ key = "hello";
|
|
375
|
+ break;
|
|
376
|
+
|
|
377
|
+ case LORA_SML_SUM_WH:
|
|
378
|
+ key = "Sum_Wh";
|
|
379
|
+ break;
|
|
380
|
+
|
|
381
|
+ case LORA_SML_T1_WH:
|
|
382
|
+ key = "T1_Wh";
|
|
383
|
+ break;
|
|
384
|
+
|
|
385
|
+ case LORA_SML_T2_WH:
|
|
386
|
+ key = "T2_Wh";
|
|
387
|
+ break;
|
|
388
|
+
|
|
389
|
+ case LORA_SML_SUM_W:
|
|
390
|
+ key = "Sum_W";
|
|
391
|
+ break;
|
|
392
|
+
|
|
393
|
+ case LORA_SML_L1_W:
|
|
394
|
+ key = "L1_W";
|
|
395
|
+ break;
|
|
396
|
+
|
|
397
|
+ case LORA_SML_L2_W:
|
|
398
|
+ key = "L2_W";
|
|
399
|
+ break;
|
|
400
|
+
|
|
401
|
+ case LORA_SML_L3_W:
|
|
402
|
+ key = "L3_W";
|
|
403
|
+ break;
|
|
404
|
+
|
|
405
|
+ default:
|
|
406
|
+ key = "unknown";
|
|
407
|
+ break;
|
|
408
|
+ }
|
|
409
|
+
|
|
410
|
+ writeSensorDatum("environment", "sml", SENSOR_LOCATION, key, msg->value);
|
|
411
|
+ }
|
390
|
412
|
#endif // ENABLE_INFLUXDB_LOGGING
|
|
413
|
+ }
|
391
|
414
|
}
|
392
|
415
|
|
393
|
416
|
success = true;
|
|
@@ -402,39 +425,21 @@ void lora_run(void) {
|
402
|
425
|
lora_sml_handle_cache();
|
403
|
426
|
#endif // FEATURE_SML
|
404
|
427
|
|
405
|
|
- bool tx_legal = millis() > last_tx + minimum_pause;
|
406
|
|
-
|
407
|
|
-#ifdef LORA_TEST_TX
|
408
|
|
- // Transmit a packet every PAUSE seconds or when the button is pressed
|
409
|
|
- if ((PAUSE && tx_legal && millis() - last_tx > (PAUSE * 1000)) || button.isSingleClick()) {
|
410
|
|
- // In case of button click, tell user to wait
|
411
|
|
- if (!tx_legal) {
|
412
|
|
- debug.printf("Legal limit, wait %i sec.\n", (int)((minimum_pause - (millis() - last_tx)) / 1000) + 1);
|
413
|
|
- return;
|
414
|
|
- }
|
415
|
|
-
|
416
|
|
- String s = String(test_counter++);
|
417
|
|
- lora_tx(s.c_str(), s.length());
|
418
|
|
- }
|
419
|
|
-#else // LORA_TEST_TX
|
420
|
428
|
if (button.isSingleClick()) {
|
421
|
429
|
// In case of button click, tell user to wait
|
|
430
|
+ bool tx_legal = millis() > last_tx + minimum_pause;
|
422
|
431
|
if (!tx_legal) {
|
423
|
432
|
debug.printf("Legal limit, wait %i sec.\n", (int)((minimum_pause - (millis() - last_tx)) / 1000) + 1);
|
424
|
433
|
return;
|
425
|
434
|
}
|
426
|
435
|
|
|
436
|
+ // send test hello message on lorarx target, or battery state on loratx target
|
427
|
437
|
#ifdef FEATURE_SML
|
428
|
438
|
lora_sml_send(LORA_SML_BAT_V, lora_get_mangled_bat(), 0);
|
429
|
439
|
#else // FEATURE_SML
|
430
|
|
- uint8_t data[sizeof(double) + 1];
|
431
|
|
- data[0] = LORA_SML_HELLO;
|
432
|
|
- double tmp = -23.42;
|
433
|
|
- memcpy(data + 1, &tmp, sizeof(double));
|
434
|
|
- lora_tx(data, sizeof(data));
|
|
440
|
+ lora_tx(LORA_SML_HELLO, -23.42);
|
435
|
441
|
#endif // FEATURE_SML
|
436
|
442
|
}
|
437
|
|
-#endif // LORA_TEST_TX
|
438
|
443
|
}
|
439
|
444
|
|
440
|
445
|
#endif // FEATURE_LORA
|