/* * * Oliver Brandmueller 2017/2018 * Klaus Wilting 2018 * * some lines of code taken from: * * Copyright (c) 2017, Ɓukasz Marcin Podkalicki * 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 // OLED driver #include #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 #include // Basic Config #include "loraconf.h" #include "configmanager.h" // WiFi Functions #include #include #include #include #include #include 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 > 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 to be checked */ // 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"); ESP_LOGI(TAG, "ESP32 SDK: %s", ESP.getSdkVersion()); #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 ------------------------------------------------------------ */