Initial upload

This commit is contained in:
Verkehrsrot authored and GitHub committed 2018-03-18 19:45:17 +01:00
1 parent c2db6ee4b6
commit f238dc3f0f
45 files changed
+10444 -201

No files matched your search

+37
View File
@@ -0,0 +1,37 @@
#ifdef LOPY
#include <Arduino.h>
// Local logging tag
static const char *TAG = "antenna";
static antenna_type_t antenna_type_selected = ANTENNA_TYPE_INTERNAL;
void antenna_init(void) {
gpio_config_t gpioconf = {.pin_bit_mask = 1ull << PIN_ANTENNA_SWITCH,
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE};
gpio_config(&gpioconf);
}
void antenna_select (antenna_type_t _antenna) {
if (PIN_ANTENNA_SWITCH < 32) {
// set the pin value
if (_antenna == ANTENNA_TYPE_EXTERNAL) {
GPIO_REG_WRITE(GPIO_OUT_W1TS_REG, 1 << PIN_ANTENNA_SWITCH);
} else {
GPIO_REG_WRITE(GPIO_OUT_W1TC_REG, 1 << PIN_ANTENNA_SWITCH);
}
} else {
if (_antenna == ANTENNA_TYPE_EXTERNAL) {
GPIO_REG_WRITE(GPIO_OUT1_W1TS_REG, 1 << (PIN_ANTENNA_SWITCH & 31));
} else {
GPIO_REG_WRITE(GPIO_OUT1_W1TC_REG, 1 << (PIN_ANTENNA_SWITCH & 31));
}
}
antenna_type_selected = _antenna;
}
#endif //
+38
View File
@@ -0,0 +1,38 @@
// Log Level magic
#include "main.h"
// not using this seems to break U8X8LIB
#include <Arduino.h>
// Local logging tag
static const char *TAG = "blecount";
// Basic Config
#include "globals.h"
#include "loraconf.h"
#ifdef BLECOUNTER
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
}
};
void BLECount() {
u8x8.clearLine(3);
u8x8.drawString(0,3,"BLE Scan...");
BLEDevice::init("PaxCnt");
BLEScan* pBLEScan = BLEDevice::getScan(); //create new scan
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
BLEScanResults foundDevices = pBLEScan->start(cfg.blescancycle);
u8x8.clearLine(3);
u8x8.setCursor(0,3);
blenum=foundDevices.getCount();
u8x8.printf("BLE#: %4i",blenum);
}
#endif
+248
View File
@@ -0,0 +1,248 @@
/* configmanager persists runtime configuration using NVRAM of ESP32*/
#include "globals.h"
#include <nvs.h>
#include <nvs_flash.h>
// Local logging tag
static const char *TAG = "configmanager";
nvs_handle my_handle;
esp_err_t err;
// populate cfg vars with factory settings
void defaultConfig() {
cfg.lorasf = LORASFDEFAULT; // 7-12, initial lora spreadfactor defined in main.h
cfg.txpower = 15; // 2-15, lora tx power
cfg.adrmode = 1; // 0=disabled, 1=enabled
cfg.screensaver = 0; // 0=disabled, 1=enabled
cfg.screenon = 1; // 0=disbaled, 1=enabled
cfg.countermode = 0; // 0=cyclic, 1=cumulative, 2=cyclic confirmed
cfg.rssilimit = 0; // threshold for rssilimiter, negative value!
cfg.wifiscancycle = SEND_SECS; // wifi scan cycle [seconds/2]
cfg.wifichancycle = WIFI_CHANNEL_SWITCH_INTERVAL; // wifi channel switch cycle [seconds/100]
cfg.blescancycle = BLESCANTIME; // BLE scan cycle [seconds]
cfg.blescan = 0; // 0=disabled, 1=enabled
strncpy( cfg.version, PROGVERSION, sizeof(cfg.version)-1 );
}
void open_storage() {
err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
// NVS partition was truncated and needs to be erased
// Retry nvs_flash_init
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK( err );
// Open
ESP_LOGI(TAG, "Opening NVS");
err = nvs_open("config", NVS_READWRITE, &my_handle);
if (err != ESP_OK)
ESP_LOGI(TAG, "Error (%d) opening NVS handle", err);
else
ESP_LOGI(TAG, "Done");
}
// erase all keys and values in NVRAM
void eraseConfig() {
ESP_LOGI(TAG, "Clearing settings in NVS");
open_storage();
if (err == ESP_OK) {
nvs_erase_all(my_handle);
nvs_commit(my_handle);
nvs_close(my_handle);
ESP_LOGI(TAG, "Done");}
else {
ESP_LOGW(TAG, "NVS erase failed"); }
}
// save current configuration from RAM to NVRAM
void saveConfig() {
ESP_LOGI(TAG, "Storing settings in NVS");
open_storage();
if (err == ESP_OK) {
int8_t flash8 = 0;
int16_t flash16 = 0;
size_t required_size;
char storedversion[10];
if( nvs_get_str(my_handle, "version", storedversion, &required_size) != ESP_OK || strcmp(storedversion, cfg.version) != 0 )
nvs_set_str(my_handle, "version", cfg.version);
if( nvs_get_i8(my_handle, "lorasf", &flash8) != ESP_OK || flash8 != cfg.lorasf )
nvs_set_i8(my_handle, "lorasf", cfg.lorasf);
if( nvs_get_i8(my_handle, "txpower", &flash8) != ESP_OK || flash8 != cfg.txpower )
nvs_set_i8(my_handle, "txpower", cfg.txpower);
if( nvs_get_i8(my_handle, "adrmode", &flash8) != ESP_OK || flash8 != cfg.adrmode )
nvs_set_i8(my_handle, "adrmode", cfg.adrmode);
if( nvs_get_i8(my_handle, "screensaver", &flash8) != ESP_OK || flash8 != cfg.screensaver )
nvs_set_i8(my_handle, "screensaver", cfg.screensaver);
if( nvs_get_i8(my_handle, "screenon", &flash8) != ESP_OK || flash8 != cfg.screenon )
nvs_set_i8(my_handle, "screenon", cfg.screenon);
if( nvs_get_i8(my_handle, "countermode", &flash8) != ESP_OK || flash8 != cfg.countermode )
nvs_set_i8(my_handle, "countermode", cfg.countermode);
if( nvs_get_i8(my_handle, "wifiscancycle", &flash8) != ESP_OK || flash8 != cfg.wifiscancycle )
nvs_set_i8(my_handle, "wifiscancycle", cfg.wifiscancycle);
if( nvs_get_i8(my_handle, "wifichancycle", &flash8) != ESP_OK || flash8 != cfg.wifichancycle )
nvs_set_i8(my_handle, "wifichancycle", cfg.wifichancycle);
if( nvs_get_i8(my_handle, "blescancycle", &flash8) != ESP_OK || flash8 != cfg.blescancycle )
nvs_set_i8(my_handle, "blescancycle", cfg.blescancycle);
if( nvs_get_i8(my_handle, "blescanmode", &flash8) != ESP_OK || flash8 != cfg.blescan )
nvs_set_i8(my_handle, "blescanmode", cfg.blescan);
if( nvs_get_i16(my_handle, "rssilimit", &flash16) != ESP_OK || flash16 != cfg.rssilimit )
nvs_set_i16(my_handle, "rssilimit", cfg.rssilimit);
err = nvs_commit(my_handle);
nvs_close(my_handle);
if ( err == ESP_OK ) {
ESP_LOGI(TAG, "Done");
} else {
ESP_LOGW(TAG, "NVS config write failed");
}
} else {
ESP_LOGW(TAG, "Error (%d) opening NVS handle", err);
}
}
// set and save cfg.version
void migrateVersion() {
sprintf(cfg.version, "%s", PROGVERSION);
ESP_LOGI(TAG, "version set to %s", cfg.version);
saveConfig();
}
// load configuration from NVRAM into RAM and make it current
void loadConfig() {
defaultConfig(); // start with factory settings
ESP_LOGI(TAG, "Reading settings from NVS");
open_storage();
if (err != ESP_OK) {
ESP_LOGW(TAG,"Error (%d) opening NVS handle, storing defaults", err);
saveConfig(); } // saves factory settings to NVRAM
else {
int8_t flash8 = 0;
int16_t flash16 = 0;
size_t required_size;
// check if configuration stored in NVRAM matches PROGVERSION
if( nvs_get_str(my_handle, "version", NULL, &required_size) == ESP_OK ) {
nvs_get_str(my_handle, "version", cfg.version, &required_size);
ESP_LOGI(TAG, "NVRAM settings version = %s", cfg.version);
if (strcmp(cfg.version, PROGVERSION)) {
ESP_LOGI(TAG, "migrating NVRAM settings to new version %s", PROGVERSION);
nvs_close(my_handle);
migrateVersion();
}
} else {
ESP_LOGI(TAG, "new version %s, deleting NVRAM settings", PROGVERSION);
nvs_close(my_handle);
eraseConfig();
migrateVersion();
}
// overwrite defaults with valid values from NVRAM
if( nvs_get_i8(my_handle, "lorasf", &flash8) == ESP_OK ) {
cfg.lorasf = flash8;
ESP_LOGI(TAG, "lorasf = %i", flash8);
} else {
ESP_LOGI(TAG, "lorasf set to default %i", cfg.lorasf);
saveConfig();
}
if( nvs_get_i8(my_handle, "txpower", &flash8) == ESP_OK ) {
cfg.txpower = flash8;
ESP_LOGI(TAG, "txpower = %i", flash8);
} else {
ESP_LOGI(TAG, "txpower set to default %i", cfg.txpower);
saveConfig();
}
if( nvs_get_i8(my_handle, "adrmode", &flash8) == ESP_OK ) {
cfg.adrmode = flash8;
ESP_LOGI(TAG, "adrmode = %i", flash8);
} else {
ESP_LOGI(TAG, "adrmode set to default %i", cfg.adrmode);
saveConfig();
}
if( nvs_get_i8(my_handle, "screensaver", &flash8) == ESP_OK ) {
cfg.screensaver = flash8;
ESP_LOGI(TAG, "screensaver = %i", flash8);
} else {
ESP_LOGI(TAG, "screensaver set to default %i", cfg.screensaver);
saveConfig();
}
if( nvs_get_i8(my_handle, "screenon", &flash8) == ESP_OK ) {
cfg.screenon = flash8;
ESP_LOGI(TAG, "screenon = %i", flash8);
} else {
ESP_LOGI(TAG, "screenon set to default %i", cfg.screenon);
saveConfig();
}
if( nvs_get_i8(my_handle, "countermode", &flash8) == ESP_OK ) {
cfg.countermode = flash8;
ESP_LOGI(TAG, "countermode = %i", flash8);
} else {
ESP_LOGI(TAG, "countermode set to default %i", cfg.countermode);
saveConfig();
}
if( nvs_get_i8(my_handle, "wifiscancycle", &flash8) == ESP_OK ) {
cfg.wifiscancycle = flash8;
ESP_LOGI(TAG, "wifiscancycle = %i", flash8);
} else {
ESP_LOGI(TAG, "WIFI scan cycle set to default %i", cfg.wifiscancycle);
saveConfig();
}
if( nvs_get_i8(my_handle, "wifichancycle", &flash8) == ESP_OK ) {
cfg.wifichancycle = flash8;
ESP_LOGI(TAG, "wifichancycle = %i", flash8);
} else {
ESP_LOGI(TAG, "WIFI channel cycle set to default %i", cfg.wifichancycle);
saveConfig();
}
if( nvs_get_i8(my_handle, "blescancycle", &flash8) == ESP_OK ) {
cfg.blescancycle = flash8;
ESP_LOGI(TAG, "blescancycle = %i", flash8);
} else {
ESP_LOGI(TAG, "BLEscan cycle set to default %i", cfg.blescancycle);
saveConfig();
}
if( nvs_get_i8(my_handle, "blescanmode", &flash8) == ESP_OK ) {
cfg.blescan = flash8;
ESP_LOGI(TAG, "BLEscanmode = %i", flash8);
} else {
ESP_LOGI(TAG, "BLEscanmode set to default %i", cfg.blescan);
saveConfig();
}
if( nvs_get_i16(my_handle, "rssilimit", &flash16) == ESP_OK ) {
cfg.rssilimit = flash16;
ESP_LOGI(TAG, "rssilimit = %i", flash16);
} else {
ESP_LOGI(TAG, "rssilimit set to default %i", cfg.rssilimit);
saveConfig();
}
nvs_close(my_handle);
ESP_LOGI(TAG, "Done");
}
}
+16
View File
@@ -0,0 +1,16 @@
/* struct holding devices's runtime configuration */
typedef struct {
int8_t lorasf; // 7-12, lora spreadfactor
int8_t txpower; // 2-15, lora tx power
int8_t adrmode; // 0=disabled, 1=enabled
int8_t screensaver; // 0=disabled, 1=enabled
int8_t screenon; // 0=disabled, 1=enabled
int8_t countermode; // 0=cyclic unconfirmed, 1=cumulative, 2=cyclic confirmed
int16_t rssilimit; // threshold for rssilimiter, negative value!
int8_t wifiscancycle; // wifi scan cycle [seconds/2]
int8_t wifichancycle; // wifi channel switch cycle [seconds/100]
int8_t blescancycle; // BLE scan cycle [seconds]
int8_t blescan; // 0=disabled, 1=enabled
char version[10]; // Firmware version
} configData_t;
+40
View File
@@ -0,0 +1,40 @@
// First things first
#include "main.h"
// The mother of all embedded development...
#include <Arduino.h>
// we neededthis to ESP_LOGx on arduino framework
#include "esp32-hal-log.h"
#include <String.h>
// std::set for unified array functions
#include <set>
// OLED Display
#include <U8x8lib.h>
// LMIC-Arduino LoRaWAN Stack
#include <lmic.h>
#include <hal/hal.h>
// configData_t
#include "configmanager.h"
extern uint8_t mydata[];
extern uint64_t uptimecounter;
extern int macnum, blenum, countermode, screensaver, adrmode, lorasf, txpower, rlim;
extern bool joinstate;
extern osjob_t sendjob;
extern std::set<uint64_t, std::greater <uint64_t> > macs;
extern U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8;
extern configData_t cfg;
#ifdef BLECOUNTER
extern int scanTime;
#endif
+21
View File
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2016, Pycom Limited.
*
* This software is licensed under the GNU GPL version 3 or any
* later version, with permitted additional terms. For more information
* see the Pycom Licence v1.0 document supplied with this file, or
* available at https://www.pycom.io/opensource/licensing
*/
#ifndef _ANTENNA_H_
#define _ANTENNA_H_
typedef enum {
ANTENNA_TYPE_INTERNAL = 0,
ANTENNA_TYPE_EXTERNAL
} antenna_type_t;
extern void antenna_init (void);
extern void antenna_select (antenna_type_t antenna_type);
#endif /* _ANTENNA_H_ */
+24
View File
@@ -0,0 +1,24 @@
// Hardware related definitions for Heltec LoRa-32 Board
#define HELTEC
#define HAS_DISPLAY // has OLED-Display
#define HAS_LED // has on usable board LED
#define HAS_BUTTON // has onboard button
#define CFG_sx1276_radio 1
// re-define pin definitions of pins_arduino.h
#define PIN_SPI_SS 18 // ESP32 GPIO18 (Pin18) -- SX1276 NSS (Pin19) SPI Chip Select Input
#define PIN_SPI_MOSI 27 // ESP32 GPIO27 (Pin27) -- SX1276 MOSI (Pin18) SPI Data Input
#define PIN_SPI_MISO 19 // ESP32 GPIO19 (Pin19) -- SX1276 MISO (Pin17) SPI Data Output
#define PIN_SPI_SCK 5 // ESP32 GPIO5 (Pin5) -- SX1276 SCK (Pin16) SPI Clock Input
// non arduino pin definitions
#define RST 14 // ESP32 GPIO14 (Pin14) -- SX1276 NRESET (Pin7) Reset Trigger Input
#define DIO0 26 // ESP32 GPIO26 (Pin15) -- SX1276 DIO0 (Pin8) used by LMIC for detecting LoRa RX_Done & TX_Done
#define DIO1 33 // ESP32 GPIO33 (Pin13) -- SX1276 DIO1 (Pin9) used by LMIC for detecting LoRa RX_Timeout
#define DIO2 32 // ESP32 GPIO32 (Pin12) -- SX1276 DIO2 (Pin10) not used by LMIC for LoRa (Timeout for FSK only)
// Hardware pin definitions for Heltec LoRa-32 Board with OLED SSD1306 I2C Display
#define OLED_RST 16 // ESP32 GPIO16 (Pin16) -- SD1306 Reset
#define OLED_SDA 4 // ESP32 GPIO4 (Pin4) -- SD1306 Data
#define OLED_SCL 15 // ESP32 GPIO15 (Pin15) -- SD1306 Clock
+18
View File
@@ -0,0 +1,18 @@
// Hardware related definitions for Pycom LoPy Board (not: LoPy4)
#define LOPY
#define CFG_sx1272_radio 1
// Hardware pin definitions for Pycom LoPy board
#define PIN_SPI_SS 17
#define PIN_SPI_MOSI 27
#define PIN_SPI_MISO 19
#define PIN_SPI_SCK 5
#define RST 18
#define DIO0 23 // LoRa IRQ
#define DIO1 23 // workaround
#define DIO2 23 // workaround
// select WIFI antenna (internal = onboard / external = u.fl socket)
#define PIN_ANTENNA_SWITCH 16
#define WIFI_LOPY_ANTENNA ANTENNA_TYPE_INTERNAL
+18
View File
@@ -0,0 +1,18 @@
// Hardware related definitions for Pycom LoPy Board (not: LoPy4)
#define LOPY
#define CFG_sx1276_radio 1
// Hardware pin definitions for Pycom LoPy4 board
#define PIN_SPI_SS 18
#define PIN_SPI_MOSI 27
#define PIN_SPI_MISO 19
#define PIN_SPI_SCK 5
#define RST LMIC_UNUSED_PIN
#define DIO0 23 // LoRa IRQ
#define DIO1 23 // workaround
#define DIO2 23 // workaround
// select WIFI antenna (internal = onboard / external = u.fl socket)
#define PIN_ANTENNA_SWITCH 21
#define WIFI_LOPY_ANTENNA ANTENNA_TYPE_INTERNAL
+48
View File
@@ -0,0 +1,48 @@
// Hardware related definitions for TTGO V2 Board
#define TTGO
#define HAS_DISPLAY // has OLED-Display
#define CFG_sx1276_radio 1
// re-define pin definitions of pins_arduino.h
#define PIN_SPI_SS 18 // ESP32 GPIO18 (Pin18) -- SX1276 NSS (Pin19) SPI Chip Select Input
#define PIN_SPI_MOSI 27 // ESP32 GPIO27 (Pin27) -- SX1276 MOSI (Pin18) SPI Data Input
#define PIN_SPI_MISO 19 // ESP32 GPIO19 (Pin19) -- SX1276 MISO (Pin17) SPI Data Output
#define PIN_SPI_SCK 5 // ESP32 GPIO5 (Pin5) -- SX1276 SCK (Pin16) SPI Clock Input
// non arduino pin definitions
#define RST LMIC_UNUSED_PIN // not sure
#define DIO0 26 // wired on PCB
#define DIO1 33 // needs to be wired external
#define DIO2 32 // needs to be wired external (but not necessary for LoRa)
// Hardware pin definitions for TTGO V2 Board with OLED SSD1306 0,96" I2C Display
#define OLED_RST U8X8_PIN_NONE // to be checked if really not connected
#define OLED_SDA 21 // ESP32 GPIO4 (Pin4) -- SD1306 Data
#define OLED_SCL 22 // ESP32 GPIO15 (Pin15) -- SD1306 Clock
/*
ESP32 LoRa module (SPI) OLED display (I2C)
--------- ----------------- ------------------
5 SCK SCK
27 MOSI MOSI
19 MISO MISO
18 SS NSS
14 RST
26 DIO0
33 DIO1 (see note {1})
32 DIO2 (see note {2})
22 SCL SCL
21 SDA SDA
22 LED (useless, see note {3})
{1} Must be manually wired!
DIO1 is wired to a separate pin but is not wired on-board to pin/GPIO33.
Explicitly wire board pin labeled DIO1 to pin 33 (see TTGO V2.0 pinout).
{2} Must be manually wired!
DIO2 is wired to a separate pin but is not wired on-board to pin/GPIO32.
Explicitly wire board pin labeled DIO2 to pin 32 (see TTGO V2.0 pinout).
{3} The on-board LED is wired to SCL (used by display) therefore totally useless!
*/
+29
View File
@@ -0,0 +1,29 @@
/************************************************************
* LMIC LoRaWAN configuration
*
* Read the values from TTN console (or whatever applies)
*
************************************************************/
#include <Arduino.h>
/*
// Only define DEVEUI here if you don't want it to be derived from device's MAC address
// Use little endian format (lsb)
//static const u1_t DEVEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
// 0x70.
static const u1_t APPEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xB3, 0x70 };
// This key should be in big endian format (or, since it is not really a
// number but a block of memory, endianness does not really apply). In
// practice, a key taken from ttnctl can be copied as-is.
// The key shown here is the semtech default key.
static const u1_t APPKEY[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
*/
+220
View File
@@ -0,0 +1,220 @@
// Basic Config
#include "main.h"
// #include <Arduino.h>
#include "globals.h"
#include "loraconf.h"
// LMIC-Arduino LoRaWAN Stack
#include <lmic.h>
#include <hal/hal.h>
// needs to be defined here
uint8_t mydata[] = "0000";
// Local logging Tag
static const char *TAG = "lorawan";
// function defined in main.cpp
void set_onboard_led(int state);
// functions defined in rcommand.cpp
void rcommand(int cmd, int arg);
void switch_lora(int sf, int tx);
// 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
for ( i=0; i<6 ; i++) {
*p++ = dmac[5-i];
}
}
#ifdef VERBOSE
// Display a key
void printKey(const char * name, const uint8_t * key, uint8_t len, bool lsb) {
uint8_t start=lsb?len:0;
uint8_t end = lsb?0:len;
const uint8_t * p ;
char keystring[len+1] = "", keybyte[3];
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){
mydata[0] = (macnum & 0x0000ff00) >> 8;
mydata[1] = macnum & 0x000000ff;
mydata[2] = (blenum & 0x0000ff00) >> 8;
mydata[3] = blenum & 0x000000ff;
// Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND) {
ESP_LOGI(TAG, "OP_TXRXPEND, not sending");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "LORA BUSY");
} else {
// Prepare upstream data transmission at the next possible time.
LMIC_setTxData2(1, mydata, sizeof(mydata)-1, (cfg.countermode & 0x02));
ESP_LOGI(TAG, "Packet queued");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "PACKET QUEUED");
set_onboard_led(1);
}
// Next TX is scheduled after TX_COMPLETE event.
}
void onEvent (ev_t ev) {
switch(ev) {
case EV_SCAN_TIMEOUT:
ESP_LOGI(TAG, "EV_SCAN_TIMEOUT");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "SCAN TIMEOUT");
break;
case EV_BEACON_FOUND:
ESP_LOGI(TAG, "EV_BEACON_FOUND");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "BEACON FOUND");
break;
case EV_BEACON_MISSED:
ESP_LOGI(TAG, "EV_BEACON_MISSED");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "BEACON MISSED");
break;
case EV_BEACON_TRACKED:
ESP_LOGI(TAG, "EV_BEACON_TRACKED");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "BEACON TRACKED");
break;
case EV_JOINING:
ESP_LOGI(TAG, "EV_JOINING");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "JOINING");
break;
case EV_JOINED:
ESP_LOGI(TAG, "EV_JOINED");
u8x8.clearLine(6); // erase "Join Wait" message from display, see main.cpp
u8x8.clearLine(7);
u8x8.drawString(0, 7, "JOINED");
// Disable link check validation (automatically enabled
// during join, but not supported by TTN at this time).
LMIC_setLinkCheckMode(0);
// 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);
joinstate=true;
// show effective LoRa parameters after join
ESP_LOGI(TAG, "ADR=%i, SF=%i, TXPOWER=%i", cfg.adrmode, cfg.lorasf, cfg.txpower);
break;
case EV_RFU1:
ESP_LOGI(TAG, "EV_RFU1");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "RFUI");
break;
case EV_JOIN_FAILED:
ESP_LOGI(TAG, "EV_JOIN_FAILED");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "JOIN FAILED");
break;
case EV_REJOIN_FAILED:
ESP_LOGI(TAG, "EV_REJOIN_FAILED");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "REJOIN FAILED");
break;
case EV_TXCOMPLETE:
ESP_LOGI(TAG, "EV_TXCOMPLETE (includes waiting for RX windows)");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "TX COMPLETE");
set_onboard_led(0);
if (LMIC.txrxFlags & TXRX_ACK) {
ESP_LOGI(TAG, "Received ack");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "RECEIVED ACK");
}
if (LMIC.dataLen) {
ESP_LOGI(TAG, "Received %i bytes of payload", LMIC.dataLen);
u8x8.clearLine(6);
u8x8.setCursor(0, 6);
u8x8.printf("Rcvd %i bytes", LMIC.dataLen);
u8x8.clearLine(7);
u8x8.setCursor(0, 7);
// LMIC.snr = SNR twos compliment [dB] * 4
// LMIC.rssi = RSSI [dBm] (-196...+63)
u8x8.printf("RSSI %d SNR %d", LMIC.rssi, (signed char)LMIC.snr / 4);
// 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;
for (i=k; i<=l; i+=2)
rcommand(buffer[i], buffer[i+1]);
delete[] buffer; //free memory
}
}
break;
case EV_LOST_TSYNC:
ESP_LOGI(TAG, "EV_LOST_TSYNC");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "LOST TSYNC");
break;
case EV_RESET:
ESP_LOGI(TAG, "EV_RESET");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "RESET");
break;
case EV_RXCOMPLETE:
// data received in ping slot
ESP_LOGI(TAG, "EV_RXCOMPLETE");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "RX COMPLETE");
break;
case EV_LINK_DEAD:
ESP_LOGI(TAG, "EV_LINK_DEAD");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "LINK DEAD");
break;
case EV_LINK_ALIVE:
ESP_LOGI(TAG, "EV_LINK_ALIVE");
u8x8.clearLine(7);
u8x8.drawString(0, 7, "LINK ALIVE");
break;
default:
ESP_LOGI(TAG, "Unknown event");
u8x8.clearLine(7);
u8x8.setCursor(0, 7);
u8x8.printf("UNKNOWN EVENT %d", ev);
break;
}
}
+424
View File
@@ -0,0 +1,424 @@
/*
*
* Oliver Brandmueller <ob@sysadm.in> 2017/2018
* Klaus Wilting <verkehrsrot@arcor.de> 2018
*
* some lines of code taken from:
*
* Copyright (c) 2017, Łukasz Marcin Podkalicki <lpodkalicki@gmail.com>
* ESP32/016 WiFi Sniffer.
* https://github.com/lpodkalicki/blog/tree/master/esp32/016_wifi_sniffer
*
* Arduino-LMIC Library
* TTN OTAA Example
* https://github.com/matthijskooijman/arduino-lmic/blob/master/examples/ttn-otaa/
*
* nkolban esp32 snippets
* BLE Scan
* https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils/tests/BLETests/Arduino/BLE_scan
*
* parts of code in lorawan.cpp has been grabbed from RadioHead Library
*/
// First things first
#include "main.h"
// std::set for unified array functions
#include <set>
// OLED driver
#include <U8x8lib.h>
#ifdef HAS_DISPLAY
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(OLED_RST, OLED_SCL, OLED_SDA);
#else
U8X8_NULL u8x8;
#endif
// LMIC-Arduino LoRaWAN Stack
#include <lmic.h>
#include <hal/hal.h>
// Basic Config
#include "loraconf.h"
#include "configmanager.h"
// WiFi Functions
#include <esp_wifi.h>
#include <esp_wifi_types.h>
#include <esp_system.h>
#include <esp_event.h>
#include <esp_event_loop.h>
#include <esp_spi_flash.h>
configData_t cfg; // struct holds current device configuration
osjob_t sendjob, initjob; // LMIC
// Initialize global variables
int macnum = 0, blenum = 0;
uint32_t uptimecounter = 0;
bool joinstate = false;
extern uint8_t mydata[];
std::set<uint64_t, std::greater <uint64_t> > macs; // storage holds MAC frames
// this variable will be changed in the ISR, and read in main loop
static volatile bool ButtonTriggered = false;
// local Tag for logging
static const char *TAG = "paxcnt";
// Note: Log level control seems working during runtime, so we need to switch loglevel
// by compiler build option in platformio.ini
#ifndef VERBOSE
int redirect_log(const char * fmt, va_list args) {
//do nothing
return 0;
}
#endif
// defined in configmanager.cpp
void eraseConfig(void);
void saveConfig(void);
void loadConfig(void);
/* begin LMIC specific parts ------------------------------------------------------------ */
// defined in lorawan.cpp
void gen_lora_deveui(uint8_t * pdeveui);
#ifdef VERBOSE
void printKeys(void);
#endif // VERBOSE
// LMIC callback functions
void os_getArtEui (u1_t *buf) { memcpy(buf, APPEUI, 8);}
void os_getDevKey (u1_t *buf) { memcpy(buf, APPKEY, 16);}
#ifdef DEVEUI // if DEVEUI defined in loraconf.h use that and hardwire it in code ...
void os_getDevEui (u1_t *buf) { memcpy(buf, DEVEUI, 8);}
#else // ... otherwise generate DEVEUI at runtime from devices's MAC
void os_getDevEui (u1_t *buf) { gen_lora_deveui(buf);}
#endif
// LMIC enhanced Pin mapping
const lmic_pinmap lmic_pins = {
.mosi = PIN_SPI_MOSI,
.miso = PIN_SPI_MISO,
.sck = PIN_SPI_SCK,
.nss = PIN_SPI_SS,
.rxtx = LMIC_UNUSED_PIN,
.rst = RST,
.dio = {DIO0, DIO1, DIO2}
};
// LMIC functions
void onEvent(ev_t ev);
void do_send(osjob_t* j);
// LoRaWAN Initjob
static void lora_init (osjob_t* j) {
// reset MAC state
LMIC_reset();
// This tells LMIC to make the receive windows bigger, in case your clock is 1% faster or slower.
LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);
// start joining
LMIC_startJoining();
}
// LMIC Task
void lorawan_loop(void * pvParameters) {
configASSERT( ( ( uint32_t ) pvParameters ) == 1 ); // FreeRTOS check
while(1) {
os_runloop_once();
vTaskDelay(10/portTICK_PERIOD_MS);
yield();
}
}
/* end LMIC specific parts --------------------------------------------------------------- */
/* beginn hardware specific parts -------------------------------------------------------- */
#ifdef LOPY
// defined in antenna.cpp
void antenna_init (void);
void antenna_select (antenna_type_t antenna_type);
#endif
#if defined BLECOUNTER
void BLECount(void);
#else
btStop();
#endif
void set_onboard_led(int st){
#ifdef HAS_LED
switch (st) {
case 1: digitalWrite(LED_BUILTIN, HIGH); break;
case 0: digitalWrite(LED_BUILTIN, LOW); break;
}
#endif
};
#ifdef HAS_BUTTON
// Button Handling, board dependent -> perhaps to be moved to new hal.cpp
// IRAM_ATTR necessary here, see https://github.com/espressif/arduino-esp32/issues/855
void IRAM_ATTR isr_button_pressed(void) {
ButtonTriggered++; }
#endif
/* end hardware specific parts -------------------------------------------------------- */
/* begin wifi specific parts ---------------------------------------------------------- */
// defined in wifisniffer.cpp
void wifi_sniffer_init(void);
void wifi_sniffer_set_channel(uint8_t channel);
void wifi_sniffer_packet_handler(void *buff, wifi_promiscuous_pkt_type_t type);
//WiFi Sniffer Task
void wifi_sniffer_loop(void * pvParameters) {
configASSERT( ( ( uint32_t ) pvParameters ) == 1 ); // FreeRTOS check
uint8_t channel = 1;
int nloop=0, lorawait=0;
while (true) {
nloop++;
vTaskDelay(cfg.wifichancycle*10 / portTICK_PERIOD_MS);
yield();
wifi_sniffer_set_channel(channel);
channel = (channel % WIFI_CHANNEL_MAX) + 1;
// duration of one wifi scan loop reached? then send data and begin new scan cycle
if( nloop >= ((100 / cfg.wifichancycle) * (cfg.wifiscancycle * 2)) ) {
u8x8.setPowerSave(!cfg.screenon); // set display on if enabled
nloop = 0; // reset wlan sniffing loop counter
// execute BLE count if BLE function is enabled
#ifdef BLECOUNTER
if ( cfg.blescan )
BLECount();
#endif
// Prepare and execute LoRaWAN data upload
u8x8.setCursor(0,4);
u8x8.printf("MAC#: %4i", macnum);
do_send(&sendjob); // send payload
vTaskDelay(500/portTICK_PERIOD_MS);
yield();
// clear counter if not in cumulative counter mode
if ( cfg.countermode != 1 ) {
macs.erase(macs.begin(), macs.end()); // clear RAM
macnum = 0;
u8x8.clearLine(0); u8x8.clearLine(1); // clear Display counter
}
// wait until payload is sent, while wifi scanning and mac counting task continues
lorawait = 0;
while(LMIC.opmode & OP_TXRXPEND) {
if(!lorawait) u8x8.drawString(0,6,"LoRa wait ");
lorawait++;
// in case sending really fails: reset and rejoin network
if( (lorawait % MAXLORARETRY ) == 0) {
ESP_LOGI(TAG, "Payload not sent, trying reset and rejoin");
esp_restart();
};
vTaskDelay(1000/portTICK_PERIOD_MS);
yield();
}
u8x8.clearLine(6);
if (cfg.screenon && cfg.screensaver) vTaskDelay(2000/portTICK_PERIOD_MS); // pause for displaying results
yield();
u8x8.setPowerSave(1 && cfg.screensaver); // set display off if screensaver is enabled
}
}
}
/* end wifi specific parts ------------------------------------------------------------ */
// uptime counter 64bit to prevent millis() rollover after 49 days
uint64_t uptime() {
static uint32_t low32, high32;
uint32_t new_low32 = millis();
if (new_low32 < low32) high32++;
low32 = new_low32;
return (uint64_t) high32 << 32 | low32;
}
// Print a key on display
void DisplayKey(const uint8_t * key, uint8_t len, bool lsb) {
uint8_t start=lsb?len:0;
uint8_t end = lsb?0:len;
const uint8_t * p ;
for (uint8_t i=0; i<len ; i++) {
p = lsb ? key+len-i-1 : key+i;
u8x8.printf("%02X", *p);
}
u8x8.printf("\n");
}
void init_display(const char *Productname, const char *Version) {
u8x8.begin();
u8x8.setFont(u8x8_font_chroma48medium8_r);
#ifdef HAS_DISPLAY
uint8_t buf[32];
u8x8.clear();
u8x8.setFlipMode(0);
u8x8.setInverseFont(1);
u8x8.draw2x2String(0, 0, Productname);
u8x8.setInverseFont(0);
u8x8.draw2x2String(2, 2, Productname);
delay(1500);
u8x8.clear();
u8x8.setFlipMode(1);
u8x8.setInverseFont(1);
u8x8.draw2x2String(0, 0, Productname);
u8x8.setInverseFont(0);
u8x8.draw2x2String(2, 2, Productname);
delay(1500);
u8x8.setFlipMode(0);
u8x8.clear();
// Display chip information
#ifdef VERBOSE
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
u8x8.printf("ESP32 %d cores\nWiFi%s%s\n",
chip_info.cores,
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
u8x8.printf("ESP Rev.%d\n", chip_info.revision);
u8x8.printf("%dMB %s Flash\n", spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "int." : "ext.");
#endif // VERBOSE
u8x8.print(Productname);
u8x8.print(" v");
u8x8.println(PROGVERSION);
u8x8.println("DEVEUI:");
os_getDevEui((u1_t*) buf);
DisplayKey(buf, 8, true);
delay(5000);
u8x8.clear();
#endif // HAS_DISPLAY
}
/* begin Aruino SETUP ------------------------------------------------------------ */
void setup() {
// setup debug output or silence device
#ifdef VERBOSE
Serial.begin(115200);
esp_log_level_set("*", ESP_LOG_VERBOSE);
#else
// mute logs completely by redirecting them to silence function
esp_log_level_set("*", ESP_LOG_NONE);
esp_log_set_vprintf(redirect_log);
#endif
ESP_LOGI(TAG, "Starting %s %s", PROGNAME, PROGVERSION);
// ESP Event Loop
esp_event_loop_init(NULL, NULL);
// Print chip information on startup
#ifdef VERBOSE
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
ESP_LOGI(TAG, "This is ESP32 chip with %d CPU cores, WiFi%s%s, silicon revision %d, %dMB %s Flash",
chip_info.cores,
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "",
chip_info.revision, spi_flash_get_chip_size() / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
#endif // VERBOSE
// Read settings from NVRAM
loadConfig(); // includes initialize if necessary
// initialize hardware -> perhaps to be moved to new hal.cpp
#ifdef HAS_LED
// initialize LED
pinMode(LED_BUILTIN, OUTPUT); // white LED on Heltec board
digitalWrite(LED_BUILTIN, LOW);
#endif
#ifdef HAS_BUTTON
// install button interrupt
pinMode(GPIO_NUM_0, INPUT_PULLDOWN); // button "PROG" on Heltec board
attachInterrupt(digitalPinToInterrupt(GPIO_NUM_0), isr_button_pressed, FALLING);
#endif
// initialize wifi antenna
#ifdef LOPY
antenna_init();
antenna_select(WIFI_LOPY_ANTENNA);
#endif
// initialize display
init_display(PROGNAME, PROGVERSION);
u8x8.setPowerSave(!cfg.screenon); // set display off if disabled
u8x8.setCursor(0,5);
u8x8.printf(!cfg.rssilimit ? "RLIM: off" : "RLIM: %4i", cfg.rssilimit);
u8x8.drawString(0,6,"Join Wait ");
// output LoRaWAN keys to console
#ifdef VERBOSE
printKeys();
#endif // VERBOSE
os_init(); // setup LMIC
os_setCallback(&initjob, lora_init); // setup initial job & join network
wifi_sniffer_init(); // setup wifi in monitor mode and start MAC counting
// Start FreeRTOS tasks
#if CONFIG_FREERTOS_UNICORE // run all tasks on core 0 and switch off core 1
ESP_LOGI(TAG, "Starting Lora task on core 0");
xTaskCreatePinnedToCore(lorawan_loop, "loratask", 2048, ( void * ) 1, ( 5 | portPRIVILEGE_BIT ), NULL, 0);
ESP_LOGI(TAG, "Starting Wifi task on core 0");
xTaskCreatePinnedToCore(wifi_sniffer_loop, "wifisniffer", 4096, ( void * ) 1, 1, NULL, 0);
// to come here: code for switching off core 1
#else // run wifi task on core 0 and lora task on core 1
ESP_LOGI(TAG, "Starting Lora task on core 1");
xTaskCreatePinnedToCore(lorawan_loop, "loratask", 2048, ( void * ) 1, ( 5 | portPRIVILEGE_BIT ), NULL, 1);
ESP_LOGI(TAG, "Starting Wifi task on core 0");
xTaskCreatePinnedToCore(wifi_sniffer_loop, "wifisniffer", 4096, ( void * ) 1, 1, NULL, 0);
#endif
// Kickoff first sendjob, use payload "0000"
uint8_t mydata[] = "0000";
do_send(&sendjob);
}
/* end Aruino SETUP ------------------------------------------------------------ */
/* begin Aruino LOOP ------------------------------------------------------------ */
// Arduino main moop, runs on core 1
// https://techtutorialsx.com/2017/05/09/esp32-get-task-execution-core/
void loop() {
while(1) {
if (ButtonTriggered) {
ButtonTriggered = false;
ESP_LOGI(TAG, "Button pressed, resetting device to factory defaults");
eraseConfig();
esp_restart();
}
else {
vTaskDelay(1000/portTICK_PERIOD_MS);
uptimecounter = uptime() / 1000; // count uptime seconds
}
}
}
/* end Aruino LOOP ------------------------------------------------------------ */
+104
View File
@@ -0,0 +1,104 @@
// program version
#define PROGVERSION "1.2.0" // use max 10 chars here!
#define PROGNAME "PAXCNT"
// Verbose enables serial output
#define VERBOSE 1 // comment out to silence the device, for mute use build option
// set this to include BLE counting and vendor filter functions
#define VENDORFILTER 1 // comment out if you want to count things, not people
#define BLECOUNTER 1 // comment out if you don't want BLE count
// BLE scan time
#define BLESCANTIME 30 // [seconds]
// WiFi Sniffer cycle interval
#define SEND_SECS 120 // [seconds/2] -> 240 sec.
// WiFi sniffer config
#define WIFI_CHANNEL_MAX 13
#define WIFI_CHANNEL_SWITCH_INTERVAL 50 // [seconds/100] -> 0,5 sec.
// Default LoRa Spreadfactor
#define LORASFDEFAULT 9 // 7 ... 12
#define MAXLORARETRY 500 // maximum count of TX retries if LoRa busy
#define RCMDPORT 2 // LoRaWAN Port on which device listenes for remote commands
// LMIC settings
// define hardware independent LMIC settings here, settings of standard library in /lmic/config.h will be ignored
// define hardware specifics settings in platformio.ini as build_flag for hardware environment
#define CFG_eu868 1
//#define CFG_us915 1
// This is the SX1272/SX1273 radio, which is also used on the HopeRF
// RFM92 boards.
//#define CFG_sx1272_radio 1
// This is the SX1276/SX1277/SX1278/SX1279 radio, which is also used on
// the HopeRF RFM95 boards.
//#define CFG_sx1276_radio 1
// 16 μs per tick
// LMIC requires ticks to be 15.5μs - 100 μs long
#define US_PER_OSTICK_EXPONENT 4
#define US_PER_OSTICK (1 << US_PER_OSTICK_EXPONENT)
#define OSTICKS_PER_SEC (1000000 / US_PER_OSTICK)
// Set this to 1 to enable some basic debug output (using printf) about
// RF settings used during transmission and reception. Set to 2 to
// enable more verbose output. Make sure that printf is actually
// configured (e.g. on AVR it is not by default), otherwise using it can
// cause crashing.
//#define LMIC_DEBUG_LEVEL 1
// Enable this to allow using printf() to print to the given serial port
// (or any other Print object). This can be easy for debugging. The
// current implementation only works on AVR, though.
//#define LMIC_PRINTF_TO Serial
// Any runtime assertion failures are printed to this serial port (or
// any other Print object). If this is unset, any failures just silently
// halt execution.
#define LMIC_FAILURE_TO Serial
// Uncomment this to disable all code related to joining
//#define DISABLE_JOIN
// Uncomment this to disable all code related to ping
#define DISABLE_PING
// Uncomment this to disable all code related to beacon tracking.
// Requires ping to be disabled too
#define DISABLE_BEACONS
// Uncomment these to disable the corresponding MAC commands.
// Class A
//#define DISABLE_MCMD_DCAP_REQ // duty cycle cap
//#define DISABLE_MCMD_DN2P_SET // 2nd DN window param
//#define DISABLE_MCMD_SNCH_REQ // set new channel
// Class B
//#define DISABLE_MCMD_PING_SET // set ping freq, automatically disabled by DISABLE_PING
//#define DISABLE_MCMD_BCNI_ANS // next beacon start, automatical disabled by DISABLE_BEACON
// In LoRaWAN, a gateway applies I/Q inversion on TX, and nodes do the
// same on RX. This ensures that gateways can talk to nodes and vice
// versa, but gateways will not hear other gateways and nodes will not
// hear other nodes. By uncommenting this macro, this inversion is
// disabled and this node can hear other nodes. If two nodes both have
// this macro set, they can talk to each other (but they can no longer
// hear gateways). This should probably only be used when debugging
// and/or when talking to the radio directly (e.g. like in the "raw"
// example).
//#define DISABLE_INVERT_IQ_ON_RX
// This allows choosing between multiple included AES implementations.
// Make sure exactly one of these is uncommented.
//
// This selects the original AES implementation included LMIC. This
// implementation is optimized for speed on 32-bit processors using
// fairly big lookup tables, but it takes up big amounts of flash on the
// AVR architecture.
// #define USE_ORIGINAL_AES
//
// This selects the AES implementation written by Ideetroon for their
// own LoRaWAN library. It also uses lookup tables, but smaller
// byte-oriented ones, making it use a lot less flash space (but it is
// also about twice as slow as the original).
#define USE_IDEETRON_AES
+214
View File
@@ -0,0 +1,214 @@
// remote command interpreter
// parses multiple number of command / value pairs from LoRaWAN remote command port (RCMDPORT)
// checks commands and executes each command with 1 argument per command
#include "globals.h"
// Local logging tag
static const char *TAG = "rcommand";
// functions defined in configmanager.cpp
void eraseConfig(void);
void saveConfig(void);
// table of remote commands and assigned functions
typedef struct {
const int nam;
void (*func)(int);
const bool store;
} cmd_t;
// help function to assign LoRa datarates to spreadfactor values
void switch_lora (int sf, int 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: LMIC_setDrTxpow(DR_SF11,tx); cfg.lorasf=sf; break;
case 12: LMIC_setDrTxpow(DR_SF12,tx); cfg.lorasf=sf; break;
default: break;
}
}
// set of functions that can be triggered by remote commands
void set_reset(int val) {
switch (val) {
case 0: // restart device
ESP_LOGI(TAG, "Remote command: restart device");
u8x8.clearLine(5);
u8x8.setCursor(0, 5);
u8x8.printf("Reset pending ");
vTaskDelay(10000/portTICK_PERIOD_MS); // wait for LMIC to confirm LoRa downlink to server
esp_restart();
break;
case 1: // reset MAC counter
ESP_LOGI(TAG, "Remote command: reset MAC counter");
macs.erase(macs.begin(), macs.end()); // clear RAM
macnum = 0;
u8x8.clearLine(0); u8x8.clearLine(1); // clear Display counter
u8x8.clearLine(5);
u8x8.setCursor(0, 5);
u8x8.printf("Reset counter ");
break;
case 2: // reset device to factory settings
ESP_LOGI(TAG, "Remote command: reset device to factory settings");
u8x8.clearLine(5);
u8x8.setCursor(0, 5);
u8x8.printf("Factory reset ");
eraseConfig();
break;
}
};
void set_rssi(int val) {
cfg.rssilimit = val * -1;
ESP_LOGI(TAG, "Remote command: set RSSI limit to %i", cfg.rssilimit);
u8x8.clearLine(5);
u8x8.setCursor(0, 5);
u8x8.printf(!cfg.rssilimit ? "RLIM: off" : "RLIM: -%4i", cfg.rssilimit);
};
void set_wifiscancycle(int val) {
cfg.wifiscancycle = val;
ESP_LOGI(TAG, "Remote command: set Wifi scan cycle duration to %i seconds", cfg.wifiscancycle*2);
};
void set_wifichancycle(int val) {
cfg.wifichancycle = val;
ESP_LOGI(TAG, "Remote command: set Wifi channel switch interval to %i seconds", cfg.wifichancycle/100);
};
void set_blescancycle(int val) {
cfg.blescancycle = val;
ESP_LOGI(TAG, "Remote command: set Wifi channel cycle duration to %i seconds", cfg.blescancycle);
};
void set_countmode(int val) {
switch (val) {
case 0: // cyclic unconfirmed
cfg.countermode = 0;
ESP_LOGI(TAG, "Remote command: set counter mode to cyclic unconfirmed");
break;
case 1: // cumulative
cfg.countermode = 1;
ESP_LOGI(TAG, "Remote command: set counter mode to cumulative");
break;
default: // cyclic confirmed
cfg.countermode = 2;
ESP_LOGI(TAG, "Remote command: set counter mode to cyclic confirmed");
break;
}
};
void set_screensaver(int val) {
ESP_LOGI(TAG, "Remote command: set screen saver to %s ", val ? "on" : "off");
switch (val) {
case 1: cfg.screensaver = val; break;
default: cfg.screensaver = 0; break;
}
u8x8.setPowerSave(cfg.screensaver); // set display 0=on / 1=off
};
void set_display(int val) {
ESP_LOGI(TAG, "Remote command: set screen to %s", val ? "on" : "off");
switch (val) {
case 1: cfg.screenon = val; break;
default: cfg.screenon = 0; break;
}
u8x8.setPowerSave(!cfg.screenon); // set display 0=on / 1=off
};
void set_lorasf(int val) {
ESP_LOGI(TAG, "Remote command: set LoRa SF to %i", val);
switch_lora(val, cfg.txpower);
};
void set_loraadr(int val) {
ESP_LOGI(TAG, "Remote command: set LoRa ADR mode to %s", val ? "on" : "off");
switch (val) {
case 1: cfg.adrmode = val; break;
default: cfg.adrmode = 0; break;
}
LMIC_setAdrMode(cfg.adrmode);
};
void set_blescan(int val) {
ESP_LOGI(TAG, "Remote command: set BLE scan mode to %s", val ? "on" : "off");
switch (val) {
case 1: cfg.blescan = val; break;
default:
cfg.blescan = 0;
btStop();
u8x8.clearLine(3); // clear BLE results from display
break;
}
};
void set_lorapower(int val) {
ESP_LOGI(TAG, "Remote command: set LoRa TXPOWER to %i", val);
switch_lora(cfg.lorasf, val);
};
void set_noop (int val) {
ESP_LOGI(TAG, "Remote command: noop - doing nothing");
};
void get_config (int val) {
ESP_LOGI(TAG, "Remote command: get configuration");
int size = sizeof(configData_t);
// declare send buffer (char byte array)
unsigned char *sendData = new unsigned char[size];
// copy current configuration (struct) to send buffer
memcpy(sendData, &cfg, size);
LMIC_setTxData2(RCMDPORT, sendData, size-1, 0); // send data unconfirmed on RCMD Port
delete sendData; // free memory
ESP_LOGI(TAG, "Configuration data queued in send queue");
};
void get_uptime (int val) {
ESP_LOGI(TAG, "Remote command: get uptime");
int size = sizeof(uptimecounter);
unsigned char *sendData = new unsigned char[size];
memcpy(sendData, (unsigned char*)&uptimecounter, size);
LMIC_setTxData2(RCMDPORT, sendData, size-1, 0); // send data unconfirmed on RCMD Port
delete sendData; // free memory
ESP_LOGI(TAG, "Uptime queued in send queue");
};
// assign previously defined functions to set of numeric remote commands
// format: opcode, function, flag (1 = do make settings persistent / 0 = don't)
//
cmd_t table[] = {
{0x01, set_rssi, true},
{0x02, set_countmode, true},
{0x03, set_screensaver, true},
{0x04, set_display, true},
{0x05, set_lorasf, true},
{0x06, set_lorapower, true},
{0x07, set_loraadr, true},
{0x08, set_noop, false},
{0x09, set_reset, false},
{0x0a, set_wifiscancycle, true},
{0x0b, set_wifichancycle, true},
{0x0c, set_blescancycle, true},
{0x0d, set_blescan, true},
{0x80, get_config, false},
{0x81, get_uptime, false},
};
// check and execute remote command
void rcommand(int cmd, int arg) {
int i = sizeof(table) / sizeof(table[0]); // number of commands in command table
bool store_flag = false;
while(i--) {
if(cmd == table[i].nam) { // check if valid command
table[i].func(arg); // then execute assigned function
if ( table[i].store ) store_flag = true; // set save flag if function needs to store configuration
break; // exit check loop, since command was found
}
}
if (store_flag) saveConfig(); // if save flag is set: store new configuration in NVS to make it persistent
}
+1435
View File
File diff suppressed because it is too large. Load diff
+100
View File
@@ -0,0 +1,100 @@
#include "main.h"
#include <Arduino.h>
// Basic Config
#include "globals.h"
#include "loraconf.h"
// WiFi Functions
#include <esp_wifi.h>
#include <esp_wifi_types.h>
#include <esp_system.h>
#include <esp_event.h>
#include <esp_event_loop.h>
// Local logging tag
static const char *TAG = "wifisniffer";
static wifi_country_t wifi_country = {.cc="EU", .schan=1, .nchan=13, .policy=WIFI_COUNTRY_POLICY_AUTO};
#ifdef VENDORFILTER
#include <array>
#include <algorithm>
#include "vendor_array.h"
#endif
extern void wifi_sniffer_init(void);
extern void wifi_sniffer_set_channel(uint8_t channel);
extern void wifi_sniffer_packet_handler(void *buff, wifi_promiscuous_pkt_type_t type);
typedef struct {
unsigned frame_ctrl:16;
unsigned duration_id:16;
uint8_t addr1[6]; /* receiver address */
uint8_t addr2[6]; /* sender address */
uint8_t addr3[6]; /* filtering address */
unsigned sequence_ctrl:16;
uint8_t addr4[6]; /* optional */
} wifi_ieee80211_mac_hdr_t;
typedef struct {
wifi_ieee80211_mac_hdr_t hdr;
uint8_t payload[0]; /* network data ended with 4 bytes csum (CRC32) */
} wifi_ieee80211_packet_t;
void wifi_sniffer_init(void) {
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_country(&wifi_country) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_NULL) );
ESP_ERROR_CHECK( esp_wifi_start() );
ESP_ERROR_CHECK( esp_wifi_set_max_tx_power(-128) ); // we don't need to TX, so we use lowest power level to save energy
wifi_promiscuous_filter_t filter = {.filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT}; // we need only MGMT frames
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_filter(&filter)); // set MAC frame filter
ESP_ERROR_CHECK(esp_wifi_set_promiscuous_rx_cb(&wifi_sniffer_packet_handler));
ESP_ERROR_CHECK(esp_wifi_set_promiscuous(true));
}
void wifi_sniffer_set_channel(uint8_t channel) {
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
}
void wifi_sniffer_packet_handler(void* buff, wifi_promiscuous_pkt_type_t type) {
const wifi_promiscuous_pkt_t *ppkt = (wifi_promiscuous_pkt_t *)buff;
const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)ppkt->payload;
const wifi_ieee80211_mac_hdr_t *hdr = &ipkt->hdr;
char counter [10];
if (( cfg.rssilimit == 0 ) || (ppkt->rx_ctrl.rssi > cfg.rssilimit )) { // rssi is negative value
uint64_t addr2int = ( (uint64_t)hdr->addr2[0] ) | ( (uint64_t)hdr->addr2[1] << 8 ) | ( (uint64_t)hdr->addr2[2] << 16 ) | \
( (uint64_t)hdr->addr2[3] << 24 ) | ( (uint64_t)hdr->addr2[4] << 32 ) | ( (uint64_t)hdr->addr2[5] << 40 );
#ifdef VENDORFILTER
uint32_t vendor2int = ( (uint32_t)hdr->addr2[2] ) | ( (uint32_t)hdr->addr2[1] << 8 ) | ( (uint32_t)hdr->addr2[0] << 16 );
if ( std::find(vendors.begin(), vendors.end(), vendor2int) != vendors.end() ) {
#endif
macs.insert(addr2int);
// INFO: RSSI when adding MAC
ESP_LOGI(TAG, "WiFi RSSI: %02d", ppkt->rx_ctrl.rssi);
// if new unique MAC logged increment counter on display
if ( macs.size() > macnum ) {
macnum = macs.size();
itoa(macnum, counter, 10);
u8x8.draw2x2String(0, 0, counter);
ESP_LOGI(TAG, "MAC counter: %4i", macnum);
}
#ifdef VENDORFILTER
}
#endif
} else {
ESP_LOGI(TAG, "Ignoring RSSI %02d (limit: %i)", ppkt->rx_ctrl.rssi, cfg.rssilimit );
}
yield();
}