diff --git a/LICENSE b/LICENSE index 82a5eca3..aa52acab 100644 --- a/LICENSE +++ b/LICENSE @@ -228,13 +228,13 @@ under this Licence: Most source files in this repository are made available under the Eclipse Public License v1.0. The examples which use a more liberal license. Some of the AES code is available under the LGPL. Refer to each individual source file for more details." ------------------------------------------------------------------------------------------------ -blecount.cpp +blescan.cpp -Parts of blecount.cpp were derived or taken from +Parts of blescan.cpp were derived or taken from nkolban esp32 snippets -BLE Scan -https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils/tests/BLETests/Arduino/BLE_scan +BLE GAP DUMP +https://github.com/nkolban/esp32-snippets/tree/master/BLE/scanner under this Licence: diff --git a/README.md b/README.md index d5eb5b90..372fc03f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # ESP32-Paxcounter **Wifi & Bluetooth driven, LoRaWAN enabled, battery powered mini Paxcounter built on cheap ESP32 boards** +---> check branch "development" for latest alpha version <--- + # Use case @@ -20,13 +22,13 @@ This can all be done with a single small and cheap ESP32 board for less than $20 Currently supported IoT boards: - Heltec LoRa-32 {1} - TTGOv1 {1} -- TTGOv2 {1} +- TTGOv2 {1}{4} - Pycom LoPy {2} - Pycom LoPy4 {2} - LoLin32 with [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora) {2}{3} - LoLin32 Lite with [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora) {2}{3} -{1} on board OLED Display supported; {2} on board RGB LED supported; {3} on board Hardware unique DEVEUI supported +{1} on board OLED Display supported; {2} on board RGB LED supported; {3} on board Hardware unique DEVEUI supported; {4} special wiring needed, see instructions in /hal/ttgov2.h Target platform must be selected in [platformio.ini](https://github.com/cyberman54/ESP32-Paxcounter/blob/master/platformio.ini).
Hardware dependent settings (pinout etc.) are stored in board files in /hal directory.
@@ -36,15 +38,15 @@ Hardware dependent settings (pinout etc.) are stored in board files in /hal dire Power consumption: -- Heltec ~650mW -- TTGOv1 ~650mW -- TTGOv2 ~670mW -- LoPy with expansion board: ~530mW -- LoPy pure, without expansion board: ~460mW +- Heltec ~720mW +- TTGOv1 TBD +- TTGOv2 ~990mW +- LoPy with expansion board: ~690mW +- LoPy pure, without expansion board: TBD - LoLin32 with [LoraNode32 shield](https://github.com/hallard/LoLin32-Lora): TBD - LoLin32 Lite with [LoraNode32-Lite shield](https://github.com/hallard/LoLin32-Lite-Lora): TBD -These results where metered with software version 1.2.0 during active wifi scan, no LoRa TX’ing, OLED display off, 5V USB powered. +These results where metered with software version 1.2.97 while continuously scanning wifi and ble, no LoRa TX’ing, OLED display (if present) on, 5V USB powered. # Building @@ -62,8 +64,8 @@ If your device has silicon **Unique ID** which is stored in serial EEPROM Microc To upload the code to your ESP32 board this needs to be switched from run to bootloader mode. Boards with USB bridge like Heltec and TTGO usually have an onboard logic which allows soft switching by the upload tool. In PlatformIO this happenes automatically.

The LoPy/LoPy4 board needs to be set manually. See these -instructions how to do it.

-For the LoPy/LoPy4 the original Pycom firmware is not needed here, so there is no need to update it before flashing Paxcounter. Just flash the paxcounter code on your LoPy/LoPy4. If you want to go back to the Pycom firmware, no problem. Download the firmware from Pycom and flash it over. +instructions how to do it. Don't forget to press on board reset button after switching between run and bootloader mode.

+The original Pycom firmware is not needed, so there is no need to update it before flashing Paxcounter. Just flash the compiled paxcounter binary (.elf file) on your LoPy/LoPy4. If you later want to go back to the Pycom firmware, download the firmware from Pycom and flash it over. # Legal note @@ -102,10 +104,10 @@ Multiple command/parameter pairs can be concatenated and sent in one single payl Note: all settings are stored in NVRAM and will be reloaded when device starts. To reset device to factory settings press button (if device has one), or send remote command 09 02 09 00 unconfirmed(!) once. -0x01 set Wifi scan RSSI limit +0x01 set scan RSSI limit - 1 ... 255 used for wifi scan radius (greater values increase wifi scan radius, values 50...110 make sense) - 0 = Wifi rssi limiter disabled [default] + 1 ... 255 used for wifi and bluetooth scan radius (greater values increase scan radius, values 50...110 make sense) + 0 = RSSI limiter disabled [default] 0x02 set counter mode @@ -113,7 +115,7 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts. 1 = cumulative counter, mac counter is never reset 2 = cyclic confirmed, like 0 but data is resent until confirmation by network received -0x03 set screen saver mode +0x03 (NOT YET IMPLEMENTED) set screen saver mode 0 = screen saver off [default] 1 = screen saver on @@ -161,12 +163,12 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts. 0x0C set BLE scan cycle timer 0 ... 255 duration of a BLE scan cycle in seconds - e.g. 15 -> 1 cycle runs for 15 seconds [default] + e.g. 11 -> 1 cycle runs for 11 seconds [default] -0x0D set BLE scan cycle frequency +0x0D (NOT YET IMPLEMENTED) set BLE and WIFI vendorfilter mode - run BLE scan once after 0 ... 255 full wifi scans - e.g. 2 -> BLE scan runs once after each 2nd wifi scan [default] + 0 = disabled (use to count devices, not people) + 1 = enabled [default] 0x0E set BLE scan mode @@ -197,9 +199,9 @@ device answers with it's current configuration. The configuration is a C structu byte 9: Wifi scan cycle duration in seconds/2 (0..255) byte 10: Wifi channel switch interval in seconds/100 (0..255) byte 11: BLE scan cycle duration in seconds (0..255) - byte 12: BLE scan frequency, do once after (0..255) full wifi scans - byte 13: BLE scan mode (1=on, 0=0ff) - byte 14: Wifi antenna switch (0=internal, 1=external) + byte 12: BLE scan mode (1=on, 0=0ff) + byte 13: Wifi antenna switch (0=internal, 1=external) + byte 14: Vendorfilter mode (0=disabled, 1=enabled) byte 15: RGB LED luminosity (0..100 %) bytes 16-25: Software version (ASCII format) diff --git a/platformio.ini b/platformio.ini index 329190a2..fff50de0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,6 +8,7 @@ ; Please visit documentation for the other options and examples ; http://docs.platformio.org/page/projectconf.html + ; ---> SELECT TARGET PLATFORM HERE! <--- [platformio] env_default = heltec_wifi_lora_32 @@ -17,185 +18,115 @@ env_default = heltec_wifi_lora_32 ;env_default = lopy4 ;env_default = lolin32lite_lora ;env_default = lolin32_lora +; +description = Paxcounter is a proof-of-concept ESP32 device for metering passenger flows in realtime. It counts how many mobile devices are around. + +[common_env_data] +lib_deps_display = + U8g2@>=2.22.14 +lib_deps_rgbled = + SmartLeds +build_flags = +; we need build_flag for logging, otherwise we can't use ESP_LOGx in arduino framework +; ---> NOTE: For production run set DEBUG_LEVEL level to NONE! <--- +; otherwise device may crash in dense environments due to serial buffer overflow +; + -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE +; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO +; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE +; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG +; +; override lora settings from LMiC library in lmic/config.h and use main.h instead + -D_lmic_config_h_ + -include "src/main.h" [env:heltec_wifi_lora_32] platform = espressif32 -board = heltec_wifi_lora_32 framework = arduino +board = heltec_wifi_lora_32 monitor_baud = 115200 -upload_speed = 921600 +upload_speed = 115200 lib_deps = - U8g2 - ESP32 BLE Arduino@>=0.4.9 + ${common_env_data.lib_deps_display} build_flags = -;set log level, we need build_flag for this, otherwise we can't use ESP_LOGx in arduino framework - -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO -; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE -; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE -;needed for ESP32 BLE Ardunio v0.4.9 - -fexceptions - -std=c++11 -;override lora settings from LMiC library in lmic/config.h and use main.h instead - -D_lmic_config_h_ + ${common_env_data.build_flags} -Dheltec_wifi_lora_32 - -include "src/main.h" -include "src/hal/heltec.h" -;FreeRTOS single core operation, switches off core 1 (see arduino-esp32/cores/esp32/main.cpp) -; -DCONFIG_FREERTOS_UNICORE [env:ttgov1] platform = espressif32 -board = esp32dev framework = arduino +board = esp32dev monitor_baud = 115200 -; On my V1, upload does not works over default 115200 -upload_speed = 921600 -;upload_port = COM15 +upload_speed = 115200 lib_deps = - U8g2 - ESP32 BLE Arduino@>=0.4.9 + ${common_env_data.lib_deps_display} build_flags = -;set log level, we need build_flag for this, otherwise we can't use ESP_LOGx in arduino framework - -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO -; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE -; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE -;needed for ESP32 BLE Ardunio v0.4.9 - -fexceptions - -std=c++11 -;override lora settings from LMiC library in lmic/config.h and use main.h instead + ${common_env_data.build_flags} -Dttgov1 - -D_lmic_config_h_ - -include "src/main.h" -include "src/hal/ttgov1.h" -;FreeRTOS single core operation, switches off core 1 (see arduino-esp32/cores/esp32/main.cpp) -; -DCONFIG_FREERTOS_UNICORE - [env:ttgov2] platform = espressif32 -board = esp32dev framework = arduino +board = esp32dev monitor_baud = 115200 upload_speed = 921600 lib_deps = - U8g2 - ESP32 BLE Arduino@>=0.4.9 + ${common_env_data.lib_deps_display} build_flags = -;set log level, we need build_flag for this, otherwise we can't use ESP_LOGx in arduino framework - -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO -; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE -; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE -;needed for ESP32 BLE Ardunio v0.4.9 - -fexceptions - -std=c++11 -;override lora settings from LMiC library in lmic/config.h and use main.h instead - -D_lmic_config_h_ + ${common_env_data.build_flags} -Dttgov2 - -include "src/main.h" -include "src/hal/ttgov2.h" -;FreeRTOS single core operation, switches off core 1 (see arduino-esp32/cores/esp32/main.cpp) -; -DCONFIG_FREERTOS_UNICORE [env:lopy] platform = espressif32 -board = esp32dev framework = arduino +board = esp32dev monitor_baud = 115200 upload_speed = 921600 lib_deps = - U8g2@>2.21.7 - ESP32 BLE Arduino@>=0.4.9 - SmartLeds + ${common_env_data.lib_deps_rgbled} build_flags = -;set log level, we need build_flag for this, otherwise we can't use ESP_LOGx in arduino framework - -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO -; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE -; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE -;needed for ESP32 BLE Ardunio v0.4.9 - -fexceptions - -std=c++11 -;override lora settings from LMiC library in lmic/config.h and use main.h instead + ${common_env_data.build_flags} -Dlopy - -D_lmic_config_h_ - -include "src/main.h" -include "src/hal/lopy.h" -;FreeRTOS single core operation, switches off core 1 (see arduino-esp32/cores/esp32/main.cpp) -; -DCONFIG_FREERTOS_UNICORE [env:lopy4] platform = espressif32 -board = esp32dev framework = arduino +board = esp32dev monitor_baud = 115200 upload_speed = 921600 lib_deps = - U8g2@>2.21.7 - ESP32 BLE Arduino@>=0.4.9 - SmartLeds + ${common_env_data.lib_deps_rgbled} build_flags = -;set log level, we need build_flag for this, otherwise we can't use ESP_LOGx in arduino framework - -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO -; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE -; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE -;needed for ESP32 BLE Ardunio v0.4.9 - -fexceptions - -std=c++11 -;override lora settings from LMiC library in lmic/config.h and use main.h instead - -D_lmic_config_h_ + ${common_env_data.build_flags} -Dlopy4 - -include "src/main.h" -include "src/hal/lopy4.h" -;FreeRTOS single core operation, switches off core 1 (see arduino-esp32/cores/esp32/main.cpp) -; -DCONFIG_FREERTOS_UNICORE [env:lolin32lite_lora] platform = espressif32 -board = lolin32 framework = arduino +board = lolin32 monitor_baud = 115200 upload_speed = 256000 lib_deps = - U8g2 - ESP32 BLE Arduino@>=0.4.9 - SmartLeds + ${common_env_data.lib_deps_rgbled} build_flags = -;set log level, we need build_flag for this, otherwise we can't use ESP_LOGx in arduino framework - -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO -; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE -; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE -;needed for ESP32 BLE Ardunio v0.4.9 - -fexceptions - -std=c++11 -;override lora settings from LMiC library in lmic/config.h and use main.h instead - -D_lmic_config_h_ + ${common_env_data.build_flags} -Dlolin32lite_lora - -include "src/main.h" -include "src/hal/lolin32lite_lora.h" -;FreeRTOS single core operation, switches off core 1 (see arduino-esp32/cores/esp32/main.cpp) -; -DCONFIG_FREERTOS_UNICORE [env:lolin32_lora] platform = espressif32 +framework = arduino board = lolin32 -framework = arduino monitor_baud = 115200 upload_speed = 921600 lib_deps = - U8g2 - ESP32 BLE Arduino@>=0.4.9 - SmartLeds + ${common_env_data.lib_deps_rgbled} build_flags = -;set log level, we need build_flag for this, otherwise we can't use ESP_LOGx in arduino framework - -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO -; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE -; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE -;needed for ESP32 BLE Ardunio v0.4.9 - -fexceptions - -std=c++11 -;override lora settings from LMiC library in lmic/config.h and use main.h instead - -D_lmic_config_h_ + ${common_env_data.build_flags} -Dlolin32_lora - -include "src/main.h" - -include "src/hal/lolin32_lora.h" -;FreeRTOS single core operation, switches off core 1 (see arduino-esp32/cores/esp32/main.cpp) -; -DCONFIG_FREERTOS_UNICORE + -include "src/hal/lolin32_lora.h" \ No newline at end of file diff --git a/src/blecsan.cpp b/src/blecsan.cpp new file mode 100644 index 00000000..4e028aaf --- /dev/null +++ b/src/blecsan.cpp @@ -0,0 +1,293 @@ +#ifdef BLECOUNTER + +/* code snippets taken from +https://github.com/nkolban/esp32-snippets/tree/master/BLE/scanner +*/ + +// Basic Config +#include "globals.h" + +// Bluetooth specific includes +#include +#include +#include +#include // needed for BLE_ADDR types, do not remove +#include + +#define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] + +// local Tag for logging +static const char *TAG = "bt_loop"; + +// defined in macsniff.cpp +bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type); + +// Prototypes +static const char *bt_addr_t_to_string(esp_ble_addr_type_t type); +static const char *btsig_gap_type(uint32_t gap_type); +static void gap_callback_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); + +static const char *bt_addr_t_to_string(esp_ble_addr_type_t type) { + switch(type) { + case BLE_ADDR_TYPE_PUBLIC: + return "BLE_ADDR_TYPE_PUBLIC"; + case BLE_ADDR_TYPE_RANDOM: + return "BLE_ADDR_TYPE_RANDOM"; + case BLE_ADDR_TYPE_RPA_PUBLIC: + return "BLE_ADDR_TYPE_RPA_PUBLIC"; + case BLE_ADDR_TYPE_RPA_RANDOM: + return "BLE_ADDR_TYPE_RPA_RANDOM"; + default: + return "Unknown addr_t"; + } +} // bt_addr_t_to_string + +static const char *btsig_gap_type(uint32_t gap_type) { + switch (gap_type) + { + case 0x01: return "Flags"; + case 0x02: return "Incomplete List of 16-bit Service Class UUIDs"; + case 0x03: return "Complete List of 16-bit Service Class UUIDs"; + case 0x04: return "Incomplete List of 32-bit Service Class UUIDs"; + case 0x05: return "Complete List of 32-bit Service Class UUIDs"; + case 0x06: return "Incomplete List of 128-bit Service Class UUIDs"; + case 0x07: return "Complete List of 128-bit Service Class UUIDs"; + case 0x08: return "Shortened Local Name"; + case 0x09: return "Complete Local Name"; + case 0x0A: return "Tx Power Level"; + case 0x0D: return "Class of Device"; + case 0x0E: return "Simple Pairing Hash C/C-192"; + case 0x0F: return "Simple Pairing Randomizer R/R-192"; + case 0x10: return "Device ID/Security Manager TK Value"; + case 0x11: return "Security Manager Out of Band Flags"; + case 0x12: return "Slave Connection Interval Range"; + case 0x14: return "List of 16-bit Service Solicitation UUIDs"; + case 0x1F: return "List of 32-bit Service Solicitation UUIDs"; + case 0x15: return "List of 128-bit Service Solicitation UUIDs"; + case 0x16: return "Service Data - 16-bit UUID"; + case 0x20: return "Service Data - 32-bit UUID"; + case 0x21: return "Service Data - 128-bit UUID"; + case 0x22: return "LE Secure Connections Confirmation Value"; + case 0x23: return "LE Secure Connections Random Value"; + case 0x24: return "URI"; + case 0x25: return "Indoor Positioning"; + case 0x26: return "Transport Discovery Data"; + case 0x17: return "Public Target Address"; + case 0x18: return "Random Target Address"; + case 0x19: return "Appearance"; + case 0x1A: return "Advertising Interval"; + case 0x1B: return "LE Bluetooth Device Address"; + case 0x1C: return "LE Role"; + case 0x1D: return "Simple Pairing Hash C-256"; + case 0x1E: return "Simple Pairing Randomizer R-256"; + case 0x3D: return "3D Information Data"; + case 0xFF: return "Manufacturer Specific Data"; + + default: + return "Unknown type"; + } +} // btsig_gap_type + + +static void gap_callback_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) +{ + esp_ble_gap_cb_param_t *p = (esp_ble_gap_cb_param_t *)param; + esp_err_t status; + + ESP_LOGD(tag, "BT payload rcvd -> type: 0x%.2x -> %s", *p->scan_rst.ble_adv, btsig_gap_type(*p->scan_rst.ble_adv)); + + switch (event) + { + case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: + { // restart scan + status = esp_ble_gap_start_scanning(BLESCANTIME); + if (status != ESP_OK) + { + ESP_LOGE(TAG, "esp_ble_gap_start_scanning: rc=%d", status); + } + } + break; + + case ESP_GAP_BLE_SCAN_RESULT_EVT: + { + if ( p->scan_rst.search_evt == ESP_GAP_SEARCH_INQ_CMPL_EVT) // Inquiry complete, scan is done + { // restart scan + status = esp_ble_gap_start_scanning (BLESCANTIME); + if (status != ESP_OK) + { + ESP_LOGE(TAG, "esp_ble_gap_start_scanning: rc=%d", status); + } + return; + } + + if (p->scan_rst.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) // Inquiry result for a peer device + { // evaluate sniffed packet + ESP_LOGD(TAG, "Device address (bda): %02x:%02x:%02x:%02x:%02x:%02x", BT_BD_ADDR_HEX(p->scan_rst.bda)); + ESP_LOGD(TAG, "Addr_type : %s", bt_addr_t_to_string(p->scan_rst.ble_addr_type)); + ESP_LOGD(TAG, "RSSI : %d", p->scan_rst.rssi); + + if (!( cfg.rssilimit == 0 ) || (p->scan_rst.rssi > cfg.rssilimit )) { // rssi is negative value + ESP_LOGI(TAG, "BLTH RSSI %d -> ignoring (limit: %d)", p->scan_rst.rssi, cfg.rssilimit); + break; + } + + #ifdef VENDORFILTER + + if (p->scan_rst.ble_addr_type == BLE_ADDR_TYPE_RANDOM) goto skip; + if (p->scan_rst.ble_addr_type == BLE_ADDR_TYPE_RPA_RANDOM) goto skip; + + #endif + + // add this device and show new count total if it was not previously added + if (cfg.blescan) // count only if BLE scan is enabled + mac_add((uint8_t *) p->scan_rst.bda, p->scan_rst.rssi, MAC_SNIFF_BLE); + break; + + skip: + ESP_LOGD(TAG, "BT device filtered"); + break; + + + /* to be improved in vendorfilter if: + + // you can search for elements in the payload using the + // function esp_ble_resolve_adv_data() + // + // Like this, that scans for the "Complete name" (looking inside the payload buffer) + // uint8_t len; + // uint8_t *data = esp_ble_resolve_adv_data(p->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_CMPL, &len); + + filter BLE devices using their advertisements to get filter alternative to vendor OUI + if vendorfiltering is on, we ... + - want to count: mobile phones and tablets + - don't want to count: beacons, peripherals (earphones, headsets, printers), cars and machines + see + https://github.com/nkolban/ESP32_BLE_Arduino/blob/master/src/BLEAdvertisedDevice.cpp + + http://www.libelium.com/products/meshlium/smartphone-detection/ + + https://www.question-defense.com/2013/01/12/bluetooth-cod-bluetooth-class-of-deviceclass-of-service-explained + + https://www.bluetooth.com/specifications/assigned-numbers/baseband + + "The Class of Device (CoD) in case of Bluetooth which allows us to differentiate the type of + device (smartphone, handsfree, computer, LAN/network AP). With this parameter we can + differentiate among pedestrians and vehicles." + + */ + + } + + } + break; + + default: + break; + } +} // gap_callback_handler + + +esp_err_t register_ble_functionality(void) +{ + esp_err_t status; + + ESP_LOGI(TAG, "Register GAP callback"); + + // This function is called to occur gap event, such as scan result. + //register the scan callback function to the gap module + status = esp_ble_gap_register_callback(gap_callback_handler); + if (status != ESP_OK) + { + ESP_LOGE(TAG, "esp_ble_gap_register_callback: rc=%d", status); + return ESP_FAIL; + } + + static esp_ble_scan_params_t ble_scan_params = + { + .scan_type = BLE_SCAN_TYPE_PASSIVE, + .own_addr_type = BLE_ADDR_TYPE_RANDOM, + + #ifdef VENDORFILTER + .scan_filter_policy = BLE_SCAN_FILTER_ALLOW_WLIST_PRA_DIR, + // ADV_IND, ADV_NONCONN_IND, ADV_SCAN_IND packets are used for broadcasting + // data in broadcast applications (e.g., Beacons), so we don't want them in vendorfilter mode + #else + .scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL, + #endif + .scan_interval = (uint16_t) (BLESCANINTERVAL / 0.625), // Time = N * 0.625 msec + .scan_window = (uint16_t) (BLESCANWINDOW / 0.625) // Time = N * 0.625 msec + }; + + ESP_LOGI(TAG, "Set GAP scan parameters"); + + // This function is called to set scan parameters. + status = esp_ble_gap_set_scan_params(&ble_scan_params); + if (status != ESP_OK) + { + ESP_LOGE(TAG, "esp_ble_gap_set_scan_params: rc=%d", status); + return ESP_FAIL; + } + + return ESP_OK ; +} + + +// Main start code running in its own Xtask +void bt_loop(void *ignore) +{ + esp_err_t status; + + // Initialize BT controller to allocate task and other resource. + ESP_LOGI(TAG, "Enabling Bluetooth Controller"); + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + if (esp_bt_controller_init(&bt_cfg) != ESP_OK) + { + ESP_LOGE(TAG, "Bluetooth controller initialize failed"); + goto end; + } + + // Enable BT controller + if (esp_bt_controller_enable(ESP_BT_MODE_BTDM) != ESP_OK) + { + ESP_LOGE(TAG, "Bluetooth controller enable failed"); + goto end; + } + + // Init and alloc the resource for bluetooth, must be prior to every bluetooth stuff + ESP_LOGI(TAG, "Init Bluetooth stack"); + status = esp_bluedroid_init(); + if (status != ESP_OK) + { + ESP_LOGE(TAG, "%s init bluetooth failed\n", __func__); + goto end; + } + + // Enable bluetooth, must after esp_bluedroid_init() + status = esp_bluedroid_enable(); + if (status != ESP_OK) + { + ESP_LOGE(TAG, "%s enable bluetooth failed\n", __func__); + goto end; + } + + ESP_LOGI(TAG, "Register BLE functionality"); + status = register_ble_functionality(); + if (status != ESP_OK) + { + ESP_LOGE(TAG, "Register BLE functionality failed"); + goto end; + } + + while(1) + { + vTaskDelay(500/portTICK_PERIOD_MS); + yield(); + } + +end: + ESP_LOGI(TAG, "Terminating BT logging task"); + vTaskDelete(NULL); + +} // bt_loop + +#endif // BLECOUNTER \ No newline at end of file diff --git a/src/configmanager.cpp b/src/configmanager.cpp index 6227109e..49341163 100644 --- a/src/configmanager.cpp +++ b/src/configmanager.cpp @@ -28,9 +28,9 @@ void defaultConfig() { cfg.wifiscancycle = SEND_SECS; // wifi scan cycle [seconds/2] cfg.wifichancycle = WIFI_CHANNEL_SWITCH_INTERVAL; // wifi channel switch cycle [seconds/100] cfg.blescantime = BLESCANTIME; // BLE scan cycle duration [seconds] - cfg.blescancycle = BLESCANCYCLE; // do a BLE scan after [BLESCANCYCLE] full Wifi scan cycles cfg.blescan = 1; // 0=disabled, 1=enabled cfg.wifiant = 0; // 0=internal, 1=external (for LoPy/LoPy4) + cfg.vendorfilter = 1; // 0=disabled, 1=enabled cfg.rgblum = RGBLUMINOSITY; // RGB Led luminosity (0..100%) strncpy( cfg.version, PROGVERSION, sizeof(cfg.version)-1 ); @@ -108,15 +108,15 @@ void saveConfig() { if( nvs_get_i8(my_handle, "blescantime", &flash8) != ESP_OK || flash8 != cfg.blescantime ) nvs_set_i8(my_handle, "blescantime", cfg.blescantime); - 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_i8(my_handle, "wifiant", &flash8) != ESP_OK || flash8 != cfg.wifiant ) nvs_set_i8(my_handle, "wifiant", cfg.wifiant); + if( nvs_get_i8(my_handle, "vendorfilter", &flash8) != ESP_OK || flash8 != cfg.vendorfilter ) + nvs_set_i8(my_handle, "vendorfilter", cfg.vendorfilter); + if( nvs_get_i8(my_handle, "rgblum", &flash8) != ESP_OK || flash8 != cfg.rgblum ) nvs_set_i8(my_handle, "rgblum", cfg.rgblum); @@ -244,6 +244,14 @@ void loadConfig() { saveConfig(); } + if( nvs_get_i8(my_handle, "vendorfilter", &flash8) == ESP_OK ) { + cfg.vendorfilter = flash8; + ESP_LOGI(TAG, "vendorfilter = %i", flash8); + } else { + ESP_LOGI(TAG, "Vendorfilter mode set to default %i", cfg.vendorfilter); + saveConfig(); + } + if( nvs_get_i8(my_handle, "rgblum", &flash8) == ESP_OK ) { cfg.rgblum = flash8; ESP_LOGI(TAG, "rgbluminosity = %i", flash8); @@ -260,14 +268,6 @@ void loadConfig() { saveConfig(); } - if( nvs_get_i8(my_handle, "blescancycle", &flash8) == ESP_OK ) { - cfg.blescancycle = flash8; - ESP_LOGI(TAG, "blescancycle = %i", flash8); - } else { - ESP_LOGI(TAG, "BLEscancycle 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); @@ -287,8 +287,8 @@ void loadConfig() { nvs_close(my_handle); ESP_LOGI(TAG, "Done"); - // put actions to be triggered on loaded config here - u8x8.setPowerSave(!cfg.screenon); // set display on/off + // put actions to be triggered after config loaded here + #ifdef HAS_ANTENNA_SWITCH // set antenna type, if device has one antenna_select(cfg.wifiant); #endif diff --git a/src/globals.h b/src/globals.h index 396f7fa9..72598669 100644 --- a/src/globals.h +++ b/src/globals.h @@ -6,8 +6,10 @@ #include #include -// OLED Display -#include +#ifdef HAS_DISPLAY + // OLED Display + #include +#endif // LMIC-Arduino LoRaWAN Stack #include @@ -33,9 +35,9 @@ typedef struct { int8_t wifiscancycle; // wifi scan cycle [seconds/2] int8_t wifichancycle; // wifi channel switch cycle [seconds/100] int8_t blescantime; // BLE scan cycle duration [seconds] - int8_t blescancycle; // BLE scan frequency, once after [blescancycle] full wifi scans int8_t blescan; // 0=disabled, 1=enabled int8_t wifiant; // 0=internal, 1=external (for LoPy/LoPy4) + int8_t vendorfilter; // 0=disabled, 1=enabled int8_t rgblum; // RGB Led luminosity (0..100%) char version[10]; // Firmware version } configData_t; @@ -44,6 +46,7 @@ extern configData_t cfg; extern uint8_t mydata[]; extern uint64_t uptimecounter; extern osjob_t sendjob; +extern char display_lora[], display_lmic[]; extern int countermode, screensaver, adrmode, lorasf, txpower, rlim; extern bool joinstate; extern std::set wifis; @@ -51,11 +54,9 @@ extern std::set macs; #ifdef HAS_DISPLAY extern HAS_DISPLAY u8x8; -#else - extern U8X8_NULL u8x8; #endif #ifdef BLECOUNTER extern int scanTime; - extern std::set bles; + extern std::set bles; #endif diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 3d061893..fd8693e3 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -65,7 +65,7 @@ void get_hard_deveui(uint8_t *pdeveui) { Wire.requestFrom(MCP_24AA02E64_I2C_ADDRESS, 8); while (Wire.available()) { data = Wire.read(); - sprintf(deveui+strlen(deveui), "%02X ", data) ; + sprintf(deveui+strlen(deveui), "%02X ", data); *pdeveui++ = data; } i2c_ret = Wire.endTransmission(); @@ -135,15 +135,14 @@ void do_send(osjob_t* j){ //mydata[5] = data & 0xff; // Check if there is not a current TX/RX job running - u8x8.clearLine(7); if (LMIC.opmode & OP_TXRXPEND) { ESP_LOGI(TAG, "OP_TXRXPEND, not sending"); - u8x8.drawString(0, 7, "LORA BUSY"); + sprintf(display_lmic, "LORA BUSY"); } else { // Prepare upstream data transmission at the next possible time. LMIC_setTxData2(1, mydata, sizeof(mydata), (cfg.countermode & 0x02)); ESP_LOGI(TAG, "Packet queued"); - u8x8.drawString(0, 7, "PACKET QUEUED"); + sprintf(display_lmic, "PACKET QUEUED"); } // Next TX is scheduled after TX_COMPLETE event. } @@ -168,7 +167,7 @@ void onEvent (ev_t ev) { case EV_JOINED: strcpy_P(buff, PSTR("JOINED")); - u8x8.clearLine(6); // erase "Join Wait" message from display, see main.cpp + sprintf(display_lora, " "); // erase "Join Wait" message from display // Disable link check validation (automatically enabled // during join, but not supported by TTN at this time). LMIC_setLinkCheckMode(0); @@ -182,23 +181,21 @@ void onEvent (ev_t ev) { break; case EV_TXCOMPLETE: ESP_LOGI(TAG, "EV_TXCOMPLETE (includes waiting for RX windows)"); - u8x8.clearLine(7); if (LMIC.txrxFlags & TXRX_ACK) { ESP_LOGI(TAG, "Received ack"); - u8x8.drawString(0, 7, "RECEIVED ACK"); + sprintf(display_lmic, "RECEIVED ACK"); + } else { - u8x8.drawString(0, 7, "TX COMPLETE"); + sprintf(display_lmic, "TX COMPLETE"); } if (LMIC.dataLen) { ESP_LOGI(TAG, "Received %d bytes of payload", LMIC.dataLen); - u8x8.clearLine(6); - u8x8.setCursor(0, 6); - u8x8.printf("Rcvd %d bytes", LMIC.dataLen); - u8x8.clearLine(7); - u8x8.setCursor(0, 7); + sprintf(display_lora, "Rcvd %d bytes", LMIC.dataLen); + // 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); + sprintf(display_lmic, "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 @@ -217,8 +214,7 @@ void onEvent (ev_t ev) { // Log & Display if asked if (*buff) { ESP_LOGI(TAG, "EV_%s", buff); - u8x8.clearLine(7); - u8x8.drawString(0, 7, buff); + sprintf(display_lmic, buff); } diff --git a/src/macsniff.cpp b/src/macsniff.cpp index 624dcba3..6084d6be 100644 --- a/src/macsniff.cpp +++ b/src/macsniff.cpp @@ -2,13 +2,6 @@ // Basic Config #include "globals.h" -#ifdef BLECOUNTER - #include - #include - #include - #include -#endif - #ifdef VENDORFILTER #include #include @@ -20,7 +13,6 @@ static const char *TAG = "macsniff"; static wifi_country_t wifi_country = {.cc=WIFI_MY_COUNTRY, .schan=WIFI_CHANNEL_MIN, .nchan=WIFI_CHANNEL_MAX, .policy=WIFI_COUNTRY_POLICY_MANUAL}; -uint16_t currentScanDevice = 0; uint16_t salt; uint16_t salt_reset(void) { @@ -42,38 +34,40 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) { #ifdef VENDORFILTER vendor2int = ( (uint32_t)paddr[2] ) | ( (uint32_t)paddr[1] << 8 ) | ( (uint32_t)paddr[0] << 16 ); - // No vendor filter for BLE + // use OUI vendor filter list only on Wifi, not on BLE if ( (sniff_type==MAC_SNIFF_BLE) || std::find(vendors.begin(), vendors.end(), vendor2int) != vendors.end() ) { #endif - // salt and hash MAC, and if new unique one, store identifier in container and increment counter on display - // https://en.wikipedia.org/wiki/MAC_Address_Anonymization + // salt and hash MAC, and if new unique one, store identifier in container and increment counter on display + // https://en.wikipedia.org/wiki/MAC_Address_Anonymization - addr2int += (uint32_t) salt; // add 16-bit salt to pseudo MAC - snprintf(buff, sizeof(buff), "%08X", addr2int); // convert unsigned 32-bit salted MAC to 8 digit hex string - hashedmac = rokkit(&buff[3], 5); // hash MAC last string value, use 5 chars to fit hash in uint16_t container - auto newmac = macs.insert(hashedmac); // add hashed MAC to total container if new unique - added = newmac.second ? true:false; // true if hashed MAC is unique in container + addr2int += (uint32_t) salt; // add 16-bit salt to pseudo MAC + snprintf(buff, sizeof(buff), "%08X", addr2int); // convert unsigned 32-bit salted MAC to 8 digit hex string + hashedmac = rokkit(&buff[3], 5); // hash MAC last string value, use 5 chars to fit hash in uint16_t container + auto newmac = macs.insert(hashedmac); // add hashed MAC to total container if new unique + added = newmac.second ? true:false; // true if hashed MAC is unique in container - // Insert only if it was not found on global count - if (added) { - if (sniff_type == MAC_SNIFF_WIFI ) { - rgb_set_color(COLOR_GREEN); - wifis.insert(hashedmac); // add hashed MAC to wifi container if new unique - } - #ifdef BLECOUNTER - else if (sniff_type == MAC_SNIFF_BLE ) { - rgb_set_color(COLOR_MAGENTA); - bles.insert(hashedmac); // add hashed MAC to BLE container if new unique + // Insert only if it was not found on global count + if (added) { + + if (sniff_type == MAC_SNIFF_WIFI ) { + rgb_set_color(COLOR_GREEN); + wifis.insert(hashedmac); // add hashed MAC to wifi container + } + #ifdef BLECOUNTER + else if (sniff_type == MAC_SNIFF_BLE ) { + rgb_set_color(COLOR_MAGENTA); + bles.insert(hashedmac); // add hashed MAC to BLE container } - #endif - // Not sure user will have time to see the LED - // TBD do light off further in the code - rgb_set_color(COLOR_NONE); - } + #endif - ESP_LOGI(TAG, "%s RSSI %ddBi -> MAC %s -> Hash %04X -> WiFi:%d BLE:%d %s", - sniff_type==MAC_SNIFF_WIFI ? "WiFi":"BLE ", + // Not sure user will have time to see the LED + // TBD do light off further in the code + rgb_set_color(COLOR_NONE); + } + + ESP_LOGI(TAG, "%s RSSI %ddBi -> MAC %s -> Hash %04X -> WiFi:%d BLTH:%d %s", + sniff_type==MAC_SNIFF_WIFI ? "WiFi":"BLTH", rssi, buff, hashedmac, (int) wifis.size(), #ifdef BLECOUNTER @@ -81,12 +75,12 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) { #else 0, #endif - added ? "New" : "Already seen"); + added ? "new" : "known"); #ifdef VENDORFILTER } else { // Very noisy - //ESP_LOGI(TAG, "Filtered MAC %02X:%02X:%02X:%02X:%02X:%02X", paddr[0],paddr[1],paddr[2],paddr[3],paddr[5],paddr[5]); + // ESP_LOGD(TAG, "Filtered MAC %02X:%02X:%02X:%02X:%02X:%02X", paddr[0],paddr[1],paddr[2],paddr[3],paddr[5],paddr[5]); } #endif @@ -94,65 +88,6 @@ bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) { return added; // function returns bool if a new and unique Wifi or BLE mac was counted (true) or not (false) } -#ifdef BLECOUNTER - -class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { - void onResult(BLEAdvertisedDevice advertisedDevice) { - int lastcount = (int) macs.size(); - uint8_t *p = (uint8_t *) advertisedDevice.getAddress().getNative(); - - /* to be done here: - #ifdef VENDORFILTER - - filter BLE devices using their advertisements to get filter alternative to vendor OUI - if vendorfiltering is on, we ... - - want to count: mobile phones and tablets - - don't want to count: beacons, peripherals (earphones, headsets, printers), cars and machines - see - https://github.com/nkolban/ESP32_BLE_Arduino/blob/master/src/BLEAdvertisedDevice.cpp - - http://www.libelium.com/products/meshlium/smartphone-detection/ - - https://www.question-defense.com/2013/01/12/bluetooth-cod-bluetooth-class-of-deviceclass-of-service-explained - - https://www.bluetooth.com/specifications/assigned-numbers/baseband - - "The Class of Device (CoD) in case of Bluetooth which allows us to differentiate the type of - device (smartphone, handsfree, computer, LAN/network AP). With this parameter we can - differentiate among pedestrians and vehicles." - - #endif - */ - - // Current devices seen on this scan session - currentScanDevice++; - u8x8.setCursor(11,3); - u8x8.printf("%-4d", currentScanDevice); - // add this device and show new count total if it was not previously added - if ( mac_add(p, advertisedDevice.getRSSI(), MAC_SNIFF_BLE) ) { - char buff[16]; - snprintf(buff, sizeof(buff), "PAX:%-4d", (int) macs.size()); // convert 16-bit MAC counter to decimal counter value - u8x8.draw2x2String(0, 0, buff); // display number on unique macs total Wifi + BLE - } - } -}; - -void BLECount() { - ESP_LOGI(TAG, "BLE scan started"); - currentScanDevice = 0; // Set 0 seen device on this scan session - u8x8.drawString(0,3,"Scanning->"); - BLEDevice::init(""); // we don't want to be seen by a name - BLEScanResults foundDevices; // instance for getting count - BLEScan* pBLEScan = BLEDevice::getScan(); //create new scan - pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); - pBLEScan->setActiveScan(false); // An active scan would mean that we will wish unneeeded scan responses - pBLEScan->setWindow(BLESCANWINDOW); - pBLEScan->setInterval(BLESCANINTERVAL); - pBLEScan->start(cfg.blescantime); // note: this is a blocking call - ESP_LOGI(TAG, "BLE scan done, seen %d device(s)", foundDevices.getCount()); -} -#endif - void wifi_sniffer_init(void) { wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); cfg.nvs_enable = 0; // we don't need any wifi settings from NVRAM @@ -181,6 +116,5 @@ void wifi_sniffer_packet_handler(void* buff, wifi_promiscuous_pkt_type_t type) { } else { ESP_LOGI(TAG, "WiFi RSSI %d -> ignoring (limit: %d)", ppkt->rx_ctrl.rssi, cfg.rssilimit); } - //yield(); } diff --git a/src/macsniff.h b/src/macsniff.h index 9fa2496b..441ab157 100644 --- a/src/macsniff.h +++ b/src/macsniff.h @@ -19,10 +19,7 @@ typedef struct { uint8_t payload[0]; /* network data ended with 4 bytes csum (CRC32) */ } wifi_ieee80211_packet_t; -extern uint16_t currentScanDevice; - uint16_t salt_reset(void); -void BLECount(); 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); diff --git a/src/main.cpp b/src/main.cpp index 518e81ad..2bfadabd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,9 +27,8 @@ Refer to LICENSE.txt file in repository for more details. // std::set for unified array functions #include -// OLED driver -#include -#include // Does nothing and avoid any compilation error with I2C +// Does nothing and avoid any compilation error with I2C +#include // LMIC-Arduino LoRaWAN Stack #include "loraconf.h" @@ -45,6 +44,8 @@ configData_t cfg; // struct holds current device configuration osjob_t sendjob, initjob; // LMIC // Initialize global variables +char display_lora[16], display_lmic[16]; +uint8_t channel = 0; int macnum = 0; uint64_t uptimecounter = 0; bool joinstate = false; @@ -205,8 +206,6 @@ void lorawan_loop(void * pvParameters) { #ifdef HAS_DISPLAY HAS_DISPLAY u8x8(OLED_RST, OLED_SCL, OLED_SDA); -#else - U8X8_NULL u8x8; #endif #ifdef HAS_ANTENNA_SWITCH @@ -215,9 +214,7 @@ void lorawan_loop(void * pvParameters) { void antenna_select(const int8_t _ant); #endif -#ifdef BLECOUNTER - void BLECount(void); -#else +#ifndef BLECOUNTER bool btstop = btStop(); #endif @@ -253,11 +250,14 @@ 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); +// defined in blescan.cpp +void bt_loop(void *ignore); + // Sniffer Task void sniffer_loop(void * pvParameters) { configASSERT( ( ( uint32_t ) pvParameters ) == 1 ); // FreeRTOS check - uint8_t channel=0; + channel=0; char buff[16]; int nloop=0, lorawait=0; @@ -269,31 +269,10 @@ void sniffer_loop(void * pvParameters) { yield(); channel = (channel % WIFI_CHANNEL_MAX) + 1; // rotates variable channel 1..WIFI_CHANNEL_MAX wifi_sniffer_set_channel(channel); - ESP_LOGI(TAG, "Wifi set channel %d", channel); - - snprintf(buff, sizeof(buff), "PAX:%d", (int) macs.size()); // convert 16-bit MAC counter to decimal counter value - u8x8.draw2x2String(0, 0, buff); // display number on unique macs total - - #ifdef BLECOUNTER - // We just state out of BLE scanning - u8x8.setCursor(0,3); - if (currentScanDevice) { - u8x8.printf("BLE: %-4d %-4d", (int) bles.size(), currentScanDevice); - } else { - u8x8.printf("BLE: %-4d", (int) bles.size()); - } - #endif - - u8x8.setCursor(0,4); - u8x8.printf("WIFI: %-4d", (int) wifis.size()); - u8x8.setCursor(11,4); - u8x8.printf("ch:%02i", channel); - u8x8.setCursor(0,5); - u8x8.printf(!cfg.rssilimit ? "RLIM: off" : "RLIM: %-3d", cfg.rssilimit); + ESP_LOGD(TAG, "Wifi set channel %d", channel); // duration of one wifi scan loop reached? then send data and begin new scan cycle if ( nloop >= ( (100 / cfg.wifichancycle) * (cfg.wifiscancycle * 2)) +1 ) { - u8x8.setPowerSave(!cfg.screenon); // set display on if enabled nloop=0; channel=0; // reset wifi scan + channel loop counter do_send(&sendjob); // Prepare and execute LoRaWAN data upload vTaskDelay(500/portTICK_PERIOD_MS); @@ -307,15 +286,13 @@ void sniffer_loop(void * pvParameters) { bles.clear(); // clear BLE macs counter #endif salt_reset(); // get new salt for salting hashes - u8x8.clearLine(0); // clear Display counter - u8x8.clearLine(1); } - // wait until payload is sent, while wifi scanning and mac counting task continues + // check if payload is sent lorawait = 0; while(LMIC.opmode & OP_TXRXPEND) { if(!lorawait) - u8x8.drawString(0,6,"LoRa wait "); + sprintf(display_lora, "LoRa wait"); lorawait++; // in case sending really fails: reset and rejoin network if( (lorawait % MAXLORARETRY ) == 0) { @@ -325,26 +302,20 @@ void sniffer_loop(void * pvParameters) { vTaskDelay(1000/portTICK_PERIOD_MS); yield(); } - - u8x8.clearLine(6); - + sprintf(display_lora, " "); // clear LoRa wait message fromd display + + /* // TBD: need to check if long 2000ms pause causes stack problems while scanning continues 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 of send data cycle - else { - #ifdef BLECOUNTER - if (nloop % (WIFI_CHANNEL_MAX * cfg.blescancycle) == 0 ) // once after cfg.blescancycle Wifi scans, do a BLE scan - if (cfg.blescan) { // execute BLE count if BLE function is enabled - BLECount(); // start BLE scan, this is a blocking call - } - #endif - } // end of channel rotation loop - } // end of infinite wifi scan loop + } // end of infinite wifi channel rotation loop } /* end wifi specific parts ------------------------------------------------------------ */ @@ -358,6 +329,7 @@ uint64_t uptime() { return (uint64_t) high32 << 32 | low32; } +#ifdef HAS_DISPLAY // Print a key on display void DisplayKey(const uint8_t * key, uint8_t len, bool lsb) { uint8_t start=lsb?len:0; @@ -371,10 +343,9 @@ void DisplayKey(const uint8_t * key, uint8_t len, bool lsb) { } void init_display(const char *Productname, const char *Version) { + uint8_t buf[32]; u8x8.begin(); u8x8.setFont(u8x8_font_chroma48medium8_r); -#ifdef HAS_DISPLAY - uint8_t buf[32]; u8x8.clear(); u8x8.setFlipMode(0); u8x8.setInverseFont(1); @@ -418,8 +389,8 @@ void init_display(const char *Productname, const char *Version) { DisplayKey(buf, 8, true); delay(5000); u8x8.clear(); -#endif // HAS_DISPLAY } +#endif // HAS_DISPLAY /* begin Aruino SETUP ------------------------------------------------------------ */ @@ -487,12 +458,21 @@ void setup() { antenna_init(); #endif +#ifdef HAS_DISPLAY // initialize display init_display(PROGNAME, PROGVERSION); u8x8.setPowerSave(!cfg.screenon); // set display off if disabled + u8x8.draw2x2String(0, 0, "PAX:0"); + u8x8.setCursor(0,4); + u8x8.printf("WIFI: 0"); + #ifdef BLECOUNTER + u8x8.setCursor(0,3); + u8x8.printf("BLTH: 0"); + #endif u8x8.setCursor(0,5); u8x8.printf(!cfg.rssilimit ? "RLIM: off" : "RLIM: %d", cfg.rssilimit); - u8x8.drawString(0,6,"Join Wait "); + sprintf(display_lora, "Join wait"); +#endif // output LoRaWAN keys to console #ifdef VERBOSE @@ -507,18 +487,16 @@ wifi_sniffer_init(); // setup wifi in monitor mode and start MAC counting // note: do this *after* wifi has started, since gets it's seed from RF noise salt_reset(); // get new 16bit for salting hashes -// 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(sniffer_loop, "wifisniffer", 4096, ( void * ) 1, 1, NULL, 0); +// run wifi task on core 0 and lora task on core 1 and bt task on core 0 +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(sniffer_loop, "wifisniffer", 16384, ( void * ) 1, 1, NULL, 0); +#ifdef BLECOUNTER + if (cfg.blescan) { // start BLE task only if BLE function is enabled in NVRAM configuration + ESP_LOGI(TAG, "Starting Bluetooth task on core 0"); + xTaskCreatePinnedToCore(bt_loop, "btscan", 16384, NULL, 5, NULL, 0); + } #endif // Finally: kickoff first sendjob and join, then send initial payload "0000" @@ -534,20 +512,57 @@ do_send(&sendjob); // Arduino main moop, runs on core 1 // https://techtutorialsx.com/2017/05/09/esp32-get-task-execution-core/ void loop() { - while(1) { -#ifdef HAS_BUTTON - if (ButtonTriggered) { - ButtonTriggered = false; - ESP_LOGI(TAG, "Button pressed, resetting device to factory defaults"); - eraseConfig(); - esp_restart(); + + uptimecounter = uptime() / 1000; // count uptime seconds + + #ifdef HAS_BUTTON // ...then check if pressed + if (ButtonTriggered) { + ButtonTriggered = false; + ESP_LOGI(TAG, "Button pressed, resetting device to factory defaults"); + eraseConfig(); + esp_restart(); } - else -#endif - { vTaskDelay(1000/portTICK_PERIOD_MS); - uptimecounter = uptime() / 1000; // count uptime seconds - } - } + #endif + + #ifdef HAS_DISPLAY // ...then update mask + + // set display on/off according to current device configuration + u8x8.setPowerSave(!cfg.screenon); + + // update counter display (lines 0-4) + char buff[16]; + snprintf(buff, sizeof(buff), "PAX:%-4d", (int) macs.size()); // convert 16-bit MAC counter to decimal counter value + u8x8.draw2x2String(0, 0, buff); // display number on unique macs total Wifi + BLE + u8x8.setCursor(0,4); + u8x8.printf("WIFI: %-4d", (int) wifis.size()); + #ifdef BLECOUNTER + u8x8.setCursor(0,3); + if (cfg.blescan) + u8x8.printf("BLTH: %-4d", (int) bles.size()); + else + u8x8.printf("%-16s", "BLTH: off"); + #endif + + // update wifi channel display (line 4) + u8x8.setCursor(11,4); + u8x8.printf("ch:%02i", channel); + + // update RSSI limiter status display (line 5) + u8x8.setCursor(0,5); + u8x8.printf(!cfg.rssilimit ? "RLIM: off" : "RLIM: %-4d", cfg.rssilimit); + + // update LoRa status display (line 6) + u8x8.setCursor(0,6); + u8x8.printf("%-16s", display_lora); + + // update LMiC event display (line 7) + u8x8.setCursor(0,7); + u8x8.printf("%-16s", display_lmic); + + #endif + + vTaskDelay(1000/DISPLAYFPS/portTICK_PERIOD_MS); + } /* end Aruino LOOP ------------------------------------------------------------ */ diff --git a/src/main.h b/src/main.h index 305bd81a..490fea31 100644 --- a/src/main.h +++ b/src/main.h @@ -1,7 +1,7 @@ #pragma once // program version - note: increment version after modifications to configData_t struct!! -#define PROGVERSION "1.2.95" // use max 10 chars here! +#define PROGVERSION "1.3.01" // use max 10 chars here! #define PROGNAME "PAXCNT" // Verbose enables serial output @@ -12,7 +12,6 @@ #define BLECOUNTER 1 // comment out if you don't want BLE count // BLE scan parameters -#define BLESCANCYCLE 2 // BLE scan once after each wifi scans #define BLESCANTIME 11 // [seconds] scan duration, see note below #define BLESCANWINDOW 10 // [milliseconds] scan window, see below, 3 .. 10240, default 10 #define BLESCANINTERVAL 10 // [milliseconds] how long to wait between scans, 3 .. 10240, default 10 @@ -47,6 +46,9 @@ // Default RGB LED luminosity (in %) #define RGBLUMINOSITY 30 // 30% +// OLED Display refresh cycle (in Milliseconds) +#define DISPLAYFPS 5 // [fps] -> 5 Frames per second ps = 200ms refreseh cycle + // 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 diff --git a/src/rcommand.cpp b/src/rcommand.cpp index b99fe35f..29ed2f1c 100644 --- a/src/rcommand.cpp +++ b/src/rcommand.cpp @@ -58,9 +58,7 @@ 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 "); + sprintf(display_lora, "Reset pending"); vTaskDelay(10000/portTICK_PERIOD_MS); // wait for LMIC to confirm LoRa downlink to server esp_restart(); break; @@ -72,16 +70,11 @@ void set_reset(int val) { bles.clear(); // clear BLE macs container #endif salt_reset(); // get new 16bit salt - u8x8.clearLine(0); u8x8.clearLine(1); // clear Display counter - u8x8.clearLine(5); - u8x8.setCursor(0, 5); - u8x8.printf("Reset counter "); + sprintf(display_lora, "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 "); + sprintf(display_lora, "Factory reset"); eraseConfig(); break; } @@ -90,9 +83,6 @@ void set_reset(int val) { 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) { @@ -110,11 +100,6 @@ void set_blescantime(int val) { ESP_LOGI(TAG, "Remote command: set BLE scan time to %i seconds", cfg.blescantime); }; -void set_blescancycle(int val) { - cfg.blescancycle = val; - ESP_LOGI(TAG, "Remote command: set BLE scan cycle to %i", cfg.blescancycle); -}; - void set_countmode(int val) { switch (val) { case 0: // cyclic unconfirmed @@ -138,7 +123,6 @@ void set_screensaver(int 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) { @@ -147,7 +131,6 @@ void set_display(int 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) { @@ -167,12 +150,15 @@ void set_loraadr(int val) { 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; + case 0: + cfg.blescan = 0; + #ifdef BLECOUNTER + bles.clear(); // clear BLE macs container + #endif + break; + default: + cfg.blescan = 1; + break; } }; @@ -187,6 +173,14 @@ void set_wifiant(int val) { #endif }; +void set_vendorfilter(int val) { + ESP_LOGI(TAG, "Remote command: set vendorfilter mode to %s", val ? "on" : "off"); + switch (val) { + case 1: cfg.vendorfilter = val; break; + default: cfg.vendorfilter = 0; break; + } +}; + void set_rgblum(int val) { // Avoid wrong parameters cfg.rgblum = (val>=0 && val<=100) ? (uint8_t) val : RGBLUMINOSITY; @@ -241,17 +235,17 @@ void get_cputemp (int val) { cmd_t table[] = { {0x01, set_rssi, true}, {0x02, set_countmode, true}, - {0x03, set_screensaver, true}, + {0x03, set_noop, false}, {0x04, set_display, true}, {0x05, set_lorasf, true}, {0x06, set_lorapower, true}, {0x07, set_loraadr, true}, - {0x08, set_noop, false}, + {0x08, set_screensaver, true}, {0x09, set_reset, false}, {0x0a, set_wifiscancycle, true}, {0x0b, set_wifichancycle, true}, {0x0c, set_blescantime, true}, - {0x0d, set_blescancycle, true}, + {0x0d, set_vendorfilter, false}, {0x0e, set_blescan, true}, {0x0f, set_wifiant, true}, {0x10, set_rgblum, true},