2018-03-18 19:45:17 +01:00
|
|
|
// Basic Config
|
|
|
|
#include "globals.h"
|
|
|
|
|
|
|
|
// LMIC-Arduino LoRaWAN Stack
|
2018-03-21 18:03:14 +01:00
|
|
|
#include "loraconf.h"
|
2018-03-18 19:45:17 +01:00
|
|
|
#include <lmic.h>
|
|
|
|
#include <hal/hal.h>
|
|
|
|
|
2018-04-04 01:26:05 +02:00
|
|
|
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
2018-04-05 21:47:43 +02:00
|
|
|
#include <Wire.h> // Needed for 24AA02E64, does not hurt anything if included and not used
|
2018-04-04 01:26:05 +02:00
|
|
|
#endif
|
|
|
|
|
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
|
|
|
|
|
|
|
// functions defined in rcommand.cpp
|
2018-04-28 14:09:27 +02:00
|
|
|
void rcommand(uint8_t cmd, uint8_t arg);
|
|
|
|
void switch_lora(uint8_t sf, uint8_t tx);
|
2018-03-18 19:45:17 +01:00
|
|
|
|
|
|
|
// DevEUI generator using devices's MAC address
|
|
|
|
void gen_lora_deveui(uint8_t *pdeveui) {
|
|
|
|
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
|
2018-04-04 01:26:05 +02:00
|
|
|
for ( i=0; i<6 ; i++) {
|
|
|
|
*p++ = dmac[5-i];
|
|
|
|
}
|
2018-03-18 19:45:17 +01:00
|
|
|
}
|
|
|
|
|
2018-03-21 22:32:59 +01:00
|
|
|
// Function to do a byte swap in a byte array
|
|
|
|
void RevBytes(unsigned char* b, size_t c)
|
|
|
|
{
|
|
|
|
u1_t i;
|
|
|
|
for (i = 0; i < c / 2; i++)
|
|
|
|
{ unsigned char t = b[i];
|
|
|
|
b[i] = b[c - 1 - i];
|
|
|
|
b[c - 1 - i] = t; }
|
|
|
|
}
|
|
|
|
|
2018-04-04 01:26:05 +02:00
|
|
|
void get_hard_deveui(uint8_t *pdeveui) {
|
|
|
|
// read DEVEUI from Microchip 24AA02E64 2Kb serial eeprom if present
|
|
|
|
#ifdef MCP_24AA02E64_I2C_ADDRESS
|
|
|
|
uint8_t i2c_ret;
|
|
|
|
// Init this just in case, no more to 100KHz
|
|
|
|
Wire.begin(OLED_SDA, OLED_SCL, 100000);
|
|
|
|
Wire.beginTransmission(MCP_24AA02E64_I2C_ADDRESS);
|
|
|
|
Wire.write(MCP_24AA02E64_MAC_ADDRESS);
|
|
|
|
i2c_ret = Wire.endTransmission();
|
|
|
|
// check if device seen on i2c bus
|
|
|
|
if (i2c_ret == 0) {
|
|
|
|
char deveui[32]="";
|
|
|
|
uint8_t data;
|
|
|
|
Wire.beginTransmission(MCP_24AA02E64_I2C_ADDRESS);
|
|
|
|
Wire.write(MCP_24AA02E64_MAC_ADDRESS);
|
|
|
|
Wire.requestFrom(MCP_24AA02E64_I2C_ADDRESS, 8);
|
|
|
|
while (Wire.available()) {
|
|
|
|
data = Wire.read();
|
2018-04-15 23:50:53 +02:00
|
|
|
sprintf(deveui+strlen(deveui), "%02X ", data);
|
2018-04-04 01:26:05 +02:00
|
|
|
*pdeveui++ = data;
|
|
|
|
}
|
|
|
|
i2c_ret = Wire.endTransmission();
|
|
|
|
ESP_LOGI(TAG, "Serial EEPROM 24AA02E64 found, read DEVEUI %s", deveui);
|
|
|
|
} else {
|
|
|
|
ESP_LOGI(TAG, "Serial EEPROM 24AA02E64 not found ret=%d", i2c_ret);
|
|
|
|
}
|
|
|
|
// Set back to 400KHz to speed up OLED
|
|
|
|
Wire.setClock(400000);
|
|
|
|
#endif // MCP 24AA02E64
|
|
|
|
}
|
|
|
|
|
2018-03-18 19:45:17 +01:00
|
|
|
#ifdef VERBOSE
|
|
|
|
|
|
|
|
// Display a key
|
|
|
|
void printKey(const char * name, const uint8_t * key, uint8_t len, bool lsb) {
|
|
|
|
const uint8_t * p ;
|
2018-03-24 11:28:33 +01:00
|
|
|
char keystring[len+1] = "", keybyte[3];
|
2018-03-18 19:45:17 +01:00
|
|
|
for (uint8_t i=0; i<len ; i++) {
|
|
|
|
p = lsb ? key+len-i-1 : key+i;
|
|
|
|
sprintf(keybyte, "%02X", * p);
|
|
|
|
strncat(keystring, keybyte, 2);
|
|
|
|
}
|
|
|
|
ESP_LOGI(TAG, "%s: %s", name, keystring);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Display OTAA keys
|
|
|
|
void printKeys(void) {
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // VERBOSE
|
|
|
|
|
|
|
|
void do_send(osjob_t* j){
|
2018-05-20 21:48:21 +02:00
|
|
|
|
|
|
|
// Check if there is a pending TX/RX job running
|
|
|
|
if (LMIC.opmode & OP_TXRXPEND) {
|
2018-06-08 22:41:37 +02:00
|
|
|
ESP_LOGI(TAG, "LoRa busy, rescheduling");
|
2018-05-20 21:48:21 +02:00
|
|
|
sprintf(display_lmic, "LORA BUSY");
|
2018-05-20 21:57:03 +02:00
|
|
|
goto end;
|
2018-05-20 21:48:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// prepare payload with sum of unique WIFI MACs seen
|
2018-05-21 17:48:43 +02:00
|
|
|
static uint8_t mydata[4];
|
|
|
|
|
2018-04-19 10:55:59 +02:00
|
|
|
mydata[0] = (macs_wifi & 0xff00) >> 8;
|
|
|
|
mydata[1] = macs_wifi & 0xff;
|
2018-04-02 01:36:34 +02:00
|
|
|
|
2018-05-20 21:48:21 +02:00
|
|
|
if (cfg.blescan) {
|
|
|
|
// append sum of unique BLE MACs seen to payload
|
2018-04-19 10:55:59 +02:00
|
|
|
mydata[2] = (macs_ble & 0xff00) >> 8;
|
2018-05-20 21:48:21 +02:00
|
|
|
mydata[3] = macs_ble & 0xff;
|
|
|
|
} else {
|
2018-04-17 22:42:06 +02:00
|
|
|
mydata[2] = 0;
|
|
|
|
mydata[3] = 0;
|
2018-05-20 21:48:21 +02:00
|
|
|
}
|
2018-04-02 01:36:34 +02:00
|
|
|
|
2018-06-08 22:41:37 +02:00
|
|
|
|
|
|
|
|
2018-05-20 21:48:21 +02:00
|
|
|
// Prepare upstream data transmission at the next possible time.
|
2018-06-08 22:41:37 +02:00
|
|
|
LMIC_setTxData2(COUNTERPORT, mydata, sizeof(mydata), (cfg.countermode & 0x02));
|
|
|
|
ESP_LOGI(TAG, "%d bytes queued to send", sizeof(mydata));
|
2018-05-20 21:48:21 +02:00
|
|
|
sprintf(display_lmic, "PACKET QUEUED");
|
2018-06-08 22:41:37 +02:00
|
|
|
|
|
|
|
#ifdef HAS_GPS
|
|
|
|
if (cfg.gpsmode && my_gps.location.isValid()) {
|
|
|
|
gps_status.latitude = my_gps.location.lat();
|
|
|
|
gps_status.longitude = my_gps.location.lng();
|
|
|
|
gps_status.satellites = my_gps.satellites.value();
|
|
|
|
gps_status.hdop = my_gps.hdop.value();
|
|
|
|
gps_status.altitude = my_gps.altitude.meters();
|
|
|
|
LMIC_setTxData2(GPSPORT, (byte*)&gps_status, sizeof(gps_status), (cfg.countermode & 0x02));
|
|
|
|
ESP_LOGI(TAG, "HDOP=%d, SATS=%d, LAT=%d, LON=%d", gps_status.hdop, gps_status.satellites, gps_status.latitude, gps_status.longitude );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-05-20 21:48:21 +02:00
|
|
|
// clear counter if not in cumulative counter mode
|
|
|
|
if (cfg.countermode != 1) {
|
|
|
|
reset_counters(); // clear macs container and reset all counters
|
|
|
|
reset_salt(); // get new salt for salting hashes
|
|
|
|
ESP_LOGI(TAG, "Counter cleared (countermode = %d)", cfg.countermode);
|
2018-03-18 19:45:17 +01:00
|
|
|
}
|
2018-04-27 18:32:36 +02:00
|
|
|
|
|
|
|
// Schedule next transmission
|
2018-05-20 21:57:03 +02:00
|
|
|
end:
|
2018-04-28 13:07:35 +02:00
|
|
|
os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(cfg.sendcycle * 2), do_send);
|
2018-04-27 18:32:36 +02:00
|
|
|
|
|
|
|
} // do_send()
|
2018-03-18 19:45:17 +01:00
|
|
|
|
|
|
|
void onEvent (ev_t ev) {
|
2018-04-05 14:34:39 +02:00
|
|
|
char buff[24]="";
|
2018-05-21 14:16:25 +02:00
|
|
|
|
2018-03-18 19:45:17 +01:00
|
|
|
switch(ev) {
|
2018-04-05 14:34:39 +02:00
|
|
|
case EV_SCAN_TIMEOUT: strcpy_P(buff, PSTR("SCAN TIMEOUT")); break;
|
|
|
|
case EV_BEACON_FOUND: strcpy_P(buff, PSTR("BEACON FOUND")); break;
|
2018-04-05 21:47:43 +02:00
|
|
|
case EV_BEACON_MISSED: strcpy_P(buff, PSTR("BEACON MISSED")); break;
|
2018-04-05 14:34:39 +02:00
|
|
|
case EV_BEACON_TRACKED: strcpy_P(buff, PSTR("BEACON TRACKED")); break;
|
|
|
|
case EV_JOINING: strcpy_P(buff, PSTR("JOINING")); break;
|
|
|
|
case EV_LOST_TSYNC: strcpy_P(buff, PSTR("LOST TSYNC")); break;
|
|
|
|
case EV_RESET: strcpy_P(buff, PSTR("RESET")); break;
|
|
|
|
case EV_RXCOMPLETE: strcpy_P(buff, PSTR("RX COMPLETE")); break;
|
|
|
|
case EV_LINK_DEAD: strcpy_P(buff, PSTR("LINK DEAD")); break;
|
|
|
|
case EV_LINK_ALIVE: strcpy_P(buff, PSTR("LINK ALIVE")); break;
|
|
|
|
case EV_RFU1: strcpy_P(buff, PSTR("RFUI")); break;
|
|
|
|
case EV_JOIN_FAILED: strcpy_P(buff, PSTR("JOIN FAILED")); break;
|
|
|
|
case EV_REJOIN_FAILED: strcpy_P(buff, PSTR("REJOIN FAILED")); break;
|
|
|
|
|
2018-03-18 19:45:17 +01:00
|
|
|
case EV_JOINED:
|
2018-04-27 18:32:36 +02:00
|
|
|
|
2018-04-05 14:34:39 +02:00
|
|
|
strcpy_P(buff, PSTR("JOINED"));
|
2018-05-27 17:42:18 +02:00
|
|
|
sprintf(display_lora, " "); // clear previous lmic status message from display
|
2018-04-27 18:32:36 +02:00
|
|
|
|
2018-03-18 19:45:17 +01:00
|
|
|
// Disable link check validation (automatically enabled
|
2018-05-21 17:48:43 +02:00
|
|
|
// during join, but not supported by TTN at this time). -> do we need this?
|
2018-06-03 22:02:22 +02:00
|
|
|
// LMIC_setLinkCheckMode(0);
|
2018-05-21 14:16:25 +02:00
|
|
|
|
2018-03-18 19:45:17 +01:00
|
|
|
// set data rate adaptation
|
|
|
|
LMIC_setAdrMode(cfg.adrmode);
|
|
|
|
// Set data rate and transmit power (note: txpower seems to be ignored by the library)
|
|
|
|
switch_lora(cfg.lorasf,cfg.txpower);
|
2018-04-27 18:32:36 +02:00
|
|
|
|
2018-03-18 19:45:17 +01:00
|
|
|
// show effective LoRa parameters after join
|
2018-04-27 21:29:46 +02:00
|
|
|
ESP_LOGI(TAG, "ADR=%d, SF=%d, TXPOWER=%d", cfg.adrmode, cfg.lorasf, cfg.txpower);
|
2018-03-18 19:45:17 +01:00
|
|
|
break;
|
2018-04-27 18:32:36 +02:00
|
|
|
|
2018-03-18 19:45:17 +01:00
|
|
|
case EV_TXCOMPLETE:
|
2018-04-15 23:50:53 +02:00
|
|
|
|
2018-04-27 18:32:36 +02:00
|
|
|
strcpy_P(buff, (LMIC.txrxFlags & TXRX_ACK) ? PSTR("RECEIVED ACK") : PSTR("TX COMPLETE"));
|
2018-05-27 17:42:18 +02:00
|
|
|
sprintf(display_lora, " "); // clear previous lmic status message from display
|
2018-04-27 18:32:36 +02:00
|
|
|
|
|
|
|
if (LMIC.dataLen) {
|
|
|
|
ESP_LOGI(TAG, "Received %d bytes of payload, RSSI %d SNR %d", LMIC.dataLen, LMIC.rssi, (signed char)LMIC.snr / 4);
|
2018-03-18 19:45:17 +01:00
|
|
|
// LMIC.snr = SNR twos compliment [dB] * 4
|
2018-03-31 23:22:46 +02:00
|
|
|
// LMIC.rssi = RSSI [dBm] (-196...+63)
|
2018-04-27 18:32:36 +02:00
|
|
|
sprintf(display_lora, "RSSI %d SNR %d", LMIC.rssi, (signed char)LMIC.snr / 4 );
|
2018-04-15 23:50:53 +02:00
|
|
|
|
2018-03-18 19:45:17 +01:00
|
|
|
// check if payload received on command port, then call remote command interpreter
|
|
|
|
if ( (LMIC.txrxFlags & TXRX_PORT) && (LMIC.frame[LMIC.dataBeg-1] == RCMDPORT ) ) {
|
|
|
|
// caution: buffering LMIC values here because rcommand() can modify LMIC.frame
|
|
|
|
unsigned char* buffer = new unsigned char[MAX_LEN_FRAME];
|
|
|
|
memcpy(buffer, LMIC.frame, MAX_LEN_FRAME); //Copy data from cfg to char*
|
|
|
|
int i, k = LMIC.dataBeg, l = LMIC.dataBeg+LMIC.dataLen-2;
|
2018-06-08 22:41:37 +02:00
|
|
|
for (i=k; i<=l; i+=2) {
|
2018-03-18 19:45:17 +01:00
|
|
|
rcommand(buffer[i], buffer[i+1]);
|
2018-06-08 22:41:37 +02:00
|
|
|
}
|
2018-03-18 19:45:17 +01:00
|
|
|
delete[] buffer; //free memory
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2018-04-27 18:32:36 +02:00
|
|
|
|
2018-04-05 14:34:39 +02:00
|
|
|
default: sprintf_P(buff, PSTR("UNKNOWN EVENT %d"), ev); break;
|
2018-03-18 19:45:17 +01:00
|
|
|
}
|
2018-04-05 14:34:39 +02:00
|
|
|
|
|
|
|
// Log & Display if asked
|
|
|
|
if (*buff) {
|
|
|
|
ESP_LOGI(TAG, "EV_%s", buff);
|
2018-04-15 23:50:53 +02:00
|
|
|
sprintf(display_lmic, buff);
|
2018-04-05 14:34:39 +02:00
|
|
|
}
|
2018-04-27 18:32:36 +02:00
|
|
|
|
|
|
|
} // onEvent()
|
2018-03-31 23:22:46 +02:00
|
|
|
|