2018-03-18 19:45:17 +01:00
|
|
|
// Basic Config
|
2019-03-14 19:52:10 +01:00
|
|
|
#if (HAS_LORA)
|
2018-09-20 17:33:52 +02:00
|
|
|
#include "lorawan.h"
|
2019-03-11 18:09:01 +01:00
|
|
|
#endif
|
2018-04-04 01:26:05 +02:00
|
|
|
|
2018-03-18 19:45:17 +01:00
|
|
|
// Local logging Tag
|
2018-06-02 18:28:01 +02:00
|
|
|
static const char TAG[] = "lora";
|
2018-03-18 19:45:17 +01:00
|
|
|
|
2019-03-14 19:52:10 +01:00
|
|
|
#if (HAS_LORA)
|
2018-11-03 20:44:54 +01:00
|
|
|
|
2019-02-16 15:02:07 +01:00
|
|
|
#if CLOCK_ERROR_PROCENTAGE > 7
|
2019-02-12 23:57:05 +01:00
|
|
|
#warning CLOCK_ERROR_PROCENTAGE value in lmic_config.h is too high; values > 7 will cause side effects
|
|
|
|
#endif
|
|
|
|
|
2019-03-31 15:47:19 +02:00
|
|
|
#if (TIME_SYNC_LORAWAN)
|
|
|
|
#ifndef LMIC_ENABLE_DeviceTimeReq
|
|
|
|
#define LMIC_ENABLE_DeviceTimeReq 1
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2018-10-03 16:24:45 +02:00
|
|
|
osjob_t sendjob;
|
|
|
|
QueueHandle_t LoraSendQueue;
|
2019-08-02 21:53:05 +02:00
|
|
|
TaskHandle_t lmicTask = NULL;
|
2018-10-03 16:24:45 +02:00
|
|
|
|
2018-11-27 10:10:20 +01:00
|
|
|
class MyHalConfig_t : public Arduino_LMIC::HalConfiguration_t {
|
2018-11-26 22:49:45 +01:00
|
|
|
|
|
|
|
public:
|
2018-11-27 10:10:20 +01:00
|
|
|
MyHalConfig_t(){};
|
2018-11-26 22:49:45 +01:00
|
|
|
virtual void begin(void) override {
|
|
|
|
SPI.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-11-27 10:10:20 +01:00
|
|
|
MyHalConfig_t myHalConfig{};
|
2018-11-26 22:49:45 +01:00
|
|
|
|
2018-11-27 10:10:20 +01:00
|
|
|
// LMIC pin mapping
|
2019-02-19 18:37:35 +01:00
|
|
|
|
2018-11-26 23:56:25 +01:00
|
|
|
const lmic_pinmap lmic_pins = {
|
|
|
|
.nss = LORA_CS,
|
|
|
|
.rxtx = LMIC_UNUSED_PIN,
|
2019-02-19 18:37:35 +01:00
|
|
|
.rst = LORA_RST == NOT_A_PIN ? LMIC_UNUSED_PIN : LORA_RST,
|
|
|
|
.dio = {LORA_IRQ, LORA_IO1,
|
|
|
|
LORA_IO2 == NOT_A_PIN ? LMIC_UNUSED_PIN : LORA_IO2},
|
2018-10-21 19:00:20 +02:00
|
|
|
// optional: set polarity of rxtx pin.
|
2018-11-26 22:49:45 +01:00
|
|
|
.rxtx_rx_active = 0,
|
2018-10-21 19:00:20 +02:00
|
|
|
// optional: set RSSI cal for listen-before-talk
|
|
|
|
// this value is in dB, and is added to RSSI
|
|
|
|
// measured prior to decision.
|
|
|
|
// Must include noise guardband! Ignored in US,
|
|
|
|
// EU, IN, other markets where LBT is not required.
|
2018-11-26 22:49:45 +01:00
|
|
|
.rssi_cal = 0,
|
2018-10-21 19:00:20 +02:00
|
|
|
// optional: override LMIC_SPI_FREQ if non-zero
|
2018-11-26 22:49:45 +01:00
|
|
|
.spi_freq = 0,
|
2018-11-26 23:56:25 +01:00
|
|
|
.pConfig = &myHalConfig};
|
2018-07-23 13:20:06 +02:00
|
|
|
|
2018-03-18 19:45:17 +01:00
|
|
|
// DevEUI generator using devices's MAC address
|
|
|
|
void gen_lora_deveui(uint8_t *pdeveui) {
|
2018-06-12 12:52:48 +02:00
|
|
|
uint8_t *p = pdeveui, dmac[6];
|
|
|
|
int i = 0;
|
|
|
|
esp_efuse_mac_get_default(dmac);
|
|
|
|
// deveui is LSB, we reverse it so TTN DEVEUI display
|
|
|
|
// will remain the same as MAC address
|
|
|
|
// MAC is 6 bytes, devEUI 8, set first 2 ones
|
|
|
|
// with an arbitrary value
|
|
|
|
*p++ = 0xFF;
|
|
|
|
*p++ = 0xFE;
|
|
|
|
// Then next 6 bytes are mac address reversed
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
*p++ = dmac[5 - i];
|
|
|
|
}
|
2018-03-18 19:45:17 +01:00
|
|
|
}
|
|
|
|
|
2018-09-20 17:33:52 +02:00
|
|
|
/* new version, does it with well formed mac according IEEE spec, but is
|
|
|
|
breaking change
|
2018-09-19 19:34:02 +02:00
|
|
|
// DevEUI generator using devices's MAC address
|
|
|
|
void gen_lora_deveui(uint8_t *pdeveui) {
|
|
|
|
uint8_t *p = pdeveui, dmac[6];
|
|
|
|
ESP_ERROR_CHECK(esp_efuse_mac_get_default(dmac));
|
2018-09-20 13:23:22 +02:00
|
|
|
// deveui is LSB, we reverse it so TTN DEVEUI display
|
2018-09-20 12:53:58 +02:00
|
|
|
// will remain the same as MAC address
|
|
|
|
// MAC is 6 bytes, devEUI 8, set middle 2 ones
|
|
|
|
// to an arbitrary value
|
2018-09-19 19:36:41 +02:00
|
|
|
*p++ = dmac[5];
|
|
|
|
*p++ = dmac[4];
|
|
|
|
*p++ = dmac[3];
|
2018-09-19 19:34:02 +02:00
|
|
|
*p++ = 0xfe;
|
2018-09-27 22:04:51 +02:00
|
|
|
*p++ = 0xff;
|
2018-09-19 19:36:41 +02:00
|
|
|
*p++ = dmac[2];
|
|
|
|
*p++ = dmac[1];
|
|
|
|
*p++ = dmac[0];
|
2018-09-19 19:34:02 +02:00
|
|
|
}
|
2018-09-20 17:33:52 +02:00
|
|
|
*/
|
2018-09-19 19:34:02 +02:00
|
|
|
|
2018-03-21 22:32:59 +01:00
|
|
|
// Function to do a byte swap in a byte array
|
2018-06-12 12:52:48 +02:00
|
|
|
void RevBytes(unsigned char *b, size_t c) {
|
2018-03-21 22:32:59 +01:00
|
|
|
u1_t i;
|
2018-06-12 12:52:48 +02:00
|
|
|
for (i = 0; i < c / 2; i++) {
|
|
|
|
unsigned char t = b[i];
|
2018-03-21 22:32:59 +01:00
|
|
|
b[i] = b[c - 1 - i];
|
2018-06-12 12:52:48 +02:00
|
|
|
b[c - 1 - i] = t;
|
|
|
|
}
|
2018-03-21 22:32:59 +01:00
|
|
|
}
|
|
|
|
|
2018-07-15 14:28:05 +02:00
|
|
|
// LMIC callback functions
|
|
|
|
void os_getDevKey(u1_t *buf) { memcpy(buf, APPKEY, 16); }
|
|
|
|
|
|
|
|
void os_getArtEui(u1_t *buf) {
|
|
|
|
memcpy(buf, APPEUI, 8);
|
|
|
|
RevBytes(buf, 8); // TTN requires it in LSB First order, so we swap bytes
|
|
|
|
}
|
|
|
|
|
|
|
|
void os_getDevEui(u1_t *buf) {
|
|
|
|
int i = 0, k = 0;
|
|
|
|
memcpy(buf, DEVEUI, 8); // get fixed DEVEUI from loraconf.h
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
k += buf[i];
|
|
|
|
}
|
|
|
|
if (k) {
|
|
|
|
RevBytes(buf, 8); // use fixed DEVEUI and swap bytes to LSB format
|
|
|
|
} else {
|
|
|
|
gen_lora_deveui(buf); // generate DEVEUI from device's MAC
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get MCP 24AA02E64 hardware DEVEUI (override default settings if found)
|
|
|
|
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
|
|
|
get_hard_deveui(buf);
|
|
|
|
RevBytes(buf, 8); // swap bytes to LSB format
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-04-04 01:26:05 +02:00
|
|
|
void get_hard_deveui(uint8_t *pdeveui) {
|
2018-06-12 12:52:48 +02:00
|
|
|
// read DEVEUI from Microchip 24AA02E64 2Kb serial eeprom if present
|
2018-04-04 01:26:05 +02:00
|
|
|
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
2018-09-20 13:23:22 +02:00
|
|
|
|
2018-09-20 17:33:52 +02:00
|
|
|
uint8_t i2c_ret;
|
|
|
|
|
2018-06-12 12:52:48 +02:00
|
|
|
// Init this just in case, no more to 100KHz
|
2018-10-22 14:06:47 +02:00
|
|
|
Wire.begin(MY_OLED_SDA, MY_OLED_SCL, 100000);
|
2018-06-12 12:52:48 +02:00
|
|
|
Wire.beginTransmission(MCP_24AA02E64_I2C_ADDRESS);
|
|
|
|
Wire.write(MCP_24AA02E64_MAC_ADDRESS);
|
2018-09-20 17:33:52 +02:00
|
|
|
i2c_ret = Wire.endTransmission();
|
2018-09-20 13:23:22 +02:00
|
|
|
|
|
|
|
// check if device was seen on i2c bus
|
2018-09-20 19:36:32 +02:00
|
|
|
if (i2c_ret == 0) {
|
2018-06-12 12:52:48 +02:00
|
|
|
char deveui[32] = "";
|
|
|
|
uint8_t data;
|
2018-09-20 13:23:22 +02:00
|
|
|
|
2018-04-04 01:26:05 +02:00
|
|
|
Wire.beginTransmission(MCP_24AA02E64_I2C_ADDRESS);
|
2018-06-12 12:52:48 +02:00
|
|
|
Wire.write(MCP_24AA02E64_MAC_ADDRESS);
|
2018-09-20 13:23:22 +02:00
|
|
|
Wire.endTransmission();
|
|
|
|
|
2018-09-20 17:33:52 +02:00
|
|
|
Wire.requestFrom(MCP_24AA02E64_I2C_ADDRESS, 8);
|
|
|
|
while (Wire.available()) {
|
|
|
|
data = Wire.read();
|
|
|
|
sprintf(deveui + strlen(deveui), "%02X ", data);
|
|
|
|
*pdeveui++ = data;
|
2018-06-10 21:46:58 +02:00
|
|
|
}
|
2018-09-20 17:33:52 +02:00
|
|
|
ESP_LOGI(TAG, "Serial EEPROM found, read DEVEUI %s", deveui);
|
|
|
|
} else
|
|
|
|
ESP_LOGI(TAG, "Could not read DEVEUI from serial EEPROM");
|
2018-09-20 13:23:22 +02:00
|
|
|
|
2018-06-12 12:52:48 +02:00
|
|
|
// Set back to 400KHz to speed up OLED
|
|
|
|
Wire.setClock(400000);
|
|
|
|
#endif // MCP 24AA02E64
|
2018-04-04 01:26:05 +02:00
|
|
|
}
|
|
|
|
|
2019-03-09 00:53:11 +01:00
|
|
|
#if (VERBOSE)
|
2018-03-18 19:45:17 +01:00
|
|
|
|
|
|
|
// Display OTAA keys
|
2018-08-03 23:50:04 +02:00
|
|
|
void showLoraKeys(void) {
|
2018-06-12 12:52:48 +02:00
|
|
|
// LMIC may not have used callback to fill
|
|
|
|
// all EUI buffer so we do it here to a temp
|
|
|
|
// buffer to be able to display them
|
|
|
|
uint8_t buf[32];
|
|
|
|
os_getDevEui((u1_t *)buf);
|
|
|
|
printKey("DevEUI", buf, 8, true);
|
|
|
|
os_getArtEui((u1_t *)buf);
|
|
|
|
printKey("AppEUI", buf, 8, true);
|
|
|
|
os_getDevKey((u1_t *)buf);
|
|
|
|
printKey("AppKey", buf, 16, false);
|
2018-03-18 19:45:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif // VERBOSE
|
|
|
|
|
2018-06-12 12:52:48 +02:00
|
|
|
void onEvent(ev_t ev) {
|
|
|
|
char buff[24] = "";
|
2019-03-09 15:25:44 +01:00
|
|
|
|
2018-06-12 12:52:48 +02:00
|
|
|
switch (ev) {
|
2018-10-21 19:00:20 +02:00
|
|
|
|
2018-06-12 12:52:48 +02:00
|
|
|
case EV_SCAN_TIMEOUT:
|
2019-03-23 11:01:49 +01:00
|
|
|
strcpy_P(buff, PSTR("SCAN TIMEOUT"));
|
2018-06-12 12:52:48 +02:00
|
|
|
break;
|
2018-10-21 19:00:20 +02:00
|
|
|
|
2018-06-12 12:52:48 +02:00
|
|
|
case EV_BEACON_FOUND:
|
2019-03-23 11:01:49 +01:00
|
|
|
strcpy_P(buff, PSTR("BEACON FOUND"));
|
2018-06-12 12:52:48 +02:00
|
|
|
break;
|
2018-10-21 19:00:20 +02:00
|
|
|
|
2018-06-12 12:52:48 +02:00
|
|
|
case EV_BEACON_MISSED:
|
2019-03-23 11:01:49 +01:00
|
|
|
strcpy_P(buff, PSTR("BEACON MISSED"));
|
2018-06-12 12:52:48 +02:00
|
|
|
break;
|
2018-10-21 19:00:20 +02:00
|
|
|
|
2018-06-12 12:52:48 +02:00
|
|
|
case EV_BEACON_TRACKED:
|
2019-03-23 11:01:49 +01:00
|
|
|
strcpy_P(buff, PSTR("BEACON TRACKED"));
|
2018-06-12 12:52:48 +02:00
|
|
|
break;
|
2018-10-21 19:00:20 +02:00
|
|
|
|
2018-06-12 12:52:48 +02:00
|
|
|
case EV_JOINING:
|
|
|
|
strcpy_P(buff, PSTR("JOINING"));
|
|
|
|
break;
|
2018-06-10 21:03:16 +02:00
|
|
|
|
2018-06-12 12:52:48 +02:00
|
|
|
case EV_JOINED:
|
|
|
|
strcpy_P(buff, PSTR("JOINED"));
|
2018-07-14 20:07:33 +02:00
|
|
|
sprintf(display_line6, " "); // clear previous lmic status
|
2018-08-07 21:10:34 +02:00
|
|
|
// set data rate adaptation according to saved setting
|
2018-06-12 12:52:48 +02:00
|
|
|
LMIC_setAdrMode(cfg.adrmode);
|
2018-08-10 16:33:47 +02:00
|
|
|
// set cyclic lmic link check to off if no ADR because is not supported by
|
|
|
|
// ttn (but enabled by lmic after join)
|
|
|
|
LMIC_setLinkCheckMode(cfg.adrmode);
|
2018-06-12 12:52:48 +02:00
|
|
|
// Set data rate and transmit power (note: txpower seems to be ignored by
|
|
|
|
// the library)
|
|
|
|
switch_lora(cfg.lorasf, cfg.txpower);
|
2018-10-03 16:24:45 +02:00
|
|
|
// kickoff first send job
|
|
|
|
os_setCallback(&sendjob, lora_send);
|
2018-06-12 12:52:48 +02:00
|
|
|
// show effective LoRa parameters after join
|
2019-04-13 13:59:30 +02:00
|
|
|
ESP_LOGI(TAG, "DEVaddr=%08X", LMIC.devaddr);
|
2018-06-12 12:52:48 +02:00
|
|
|
break;
|
|
|
|
|
2019-03-23 11:01:49 +01:00
|
|
|
case EV_RFU1:
|
|
|
|
strcpy_P(buff, PSTR("RFU1"));
|
|
|
|
break;
|
|
|
|
|
2018-10-21 19:00:20 +02:00
|
|
|
case EV_JOIN_FAILED:
|
2019-03-23 11:01:49 +01:00
|
|
|
strcpy_P(buff, PSTR("JOIN FAILED"));
|
2018-10-21 19:00:20 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case EV_REJOIN_FAILED:
|
2019-03-23 11:01:49 +01:00
|
|
|
strcpy_P(buff, PSTR("REJOIN FAILED"));
|
2018-10-21 19:00:20 +02:00
|
|
|
break;
|
2018-06-12 12:52:48 +02:00
|
|
|
|
2018-10-21 19:00:20 +02:00
|
|
|
case EV_TXCOMPLETE:
|
2019-03-06 23:21:46 +01:00
|
|
|
|
2019-03-31 15:56:56 +02:00
|
|
|
#if (TIME_SYNC_LORASERVER)
|
2019-03-09 22:08:57 +01:00
|
|
|
// if last packet sent was a timesync request, store TX timestamp
|
2019-04-07 14:06:47 +02:00
|
|
|
if (LMIC.pendTxPort == TIMEPORT)
|
2019-03-14 19:52:10 +01:00
|
|
|
store_time_sync_req(osticks2ms(LMIC.txend)); // milliseconds
|
2019-03-06 23:21:46 +01:00
|
|
|
#endif
|
|
|
|
|
2019-03-23 11:01:49 +01:00
|
|
|
strcpy_P(buff, (LMIC.txrxFlags & TXRX_ACK) ? PSTR("RECEIVED ACK")
|
|
|
|
: PSTR("TX COMPLETE"));
|
2018-07-14 20:07:33 +02:00
|
|
|
sprintf(display_line6, " "); // clear previous lmic status
|
2018-06-12 12:52:48 +02:00
|
|
|
|
2019-03-16 21:01:43 +01:00
|
|
|
if (LMIC.dataLen) { // did we receive payload data -> display info
|
2019-03-13 20:20:19 +01:00
|
|
|
ESP_LOGI(TAG, "Received %d bytes of payload, RSSI %d SNR %d",
|
2018-11-25 22:16:14 +01:00
|
|
|
LMIC.dataLen, LMIC.rssi, LMIC.snr / 4);
|
2019-03-13 20:20:19 +01:00
|
|
|
sprintf(display_line6, "RSSI %d SNR %d", LMIC.rssi, LMIC.snr / 4);
|
2018-06-12 12:52:48 +02:00
|
|
|
|
2019-03-12 23:50:02 +01:00
|
|
|
if (LMIC.txrxFlags & TXRX_PORT) { // FPort -> use to switch
|
2019-04-06 16:43:12 +02:00
|
|
|
|
2019-03-12 23:50:02 +01:00
|
|
|
switch (LMIC.frame[LMIC.dataBeg - 1]) {
|
2019-04-06 16:43:12 +02:00
|
|
|
|
2019-03-12 23:50:02 +01:00
|
|
|
case RCMDPORT: // opcode -> call rcommand interpreter
|
|
|
|
rcommand(LMIC.frame + LMIC.dataBeg, LMIC.dataLen);
|
|
|
|
break;
|
2019-04-06 16:43:12 +02:00
|
|
|
|
2019-04-07 14:06:47 +02:00
|
|
|
default:
|
2019-04-06 16:43:12 +02:00
|
|
|
|
|
|
|
#if (TIME_SYNC_LORASERVER)
|
2019-04-07 14:06:47 +02:00
|
|
|
// timesync answer -> call timesync processor
|
2019-04-06 16:43:12 +02:00
|
|
|
if ((LMIC.frame[LMIC.dataBeg - 1] >= TIMEANSWERPORT_MIN) &&
|
|
|
|
(LMIC.frame[LMIC.dataBeg - 1] <= TIMEANSWERPORT_MAX)) {
|
|
|
|
recv_timesync_ans(LMIC.frame[LMIC.dataBeg - 1],
|
|
|
|
LMIC.frame + LMIC.dataBeg, LMIC.dataLen);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
2019-04-07 14:06:47 +02:00
|
|
|
// unknown port -> display info
|
2019-03-12 23:50:02 +01:00
|
|
|
ESP_LOGI(TAG, "Received data on unsupported port #%d",
|
|
|
|
LMIC.frame[LMIC.dataBeg - 1]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-06-10 21:46:58 +02:00
|
|
|
}
|
2018-06-12 12:52:48 +02:00
|
|
|
break;
|
|
|
|
|
2018-10-21 19:00:20 +02:00
|
|
|
case EV_LOST_TSYNC:
|
2019-03-23 11:01:49 +01:00
|
|
|
strcpy_P(buff, PSTR("LOST TSYNC"));
|
2018-10-21 19:00:20 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case EV_RESET:
|
|
|
|
strcpy_P(buff, PSTR("RESET"));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EV_RXCOMPLETE:
|
|
|
|
// data received in ping slot
|
2019-03-23 11:01:49 +01:00
|
|
|
strcpy_P(buff, PSTR("RX COMPLETE"));
|
2018-10-21 19:00:20 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case EV_LINK_DEAD:
|
2019-03-23 11:01:49 +01:00
|
|
|
strcpy_P(buff, PSTR("LINK DEAD"));
|
2018-10-21 19:00:20 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case EV_LINK_ALIVE:
|
2018-11-25 20:56:14 +01:00
|
|
|
strcpy_P(buff, PSTR("LINK_ALIVE"));
|
2018-10-21 19:00:20 +02:00
|
|
|
break;
|
|
|
|
|
2019-03-23 11:01:49 +01:00
|
|
|
case EV_SCAN_FOUND:
|
|
|
|
strcpy_P(buff, PSTR("SCAN FOUND"));
|
|
|
|
break;
|
|
|
|
|
2018-10-21 19:00:20 +02:00
|
|
|
case EV_TXSTART:
|
2019-07-22 22:00:39 +02:00
|
|
|
if (!(LMIC.opmode & OP_JOINING)) {
|
2019-04-07 14:06:47 +02:00
|
|
|
#if (TIME_SYNC_LORASERVER)
|
|
|
|
// if last packet sent was a timesync request, store TX time
|
2019-04-07 16:13:04 +02:00
|
|
|
if (LMIC.pendTxPort == TIMEPORT)
|
|
|
|
strcpy_P(buff, PSTR("TX TIMESYNC"));
|
2019-04-07 14:06:47 +02:00
|
|
|
else
|
|
|
|
#endif
|
|
|
|
strcpy_P(buff, PSTR("TX START"));
|
2019-07-22 22:00:39 +02:00
|
|
|
}
|
2018-10-21 19:00:20 +02:00
|
|
|
break;
|
|
|
|
|
2019-03-23 11:01:49 +01:00
|
|
|
case EV_TXCANCELED:
|
|
|
|
strcpy_P(buff, PSTR("TX CANCELLED"));
|
2018-10-22 19:42:27 +02:00
|
|
|
break;
|
|
|
|
|
2019-03-23 11:01:49 +01:00
|
|
|
case EV_RXSTART:
|
|
|
|
strcpy_P(buff, PSTR("RX START"));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EV_JOIN_TXCOMPLETE:
|
2019-03-24 16:23:34 +01:00
|
|
|
strcpy_P(buff, PSTR("JOIN WAIT"));
|
2018-10-22 19:42:27 +02:00
|
|
|
break;
|
2018-10-21 19:00:20 +02:00
|
|
|
|
2018-06-12 12:52:48 +02:00
|
|
|
default:
|
2019-03-23 11:01:49 +01:00
|
|
|
sprintf_P(buff, PSTR("LMIC EV %d"), ev);
|
2018-06-12 12:52:48 +02:00
|
|
|
break;
|
|
|
|
}
|
2018-06-10 21:46:58 +02:00
|
|
|
|
2018-06-12 12:52:48 +02:00
|
|
|
// Log & Display if asked
|
|
|
|
if (*buff) {
|
2019-03-23 11:01:49 +01:00
|
|
|
ESP_LOGI(TAG, "%s", buff);
|
2018-07-14 20:07:33 +02:00
|
|
|
sprintf(display_line7, buff);
|
2018-06-12 12:52:48 +02:00
|
|
|
}
|
2018-10-21 19:00:20 +02:00
|
|
|
}
|
2018-07-14 20:07:33 +02:00
|
|
|
|
2018-08-05 12:16:54 +02:00
|
|
|
// helper function to assign LoRa datarates to numeric spreadfactor values
|
|
|
|
void switch_lora(uint8_t sf, uint8_t tx) {
|
|
|
|
if (tx > 20)
|
|
|
|
return;
|
|
|
|
cfg.txpower = tx;
|
|
|
|
switch (sf) {
|
|
|
|
case 7:
|
|
|
|
LMIC_setDrTxpow(DR_SF7, tx);
|
|
|
|
cfg.lorasf = sf;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
LMIC_setDrTxpow(DR_SF8, tx);
|
|
|
|
cfg.lorasf = sf;
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
LMIC_setDrTxpow(DR_SF9, tx);
|
|
|
|
cfg.lorasf = sf;
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
LMIC_setDrTxpow(DR_SF10, tx);
|
|
|
|
cfg.lorasf = sf;
|
|
|
|
break;
|
|
|
|
case 11:
|
2018-10-22 19:38:26 +02:00
|
|
|
#if defined(CFG_us915)
|
|
|
|
LMIC_setDrTxpow(DR_SF11CR, tx);
|
2018-08-05 12:16:54 +02:00
|
|
|
cfg.lorasf = sf;
|
|
|
|
break;
|
2018-10-22 19:38:26 +02:00
|
|
|
#else
|
|
|
|
LMIC_setDrTxpow(DR_SF11, tx);
|
2018-08-05 12:16:54 +02:00
|
|
|
cfg.lorasf = sf;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case 12:
|
2018-10-22 19:38:26 +02:00
|
|
|
#if defined(CFG_us915)
|
|
|
|
LMIC_setDrTxpow(DR_SF12CR, tx);
|
2018-08-05 12:16:54 +02:00
|
|
|
cfg.lorasf = sf;
|
|
|
|
break;
|
2018-10-22 19:38:26 +02:00
|
|
|
#else
|
|
|
|
LMIC_setDrTxpow(DR_SF12, tx);
|
2018-08-05 12:16:54 +02:00
|
|
|
cfg.lorasf = sf;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-03 16:24:45 +02:00
|
|
|
void lora_send(osjob_t *job) {
|
|
|
|
MessageBuffer_t SendBuffer;
|
|
|
|
// Check if there is a pending TX/RX job running, if yes don't eat data
|
|
|
|
// since it cannot be sent right now
|
|
|
|
if ((LMIC.opmode & (OP_JOINING | OP_REJOIN | OP_TXDATA | OP_POLL)) != 0) {
|
|
|
|
// waiting for LoRa getting ready
|
|
|
|
} else {
|
|
|
|
if (xQueueReceive(LoraSendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) {
|
2018-11-14 22:11:23 +01:00
|
|
|
// SendBuffer now filled with next payload from queue
|
2018-11-04 14:55:30 +01:00
|
|
|
if (!LMIC_setTxData2(SendBuffer.MessagePort, SendBuffer.Message,
|
2018-11-14 22:11:23 +01:00
|
|
|
SendBuffer.MessageSize, (cfg.countermode & 0x02))) {
|
2018-11-04 14:55:30 +01:00
|
|
|
ESP_LOGI(TAG, "%d byte(s) sent to LoRa", SendBuffer.MessageSize);
|
2018-11-04 11:55:25 +01:00
|
|
|
} else {
|
2018-11-04 14:55:30 +01:00
|
|
|
ESP_LOGE(TAG, "could not send %d byte(s) to LoRa",
|
2018-11-04 11:55:25 +01:00
|
|
|
SendBuffer.MessageSize);
|
|
|
|
}
|
2018-10-22 14:06:47 +02:00
|
|
|
// sprintf(display_line7, "PACKET QUEUED");
|
2018-10-03 16:24:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// reschedule job every 0,5 - 1 sec. including a bit of random to prevent
|
|
|
|
// systematic collisions
|
|
|
|
os_setTimedCallback(job, os_getTime() + 500 + ms2osticks(random(500)),
|
|
|
|
lora_send);
|
|
|
|
}
|
|
|
|
|
2018-11-03 20:29:02 +01:00
|
|
|
esp_err_t lora_stack_init() {
|
2019-02-03 14:12:21 +01:00
|
|
|
assert(SEND_QUEUE_SIZE);
|
2018-11-03 20:29:02 +01:00
|
|
|
LoraSendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t));
|
|
|
|
if (LoraSendQueue == 0) {
|
|
|
|
ESP_LOGE(TAG, "Could not create LORA send queue. Aborting.");
|
|
|
|
return ESP_FAIL;
|
|
|
|
}
|
|
|
|
ESP_LOGI(TAG, "LORA send queue created, size %d Bytes",
|
2019-07-14 16:52:18 +02:00
|
|
|
SEND_QUEUE_SIZE * sizeof(MessageBuffer_t));
|
2018-11-03 20:29:02 +01:00
|
|
|
|
2019-08-02 21:53:05 +02:00
|
|
|
// starting lorawan stack
|
2018-11-03 20:29:02 +01:00
|
|
|
ESP_LOGI(TAG, "Starting LMIC...");
|
2019-08-02 21:53:05 +02:00
|
|
|
xTaskCreatePinnedToCore(lmictask, // task function
|
|
|
|
"lmictask", // name of task
|
|
|
|
4096, // stack size of task
|
|
|
|
(void *)1, // parameter of the task
|
|
|
|
2, // priority of the task
|
|
|
|
&lmicTask, // task handle
|
|
|
|
1); // CPU core
|
2018-11-03 20:29:02 +01:00
|
|
|
|
2018-11-04 11:55:25 +01:00
|
|
|
if (!LMIC_startJoining()) { // start joining
|
|
|
|
ESP_LOGI(TAG, "Already joined");
|
|
|
|
}
|
2018-11-14 22:11:23 +01:00
|
|
|
|
2018-11-04 11:55:25 +01:00
|
|
|
return ESP_OK; // continue main program
|
2018-11-03 20:29:02 +01:00
|
|
|
}
|
|
|
|
|
2019-02-03 14:12:21 +01:00
|
|
|
void lora_enqueuedata(MessageBuffer_t *message, sendprio_t prio) {
|
2018-11-03 20:29:02 +01:00
|
|
|
// enqueue message in LORA send queue
|
2019-02-03 14:12:21 +01:00
|
|
|
BaseType_t ret;
|
2019-03-16 21:01:43 +01:00
|
|
|
MessageBuffer_t DummyBuffer;
|
2019-02-03 14:12:21 +01:00
|
|
|
switch (prio) {
|
|
|
|
case prio_high:
|
2019-03-16 21:01:43 +01:00
|
|
|
// clear space in queue if full, then fallthrough to normal
|
2019-07-16 21:00:55 +02:00
|
|
|
if (uxQueueSpacesAvailable(LoraSendQueue) == 0)
|
2019-03-16 21:01:43 +01:00
|
|
|
xQueueReceive(LoraSendQueue, &DummyBuffer, (TickType_t)0);
|
|
|
|
case prio_normal:
|
2019-02-16 15:02:07 +01:00
|
|
|
ret = xQueueSendToFront(LoraSendQueue, (void *)message, (TickType_t)0);
|
2019-02-03 14:12:21 +01:00
|
|
|
break;
|
|
|
|
case prio_low:
|
|
|
|
default:
|
|
|
|
ret = xQueueSendToBack(LoraSendQueue, (void *)message, (TickType_t)0);
|
|
|
|
break;
|
|
|
|
}
|
2019-03-09 22:08:57 +01:00
|
|
|
if (ret != pdTRUE)
|
2018-11-03 20:29:02 +01:00
|
|
|
ESP_LOGW(TAG, "LORA sendqueue is full");
|
|
|
|
}
|
|
|
|
|
2019-02-27 00:52:27 +01:00
|
|
|
void lora_queuereset(void) { xQueueReset(LoraSendQueue); }
|
2018-11-03 20:29:02 +01:00
|
|
|
|
2019-03-31 15:32:22 +02:00
|
|
|
#if (TIME_SYNC_LORAWAN)
|
2019-03-28 14:19:02 +01:00
|
|
|
void IRAM_ATTR user_request_network_time_callback(void *pVoidUserUTCTime,
|
|
|
|
int flagSuccess) {
|
2018-11-14 22:11:23 +01:00
|
|
|
// Explicit conversion from void* to uint32_t* to avoid compiler errors
|
2019-02-23 23:39:45 +01:00
|
|
|
time_t *pUserUTCTime = (time_t *)pVoidUserUTCTime;
|
2019-02-27 00:52:27 +01:00
|
|
|
|
|
|
|
// A struct that will be populated by LMIC_getNetworkTimeReference.
|
|
|
|
// It contains the following fields:
|
|
|
|
// - tLocal: the value returned by os_GetTime() when the time
|
|
|
|
// request was sent to the gateway, and
|
|
|
|
// - tNetwork: the seconds between the GPS epoch and the time
|
|
|
|
// the gateway received the time request
|
2018-11-14 22:11:23 +01:00
|
|
|
lmic_time_reference_t lmicTimeReference;
|
|
|
|
|
|
|
|
if (flagSuccess != 1) {
|
2018-11-17 18:30:19 +01:00
|
|
|
ESP_LOGW(TAG, "LoRaWAN network did not answer time request");
|
2018-11-14 22:11:23 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-16 09:52:26 +01:00
|
|
|
// Populate lmic_time_reference
|
2018-11-14 22:11:23 +01:00
|
|
|
flagSuccess = LMIC_getNetworkTimeReference(&lmicTimeReference);
|
|
|
|
if (flagSuccess != 1) {
|
2018-11-17 18:30:19 +01:00
|
|
|
ESP_LOGW(TAG, "LoRaWAN time request failed");
|
2018-11-14 22:11:23 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-07-29 14:43:37 +02:00
|
|
|
// mask application irq to ensure accurate timing
|
2019-07-23 20:43:10 +02:00
|
|
|
mask_user_IRQ();
|
2019-03-28 14:19:02 +01:00
|
|
|
|
2018-11-14 22:11:23 +01:00
|
|
|
// Update userUTCTime, considering the difference between the GPS and UTC
|
2019-03-09 15:25:44 +01:00
|
|
|
// time, and the leap seconds until year 2019
|
2018-11-14 22:11:23 +01:00
|
|
|
*pUserUTCTime = lmicTimeReference.tNetwork + 315964800;
|
|
|
|
// Current time, in ticks
|
|
|
|
ostime_t ticksNow = os_getTime();
|
|
|
|
// Time when the request was sent, in ticks
|
|
|
|
ostime_t ticksRequestSent = lmicTimeReference.tLocal;
|
2018-11-16 09:52:26 +01:00
|
|
|
// Add the delay between the instant the time was transmitted and
|
|
|
|
// the current time
|
2019-02-23 23:39:45 +01:00
|
|
|
time_t requestDelaySec = osticks2ms(ticksNow - ticksRequestSent) / 1000;
|
2018-11-14 22:11:23 +01:00
|
|
|
|
2019-01-28 23:59:52 +01:00
|
|
|
// Update system time with time read from the network
|
2019-08-03 12:27:24 +02:00
|
|
|
setMyTime(*pUserUTCTime + requestDelaySec, 0, _lora);
|
2019-03-25 19:06:54 +01:00
|
|
|
|
2019-07-23 20:07:24 +02:00
|
|
|
finish:
|
2019-07-29 14:43:37 +02:00
|
|
|
// end of time critical section: release app irq lock
|
2019-03-31 19:13:06 +02:00
|
|
|
unmask_user_IRQ();
|
2019-03-28 14:19:02 +01:00
|
|
|
|
2019-03-23 11:01:49 +01:00
|
|
|
} // user_request_network_time_callback
|
2019-03-31 15:32:22 +02:00
|
|
|
#endif // TIME_SYNC_LORAWAN
|
2019-02-27 00:52:27 +01:00
|
|
|
|
2019-08-02 21:53:05 +02:00
|
|
|
// LMIC lorawan stack task
|
|
|
|
void lmictask(void *pvParameters) {
|
|
|
|
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
|
|
|
|
2019-08-03 12:27:24 +02:00
|
|
|
os_init(); // initialize lmic run-time environment
|
2019-08-02 21:53:05 +02:00
|
|
|
LMIC_reset(); // initialize lmic MAC
|
|
|
|
LMIC_setLinkCheckMode(0);
|
|
|
|
// This tells LMIC to make the receive windows bigger, in case your clock is
|
|
|
|
// faster or slower. This causes the transceiver to be earlier switched on,
|
|
|
|
// so consuming more power. You may sharpen (reduce) CLOCK_ERROR_PERCENTAGE
|
|
|
|
// in src/lmic_config.h if you are limited on battery.
|
|
|
|
LMIC_setClockError(MAX_CLOCK_ERROR * CLOCK_ERROR_PROCENTAGE / 100);
|
|
|
|
// Set the data rate to Spreading Factor 7. This is the fastest supported
|
|
|
|
// rate for 125 kHz channels, and it minimizes air time and battery power.
|
|
|
|
// Set the transmission power to 14 dBi (25 mW).
|
|
|
|
LMIC_setDrTxpow(DR_SF7, 14);
|
|
|
|
|
|
|
|
#if defined(CFG_US915) || defined(CFG_au921)
|
|
|
|
// in the US, with TTN, it saves join time if we start on subband 1
|
|
|
|
// (channels 8-15). This will get overridden after the join by parameters
|
|
|
|
// from the network. If working with other networks or in other regions,
|
|
|
|
// this will need to be changed.
|
|
|
|
LMIC_selectSubBand(1);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
os_runloop_once(); // execute lmic scheduled jobs and events
|
|
|
|
delay(2); // yield to CPU
|
|
|
|
}
|
|
|
|
} // lmictask
|
|
|
|
|
2019-03-11 18:09:01 +01:00
|
|
|
#endif // HAS_LORA
|