diff --git a/README.md b/README.md index f64c29d0..07ca9935 100644 --- a/README.md +++ b/README.md @@ -126,8 +126,8 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts. 0x07 set LoRa Adaptive Data Rate mode 0 = ADR off - 1 = ADR on [default] - + 1 = ADR on [default] + note: set ADR to off, if device is moving, set to on, if not. 0x08 do nothing @@ -165,6 +165,11 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts. 0 = internal antenna [default] 1 = external antenna +0x0F set RGB led luminosity (works on LoPy/LoPy4 and LoRaNode32 shield only) + + 0 ... 100 percentage of luminosity (100% = full light) + e.g. 40 -> 40% of luminosity + 0x80 get device configuration device answers with it's current configuration: @@ -181,7 +186,8 @@ Note: all settings are stored in NVRAM and will be reloaded when device starts. byte 11: BLE scan cycle duration in seconds (0..255) byte 12: BLE scan mode (1=on, 0=0ff) byte 13: Wifi antenna switch (0=internal, 1=external) - bytes 14-23: Software version (ASCII format) + byte 14: RGB LED luminosity (0..100 %) + bytes 15-24: Software version (ASCII format) 0x81 get device uptime diff --git a/platformio.ini b/platformio.ini index 4c4cb5c4..64493f66 100644 --- a/platformio.ini +++ b/platformio.ini @@ -95,7 +95,7 @@ monitor_baud = 115200 lib_deps = U8g2@>2.21.7 ESP32 BLE Arduino@>=0.4.9 - ; NeoPixelBus + SmartLeds 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_VERBOSE @@ -118,8 +118,8 @@ monitor_baud = 115200 lib_deps = U8g2@>2.21.7 ESP32 BLE Arduino@>=0.4.9 - ; NeoPixelBus -build_flags = + SmartLeds +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_VERBOSE ; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE @@ -142,8 +142,8 @@ upload_speed = 256000 lib_deps = U8g2 ESP32 BLE Arduino@>=0.4.9 -; NeoPixelBus -build_flags = + SmartLeds +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_VERBOSE ; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE @@ -166,8 +166,8 @@ upload_speed = 921600 lib_deps = U8g2 ESP32 BLE Arduino@>=0.4.9 -; NeoPixelBus -build_flags = + SmartLeds +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_VERBOSE ; -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_NONE @@ -180,4 +180,3 @@ build_flags = -include "src/hal/lolin32_lora.h" ;FreeRTOS single core operation, switches off core 1 (see arduino-esp32/cores/esp32/main.cpp) ; -DCONFIG_FREERTOS_UNICORE - diff --git a/src/blecount.cpp b/src/blecount.cpp deleted file mode 100644 index d4076ee9..00000000 --- a/src/blecount.cpp +++ /dev/null @@ -1,32 +0,0 @@ - -// Basic Config -#include "globals.h" - -#ifdef BLECOUNTER -#include -#include -#include -#include - -// Local logging tag -static const char *TAG = "blecount"; - -class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { - void onResult(BLEAdvertisedDevice advertisedDevice) { - } -}; - -void BLECount() { - u8x8.clearLine(3); - u8x8.drawString(0,3,"BLE Scan..."); - BLEDevice::init(PROGNAME); - 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#: %-5i",blenum); -} -#endif \ No newline at end of file diff --git a/src/configmanager.cpp b/src/configmanager.cpp index a4c8526c..0006c93f 100644 --- a/src/configmanager.cpp +++ b/src/configmanager.cpp @@ -29,8 +29,10 @@ void defaultConfig() { 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 + cfg.blescan = 1; // 0=disabled, 1=enabled cfg.wifiant = 0; // 0=internal, 1=external (for LoPy/LoPy4) + cfg.rgblum = RGBLUMINOSITY; // RGB Led luminosity (0 100%) + strncpy( cfg.version, PROGVERSION, sizeof(cfg.version)-1 ); } @@ -47,7 +49,7 @@ void open_storage() { // Open ESP_LOGI(TAG, "Opening NVS"); err = nvs_open("config", NVS_READWRITE, &my_handle); - if (err != ESP_OK) + if (err != ESP_OK) ESP_LOGI(TAG, "Error (%d) opening NVS handle", err); else ESP_LOGI(TAG, "Done"); @@ -56,14 +58,14 @@ void open_storage() { // erase all keys and values in NVRAM void eraseConfig() { ESP_LOGI(TAG, "Clearing settings in NVS"); - open_storage(); + 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"); } + ESP_LOGI(TAG, "Done");} + else { + ESP_LOGW(TAG, "NVS erase failed"); } } // save current configuration from RAM to NVRAM @@ -75,10 +77,10 @@ void saveConfig() { 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); @@ -110,11 +112,14 @@ void saveConfig() { 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); + nvs_set_i8(my_handle, "wifiant", cfg.wifiant); + + if( nvs_get_i8(my_handle, "rgblum", &flash8) != ESP_OK || flash8 != cfg.rgblum ) + nvs_set_i8(my_handle, "rgblum", cfg.rgblum); 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 ) { @@ -146,7 +151,7 @@ void loadConfig() { 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); @@ -227,7 +232,7 @@ void loadConfig() { ESP_LOGI(TAG, "WIFI channel cycle set to default %i", cfg.wifichancycle); saveConfig(); } - + if( nvs_get_i8(my_handle, "wifiant", &flash8) == ESP_OK ) { cfg.wifiant = flash8; ESP_LOGI(TAG, "wifiantenna = %i", flash8); @@ -236,6 +241,14 @@ void loadConfig() { saveConfig(); } + if( nvs_get_i8(my_handle, "rgblum", &flash8) == ESP_OK ) { + cfg.rgblum = flash8; + ESP_LOGI(TAG, "rgbluminosity = %i", flash8); + } else { + ESP_LOGI(TAG, "RGB luminosity set to default %i", cfg.rgblum); + saveConfig(); + } + if( nvs_get_i8(my_handle, "blescancycle", &flash8) == ESP_OK ) { cfg.blescancycle = flash8; ESP_LOGI(TAG, "blescancycle = %i", flash8); @@ -251,7 +264,7 @@ void loadConfig() { 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); @@ -259,7 +272,7 @@ void loadConfig() { ESP_LOGI(TAG, "rssilimit set to default %i", cfg.rssilimit); saveConfig(); } - + nvs_close(my_handle); ESP_LOGI(TAG, "Done"); @@ -268,5 +281,5 @@ void loadConfig() { #ifdef HAS_ANTENNA_SWITCH // set antenna type, if device has one antenna_select(cfg.wifiant); #endif - } -} \ No newline at end of file + } +} diff --git a/src/globals.h b/src/globals.h index 58948a7d..f569cbbd 100644 --- a/src/globals.h +++ b/src/globals.h @@ -3,6 +3,8 @@ // std::set for unified array functions #include +#include +#include // OLED Display #include @@ -11,6 +13,12 @@ #include #include +#ifdef HAS_RGB_LED +#include +#endif +#include "rgb_led.h" +#include "macsniff.h" + // Struct holding devices's runtime configuration typedef struct { int8_t lorasf; // 7-12, lora spreadfactor @@ -25,6 +33,7 @@ typedef struct { int8_t blescancycle; // BLE scan cycle [seconds] int8_t blescan; // 0=disabled, 1=enabled int8_t wifiant; // 0=internal, 1=external (for LoPy/LoPy4) + int8_t rgblum; // RGB Led luminosity (0 100%) char version[10]; // Firmware version } configData_t; @@ -32,9 +41,9 @@ extern configData_t cfg; extern uint8_t mydata[]; extern uint64_t uptimecounter; extern osjob_t sendjob; -extern uint16_t macnum, blenum, salt; -extern int countermode, screensaver, adrmode, lorasf, txpower, rlim; +extern int countermode, screensaver, adrmode, lorasf, txpower, rlim, salt; extern bool joinstate; +extern std::set wifis; extern std::set macs; #ifdef HAS_DISPLAY @@ -45,4 +54,5 @@ extern std::set macs; #ifdef BLECOUNTER extern int scanTime; -#endif \ No newline at end of file + extern std::set bles; +#endif diff --git a/src/hal/lolin32_lora.h b/src/hal/lolin32_lora.h index e446f28b..c6c44337 100644 --- a/src/hal/lolin32_lora.h +++ b/src/hal/lolin32_lora.h @@ -6,6 +6,7 @@ #define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board #define HAS_LED NOT_A_PIN // Led os on same pin than Lora SS pin, to avoid pb, we don't use it +#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW // Anyway shield is on over the LoLin32 board, so we won't be able to see this LED #define HAS_RGB_LED 13 // ESP32 GPIO13 (pin13) On Board Shield WS2812B RGB LED #define HAS_BUTTON 15 // ESP32 GPIO15 (pin15) Button is on the LoraNode32 shield @@ -30,4 +31,3 @@ #define OLED_RST U8X8_PIN_NONE // Not reset pin #define OLED_SDA 21 // ESP32 GPIO21 (Pin21) -- OLED SDA #define OLED_SCL 22 // ESP32 GPIO22 (Pin22) -- OLED SCL - diff --git a/src/hal/lolin32lite_lora.h b/src/hal/lolin32lite_lora.h index 698ec60e..c9ce785b 100644 --- a/src/hal/lolin32lite_lora.h +++ b/src/hal/lolin32lite_lora.h @@ -5,8 +5,8 @@ #define DISABLE_BROWNOUT 1 // comment out if you want to keep brownout feature #define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board -#define HAS_LED NOT_A_PIN // Led os on same pin than Lora SS pin, to avoid pb, we don't use it - // Anyway shield is on over the LoLin32 board, so we won't be able to see this LED +#define HAS_LED 22 // ESP32 GPIO12 (pin22) On Board LED +#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW #define HAS_RGB_LED 13 // ESP32 GPIO13 (pin13) On Board Shield WS2812B RGB LED #define HAS_BUTTON 15 // ESP32 GPIO15 (pin15) Button is on the LoraNode32 shield #define BUTTON_PULLUP 1 // Button need pullup instead of default pulldown @@ -30,4 +30,3 @@ #define OLED_RST U8X8_PIN_NONE // Not reset pin #define OLED_SDA 14 // ESP32 GPIO14 (Pin14) -- OLED SDA #define OLED_SCL 12 // ESP32 GPIO12 (Pin12) -- OLED SCL - diff --git a/src/hal/ttgov1.h b/src/hal/ttgov1.h index da9262e0..55f6eebf 100644 --- a/src/hal/ttgov1.h +++ b/src/hal/ttgov1.h @@ -4,6 +4,7 @@ #define HAS_DISPLAY U8X8_SSD1306_128X64_NONAME_HW_I2C // OLED-Display on board #define HAS_LED GPIO_NUM_2 // white LED on board +#define LED_ACTIVE_LOW 1 // Onboard LED is active when pin is LOW #define HAS_BUTTON GPIO_NUM_0 // button "PRG" on board // re-define pin definitions of pins_arduino.h @@ -21,4 +22,4 @@ // Hardware pin definitions for TTGOv1 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 \ No newline at end of file +#define OLED_SCL 15 // ESP32 GPIO15 (Pin15) -- SD1306 Clock diff --git a/src/lorawan.cpp b/src/lorawan.cpp index 64eea864..0f0f86eb 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -79,10 +79,22 @@ void printKeys(void) { #endif // VERBOSE void do_send(osjob_t* j){ - mydata[0] = (macnum & 0xff00) >> 8; - mydata[1] = macnum & 0x00ff; - mydata[2] = (blenum & 0xff00) >> 8; - mydata[3] = blenum & 0x00ff; + uint16_t data; + // Total BLE+WIFI unique MACs seen + data = (uint16_t) macs.size(); + mydata[0] = (data & 0xff00) >> 8; + mydata[1] = data & 0xff; + + // Sum of unique BLE MACs seen + data = (uint16_t) bles.size(); + mydata[2] = (data & 0xff00) >> 8; + mydata[3] = data & 0xff; + + // Sum of unique WIFI MACs seen + // TBD ? + //data = (uint16_t) wifis.size(); + //mydata[4] = (data & 0xff00) >> 8; + //mydata[5] = data & 0xff; // Check if there is not a current TX/RX job running if (LMIC.opmode & OP_TXRXPEND) { @@ -95,7 +107,6 @@ void do_send(osjob_t* j){ 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. } @@ -162,7 +173,6 @@ void onEvent (ev_t ev) { 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); @@ -176,7 +186,7 @@ void onEvent (ev_t ev) { u8x8.clearLine(7); u8x8.setCursor(0, 7); // LMIC.snr = SNR twos compliment [dB] * 4 - // LMIC.rssi = RSSI [dBm] (-196...+63) + // 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 ) ) { @@ -223,4 +233,5 @@ void onEvent (ev_t ev) { u8x8.printf("UNKNOWN EVENT %d", ev); break; } -} \ No newline at end of file +} + diff --git a/src/macsniff.cpp b/src/macsniff.cpp new file mode 100644 index 00000000..e4fe8272 --- /dev/null +++ b/src/macsniff.cpp @@ -0,0 +1,141 @@ + +// Basic Config +#include "main.h" +#include "globals.h" + +#ifdef BLECOUNTER + #include + #include + #include + #include +#endif + +#ifdef VENDORFILTER + #include + #include + #include "vendor_array.h" +#endif + +// Local logging tag +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; + +bool mac_add(uint8_t *paddr, int8_t rssi, bool sniff_type) { + + char counter [6]; // uint16_t -> 2 byte -> 5 decimals + '0' terminator -> 6 chars + char macbuf [21]; // uint64_t -> 8 byte -> 20 decimals + '0' terminator -> 21 chars + char typebuff[8]; + uint64_t addr2int; + uint32_t vendor2int; + uint16_t hashedmac; + std::pair::iterator, bool> newmac; + + addr2int = ( (uint64_t)paddr[0] ) | ( (uint64_t)paddr[1] << 8 ) | ( (uint64_t)paddr[2] << 16 ) | \ + ( (uint64_t)paddr[3] << 24 ) | ( (uint64_t)paddr[4] << 32 ) | ( (uint64_t)paddr[5] << 40 ); + + #ifdef VENDORFILTER + vendor2int = ( (uint32_t)paddr[2] ) | ( (uint32_t)paddr[1] << 8 ) | ( (uint32_t)paddr[0] << 16 ); + // No vendor filter for 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 + + addr2int |= (uint64_t) salt << 48; // prepend 16-bit salt to 48-bit MAC + snprintf(macbuf, 21, "%llx", addr2int); // convert unsigned 64-bit salted MAC to 16 digit hex string + hashedmac = rokkit(macbuf, 5); // hash MAC string, use 5 chars to fit hash in uint16_t container + newmac = macs.insert(hashedmac); // add hashed MAC to total container if new unique + + if (sniff_type == MAC_SNIFF_WIFI ) { + newmac = wifis.insert(hashedmac); // add hashed MAC to wifi container if new unique + strcpy(typebuff, "WiFi"); + } else if (sniff_type == MAC_SNIFF_BLE ) { + newmac = bles.insert(hashedmac); // add hashed MAC to BLE container if new unique + strcpy(typebuff, "BLE "); + } + + if (newmac.second) { // first time seen this WIFI or BLE MAC + snprintf(counter, 6, "%i", macs.size()); // convert 16-bit MAC counter to decimal counter value + u8x8.draw2x2String(0, 0, counter); + ESP_LOGI(TAG, "%s RSSI %04d -> Hash %04x -> #%05i", typebuff, rssi, hashedmac, macs.size()); + } else { // already seen WIFI or BLE MAC + ESP_LOGI(TAG, "%s RSSI %04d -> already seen", typebuff, rssi); + } + + #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]); + } + #endif + + // True if MAC WiFi/BLE was new + return newmac.second; +} + +#ifdef BLECOUNTER + +class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { + void onResult(BLEAdvertisedDevice advertisedDevice) { + uint8_t *p = (uint8_t *) advertisedDevice.getAddress().getNative(); + + // Current devices seen on this scan session + currentScanDevice++; + mac_add(p, advertisedDevice.getRSSI(), MAC_SNIFF_BLE); + u8x8.setCursor(12,3); + u8x8.printf("%d", currentScanDevice); + } +}; + +void BLECount() { + int blenum = 0; // Total device seen on this scan session + currentScanDevice = 0; // Set 0 seen device on this scan session + u8x8.clearLine(3); + u8x8.drawString(0,3,"BLE Scan..."); + BLEDevice::init(PROGNAME); + 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); + blenum=foundDevices.getCount(); + u8x8.clearLine(3); + u8x8.setCursor(0,3); + u8x8.printf("BLE#: %-5i %-3i",bles.size(), blenum); +} +#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 + wifi_promiscuous_filter_t filter = {.filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT}; // we need only MGMT frames + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); // configure Wifi with cfg + ESP_ERROR_CHECK(esp_wifi_set_country(&wifi_country)); // set locales for RF and channels + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); // we don't need NVRAM + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL)); + 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)); // now switch on monitor mode +} + +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; + + if (( cfg.rssilimit == 0 ) || (ppkt->rx_ctrl.rssi > cfg.rssilimit )) { // rssi is negative value + uint8_t *p = (uint8_t *) hdr->addr2; + mac_add(p, ppkt->rx_ctrl.rssi, MAC_SNIFF_WIFI) ; + } else { + ESP_LOGI(TAG, "WiFi RSSI %04d -> ignoring (limit: %i)", ppkt->rx_ctrl.rssi, cfg.rssilimit); + } + yield(); +} + diff --git a/src/macsniff.h b/src/macsniff.h new file mode 100644 index 00000000..423c62b8 --- /dev/null +++ b/src/macsniff.h @@ -0,0 +1,28 @@ +// ESP32 Functions +#include + +#define MAC_SNIFF_WIFI 0 +#define MAC_SNIFF_BLE 1 + +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 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); + +// function defined in rokkithash.cpp +uint32_t rokkit(const char * , int ); diff --git a/src/main.cpp b/src/main.cpp index a54489cb..94740598 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,6 +25,9 @@ Refer to LICENSE.txt file in repository for more details. #include "main.h" #include "globals.h" +// std::set for unified array functions +#include + // OLED driver #include @@ -42,11 +45,17 @@ configData_t cfg; // struct holds current device configuration osjob_t sendjob, initjob; // LMIC // Initialize global variables -uint16_t macnum = 0, blenum = 0, salt; +int macnum = 0, salt; uint64_t uptimecounter = 0; bool joinstate = false; -std::set macs; // associative container holds filtered MAC adresses +std::set macs; // associative container holds total of unique MAC adress hashes (Wifi + BLE) +std::set wifis; // associative container holds unique Wifi MAC adress hashes + +#ifdef BLECOUNTER + std::set bles; // associative container holds unique BLE MAC adresses hashes + int scanTime; +#endif // this variable will be changed in the ISR, and read in main loop static volatile bool ButtonTriggered = false; @@ -67,29 +76,19 @@ void eraseConfig(void); void saveConfig(void); void loadConfig(void); -/* begin LMIC specific parts ------------------------------------------------------------ */ +#ifdef HAS_LED + void set_onboard_led(int st); +#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} -}; +/* begin LMIC specific parts ------------------------------------------------------------ */ // defined in lorawan.cpp void gen_lora_deveui(uint8_t * pdeveui); void RevBytes(unsigned char* b, size_t c); + #ifdef VERBOSE void printKeys(void); -#endif - -// LMIC functions -void onEvent(ev_t ev); -void do_send(osjob_t* j); +#endif // VERBOSE // LMIC callback functions void os_getDevKey (u1_t *buf) { @@ -112,6 +111,21 @@ void os_getDevEui (u1_t* buf) { gen_lora_deveui(buf); // generate DEVEUI from device's MAC } +// 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 @@ -125,8 +139,48 @@ static void lora_init (osjob_t* j) { // LMIC Task void lorawan_loop(void * pvParameters) { configASSERT( ( ( uint32_t ) pvParameters ) == 1 ); // FreeRTOS check + + static bool led_state ; + bool new_led_state ; + while(1) { + uint16_t color; os_runloop_once(); + + // All follow is Led management + // Let join at the begining of if sequence, + // is prior to send because joining state send data + if ( LMIC.opmode & (OP_JOINING | OP_REJOIN) ) { + color = COLOR_YELLOW; + // Joining Quick blink 20ms on each 1/5 second + new_led_state = ((millis() % 200) < 20) ? HIGH : LOW; + + // Small blink 10ms on each 1/2sec (not when joining) + } else if (LMIC.opmode & (OP_TXDATA | OP_TXRXPEND)) { + color = COLOR_BLUE; + new_led_state = ((millis() % 500) < 20) ? HIGH : LOW; + + // This should not happen so indicate a pb + } else if ( LMIC.opmode & (OP_TXDATA | OP_TXRXPEND | OP_JOINING | OP_REJOIN) == 0 ) { + color = COLOR_RED; + // Heartbeat long blink 200ms on each 2 seconds + new_led_state = ((millis() % 2000) < 200) ? HIGH : LOW; + } else { + rgb_set_color(COLOR_NONE); + } + // led need to change state ? + // avoid digitalWrite() for nothing + if (led_state != new_led_state) { + if (new_led_state == HIGH) { + set_onboard_led(1); + rgb_set_color(color); + } else { + set_onboard_led(0); + rgb_set_color(COLOR_NONE); + } + led_state = new_led_state; + } + vTaskDelay(10/portTICK_PERIOD_MS); yield(); } @@ -159,12 +213,18 @@ void lorawan_loop(void * pvParameters) { void set_onboard_led(int st){ #ifdef HAS_LED switch (st) { - case 1: digitalWrite(HAS_LED, HIGH); break; - case 0: digitalWrite(HAS_LED, LOW); break; + #ifdef LED_ACTIVE_LOW + case 1: digitalWrite(HAS_LED, LOW); break; + case 0: digitalWrite(HAS_LED, HIGH); break; + #else + case 1: digitalWrite(HAS_LED, HIGH); break; + case 0: digitalWrite(HAS_LED, LOW); break; + #endif } #endif }; + #ifdef HAS_BUTTON // Button Handling, board dependent -> perhaps to be moved to hal/<$board.h> // IRAM_ATTR necessary here, see https://github.com/espressif/arduino-esp32/issues/855 @@ -190,35 +250,49 @@ void wifi_sniffer_loop(void * pvParameters) { int nloop=0, lorawait=0; while (true) { - nloop++; - vTaskDelay(cfg.wifichancycle*10 / portTICK_PERIOD_MS); + nloop++; // acutal number of wifi loops + + // execute BLE count if BLE function is enabled + #ifdef BLECOUNTER + // Once 2 full Wifi Channels scan, do a BLE scan + if (nloop % (WIFI_CHANNEL_MAX*2) == 0 ) { + // execute BLE count if BLE function is enabled + if (cfg.blescan) + BLECount(); + } + #endif + + vTaskDelay(cfg.wifichancycle*10 / portTICK_PERIOD_MS); yield(); - wifi_sniffer_set_channel(channel); - channel = (channel % WIFI_CHANNEL_MAX) + 1; + wifi_sniffer_set_channel(channel); + channel = (channel % WIFI_CHANNEL_MAX) + 1; + ESP_LOGI(TAG, "Wifi set channel %d", channel); + + u8x8.setCursor(0,5); + u8x8.printf(!cfg.rssilimit ? "RLIM: off" : "RLIM: %4i", cfg.rssilimit); + u8x8.setCursor(11,5); + u8x8.printf("ch:%02i", channel); + u8x8.setCursor(0,4); + u8x8.printf("MAC#: %-5i", wifis.size()); // 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#: %-5i", 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.clear(); // clear macs container + macs.clear(); // clear all macs container + wifis.clear(); // clear Wifi macs couner + #ifdef BLECOUNTER + bles.clear(); // clear BLE macs counter + #endif salt = random(65536); // get new 16bit random for salting hashes - macnum = 0; u8x8.clearLine(0); u8x8.clearLine(1); // clear Display counter } @@ -237,8 +311,10 @@ void wifi_sniffer_loop(void * pvParameters) { } u8x8.clearLine(6); - - if (cfg.screenon && cfg.screensaver) vTaskDelay(2000/portTICK_PERIOD_MS); // pause for displaying results + + 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 } @@ -336,7 +412,8 @@ void setup() { #endif ESP_LOGI(TAG, "Starting %s %s", PROGNAME, PROGVERSION); - + rgb_set_color(COLOR_NONE); + // system event handler for wifi task, needed for wifi_sniffer_init() esp_event_loop_init(NULL, NULL); @@ -355,7 +432,7 @@ void setup() { // Read settings from NVRAM loadConfig(); // includes initialize if necessary - + // initialize hardware #ifdef HAS_LED // initialize LED @@ -380,7 +457,7 @@ void setup() { antenna_init(); #endif - // initialize salt value using esp_random() called by random in arduino-esp32 core + // initialize salt value using esp_random() called by random() in arduino-esp32 core salt = random(65536); // get new 16bit random for salting hashes // initialize display diff --git a/src/main.h b/src/main.h index c01b8e6e..55e71be8 100644 --- a/src/main.h +++ b/src/main.h @@ -1,5 +1,5 @@ // program version -#define PROGVERSION "1.2.62" // use max 10 chars here! +#define PROGVERSION "1.2.8" // use max 10 chars here! #define PROGNAME "PAXCNT" // Verbose enables serial output @@ -10,22 +10,26 @@ #define BLECOUNTER 1 // comment out if you don't want BLE count // BLE scan time -#define BLESCANTIME 30 // [seconds] +#define BLESCANTIME 15 // [seconds] // WiFi Sniffer cycle interval #define SEND_SECS 120 // [seconds/2] -> 240 sec. +//#define SEND_SECS 30 // [seconds/2] -> 60 sec. // WiFi sniffer config #define WIFI_CHANNEL_MIN 1 // start channel number where scan begings #define WIFI_CHANNEL_MAX 13 // total channel number to scan #define WIFI_MY_COUNTRY "EU" // for Wifi RF settings -#define WIFI_CHANNEL_SWITCH_INTERVAL 50 // [seconds/100] -> 0,5 sec. +#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 +// Default RGB LED luminosity (in %) +#define RGBLUMINOSITY 50 // 50% + // 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 @@ -99,10 +103,10 @@ // 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 +#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 +// #define USE_IDEETRON_AES diff --git a/src/rcommand.cpp b/src/rcommand.cpp index e1524e19..95f13ea1 100644 --- a/src/rcommand.cpp +++ b/src/rcommand.cpp @@ -67,8 +67,9 @@ void set_reset(int val) { break; case 1: // reset MAC counter ESP_LOGI(TAG, "Remote command: reset MAC counter"); - macs.clear(); // clear macs container - macnum = 0; + macs.clear(); // clear all macs container + wifis.clear(); // clear Wifi macs container + bles.clear(); // clear BLE macs container salt = random(65536); // get new 16bit random for salting hashes u8x8.clearLine(0); u8x8.clearLine(1); // clear Display counter u8x8.clearLine(5); @@ -140,7 +141,7 @@ 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 + u8x8.setPowerSave(!cfg.screenon); // set display 0=on / 1=off }; void set_lorasf(int val) { @@ -161,8 +162,8 @@ 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; + default: + cfg.blescan = 0; btStop(); u8x8.clearLine(3); // clear BLE results from display break; @@ -180,6 +181,12 @@ void set_wifiant(int val) { #endif }; +void set_rgblum(int val) { + // Avoid wrong parameters + cfg.rgblum = (val>=0 && val<=100) ? (uint8_t) val : RGBLUMINOSITY; + ESP_LOGI(TAG, "Remote command: set RGB Led luminosity %d", cfg.rgblum); +}; + void set_lorapower(int val) { ESP_LOGI(TAG, "Remote command: set LoRa TXPOWER to %i", val); switch_lora(cfg.lorasf, val); @@ -240,13 +247,14 @@ cmd_t table[] = { {0x0c, set_blescancycle, true}, {0x0d, set_blescan, true}, {0x0e, set_wifiant, true}, + {0x0f, set_rgblum, true}, {0x80, get_config, false}, {0x81, get_uptime, false}, {0x82, get_cputemp, false} }; // check and execute remote command -void rcommand(int cmd, int arg) { +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--) { diff --git a/src/rgb_led.cpp b/src/rgb_led.cpp new file mode 100644 index 00000000..274695e4 --- /dev/null +++ b/src/rgb_led.cpp @@ -0,0 +1,87 @@ +// Basic Config +#include "main.h" +#include "globals.h" + +#ifdef HAS_RGB_LED + +// RGB Led instance +SmartLed rgb_led(LED_WS2812, 1, HAS_RGB_LED); + +// Luminosity from 0 to 100% +uint8_t rgb_luminosity = 50 ; + +float rgb_CalcColor(float p, float q, float t) +{ + if (t < 0.0f) + t += 1.0f; + if (t > 1.0f) + t -= 1.0f; + + if (t < 1.0f / 6.0f) + return p + (q - p) * 6.0f * t; + + if (t < 0.5f) + return q; + + if (t < 2.0f / 3.0f) + return p + ((q - p) * (2.0f / 3.0f - t) * 6.0f); + + return p; +} + +// ------------------------------------------------------------------------ +// Hue, Saturation, Lightness color members +// HslColor using H, S, L values (0.0 - 1.0) +// L should be limited to between (0.0 - 0.5) +// ------------------------------------------------------------------------ +RGBColor rgb_hsl2rgb(float h, float s, float l) +{ + RGBColor RGB_color; + float r; + float g; + float b; + + if (s == 0.0f || l == 0.0f) + { + r = g = b = l; // achromatic or black + } + else + { + float q = l < 0.5f ? l * (1.0f + s) : l + s - (l * s); + float p = 2.0f * l - q; + r = rgb_CalcColor(p, q, h + 1.0f / 3.0f); + g = rgb_CalcColor(p, q, h); + b = rgb_CalcColor(p, q, h - 1.0f / 3.0f); + } + + RGB_color.R = (uint8_t)(r * 255.0f); + RGB_color.G = (uint8_t)(g * 255.0f); + RGB_color.B = (uint8_t)(b * 255.0f); + + return RGB_color; +} + +void rgb_set_color(uint16_t hue) { + if (hue == COLOR_NONE) { + // Off + rgb_led[0] = Rgb(0,0,0); + } else { + // see http://www.workwithcolor.com/blue-color-hue-range-01.htm + // H (is color from 0..360) should be between 0.0 and 1.0 + // S is saturation keep it to 1 + // L is brightness should be between 0.0 and 0.5 + // rgb_luminosity is between 0 and 100 (percent) + RGBColor target = rgb_hsl2rgb( hue / 360.0f, 1.0f, 0.005f * cfg.rgblum); + //uint32_t color = target.R<<16 | target.G<<8 | target.B; + rgb_led[0] = Rgb(target.R, target.G, target.B); + } + // Show + rgb_led.show(); +} + +#else + +// No RGB LED empty functions +void rgb_set_color(uint16_t hue) {} + +#endif diff --git a/src/rgb_led.h b/src/rgb_led.h new file mode 100644 index 00000000..589b3f94 --- /dev/null +++ b/src/rgb_led.h @@ -0,0 +1,30 @@ + +#pragma once + +// value for HSL color +// see http://www.workwithcolor.com/blue-color-hue-range-01.htm +#define COLOR_RED 0 +#define COLOR_ORANGE 30 +#define COLOR_ORANGE_YELLOW 45 +#define COLOR_YELLOW 60 +#define COLOR_YELLOW_GREEN 90 +#define COLOR_GREEN 120 +#define COLOR_GREEN_CYAN 165 +#define COLOR_CYAN 180 +#define COLOR_CYAN_BLUE 210 +#define COLOR_BLUE 240 +#define COLOR_BLUE_MAGENTA 275 +#define COLOR_MAGENTA 300 +#define COLOR_PINK 350 +#define COLOR_WHITE 360 +#define COLOR_NONE 999 + +struct RGBColor +{ + uint8_t R; + uint8_t G; + uint8_t B; +}; + +// Exported Functions +void rgb_set_color(uint16_t hue); diff --git a/src/vendor_array.h b/src/vendor_array.h index 87879006..9b610782 100644 --- a/src/vendor_array.h +++ b/src/vendor_array.h @@ -1,1435 +1,1435 @@ -std::array vendors = { \ - 0x38f23e, \ - 0x807abf, \ - 0x90e7c4, \ - 0x7c6193, \ - 0x485073, \ - 0x74e28c, \ - 0x8463d6, \ - 0xd48f33, \ - 0x2c8a72, \ - 0x980d2e, \ - 0xa826d9, \ - 0xd4206d, \ - 0x00155d, \ - 0x806c1b, \ - 0xa470d6, \ - 0x985fd3, \ - 0x1c69a5, \ - 0x382de8, \ - 0xd087e2, \ - 0x205531, \ - 0x5440ad, \ - 0x842e27, \ - 0x50f0d3, \ - 0x84119e, \ - 0x08eca9, \ - 0x10d38a, \ - 0x382dd1, \ - 0xe0cbee, \ - 0x64b853, \ - 0xf4428f, \ - 0x188331, \ - 0x8455a5, \ - 0xa87c01, \ - 0xc01173, \ - 0xbce63f, \ - 0xb857d8, \ - 0x94b10a, \ - 0xe458b8, \ - 0x088c2c, \ - 0xb86ce8, \ - 0x9c65b0, \ - 0xc8a823, \ - 0xc44202, \ - 0xd059e4, \ - 0x64b310, \ - 0x9476b7, \ - 0x8c1abf, \ - 0xb47443, \ - 0x30cbf8, \ - 0x182195, \ - 0xa88195, \ - 0x88add2, \ - 0xd0fccc, \ - 0x14c913, \ - 0x4c6641, \ - 0x3cbdd8, \ - 0x38256b, \ - 0x849866, \ - 0xe89309, \ - 0x0016db, \ - 0x5c3c27, \ - 0x10d542, \ - 0xa0821f, \ - 0xc45006, \ - 0x88329b, \ - 0xbc8ccd, \ - 0x400e85, \ - 0xec9bf3, \ - 0xf8042e, \ - 0x843838, \ - 0x54880e, \ - 0xbc79ad, \ - 0x30d6c9, \ - 0xb0df3a, \ - 0x805719, \ - 0x78a873, \ - 0x041bba, \ - 0x08fd0e, \ - 0x08d42b, \ - 0x00e3b2, \ - 0xc81479, \ - 0xf0728c, \ - 0x94350a, \ - 0x001fcd, \ - 0xd0dfc7, \ - 0x1c62b8, \ - 0x18e2c2, \ - 0x001a8a, \ - 0x002567, \ - 0xa8f274, \ - 0x001599, \ - 0x0012fb, \ - 0x7cf854, \ - 0x8cc8cd, \ - 0xe81132, \ - 0xa02195, \ - 0x8c71f8, \ - 0x04180f, \ - 0x9463d1, \ - 0x0cdfa4, \ - 0xcc051b, \ - 0x68ebae, \ - 0x60d0a9, \ - 0x60a10a, \ - 0xa07591, \ - 0x001fcc, \ - 0xec107b, \ - 0xa01081, \ - 0xf4f524, \ - 0x9c99a0, \ - 0x185936, \ - 0x98fae3, \ - 0x640980, \ - 0x8cbebe, \ - 0xf8a45f, \ - 0xbc8385, \ - 0x900628, \ - 0xd4ae05, \ - 0x3c0518, \ - 0xc40bcb, \ - 0xe8bba8, \ - 0xbc3aea, \ - 0x8c0ee3, \ - 0x6c5c14, \ - 0x78abbb, \ - 0x1816c9, \ - 0xfc8f90, \ - 0x244b03, \ - 0x988389, \ - 0x14bb6e, \ - 0x1c3ade, \ - 0xf83f51, \ - 0xd8e0e1, \ - 0xecf342, \ - 0x5092b9, \ - 0xb4bff6, \ - 0xc8d7b0, \ - 0x982d68, \ - 0xecd09f, \ - 0xe446da, \ - 0xf4f5db, \ - 0xd80831, \ - 0xdc5583, \ - 0x2c54cf, \ - 0x001fe3, \ - 0x0026e2, \ - 0x001e75, \ - 0x6cd68a, \ - 0x2021a5, \ - 0x0c4885, \ - 0xdc0b34, \ - 0xac0d1b, \ - 0x60e3ac, \ - 0xf895c7, \ - 0xc4438f, \ - 0xa816b2, \ - 0xe892a4, \ - 0x700514, \ - 0x88c9d0, \ - 0x2c598a, \ - 0x18f0e4, \ - 0xec8350, \ - 0x4cdd31, \ - 0x703eac, \ - 0x6c94f8, \ - 0x84788b, \ - 0x2cf0ee, \ - 0x68d93c, \ - 0x24e314, \ - 0x28f076, \ - 0x285aeb, \ - 0x087402, \ - 0xccc760, \ - 0x705aac, \ - 0xfc643a, \ - 0xd4e6b7, \ - 0x2802d8, \ - 0x9c2ea1, \ - 0x68967b, \ - 0xbc6778, \ - 0xa82066, \ - 0xb065bd, \ - 0xf0dce2, \ - 0x7cd1c3, \ - 0x705681, \ - 0x2cbe08, \ - 0x783a84, \ - 0x84b153, \ - 0x6476ba, \ - 0x54ae27, \ - 0xf437b7, \ - 0xf0d1a9, \ - 0x34c059, \ - 0x04f7e4, \ - 0x10ddb1, \ - 0xb4f0ab, \ - 0x848506, \ - 0x7831c1, \ - 0x8c7c92, \ - 0xd0e140, \ - 0xacfdec, \ - 0xf82793, \ - 0x40a6d9, \ - 0x109add, \ - 0xf0b479, \ - 0x58b035, \ - 0x34159e, \ - 0x286aba, \ - 0xec852f, \ - 0x44d884, \ - 0x003ee1, \ - 0x7c11be, \ - 0x04e536, \ - 0x881fa1, \ - 0x04db56, \ - 0x9cfc01, \ - 0xc81ee7, \ - 0x34363b, \ - 0xc01ada, \ - 0xacbc32, \ - 0x70700d, \ - 0x7c5049, \ - 0x503237, \ - 0xd4619d, \ - 0xb0481a, \ - 0x989e63, \ - 0xdca904, \ - 0x48a195, \ - 0x6cab31, \ - 0x6c96cf, \ - 0x3035ad, \ - 0xa8be27, \ - 0xb8634d, \ - 0x9ce33f, \ - 0xf0989d, \ - 0xace4b5, \ - 0xe42b34, \ - 0x1c36bb, \ - 0x3c2eff, \ - 0xf0766f, \ - 0x40cbc0, \ - 0x4098ad, \ - 0x6c4d73, \ - 0xc48466, \ - 0xd02b20, \ - 0x3010e4, \ - 0x380f4a, \ - 0x685b35, \ - 0xc86f1d, \ - 0x701124, \ - 0x38484c, \ - 0x041552, \ - 0x786c1c, \ - 0xbc3baf, \ - 0x00a040, \ - 0x60fec5, \ - 0xcc4463, \ - 0x6c72e7, \ - 0x18af61, \ - 0x00cdfe, \ - 0xac61ea, \ - 0x38b54d, \ - 0x60c547, \ - 0x28e02c, \ - 0x50ead6, \ - 0x4860bc, \ - 0x403004, \ - 0x0c74c2, \ - 0xa4b197, \ - 0x7cf05f, \ - 0xa4f1e8, \ - 0x70a2b3, \ - 0x4c57ca, \ - 0x68fb7e, \ - 0x90c1c6, \ - 0x9cf48e, \ - 0xfcd848, \ - 0x64b9e8, \ - 0x001cb3, \ - 0x000d93, \ - 0x30d9d9, \ - 0x6030d4, \ - 0x94bf2d, \ - 0xc49880, \ - 0xe0338e, \ - 0x68fef7, \ - 0xbce143, \ - 0x645aed, \ - 0xc0b658, \ - 0x881908, \ - 0xfc2a9c, \ - 0x48605f, \ - 0x188796, \ - 0x002376, \ - 0x84100d, \ - 0x04c23e, \ - 0x5c5188, \ - 0xe89120, \ - 0x9c6c15, \ - 0x4886e8, \ - 0x2c2997, \ - 0x102f6b, \ - 0x00eebd, \ - 0x281878, \ - 0x6045bd, \ - 0x7ced8d, \ - 0xe85b5b, \ - 0x000d3a, \ - 0xe09861, \ - 0xf4f1e1, \ - 0x60beb5, \ - 0xb4e1c4, \ - 0x70aab2, \ - 0x0026ff, \ - 0x406f2a, \ - 0x002557, \ - 0xf05a09, \ - 0x503275, \ - 0x28cc01, \ - 0xb46293, \ - 0x04fe31, \ - 0x845181, \ - 0xd831cf, \ - 0xf8d0bd, \ - 0xfcc734, \ - 0xe4b021, \ - 0xb0ec71, \ - 0x3cbbfd, \ - 0x2cae2b, \ - 0xc488e5, \ - 0x7c9122, \ - 0xe8b4c8, \ - 0x18895b, \ - 0xe0db10, \ - 0xe09971, \ - 0x6077e2, \ - 0x680571, \ - 0x6c2f2c, \ - 0x300d43, \ - 0x6c2779, \ - 0x607edd, \ - 0x9c2a83, \ - 0xe45d75, \ - 0xe4faed, \ - 0xc83f26, \ - 0x54f201, \ - 0xa06090, \ - 0xac3743, \ - 0x141f78, \ - 0x006f64, \ - 0xdc6672, \ - 0x001e7d, \ - 0x3c6200, \ - 0x0024e9, \ - 0x002399, \ - 0xe4e0c5, \ - 0xe8039a, \ - 0xc4731e, \ - 0x8c7712, \ - 0x2013e0, \ - 0x0007ab, \ - 0x0021d2, \ - 0xbc4760, \ - 0xd0176a, \ - 0x2cbaba, \ - 0x24920e, \ - 0x40d3ae, \ - 0xf01dbc, \ - 0x24dbed, \ - 0xac3613, \ - 0x1449e0, \ - 0xc0bdd1, \ - 0xe8508b, \ - 0xf025b7, \ - 0xc8ba94, \ - 0xec1f72, \ - 0x9852b1, \ - 0x1489fd, \ - 0xccfe3c, \ - 0x789ed0, \ - 0xe440e2, \ - 0x1caf05, \ - 0xe492fb, \ - 0x0073e0, \ - 0xbc4486, \ - 0x380b40, \ - 0x002490, \ - 0x0023d7, \ - 0xfca13e, \ - 0xa00798, \ - 0x945103, \ - 0xc819f7, \ - 0x2c4401, \ - 0x28e31f, \ - 0x0c1daf, \ - 0x14f65a, \ - 0x742344, \ - 0xf0b429, \ - 0xec51bc, \ - 0xf079e8, \ - 0x887598, \ - 0xd0b128, \ - 0xd00401, \ - 0xf06d78, \ - 0x10683f, \ - 0x74a722, \ - 0x58a2b5, \ - 0x64899a, \ - 0x88074b, \ - 0x64bc0c, \ - 0xa039f7, \ - 0x041b6d, \ - 0x001f6b, \ - 0x30b4b8, \ - 0x503cea, \ - 0x0c9838, \ - 0x54fcf0, \ - 0x08aed6, \ - 0xa816d0, \ - 0x88bd45, \ - 0x544e90, \ - 0xd03311, \ - 0x70e72c, \ - 0xc0cecd, \ - 0x98e0d9, \ - 0xe0accb, \ - 0x78d75f, \ - 0x2078f0, \ - 0x985aeb, \ - 0xa45e60, \ - 0x006d52, \ - 0x5cadcf, \ - 0xb8e856, \ - 0x90b21f, \ - 0xa8bbcf, \ - 0xc8b5b7, \ - 0x18af8f, \ - 0xf4f951, \ - 0xf0c1f1, \ - 0xec3586, \ - 0x88cb87, \ - 0xac3c0b, \ - 0xcc785f, \ - 0xe88d28, \ - 0x3ce072, \ - 0xf41ba1, \ - 0xa85b78, \ - 0x9cf387, \ - 0x34a395, \ - 0x48437c, \ - 0xac87a3, \ - 0x00f76f, \ - 0xc0f2fb, \ - 0x1caba7, \ - 0x60facd, \ - 0x680927, \ - 0x78a3e4, \ - 0x68a86d, \ - 0xb817c2, \ - 0xb88d12, \ - 0x5c8d4e, \ - 0xe06678, \ - 0x1c1ac0, \ - 0xc8f650, \ - 0x60d9c7, \ - 0x44fb42, \ - 0x64a3cb, \ - 0xd8d1cb, \ - 0x542696, \ - 0x14109f, \ - 0xbc52b7, \ - 0xe0c97a, \ - 0x5c95ae, \ - 0x8cfaba, \ - 0x0cbc9f, \ - 0xbc4cc4, \ - 0x0c1539, \ - 0x908d6c, \ - 0x80006e, \ - 0xb418d1, \ - 0x1499e2, \ - 0xe0c767, \ - 0xa860b6, \ - 0x24f094, \ - 0x90b0ed, \ - 0xc4b301, \ - 0xe05f45, \ - 0x483b38, \ - 0x88e87f, \ - 0xb853ac, \ - 0x2c3361, \ - 0x784f43, \ - 0x404d7f, \ - 0xbc926b, \ - 0x0452f3, \ - 0x241eeb, \ - 0xf431c3, \ - 0x64a5c3, \ - 0x606944, \ - 0xe498d6, \ - 0x0cd746, \ - 0x440010, \ - 0x1c9e46, \ - 0x7c04d0, \ - 0xbc9fef, \ - 0x8866a5, \ - 0x70f087, \ - 0x886b6e, \ - 0x4c74bf, \ - 0x844167, \ - 0xb4f61c, \ - 0xe49adc, \ - 0xb8c111, \ - 0x3408bc, \ - 0xd0817a, \ - 0xc4618b, \ - 0x68ab1e, \ - 0x2c61f6, \ - 0x0026bb, \ - 0x00254b, \ - 0x002436, \ - 0x002332, \ - 0x002312, \ - 0x0019e3, \ - 0x001451, \ - 0x000a27, \ - 0x003065, \ - 0x0050e4, \ - 0xd023db, \ - 0xe0b9ba, \ - 0x3451c9, \ - 0x8c5877, \ - 0x9803d8, \ - 0xc82a14, \ - 0x88c663, \ - 0x8c7b9d, \ - 0x5855ca, \ - 0xcc08e0, \ - 0xe80688, \ - 0x641cb0, \ - 0x3cdcbc, \ - 0xf47190, \ - 0x587a6a, \ - 0xe4c483, \ - 0x8cf5a3, \ - 0x14568e, \ - 0x8058f8, \ - 0xf0d7aa, \ - 0xc49ded, \ - 0xb0aa36, \ - 0x2c5bb8, \ - 0x1c48ce, \ - 0x24f5aa, \ - 0xf877b8, \ - 0x682737, \ - 0x5056bf, \ - 0x9097f3, \ - 0x58c5cb, \ - 0xacafb9, \ - 0x30074d, \ - 0x5c5181, \ - 0x389af6, \ - 0xe0aa96, \ - 0x507705, \ - 0x2c4053, \ - 0x084acf, \ - 0x1cddea, \ - 0x08152f, \ - 0xd461da, \ - 0xc8d083, \ - 0x88e9fe, \ - 0x88ae07, \ - 0x5c0947, \ - 0x38892c, \ - 0x40831d, \ - 0x50bc96, \ - 0x9ce65e, \ - 0x90dd5d, \ - 0x08f69c, \ - 0x00092d, \ - 0xf8db7f, \ - 0xe899c4, \ - 0x24da9b, \ - 0x1c56fe, \ - 0xe4907e, \ - 0x80c5e6, \ - 0x800184, \ - 0xf8cfc5, \ - 0xc808e9, \ - 0x206274, \ - 0x30d587, \ - 0xc0eefb, \ - 0x502e5c, \ - 0x847a88, \ - 0x0025ae, \ - 0x002538, \ - 0x0022a1, \ - 0x00125a, \ - 0x9cd917, \ - 0x9068c3, \ - 0x408805, \ - 0xf8f1b6, \ - 0x001ccc, \ - 0x94ebcd, \ - 0xa4e4b8, \ - 0x389496, \ - 0x0cb319, \ - 0x08ee8b, \ - 0xa89fba, \ - 0xfc1910, \ - 0x083d88, \ - 0x5c2e59, \ - 0x646cb2, \ - 0xf884f2, \ - 0x14b484, \ - 0x608f5c, \ - 0x4cbca5, \ - 0x78595e, \ - 0xb0d09c, \ - 0x4ca56d, \ - 0xa48431, \ - 0xe4f8ef, \ - 0x1432d1, \ - 0xe458e7, \ - 0x8cbfa6, \ - 0x7840e4, \ - 0x9000db, \ - 0x183a2d, \ - 0x08373d, \ - 0x50f520, \ - 0xa4ebd3, \ - 0x28987b, \ - 0xf40e22, \ - 0x9c3aaf, \ - 0x0821ef, \ - 0xa0cbfd, \ - 0x34145f, \ - 0x6c8fb5, \ - 0xac5f3e, \ - 0x509ea7, \ - 0xdccf96, \ - 0x6c2483, \ - 0xc09727, \ - 0xd85b2a, \ - 0xacc33a, \ - 0x88797e, \ - 0x00e091, \ - 0x6cd032, \ - 0xc041f6, \ - 0x0017d5, \ - 0x001247, \ - 0xe4121d, \ - 0x684898, \ - 0xf409d8, \ - 0xb479a7, \ - 0x002339, \ - 0xd487d8, \ - 0x184617, \ - 0x5001bb, \ - 0x380a94, \ - 0xd857ef, \ - 0x1c66aa, \ - 0x58c38b, \ - 0x001ee2, \ - 0x001c43, \ - 0x001d25, \ - 0x3c5a37, \ - 0x549b12, \ - 0x3c8bfe, \ - 0x00265d, \ - 0xd4e8b2, \ - 0x0808c2, \ - 0xb0c4e7, \ - 0xd890e8, \ - 0x34aa8b, \ - 0x24c696, \ - 0x181eb0, \ - 0x20d390, \ - 0x343111, \ - 0x34be00, \ - 0x78521a, \ - 0x7825ad, \ - 0xf4d9fb, \ - 0x0017c9, \ - 0x00166b, \ - 0x00166c, \ - 0xe47cf9, \ - 0x002454, \ - 0x20d5bf, \ - 0x30cda7, \ - 0xc87e75, \ - 0x00233a, \ - 0x60a4d0, \ - 0x2c0e3d, \ - 0xd4970b, \ - 0x64cc2e, \ - 0xb0e235, \ - 0x38a4ed, \ - 0xf48b32, \ - 0x7c787e, \ - 0xc0d3c0, \ - 0x440444, \ - 0xc09f05, \ - 0xcc2d83, \ - 0x38295a, \ - 0x4c1a3d, \ - 0xa81b5a, \ - 0xdc6dcd, \ - 0x54fa3e, \ - 0x0c8910, \ - 0xfcf136, \ - 0x981dfa, \ - 0x84a466, \ - 0x1867b0, \ - 0xccb11a, \ - 0xb8bbaf, \ - 0x60c5ad, \ - 0x28395e, \ - 0xc4ae12, \ - 0xdc74a8, \ - 0xc087eb, \ - 0x74f61c, \ - 0x986f60, \ - 0x4c189a, \ - 0x3cf591, \ - 0x602101, \ - 0xa89675, \ - 0x608e08, \ - 0x7c2edd, \ - 0x3cf7a4, \ - 0x342d0d, \ - 0x94d029, \ - 0x308454, \ - 0x4c49e3, \ - 0x087808, \ - 0xd03169, \ - 0xbc5451, \ - 0x00bf61, \ - 0xf80cf3, \ - 0x30766f, \ - 0x8c3ae3, \ - 0x78f882, \ - 0xb4f1da, \ - 0x0021fb, \ - 0xd013fd, \ - 0xa8b86e, \ - 0x04b167, \ - 0xd86375, \ - 0xdcbfe9, \ - 0x306a85, \ - 0x2047da, \ - 0x8035c1, \ - 0xd02598, \ - 0xa8667f, \ - 0x7014a6, \ - 0x10417f, \ - 0xac293a, \ - 0x94e96a, \ - 0x0c4de9, \ - 0x907240, \ - 0xa88808, \ - 0xc8e0eb, \ - 0x54e43a, \ - 0x28e14c, \ - 0x848e0c, \ - 0xb03495, \ - 0xf0f61c, \ - 0x0c3021, \ - 0xd89695, \ - 0x649abe, \ - 0x5cf5da, \ - 0x20a2e4, \ - 0xf02475, \ - 0x24a074, \ - 0x8863df, \ - 0x609217, \ - 0x34e2fd, \ - 0x0c3e9f, \ - 0x6c709f, \ - 0x6c4008, \ - 0x5c97f3, \ - 0x90fd61, \ - 0x006171, \ - 0x80e650, \ - 0xdc2b2a, \ - 0xb844d9, \ - 0xe0f5c6, \ - 0x949426, \ - 0xcc29f5, \ - 0x58404e, \ - 0xdc0c5c, \ - 0x2c200b, \ - 0xdca4ca, \ - 0x8c8fe9, \ - 0x9810e8, \ - 0xb49cdf, \ - 0xa4e975, \ - 0xc0a53e, \ - 0x9800c6, \ - 0x787b8a, \ - 0x3866f0, \ - 0x20ee28, \ - 0x08f4ab, \ - 0x8c8590, \ - 0xb48b19, \ - 0xe49a79, \ - 0x28a02b, \ - 0xb44bd2, \ - 0x2cf0a2, \ - 0xecadb8, \ - 0x9801a7, \ - 0x609ac1, \ - 0xf07960, \ - 0x9c8ba0, \ - 0x4c3275, \ - 0xe4e4ab, \ - 0xc8334b, \ - 0x00f4b9, \ - 0x0c771a, \ - 0x74e1b6, \ - 0x64200c, \ - 0xc0847a, \ - 0x183451, \ - 0xfc253f, \ - 0x1040f3, \ - 0x6cc26b, \ - 0x182032, \ - 0x70dee2, \ - 0x00c610, \ - 0x101c0c, \ - 0x7cfadf, \ - 0x5cf938, \ - 0x3871de, \ - 0xbc5436, \ - 0x9c4fda, \ - 0x1c5cf2, \ - 0x60fb42, \ - 0x002500, \ - 0x00236c, \ - 0x0021e9, \ - 0x001ff3, \ - 0x001f5b, \ - 0x001e52, \ - 0x001d4f, \ - 0x001124, \ - 0xa8fad8, \ - 0x5c969d, \ - 0xe48b7f, \ - 0x84fcfe, \ - 0x444c0c, \ - 0x8c2daa, \ - 0x6c3e6d, \ - 0x189efc, \ - 0xc09f42, \ - 0xb8f6b1, \ - 0x406c8f, \ - 0xa4d1d2, \ - 0x040cce, \ - 0xd89e3f, \ - 0x28e7cf, \ - 0xc8bcc8, \ - 0xd8a25e, \ - 0x90840d, \ - 0xf81edf, \ - 0xb0ca68, \ - 0x98ca33, \ - 0x68ef43, \ - 0xcc2db7, \ - 0xd4a33d, \ - 0xe4e0a6, \ - 0x70ef00, \ - 0x80ad16, \ - 0x641cae, \ - 0x14205e, \ - 0x5c1dd9, \ - 0x18f1d8, \ - 0xf86fc1, \ - 0xf099b6, \ - 0xdcd3a2, \ - 0x38e7d8, \ - 0xd8b377, \ - 0xb4cef6, \ - 0xd40b1a, \ - 0x5882a8, \ - 0xb4ae2b, \ - 0x0c413e, \ - 0xd0929e, \ - 0x4480eb, \ - 0xb84fd5, \ - 0xec59e7, \ - 0x3059b7, \ - 0x501ac5, \ - 0x1cb094, \ - 0xa0f450, \ - 0x002248, \ - 0xec8892, \ - 0xb07994, \ - 0x141aa3, \ - 0xccc3ea, \ - 0x34bb26, \ - 0x40786a, \ - 0xf40b93, \ - 0x68ed43, \ - 0x34bb1f, \ - 0x489d24, \ - 0x000f86, \ - 0xacee9e, \ - 0xc08997, \ - 0x2827bf, \ - 0xf05b7b, \ - 0x7cf90e, \ - 0xac5a14, \ - 0xb0c559, \ - 0xbcd11f, \ - 0xa0b4a5, \ - 0x80656d, \ - 0x48137e, \ - 0xe83a12, \ - 0x9c0298, \ - 0x6c8336, \ - 0xb8c68e, \ - 0x74458a, \ - 0xa49a58, \ - 0xb4ef39, \ - 0x14a364, \ - 0x3ca10d, \ - 0x206e9c, \ - 0x183f47, \ - 0x0c715d, \ - 0x0c1420, \ - 0xa80600, \ - 0x6cf373, \ - 0x78c3e9, \ - 0xc83870, \ - 0x288335, \ - 0x44783e, \ - 0x202d07, \ - 0x98398e, \ - 0x348a7b, \ - 0xbc765e, \ - 0x78009e, \ - 0x68c44d, \ - 0xf8e61a, \ - 0x888322, \ - 0x84b541, \ - 0x0015b9, \ - 0x001df6, \ - 0xece09b, \ - 0x606bbd, \ - 0x0000f0, \ - 0x4844f7, \ - 0x1c5a3e, \ - 0xf47b5e, \ - 0x008701, \ - 0xfc4203, \ - 0x1c232c, \ - 0xcc61e5, \ - 0x404e36, \ - 0x009ec8, \ - 0xacf7f3, \ - 0x102ab3, \ - 0x584498, \ - 0xa086c6, \ - 0x7c1dd9, \ - 0x9893cc, \ - 0x3ccd93, \ - 0xf06bca, \ - 0x3423ba, \ - 0xd022be, \ - 0xd02544, \ - 0xbc20a4, \ - 0x14f42a, \ - 0xbc851f, \ - 0xb85e7b, \ - 0xc462ea, \ - 0x0023d6, \ - 0x002491, \ - 0x001b98, \ - 0x44f459, \ - 0x34c3ac, \ - 0x94d771, \ - 0x4c3c16, \ - 0x9401c2, \ - 0xb43a28, \ - 0xd0c1b1, \ - 0xf008f1, \ - 0x78471d, \ - 0x3816d1, \ - 0xd48890, \ - 0x002566, \ - 0x00265f, \ - 0xacc1ee, \ - 0x5cba37, \ - 0x7802f8, \ - 0x3096fb, \ - 0xf0ee10, \ - 0xa43d78, \ - 0xec01ee, \ - 0xb83765, \ - 0xc4576e, \ - 0x90f1aa, \ - 0x78bdbc, \ - 0xd47ae2, \ - 0x84c0ef, \ - 0x7c1c68, \ - 0xd463c6, \ - 0x508f4c, \ - 0x7c6456, \ - 0x448f17, \ - 0x04d6aa, \ - 0x9ce063, \ - 0xf06e0b, \ - 0x5c865c, \ - 0xf0b0e7, \ - 0x209bcd, \ - 0xcc20e8, \ - 0x04d13a, \ - 0x0cf346, \ - 0x003de8, \ - 0x485929, \ - 0x34fcef, \ - 0x002483, \ - 0x001c62, \ - 0x583f54, \ - 0x40b0fa, \ - 0xa8922c, \ - 0x98d6f7, \ - 0x505527, \ - 0x0034da, \ - 0xa09169, \ - 0x88365f, \ - 0x9c8c6e, \ - 0xbcffeb, \ - 0x685acf, \ - 0x48746e, \ - 0x54724f, \ - 0x04f13e, \ - 0x600308, \ - 0x80ea96, \ - 0x24a2e1, \ - 0x90b931, \ - 0x280b5c, \ - 0xa8968a, \ - 0x9c04eb, \ - 0x885395, \ - 0x80929f, \ - 0x98b8e3, \ - 0xd8004d, \ - 0x98fe94, \ - 0x68644b, \ - 0xf099bf, \ - 0xfce998, \ - 0x48e9f1, \ - 0x4c7c5f, \ - 0x60f81d, \ - 0x689c70, \ - 0x2cb43a, \ - 0x042665, \ - 0xf4f15a, \ - 0x207d74, \ - 0x4c8d79, \ - 0xfcfc48, \ - 0x38c986, \ - 0x70ece4, \ - 0xd81d72, \ - 0x94f6a3, \ - 0x78fd94, \ - 0x48d705, \ - 0x7c6df8, \ - 0x3cab8e, \ - 0x787e61, \ - 0xd4f46f, \ - 0xc88550, \ - 0xac7f3e, \ - 0xa4c361, \ - 0x087045, \ - 0x40331a, \ - 0xdc3714, \ - 0x789f70, \ - 0x64b0a6, \ - 0x84fcac, \ - 0x6c19c0, \ - 0x20ab37, \ - 0xc0d012, \ - 0xd4dccd, \ - 0x484baa, \ - 0xf80377, \ - 0x14bd61, \ - 0x78886d, \ - 0xa85c2c, \ - 0x00db70, \ - 0xbcec5d, \ - 0xdc415f, \ - 0x30636b, \ - 0x0c5101, \ - 0x086d41, \ - 0x04d3cf, \ - 0x203cae, \ - 0x748d08, \ - 0xa03be3, \ - 0x186590, \ - 0x0010fa, \ - 0x000502, \ - 0xb8782e, \ - 0xa4d18c, \ - 0xcc25ef, \ - 0x68dbca, \ - 0x044bed, \ - 0x6c8dc1, \ - 0x38cada, \ - 0xf45c89, \ - 0x581faa, \ - 0x24ab81, \ - 0x70cd60, \ - 0x7cc537, \ - 0xc42c03, \ - 0xd83062, \ - 0x40d32d, \ - 0x7c6d62, \ - 0x286ab8, \ - 0x403cfc, \ - 0xb8c75d, \ - 0xe8040b, \ - 0xe4ce8f, \ - 0x3c0754, \ - 0xa46706, \ - 0x80b03d, \ - 0xc83c85, \ - 0xa04ea7, \ - 0x409c28, \ - 0x08e689, \ - 0x4cb199, \ - 0x98d6bb, \ - 0x3cd0f8, \ - 0x7cc3a1, \ - 0x002608, \ - 0x001ec2, \ - 0x001b63, \ - 0x0017f2, \ - 0x0016cb, \ - 0x000393, \ - 0x804971, \ - 0x64e682, \ - 0xb4f7a1, \ - 0x785dc8, \ - 0x48c796, \ - 0x804e70, \ - 0x3880df, \ - 0x1094bb, \ - 0xf01898, \ - 0x48a91c, \ - 0xa056f3, \ - 0x549963, \ - 0x28ff3c, \ - 0x902155, \ - 0x64a769, \ - 0xbccfcc, \ - 0xa4516f, \ - 0x3c8375, \ - 0x149a10, \ - 0x0ce725, \ - 0xc0335e, \ - 0x20a99b, \ - 0x4c0bbe, \ - 0x7c1e52, \ - 0xdcb4c4, \ - 0x001dd8, \ - 0x0017fa, \ - 0x0003ff, \ - 0xf8e079, \ - 0x1430c6, \ - 0xe0757d, \ - 0x9cd35b, \ - 0x60af6d, \ - 0xb85a73, \ - 0x103047, \ - 0x109266, \ - 0xb047bf, \ - 0x7c0bc6, \ - 0x804e81, \ - 0x244b81, \ - 0x50a4c8, \ - 0x8425db, \ - 0xd8c4e9, \ - 0x50c8e5, \ - 0x446d6c, \ - 0x38d40b, \ - 0x647791, \ - 0x781fdb, \ - 0x08fc88, \ - 0x30c7ae, \ - 0x18227e, \ - 0x00f46f, \ - 0x9ce6e7, \ - 0xe498d1, \ - 0x5cca1a, \ - 0x70288b, \ - 0x4849c7, \ - 0x205ef7, \ - 0x182666, \ - 0xc06599, \ - 0xcc07ab, \ - 0xe84e84, \ - 0x50fc9f, \ - 0xe432cb, \ - 0x889b39, \ - 0xbcb1f3, \ - 0x38ece4, \ - 0xccf9e8, \ - 0xf0e77e, \ - 0x5ce8eb, \ - 0xb8d9ce, \ - 0x70f927, \ - 0x301966, \ - 0x28bab5, \ - 0x103b59, \ - 0x6cb7f4, \ - 0x001ee1, \ - 0x0018af, \ - 0xbc72b1, \ - 0x78f7be, \ - 0xf49f54, \ - 0x00214c, \ - 0x001632, \ - 0xd0667b, \ - 0x001377, \ - 0x50b7c3, \ - 0x8018a7, \ - 0x444e1a, \ - 0xe8e5d6, \ - 0x5492be, \ - 0x101dc0, \ - 0x0021d1, \ - 0x68dfdd, \ - 0xc46ab7, \ - 0xfc64ba, \ - 0x2082c0, \ - 0x3480b3, \ - 0x7451ba, \ - 0x64b473, \ - 0xcc2d8c, \ - 0x949aa9, \ - 0x20dbab, \ - 0x5c9960, \ - 0x948bc1, \ - 0x4827ea, \ - 0x388c50, \ - 0xa09347, \ - 0xc8f230, \ - 0x1c77f6, \ - 0xe44790, \ - 0xd4503f, \ - 0x40163b, \ - 0x5c497d, \ - 0xe47dbd, \ - 0x503da1, \ - 0x508569, \ - 0x1077b1, \ - 0x5cf6dc, \ - 0x380195, \ - 0xbc1485, \ - 0x88d50c, \ - 0x947be7, \ - 0x00ec0a, \ - 0x54bd79, \ - 0xdc44b6, \ - 0x1007b6, \ - 0xc0174d, \ - 0xa407b6, \ - 0x149f3c, \ - 0x88b4a6, \ - 0x2c5491, \ - 0x5c70a3, \ - 0x10f96f, \ - 0xf01c13, \ - 0x00aa70, \ - 0xbcf5ac, \ - 0xccfa00, \ - 0xf8a9d0, \ - 0x805a04, \ - 0x5caf06, \ - 0xb81daa, \ - 0x10f1f2, \ - 0x0025e5, \ - 0x0022a9, \ - 0xc49a02, \ - 0x344df7, \ - 0xd41a3f, \ - 0xcc6ea4, \ - 0xa46cf1, \ - 0x0ca8a7, \ - 0x54b802, \ - 0x0469f8, \ - 0xbc6c21, \ - 0xc869cd, \ - 0x80d605, \ - 0x587f57, \ - 0xa4b805, \ - 0x70480f, \ - 0x18f643, \ - 0x748114, \ - 0x18ee69, \ - 0xf0dbe2, \ - 0xb8098a, \ - 0x549f13, \ - 0x2c1f23, \ - 0x507a55, \ - 0x9c35eb, \ - 0xa43135, \ - 0xd0034b, \ - 0xa01828, \ - 0xd0a637, \ - 0xd04f7e, \ - 0xd8bb2c, \ - 0x80be05, \ - 0xe0b52d, \ - 0x68ae20, \ - 0xe8802e, \ - 0x7c0191, \ - 0x9c293f, \ - 0x341298, \ - 0x903c92, \ - 0x24240e, \ - 0xa0999b, \ - 0xe0f847, \ - 0x442a60, \ - 0x1093e9, \ - 0xdc2b61, \ - 0xb8ff61, \ - 0x18e7f4, \ - 0x78ca39, \ - 0x5c5948, \ - 0x60334b, \ - 0x9027e4, \ - 0xd49a20, \ - 0xb09fba, \ - 0x8c006d, \ - 0xc06394, \ - 0x843835, \ - 0xe4c63d, \ - 0x54eaa8, \ - 0xa886dd, \ - 0xaccf5c, \ - 0xf0dbf8, \ - 0x98f0ab, \ - 0xdc9b9c, \ - 0x8c2937, \ - 0xdc86d8, \ - 0xa88e24, \ - 0xd8cf9c, \ - 0x04489a, \ - 0x3c15c2, \ - 0x20c9d0, \ - 0x74e2f5, \ - 0x842999, \ - 0x9c207b, \ - 0x283737, \ - 0x148fc6, \ - 0x28cfda, \ - 0x145a05, \ - 0xa0edcd, \ - 0x1ce62b, \ - 0x3090ab, \ - 0x7073cb, \ - 0xf0cba1, \ - 0x045453, \ - 0x40b395, \ - 0x008865, \ - 0x30f7c5, \ - 0x20768f, \ - 0xc0ccf8, \ - 0x80ed2c, \ - 0xe8b2ac, \ - 0x8489ad, \ - 0x8c8ef2, \ - 0xf40f24, \ - 0x84a134, \ - 0x1c9148, \ - 0x5cf7e6, \ - 0xa0d795, \ - 0xcc088d, \ - 0x00b362, \ - 0xf86214, \ - 0xb0702d, \ - 0xd0c5f3, \ - 0x60f445, \ - 0x5082d5, \ - 0x9c84bf, \ - 0x48bf6b, \ - 0x245ba7, \ - 0xbca920, \ - 0xb019c6, \ - 0x58e28f, \ - 0xac1f74, \ - 0x080007, \ - 0xe425e7, \ - 0x28cfe9, \ - 0x9060f1, \ - 0x741bb2, \ - 0x28ed6a, \ - 0x34ab37, \ - 0x60a37d, \ - 0x0056cd, \ - 0x7081eb, \ - 0x086698, \ - 0x24f677, \ - 0x7867d7, \ - 0x5433cb, \ - 0xd0d2b0, \ - 0xd88f76, \ - 0x3c2ef9, \ - 0xdc56e7, \ - 0x347c25, \ - 0xd4909c, \ - 0x041e64, \ - 0x0026b0, \ - 0x00264a, \ - 0x0025bc, \ - 0x0023df, \ - 0x002241, \ - 0x000a95, \ - 0x38e60a, \ - 0x24181d, \ - 0xf4c248, \ - 0xa8515b, \ - 0xc048e6, \ - 0xd07714, \ - 0x749eaf, \ - 0xb841a4, \ - 0xf895ea, \ - 0x50a67f, \ - 0x647033, \ - 0x846878 \ - }; +std::array vendors = { + 0x38f23e, + 0x807abf, + 0x90e7c4, + 0x7c6193, + 0x485073, + 0x74e28c, + 0x8463d6, + 0xd48f33, + 0x2c8a72, + 0x980d2e, + 0xa826d9, + 0xd4206d, + 0x00155d, + 0x806c1b, + 0xa470d6, + 0x985fd3, + 0x1c69a5, + 0x382de8, + 0xd087e2, + 0x205531, + 0x5440ad, + 0x842e27, + 0x50f0d3, + 0x84119e, + 0x08eca9, + 0x10d38a, + 0x382dd1, + 0xe0cbee, + 0x64b853, + 0xf4428f, + 0x188331, + 0x8455a5, + 0xa87c01, + 0xc01173, + 0xbce63f, + 0xb857d8, + 0x94b10a, + 0xe458b8, + 0x088c2c, + 0xb86ce8, + 0x9c65b0, + 0xc8a823, + 0xc44202, + 0xd059e4, + 0x64b310, + 0x9476b7, + 0x8c1abf, + 0xb47443, + 0x30cbf8, + 0x182195, + 0xa88195, + 0x88add2, + 0xd0fccc, + 0x14c913, + 0x4c6641, + 0x3cbdd8, + 0x38256b, + 0x849866, + 0xe89309, + 0x0016db, + 0x5c3c27, + 0x10d542, + 0xa0821f, + 0xc45006, + 0x88329b, + 0xbc8ccd, + 0x400e85, + 0xec9bf3, + 0xf8042e, + 0x843838, + 0x54880e, + 0xbc79ad, + 0x30d6c9, + 0xb0df3a, + 0x805719, + 0x78a873, + 0x041bba, + 0x08fd0e, + 0x08d42b, + 0x00e3b2, + 0xc81479, + 0xf0728c, + 0x94350a, + 0x001fcd, + 0xd0dfc7, + 0x1c62b8, + 0x18e2c2, + 0x001a8a, + 0x002567, + 0xa8f274, + 0x001599, + 0x0012fb, + 0x7cf854, + 0x8cc8cd, + 0xe81132, + 0xa02195, + 0x8c71f8, + 0x04180f, + 0x9463d1, + 0x0cdfa4, + 0xcc051b, + 0x68ebae, + 0x60d0a9, + 0x60a10a, + 0xa07591, + 0x001fcc, + 0xec107b, + 0xa01081, + 0xf4f524, + 0x9c99a0, + 0x185936, + 0x98fae3, + 0x640980, + 0x8cbebe, + 0xf8a45f, + 0xbc8385, + 0x900628, + 0xd4ae05, + 0x3c0518, + 0xc40bcb, + 0xe8bba8, + 0xbc3aea, + 0x8c0ee3, + 0x6c5c14, + 0x78abbb, + 0x1816c9, + 0xfc8f90, + 0x244b03, + 0x988389, + 0x14bb6e, + 0x1c3ade, + 0xf83f51, + 0xd8e0e1, + 0xecf342, + 0x5092b9, + 0xb4bff6, + 0xc8d7b0, + 0x982d68, + 0xecd09f, + 0xe446da, + 0xf4f5db, + 0xd80831, + 0xdc5583, + 0x2c54cf, + 0x001fe3, + 0x0026e2, + 0x001e75, + 0x6cd68a, + 0x2021a5, + 0x0c4885, + 0xdc0b34, + 0xac0d1b, + 0x60e3ac, + 0xf895c7, + 0xc4438f, + 0xa816b2, + 0xe892a4, + 0x700514, + 0x88c9d0, + 0x2c598a, + 0x18f0e4, + 0xec8350, + 0x4cdd31, + 0x703eac, + 0x6c94f8, + 0x84788b, + 0x2cf0ee, + 0x68d93c, + 0x24e314, + 0x28f076, + 0x285aeb, + 0x087402, + 0xccc760, + 0x705aac, + 0xfc643a, + 0xd4e6b7, + 0x2802d8, + 0x9c2ea1, + 0x68967b, + 0xbc6778, + 0xa82066, + 0xb065bd, + 0xf0dce2, + 0x7cd1c3, + 0x705681, + 0x2cbe08, + 0x783a84, + 0x84b153, + 0x6476ba, + 0x54ae27, + 0xf437b7, + 0xf0d1a9, + 0x34c059, + 0x04f7e4, + 0x10ddb1, + 0xb4f0ab, + 0x848506, + 0x7831c1, + 0x8c7c92, + 0xd0e140, + 0xacfdec, + 0xf82793, + 0x40a6d9, + 0x109add, + 0xf0b479, + 0x58b035, + 0x34159e, + 0x286aba, + 0xec852f, + 0x44d884, + 0x003ee1, + 0x7c11be, + 0x04e536, + 0x881fa1, + 0x04db56, + 0x9cfc01, + 0xc81ee7, + 0x34363b, + 0xc01ada, + 0xacbc32, + 0x70700d, + 0x7c5049, + 0x503237, + 0xd4619d, + 0xb0481a, + 0x989e63, + 0xdca904, + 0x48a195, + 0x6cab31, + 0x6c96cf, + 0x3035ad, + 0xa8be27, + 0xb8634d, + 0x9ce33f, + 0xf0989d, + 0xace4b5, + 0xe42b34, + 0x1c36bb, + 0x3c2eff, + 0xf0766f, + 0x40cbc0, + 0x4098ad, + 0x6c4d73, + 0xc48466, + 0xd02b20, + 0x3010e4, + 0x380f4a, + 0x685b35, + 0xc86f1d, + 0x701124, + 0x38484c, + 0x041552, + 0x786c1c, + 0xbc3baf, + 0x00a040, + 0x60fec5, + 0xcc4463, + 0x6c72e7, + 0x18af61, + 0x00cdfe, + 0xac61ea, + 0x38b54d, + 0x60c547, + 0x28e02c, + 0x50ead6, + 0x4860bc, + 0x403004, + 0x0c74c2, + 0xa4b197, + 0x7cf05f, + 0xa4f1e8, + 0x70a2b3, + 0x4c57ca, + 0x68fb7e, + 0x90c1c6, + 0x9cf48e, + 0xfcd848, + 0x64b9e8, + 0x001cb3, + 0x000d93, + 0x30d9d9, + 0x6030d4, + 0x94bf2d, + 0xc49880, + 0xe0338e, + 0x68fef7, + 0xbce143, + 0x645aed, + 0xc0b658, + 0x881908, + 0xfc2a9c, + 0x48605f, + 0x188796, + 0x002376, + 0x84100d, + 0x04c23e, + 0x5c5188, + 0xe89120, + 0x9c6c15, + 0x4886e8, + 0x2c2997, + 0x102f6b, + 0x00eebd, + 0x281878, + 0x6045bd, + 0x7ced8d, + 0xe85b5b, + 0x000d3a, + 0xe09861, + 0xf4f1e1, + 0x60beb5, + 0xb4e1c4, + 0x70aab2, + 0x0026ff, + 0x406f2a, + 0x002557, + 0xf05a09, + 0x503275, + 0x28cc01, + 0xb46293, + 0x04fe31, + 0x845181, + 0xd831cf, + 0xf8d0bd, + 0xfcc734, + 0xe4b021, + 0xb0ec71, + 0x3cbbfd, + 0x2cae2b, + 0xc488e5, + 0x7c9122, + 0xe8b4c8, + 0x18895b, + 0xe0db10, + 0xe09971, + 0x6077e2, + 0x680571, + 0x6c2f2c, + 0x300d43, + 0x6c2779, + 0x607edd, + 0x9c2a83, + 0xe45d75, + 0xe4faed, + 0xc83f26, + 0x54f201, + 0xa06090, + 0xac3743, + 0x141f78, + 0x006f64, + 0xdc6672, + 0x001e7d, + 0x3c6200, + 0x0024e9, + 0x002399, + 0xe4e0c5, + 0xe8039a, + 0xc4731e, + 0x8c7712, + 0x2013e0, + 0x0007ab, + 0x0021d2, + 0xbc4760, + 0xd0176a, + 0x2cbaba, + 0x24920e, + 0x40d3ae, + 0xf01dbc, + 0x24dbed, + 0xac3613, + 0x1449e0, + 0xc0bdd1, + 0xe8508b, + 0xf025b7, + 0xc8ba94, + 0xec1f72, + 0x9852b1, + 0x1489fd, + 0xccfe3c, + 0x789ed0, + 0xe440e2, + 0x1caf05, + 0xe492fb, + 0x0073e0, + 0xbc4486, + 0x380b40, + 0x002490, + 0x0023d7, + 0xfca13e, + 0xa00798, + 0x945103, + 0xc819f7, + 0x2c4401, + 0x28e31f, + 0x0c1daf, + 0x14f65a, + 0x742344, + 0xf0b429, + 0xec51bc, + 0xf079e8, + 0x887598, + 0xd0b128, + 0xd00401, + 0xf06d78, + 0x10683f, + 0x74a722, + 0x58a2b5, + 0x64899a, + 0x88074b, + 0x64bc0c, + 0xa039f7, + 0x041b6d, + 0x001f6b, + 0x30b4b8, + 0x503cea, + 0x0c9838, + 0x54fcf0, + 0x08aed6, + 0xa816d0, + 0x88bd45, + 0x544e90, + 0xd03311, + 0x70e72c, + 0xc0cecd, + 0x98e0d9, + 0xe0accb, + 0x78d75f, + 0x2078f0, + 0x985aeb, + 0xa45e60, + 0x006d52, + 0x5cadcf, + 0xb8e856, + 0x90b21f, + 0xa8bbcf, + 0xc8b5b7, + 0x18af8f, + 0xf4f951, + 0xf0c1f1, + 0xec3586, + 0x88cb87, + 0xac3c0b, + 0xcc785f, + 0xe88d28, + 0x3ce072, + 0xf41ba1, + 0xa85b78, + 0x9cf387, + 0x34a395, + 0x48437c, + 0xac87a3, + 0x00f76f, + 0xc0f2fb, + 0x1caba7, + 0x60facd, + 0x680927, + 0x78a3e4, + 0x68a86d, + 0xb817c2, + 0xb88d12, + 0x5c8d4e, + 0xe06678, + 0x1c1ac0, + 0xc8f650, + 0x60d9c7, + 0x44fb42, + 0x64a3cb, + 0xd8d1cb, + 0x542696, + 0x14109f, + 0xbc52b7, + 0xe0c97a, + 0x5c95ae, + 0x8cfaba, + 0x0cbc9f, + 0xbc4cc4, + 0x0c1539, + 0x908d6c, + 0x80006e, + 0xb418d1, + 0x1499e2, + 0xe0c767, + 0xa860b6, + 0x24f094, + 0x90b0ed, + 0xc4b301, + 0xe05f45, + 0x483b38, + 0x88e87f, + 0xb853ac, + 0x2c3361, + 0x784f43, + 0x404d7f, + 0xbc926b, + 0x0452f3, + 0x241eeb, + 0xf431c3, + 0x64a5c3, + 0x606944, + 0xe498d6, + 0x0cd746, + 0x440010, + 0x1c9e46, + 0x7c04d0, + 0xbc9fef, + 0x8866a5, + 0x70f087, + 0x886b6e, + 0x4c74bf, + 0x844167, + 0xb4f61c, + 0xe49adc, + 0xb8c111, + 0x3408bc, + 0xd0817a, + 0xc4618b, + 0x68ab1e, + 0x2c61f6, + 0x0026bb, + 0x00254b, + 0x002436, + 0x002332, + 0x002312, + 0x0019e3, + 0x001451, + 0x000a27, + 0x003065, + 0x0050e4, + 0xd023db, + 0xe0b9ba, + 0x3451c9, + 0x8c5877, + 0x9803d8, + 0xc82a14, + 0x88c663, + 0x8c7b9d, + 0x5855ca, + 0xcc08e0, + 0xe80688, + 0x641cb0, + 0x3cdcbc, + 0xf47190, + 0x587a6a, + 0xe4c483, + 0x8cf5a3, + 0x14568e, + 0x8058f8, + 0xf0d7aa, + 0xc49ded, + 0xb0aa36, + 0x2c5bb8, + 0x1c48ce, + 0x24f5aa, + 0xf877b8, + 0x682737, + 0x5056bf, + 0x9097f3, + 0x58c5cb, + 0xacafb9, + 0x30074d, + 0x5c5181, + 0x389af6, + 0xe0aa96, + 0x507705, + 0x2c4053, + 0x084acf, + 0x1cddea, + 0x08152f, + 0xd461da, + 0xc8d083, + 0x88e9fe, + 0x88ae07, + 0x5c0947, + 0x38892c, + 0x40831d, + 0x50bc96, + 0x9ce65e, + 0x90dd5d, + 0x08f69c, + 0x00092d, + 0xf8db7f, + 0xe899c4, + 0x24da9b, + 0x1c56fe, + 0xe4907e, + 0x80c5e6, + 0x800184, + 0xf8cfc5, + 0xc808e9, + 0x206274, + 0x30d587, + 0xc0eefb, + 0x502e5c, + 0x847a88, + 0x0025ae, + 0x002538, + 0x0022a1, + 0x00125a, + 0x9cd917, + 0x9068c3, + 0x408805, + 0xf8f1b6, + 0x001ccc, + 0x94ebcd, + 0xa4e4b8, + 0x389496, + 0x0cb319, + 0x08ee8b, + 0xa89fba, + 0xfc1910, + 0x083d88, + 0x5c2e59, + 0x646cb2, + 0xf884f2, + 0x14b484, + 0x608f5c, + 0x4cbca5, + 0x78595e, + 0xb0d09c, + 0x4ca56d, + 0xa48431, + 0xe4f8ef, + 0x1432d1, + 0xe458e7, + 0x8cbfa6, + 0x7840e4, + 0x9000db, + 0x183a2d, + 0x08373d, + 0x50f520, + 0xa4ebd3, + 0x28987b, + 0xf40e22, + 0x9c3aaf, + 0x0821ef, + 0xa0cbfd, + 0x34145f, + 0x6c8fb5, + 0xac5f3e, + 0x509ea7, + 0xdccf96, + 0x6c2483, + 0xc09727, + 0xd85b2a, + 0xacc33a, + 0x88797e, + 0x00e091, + 0x6cd032, + 0xc041f6, + 0x0017d5, + 0x001247, + 0xe4121d, + 0x684898, + 0xf409d8, + 0xb479a7, + 0x002339, + 0xd487d8, + 0x184617, + 0x5001bb, + 0x380a94, + 0xd857ef, + 0x1c66aa, + 0x58c38b, + 0x001ee2, + 0x001c43, + 0x001d25, + 0x3c5a37, + 0x549b12, + 0x3c8bfe, + 0x00265d, + 0xd4e8b2, + 0x0808c2, + 0xb0c4e7, + 0xd890e8, + 0x34aa8b, + 0x24c696, + 0x181eb0, + 0x20d390, + 0x343111, + 0x34be00, + 0x78521a, + 0x7825ad, + 0xf4d9fb, + 0x0017c9, + 0x00166b, + 0x00166c, + 0xe47cf9, + 0x002454, + 0x20d5bf, + 0x30cda7, + 0xc87e75, + 0x00233a, + 0x60a4d0, + 0x2c0e3d, + 0xd4970b, + 0x64cc2e, + 0xb0e235, + 0x38a4ed, + 0xf48b32, + 0x7c787e, + 0xc0d3c0, + 0x440444, + 0xc09f05, + 0xcc2d83, + 0x38295a, + 0x4c1a3d, + 0xa81b5a, + 0xdc6dcd, + 0x54fa3e, + 0x0c8910, + 0xfcf136, + 0x981dfa, + 0x84a466, + 0x1867b0, + 0xccb11a, + 0xb8bbaf, + 0x60c5ad, + 0x28395e, + 0xc4ae12, + 0xdc74a8, + 0xc087eb, + 0x74f61c, + 0x986f60, + 0x4c189a, + 0x3cf591, + 0x602101, + 0xa89675, + 0x608e08, + 0x7c2edd, + 0x3cf7a4, + 0x342d0d, + 0x94d029, + 0x308454, + 0x4c49e3, + 0x087808, + 0xd03169, + 0xbc5451, + 0x00bf61, + 0xf80cf3, + 0x30766f, + 0x8c3ae3, + 0x78f882, + 0xb4f1da, + 0x0021fb, + 0xd013fd, + 0xa8b86e, + 0x04b167, + 0xd86375, + 0xdcbfe9, + 0x306a85, + 0x2047da, + 0x8035c1, + 0xd02598, + 0xa8667f, + 0x7014a6, + 0x10417f, + 0xac293a, + 0x94e96a, + 0x0c4de9, + 0x907240, + 0xa88808, + 0xc8e0eb, + 0x54e43a, + 0x28e14c, + 0x848e0c, + 0xb03495, + 0xf0f61c, + 0x0c3021, + 0xd89695, + 0x649abe, + 0x5cf5da, + 0x20a2e4, + 0xf02475, + 0x24a074, + 0x8863df, + 0x609217, + 0x34e2fd, + 0x0c3e9f, + 0x6c709f, + 0x6c4008, + 0x5c97f3, + 0x90fd61, + 0x006171, + 0x80e650, + 0xdc2b2a, + 0xb844d9, + 0xe0f5c6, + 0x949426, + 0xcc29f5, + 0x58404e, + 0xdc0c5c, + 0x2c200b, + 0xdca4ca, + 0x8c8fe9, + 0x9810e8, + 0xb49cdf, + 0xa4e975, + 0xc0a53e, + 0x9800c6, + 0x787b8a, + 0x3866f0, + 0x20ee28, + 0x08f4ab, + 0x8c8590, + 0xb48b19, + 0xe49a79, + 0x28a02b, + 0xb44bd2, + 0x2cf0a2, + 0xecadb8, + 0x9801a7, + 0x609ac1, + 0xf07960, + 0x9c8ba0, + 0x4c3275, + 0xe4e4ab, + 0xc8334b, + 0x00f4b9, + 0x0c771a, + 0x74e1b6, + 0x64200c, + 0xc0847a, + 0x183451, + 0xfc253f, + 0x1040f3, + 0x6cc26b, + 0x182032, + 0x70dee2, + 0x00c610, + 0x101c0c, + 0x7cfadf, + 0x5cf938, + 0x3871de, + 0xbc5436, + 0x9c4fda, + 0x1c5cf2, + 0x60fb42, + 0x002500, + 0x00236c, + 0x0021e9, + 0x001ff3, + 0x001f5b, + 0x001e52, + 0x001d4f, + 0x001124, + 0xa8fad8, + 0x5c969d, + 0xe48b7f, + 0x84fcfe, + 0x444c0c, + 0x8c2daa, + 0x6c3e6d, + 0x189efc, + 0xc09f42, + 0xb8f6b1, + 0x406c8f, + 0xa4d1d2, + 0x040cce, + 0xd89e3f, + 0x28e7cf, + 0xc8bcc8, + 0xd8a25e, + 0x90840d, + 0xf81edf, + 0xb0ca68, + 0x98ca33, + 0x68ef43, + 0xcc2db7, + 0xd4a33d, + 0xe4e0a6, + 0x70ef00, + 0x80ad16, + 0x641cae, + 0x14205e, + 0x5c1dd9, + 0x18f1d8, + 0xf86fc1, + 0xf099b6, + 0xdcd3a2, + 0x38e7d8, + 0xd8b377, + 0xb4cef6, + 0xd40b1a, + 0x5882a8, + 0xb4ae2b, + 0x0c413e, + 0xd0929e, + 0x4480eb, + 0xb84fd5, + 0xec59e7, + 0x3059b7, + 0x501ac5, + 0x1cb094, + 0xa0f450, + 0x002248, + 0xec8892, + 0xb07994, + 0x141aa3, + 0xccc3ea, + 0x34bb26, + 0x40786a, + 0xf40b93, + 0x68ed43, + 0x34bb1f, + 0x489d24, + 0x000f86, + 0xacee9e, + 0xc08997, + 0x2827bf, + 0xf05b7b, + 0x7cf90e, + 0xac5a14, + 0xb0c559, + 0xbcd11f, + 0xa0b4a5, + 0x80656d, + 0x48137e, + 0xe83a12, + 0x9c0298, + 0x6c8336, + 0xb8c68e, + 0x74458a, + 0xa49a58, + 0xb4ef39, + 0x14a364, + 0x3ca10d, + 0x206e9c, + 0x183f47, + 0x0c715d, + 0x0c1420, + 0xa80600, + 0x6cf373, + 0x78c3e9, + 0xc83870, + 0x288335, + 0x44783e, + 0x202d07, + 0x98398e, + 0x348a7b, + 0xbc765e, + 0x78009e, + 0x68c44d, + 0xf8e61a, + 0x888322, + 0x84b541, + 0x0015b9, + 0x001df6, + 0xece09b, + 0x606bbd, + 0x0000f0, + 0x4844f7, + 0x1c5a3e, + 0xf47b5e, + 0x008701, + 0xfc4203, + 0x1c232c, + 0xcc61e5, + 0x404e36, + 0x009ec8, + 0xacf7f3, + 0x102ab3, + 0x584498, + 0xa086c6, + 0x7c1dd9, + 0x9893cc, + 0x3ccd93, + 0xf06bca, + 0x3423ba, + 0xd022be, + 0xd02544, + 0xbc20a4, + 0x14f42a, + 0xbc851f, + 0xb85e7b, + 0xc462ea, + 0x0023d6, + 0x002491, + 0x001b98, + 0x44f459, + 0x34c3ac, + 0x94d771, + 0x4c3c16, + 0x9401c2, + 0xb43a28, + 0xd0c1b1, + 0xf008f1, + 0x78471d, + 0x3816d1, + 0xd48890, + 0x002566, + 0x00265f, + 0xacc1ee, + 0x5cba37, + 0x7802f8, + 0x3096fb, + 0xf0ee10, + 0xa43d78, + 0xec01ee, + 0xb83765, + 0xc4576e, + 0x90f1aa, + 0x78bdbc, + 0xd47ae2, + 0x84c0ef, + 0x7c1c68, + 0xd463c6, + 0x508f4c, + 0x7c6456, + 0x448f17, + 0x04d6aa, + 0x9ce063, + 0xf06e0b, + 0x5c865c, + 0xf0b0e7, + 0x209bcd, + 0xcc20e8, + 0x04d13a, + 0x0cf346, + 0x003de8, + 0x485929, + 0x34fcef, + 0x002483, + 0x001c62, + 0x583f54, + 0x40b0fa, + 0xa8922c, + 0x98d6f7, + 0x505527, + 0x0034da, + 0xa09169, + 0x88365f, + 0x9c8c6e, + 0xbcffeb, + 0x685acf, + 0x48746e, + 0x54724f, + 0x04f13e, + 0x600308, + 0x80ea96, + 0x24a2e1, + 0x90b931, + 0x280b5c, + 0xa8968a, + 0x9c04eb, + 0x885395, + 0x80929f, + 0x98b8e3, + 0xd8004d, + 0x98fe94, + 0x68644b, + 0xf099bf, + 0xfce998, + 0x48e9f1, + 0x4c7c5f, + 0x60f81d, + 0x689c70, + 0x2cb43a, + 0x042665, + 0xf4f15a, + 0x207d74, + 0x4c8d79, + 0xfcfc48, + 0x38c986, + 0x70ece4, + 0xd81d72, + 0x94f6a3, + 0x78fd94, + 0x48d705, + 0x7c6df8, + 0x3cab8e, + 0x787e61, + 0xd4f46f, + 0xc88550, + 0xac7f3e, + 0xa4c361, + 0x087045, + 0x40331a, + 0xdc3714, + 0x789f70, + 0x64b0a6, + 0x84fcac, + 0x6c19c0, + 0x20ab37, + 0xc0d012, + 0xd4dccd, + 0x484baa, + 0xf80377, + 0x14bd61, + 0x78886d, + 0xa85c2c, + 0x00db70, + 0xbcec5d, + 0xdc415f, + 0x30636b, + 0x0c5101, + 0x086d41, + 0x04d3cf, + 0x203cae, + 0x748d08, + 0xa03be3, + 0x186590, + 0x0010fa, + 0x000502, + 0xb8782e, + 0xa4d18c, + 0xcc25ef, + 0x68dbca, + 0x044bed, + 0x6c8dc1, + 0x38cada, + 0xf45c89, + 0x581faa, + 0x24ab81, + 0x70cd60, + 0x7cc537, + 0xc42c03, + 0xd83062, + 0x40d32d, + 0x7c6d62, + 0x286ab8, + 0x403cfc, + 0xb8c75d, + 0xe8040b, + 0xe4ce8f, + 0x3c0754, + 0xa46706, + 0x80b03d, + 0xc83c85, + 0xa04ea7, + 0x409c28, + 0x08e689, + 0x4cb199, + 0x98d6bb, + 0x3cd0f8, + 0x7cc3a1, + 0x002608, + 0x001ec2, + 0x001b63, + 0x0017f2, + 0x0016cb, + 0x000393, + 0x804971, + 0x64e682, + 0xb4f7a1, + 0x785dc8, + 0x48c796, + 0x804e70, + 0x3880df, + 0x1094bb, + 0xf01898, + 0x48a91c, + 0xa056f3, + 0x549963, + 0x28ff3c, + 0x902155, + 0x64a769, + 0xbccfcc, + 0xa4516f, + 0x3c8375, + 0x149a10, + 0x0ce725, + 0xc0335e, + 0x20a99b, + 0x4c0bbe, + 0x7c1e52, + 0xdcb4c4, + 0x001dd8, + 0x0017fa, + 0x0003ff, + 0xf8e079, + 0x1430c6, + 0xe0757d, + 0x9cd35b, + 0x60af6d, + 0xb85a73, + 0x103047, + 0x109266, + 0xb047bf, + 0x7c0bc6, + 0x804e81, + 0x244b81, + 0x50a4c8, + 0x8425db, + 0xd8c4e9, + 0x50c8e5, + 0x446d6c, + 0x38d40b, + 0x647791, + 0x781fdb, + 0x08fc88, + 0x30c7ae, + 0x18227e, + 0x00f46f, + 0x9ce6e7, + 0xe498d1, + 0x5cca1a, + 0x70288b, + 0x4849c7, + 0x205ef7, + 0x182666, + 0xc06599, + 0xcc07ab, + 0xe84e84, + 0x50fc9f, + 0xe432cb, + 0x889b39, + 0xbcb1f3, + 0x38ece4, + 0xccf9e8, + 0xf0e77e, + 0x5ce8eb, + 0xb8d9ce, + 0x70f927, + 0x301966, + 0x28bab5, + 0x103b59, + 0x6cb7f4, + 0x001ee1, + 0x0018af, + 0xbc72b1, + 0x78f7be, + 0xf49f54, + 0x00214c, + 0x001632, + 0xd0667b, + 0x001377, + 0x50b7c3, + 0x8018a7, + 0x444e1a, + 0xe8e5d6, + 0x5492be, + 0x101dc0, + 0x0021d1, + 0x68dfdd, + 0xc46ab7, + 0xfc64ba, + 0x2082c0, + 0x3480b3, + 0x7451ba, + 0x64b473, + 0xcc2d8c, + 0x949aa9, + 0x20dbab, + 0x5c9960, + 0x948bc1, + 0x4827ea, + 0x388c50, + 0xa09347, + 0xc8f230, + 0x1c77f6, + 0xe44790, + 0xd4503f, + 0x40163b, + 0x5c497d, + 0xe47dbd, + 0x503da1, + 0x508569, + 0x1077b1, + 0x5cf6dc, + 0x380195, + 0xbc1485, + 0x88d50c, + 0x947be7, + 0x00ec0a, + 0x54bd79, + 0xdc44b6, + 0x1007b6, + 0xc0174d, + 0xa407b6, + 0x149f3c, + 0x88b4a6, + 0x2c5491, + 0x5c70a3, + 0x10f96f, + 0xf01c13, + 0x00aa70, + 0xbcf5ac, + 0xccfa00, + 0xf8a9d0, + 0x805a04, + 0x5caf06, + 0xb81daa, + 0x10f1f2, + 0x0025e5, + 0x0022a9, + 0xc49a02, + 0x344df7, + 0xd41a3f, + 0xcc6ea4, + 0xa46cf1, + 0x0ca8a7, + 0x54b802, + 0x0469f8, + 0xbc6c21, + 0xc869cd, + 0x80d605, + 0x587f57, + 0xa4b805, + 0x70480f, + 0x18f643, + 0x748114, + 0x18ee69, + 0xf0dbe2, + 0xb8098a, + 0x549f13, + 0x2c1f23, + 0x507a55, + 0x9c35eb, + 0xa43135, + 0xd0034b, + 0xa01828, + 0xd0a637, + 0xd04f7e, + 0xd8bb2c, + 0x80be05, + 0xe0b52d, + 0x68ae20, + 0xe8802e, + 0x7c0191, + 0x9c293f, + 0x341298, + 0x903c92, + 0x24240e, + 0xa0999b, + 0xe0f847, + 0x442a60, + 0x1093e9, + 0xdc2b61, + 0xb8ff61, + 0x18e7f4, + 0x78ca39, + 0x5c5948, + 0x60334b, + 0x9027e4, + 0xd49a20, + 0xb09fba, + 0x8c006d, + 0xc06394, + 0x843835, + 0xe4c63d, + 0x54eaa8, + 0xa886dd, + 0xaccf5c, + 0xf0dbf8, + 0x98f0ab, + 0xdc9b9c, + 0x8c2937, + 0xdc86d8, + 0xa88e24, + 0xd8cf9c, + 0x04489a, + 0x3c15c2, + 0x20c9d0, + 0x74e2f5, + 0x842999, + 0x9c207b, + 0x283737, + 0x148fc6, + 0x28cfda, + 0x145a05, + 0xa0edcd, + 0x1ce62b, + 0x3090ab, + 0x7073cb, + 0xf0cba1, + 0x045453, + 0x40b395, + 0x008865, + 0x30f7c5, + 0x20768f, + 0xc0ccf8, + 0x80ed2c, + 0xe8b2ac, + 0x8489ad, + 0x8c8ef2, + 0xf40f24, + 0x84a134, + 0x1c9148, + 0x5cf7e6, + 0xa0d795, + 0xcc088d, + 0x00b362, + 0xf86214, + 0xb0702d, + 0xd0c5f3, + 0x60f445, + 0x5082d5, + 0x9c84bf, + 0x48bf6b, + 0x245ba7, + 0xbca920, + 0xb019c6, + 0x58e28f, + 0xac1f74, + 0x080007, + 0xe425e7, + 0x28cfe9, + 0x9060f1, + 0x741bb2, + 0x28ed6a, + 0x34ab37, + 0x60a37d, + 0x0056cd, + 0x7081eb, + 0x086698, + 0x24f677, + 0x7867d7, + 0x5433cb, + 0xd0d2b0, + 0xd88f76, + 0x3c2ef9, + 0xdc56e7, + 0x347c25, + 0xd4909c, + 0x041e64, + 0x0026b0, + 0x00264a, + 0x0025bc, + 0x0023df, + 0x002241, + 0x000a95, + 0x38e60a, + 0x24181d, + 0xf4c248, + 0xa8515b, + 0xc048e6, + 0xd07714, + 0x749eaf, + 0xb841a4, + 0xf895ea, + 0x50a67f, + 0x647033, + 0x846878 +}; diff --git a/src/wifisniffer.cpp b/src/wifisniffer.cpp deleted file mode 100644 index 23d6f8f7..00000000 --- a/src/wifisniffer.cpp +++ /dev/null @@ -1,98 +0,0 @@ -// Basic Config -#include "main.h" -#include "globals.h" - -// ESP32 Functions -#include - -#ifdef VENDORFILTER - #include - #include - #include "vendor_array.h" -#endif - -// Local logging tag -static const char *TAG = "wifisniffer"; - -// function defined in rokkithash.cpp -uint32_t rokkit(const char * , int ); - -static wifi_country_t wifi_country = {.cc=WIFI_MY_COUNTRY, .schan=WIFI_CHANNEL_MIN, .nchan=WIFI_CHANNEL_MAX, .policy=WIFI_COUNTRY_POLICY_MANUAL}; - -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; - -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); - -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 - wifi_promiscuous_filter_t filter = {.filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT}; // we need only MGMT frames - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); // configure Wifi with cfg - ESP_ERROR_CHECK(esp_wifi_set_country(&wifi_country)); // set locales for RF and channels - ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); // we don't need NVRAM - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL)); - 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)); // now switch on monitor mode -} - -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 [6]; // uint16_t -> 2 byte -> 5 decimals + '0' terminator -> 6 chars - char macbuf [21]; // uint64_t -> 8 byte -> 10 decimals + '0' terminator -> 21 chars - uint64_t addr2int; - uint32_t vendor2int; - uint16_t hashedmac; - std::pair::iterator, bool> newmac; - - if (( cfg.rssilimit == 0 ) || (ppkt->rx_ctrl.rssi > cfg.rssilimit )) { // rssi is negative value - 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 // uses vendor array with prefiltered OUIs (no local nd no group MACs, bits 0+1 in 1st byte of OUI) - 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 - // 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 |= (uint64_t) salt << 48; // prepend 16-bit salt to 48-bit MAC - snprintf(macbuf, 21, "%llx", addr2int); // convert unsigned 64-bit salted MAC to 16 digit hex string - hashedmac = rokkit(macbuf, 5); // hash MAC string, use 5 chars to fit hash in uint16_t container - newmac = macs.insert(hashedmac); // store hashed MAC only if first time seen - if (newmac.second) { // if first time seen MAC - macnum++; // increment MAC counter - snprintf(counter, 6, "%i", macnum); // convert 16-bit MAC counter to decimal counter value - u8x8.draw2x2String(0, 0, counter); // display counter - ESP_LOGI(TAG, "#%05i: RSSI %04d -> Hash %04x", macnum, ppkt->rx_ctrl.rssi, hashedmac); - } - -#ifdef VENDORFILTER - } -#endif - } else - ESP_LOGI(TAG, "RSSI %04d -> ignoring (limit: %i)", ppkt->rx_ctrl.rssi, cfg.rssilimit); - - yield(); -}