acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

ESPWiFiAnalyzerUTF8.ino (11119B)

      1 /*
      2  * ESP WiFi Analyzer
      3  * Require ESP8266/ESP32 board support.
      4  */
      5 
      6 // POWER SAVING SETTING
      7 #define SCAN_INTERVAL 3000
      8 // #define SCAN_COUNT_SLEEP 3
      9 // #define LCD_PWR_PIN 14
     10 
     11 /*******************************************************************************
     12  * Start of Arduino_GFX setting
     13  *
     14  * Arduino_GFX try to find the settings depends on selected board in Arduino IDE
     15  * Or you can define the display dev kit not in the board list
     16  * Defalult pin list for non display dev kit:
     17  * Arduino Nano, Micro and more: CS:  9, DC:  8, RST:  7, BL:  6, SCK: 13, MOSI: 11, MISO: 12
     18  * ESP32 various dev board     : CS:  5, DC: 27, RST: 33, BL: 22, SCK: 18, MOSI: 23, MISO: nil
     19  * ESP32-C3 various dev board  : CS:  7, DC:  2, RST:  1, BL:  3, SCK:  4, MOSI:  6, MISO: nil
     20  * ESP32-S2 various dev board  : CS: 34, DC: 38, RST: 33, BL: 21, SCK: 36, MOSI: 35, MISO: nil
     21  * ESP32-S3 various dev board  : CS: 40, DC: 41, RST: 42, BL: 48, SCK: 36, MOSI: 35, MISO: nil
     22  * ESP8266 various dev board   : CS: 15, DC:  4, RST:  2, BL:  5, SCK: 14, MOSI: 13, MISO: 12
     23  * Raspberry Pi Pico dev board : CS: 17, DC: 27, RST: 26, BL: 28, SCK: 18, MOSI: 19, MISO: 16
     24  * RTL8720 BW16 old patch core : CS: 18, DC: 17, RST:  2, BL: 23, SCK: 19, MOSI: 21, MISO: 20
     25  * RTL8720_BW16 Official core  : CS:  9, DC:  8, RST:  6, BL:  3, SCK: 10, MOSI: 12, MISO: 11
     26  * RTL8722 dev board           : CS: 18, DC: 17, RST: 22, BL: 23, SCK: 13, MOSI: 11, MISO: 12
     27  * RTL8722_mini dev board      : CS: 12, DC: 14, RST: 15, BL: 13, SCK: 11, MOSI:  9, MISO: 10
     28  * Seeeduino XIAO dev board    : CS:  3, DC:  2, RST:  1, BL:  0, SCK:  8, MOSI: 10, MISO:  9
     29  * Teensy 4.1 dev board        : CS: 39, DC: 41, RST: 40, BL: 22, SCK: 13, MOSI: 11, MISO: 12
     30  ******************************************************************************/
     31 #include <U8g2lib.h>
     32 #include <Arduino_GFX_Library.h>
     33 
     34 #define GFX_BL DF_GFX_BL // default backlight pin, you may replace DF_GFX_BL to actual backlight pin
     35 
     36 /* More dev device declaration: https://github.com/moononournation/Arduino_GFX/wiki/Dev-Device-Declaration */
     37 #if defined(DISPLAY_DEV_KIT)
     38 Arduino_GFX *gfx = create_default_Arduino_GFX();
     39 #else /* !defined(DISPLAY_DEV_KIT) */
     40 
     41 /* More data bus class: https://github.com/moononournation/Arduino_GFX/wiki/Data-Bus-Class */
     42 Arduino_DataBus *bus = create_default_Arduino_DataBus();
     43 
     44 /* More display class: https://github.com/moononournation/Arduino_GFX/wiki/Display-Class */
     45 Arduino_GFX *gfx = new Arduino_ILI9341(bus, DF_GFX_RST, 3 /* rotation */, false /* IPS */);
     46 
     47 #endif /* !defined(DISPLAY_DEV_KIT) */
     48 /*******************************************************************************
     49  * End of Arduino_GFX setting
     50  ******************************************************************************/
     51 
     52 #if defined(ESP32)
     53 #include "WiFi.h"
     54 #else
     55 #include "ESP8266WiFi.h"
     56 #define log_i(format, ...) Serial.printf(format, ##__VA_ARGS__)
     57 #endif
     58 
     59 int16_t w, h, text_size, banner_height, graph_baseline, graph_height, channel_width, signal_width;
     60 
     61 // RSSI RANGE
     62 #define RSSI_CEILING -40
     63 #define RSSI_FLOOR -100
     64 
     65 // Channel color mapping from channel 1 to 14
     66 uint16_t channel_color[] = {
     67     RED, ORANGE, YELLOW, GREEN, CYAN, BLUE, MAGENTA,
     68     RED, ORANGE, YELLOW, GREEN, CYAN, BLUE, MAGENTA};
     69 
     70 uint8_t scan_count = 0;
     71 
     72 void setup()
     73 {
     74   Serial.begin(115200);
     75   // Serial.setDebugOutput(true);
     76   // while(!Serial);
     77   Serial.println("ESP WiFi Analyzer UTF8");
     78 
     79 #ifdef GFX_EXTRA_PRE_INIT
     80   GFX_EXTRA_PRE_INIT();
     81 #endif
     82 
     83   // Set WiFi to station mode and disconnect from an AP if it was previously connected
     84   WiFi.mode(WIFI_STA);
     85   WiFi.disconnect();
     86   delay(100);
     87 
     88 #if defined(LCD_PWR_PIN)
     89   pinMode(LCD_PWR_PIN, OUTPUT);    // sets the pin as output
     90   digitalWrite(LCD_PWR_PIN, HIGH); // power on
     91 #endif
     92 
     93 #ifdef GFX_BL
     94   pinMode(GFX_BL, OUTPUT);
     95   digitalWrite(GFX_BL, HIGH);
     96 #endif
     97 
     98   // init LCD
     99   gfx->begin();
    100   gfx->setUTF8Print(true); // enable UTF8 support for the Arduino print() function
    101   gfx->setFont(u8g2_font_unifont_t_cjk);
    102 
    103   w = gfx->width();
    104   h = gfx->height();
    105   text_size = (w < 224) ? 1 : 2;
    106   banner_height = text_size * 16;
    107   graph_baseline = h - (2 * 16);                            // minus 2 text lines
    108   graph_height = graph_baseline - banner_height - (2 * 16); // minus 2 text lines
    109   channel_width = w / 17;
    110   signal_width = channel_width * 2;
    111 
    112   // init banner
    113   gfx->setTextSize(text_size);
    114   gfx->fillScreen(BLACK);
    115   gfx->setTextColor(RED);
    116   gfx->setCursor(0, 28);
    117   gfx->print("ESP");
    118   gfx->setTextColor(WHITE);
    119   gfx->print(" WiFi分析儀");
    120 }
    121 
    122 bool matchBssidPrefix(uint8_t *a, uint8_t *b)
    123 {
    124   for (uint8_t i = 0; i < 5; i++)
    125   { // only compare first 5 bytes
    126     if (a[i] != b[i])
    127     {
    128       return false;
    129     }
    130   }
    131   return true;
    132 }
    133 
    134 void loop()
    135 {
    136   uint8_t ap_count_list[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    137   int32_t noise_list[] = {RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR};
    138   int32_t peak_list[] = {RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR};
    139   int16_t peak_id_list[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
    140   int32_t channel;
    141   int16_t idx;
    142   int32_t rssi;
    143   uint8_t *bssid;
    144   String ssid;
    145   uint16_t color;
    146   int16_t height, offset, text_width;
    147 
    148   // WiFi.scanNetworks will return the number of networks found
    149 #if defined(ESP32)
    150   int n = WiFi.scanNetworks(false /* async */, true /* show_hidden */, true /* passive */, 500 /* max_ms_per_chan */);
    151 #else
    152   int n = WiFi.scanNetworks(false /* async */, true /* show_hidden */);
    153 #endif
    154 
    155   // clear old graph
    156   gfx->fillRect(0, banner_height, w, h - banner_height, BLACK);
    157   gfx->setTextSize(1);
    158 
    159   if (n == 0)
    160   {
    161     gfx->setTextColor(WHITE);
    162     gfx->setCursor(0, banner_height + 14);
    163     gfx->println("找不到WiFi");
    164   }
    165   else
    166   {
    167     for (int i = 0; i < n; i++)
    168     {
    169       channel = WiFi.channel(i);
    170       idx = channel - 1;
    171       rssi = WiFi.RSSI(i);
    172       bssid = WiFi.BSSID(i);
    173 
    174       // channel peak stat
    175       if (peak_list[idx] < rssi)
    176       {
    177         peak_list[idx] = rssi;
    178         peak_id_list[idx] = i;
    179       }
    180 
    181       // check signal come from same AP
    182       bool duplicate_SSID = false;
    183       for (int j = 0; j < i; j++)
    184       {
    185         if ((WiFi.channel(j) == channel) && matchBssidPrefix(WiFi.BSSID(j), bssid))
    186         {
    187           duplicate_SSID = true;
    188           break;
    189         }
    190       }
    191 
    192       if (!duplicate_SSID)
    193       {
    194         ap_count_list[idx]++;
    195 
    196         // noise stat
    197         int32_t noise = rssi - RSSI_FLOOR;
    198         noise *= noise;
    199         if (channel > 4)
    200         {
    201           noise_list[idx - 4] += noise;
    202         }
    203         if (channel > 3)
    204         {
    205           noise_list[idx - 3] += noise;
    206         }
    207         if (channel > 2)
    208         {
    209           noise_list[idx - 2] += noise;
    210         }
    211         if (channel > 1)
    212         {
    213           noise_list[idx - 1] += noise;
    214         }
    215         noise_list[idx] += noise;
    216         if (channel < 14)
    217         {
    218           noise_list[idx + 1] += noise;
    219         }
    220         if (channel < 13)
    221         {
    222           noise_list[idx + 2] += noise;
    223         }
    224         if (channel < 12)
    225         {
    226           noise_list[idx + 3] += noise;
    227         }
    228         if (channel < 11)
    229         {
    230           noise_list[idx + 4] += noise;
    231         }
    232       }
    233     }
    234 
    235     // plot found WiFi info
    236     for (int i = 0; i < n; i++)
    237     {
    238       channel = WiFi.channel(i);
    239       idx = channel - 1;
    240       rssi = WiFi.RSSI(i);
    241       color = channel_color[idx];
    242       height = constrain(map(rssi, RSSI_FLOOR, RSSI_CEILING, 1, graph_height), 1, graph_height);
    243       offset = (channel + 1) * channel_width;
    244 
    245       // trim rssi with RSSI_FLOOR
    246       if (rssi < RSSI_FLOOR)
    247       {
    248         rssi = RSSI_FLOOR;
    249       }
    250 
    251       // plot chart
    252       // gfx->drawLine(offset, graph_baseline - height, offset - signal_width, graph_baseline + 1, color);
    253       // gfx->drawLine(offset, graph_baseline - height, offset + signal_width, graph_baseline + 1, color);
    254       gfx->startWrite();
    255       gfx->drawEllipseHelper(offset, graph_baseline + 1, signal_width, height, 0b0011, color);
    256       gfx->endWrite();
    257 
    258       if (i == peak_id_list[idx])
    259       {
    260         // Print SSID, signal strengh and if not encrypted
    261         String ssid = WiFi.SSID(i);
    262         if (ssid.length() == 0)
    263         {
    264           ssid = WiFi.BSSIDstr(i);
    265         }
    266         text_width = (ssid.length() + 6) * 8;
    267         if (text_width > w)
    268         {
    269           offset = 0;
    270         }
    271         else
    272         {
    273           offset -= signal_width;
    274           if ((offset + text_width) > w)
    275           {
    276             offset = w - text_width;
    277           }
    278         }
    279         gfx->setTextColor(color);
    280         gfx->setCursor(offset, graph_baseline - height - 2);
    281         gfx->print(ssid);
    282         gfx->print('(');
    283         gfx->print(rssi);
    284         gfx->print(')');
    285 #if defined(ESP32)
    286         if (WiFi.encryptionType(i) == WIFI_AUTH_OPEN)
    287 #else
    288         if (WiFi.encryptionType(i) == ENC_TYPE_NONE)
    289 #endif
    290         {
    291           gfx->print('*');
    292         }
    293       }
    294     }
    295   }
    296 
    297   // print WiFi stat
    298   gfx->setTextColor(WHITE);
    299   gfx->setCursor(0, banner_height + 14);
    300   gfx->print("找到");
    301   gfx->print(n);
    302   gfx->print("個WiFi,訊噪比較好:");
    303   bool listed_first_channel = false;
    304   int32_t min_noise = noise_list[0];          // init with channel 1 value
    305   for (channel = 2; channel <= 11; channel++) // channels 12-14 may not available
    306   {
    307     idx = channel - 1;
    308     log_i("min_noise: %d, noise_list[%d]: %d", min_noise, idx, noise_list[idx]);
    309     if (noise_list[idx] < min_noise)
    310     {
    311       min_noise = noise_list[idx];
    312     }
    313   }
    314 
    315   for (channel = 1; channel <= 11; channel++) // channels 12-14 may not available
    316   {
    317     idx = channel - 1;
    318     // check channel with min noise
    319     if (noise_list[idx] == min_noise)
    320     {
    321       if (!listed_first_channel)
    322       {
    323         listed_first_channel = true;
    324       }
    325       else
    326       {
    327         gfx->print(", ");
    328       }
    329       gfx->print(channel);
    330     }
    331   }
    332 
    333   // draw graph base axle
    334   gfx->drawFastHLine(0, graph_baseline, 320, WHITE);
    335   for (channel = 1; channel <= 14; channel++)
    336   {
    337     idx = channel - 1;
    338     offset = (channel + 1) * channel_width;
    339     gfx->setTextColor(channel_color[idx]);
    340     gfx->setCursor(offset - ((channel < 10) ? 4 : 8), graph_baseline + 14);
    341     gfx->print(channel);
    342     if (ap_count_list[idx] > 0)
    343     {
    344       gfx->setCursor(offset - ((ap_count_list[idx] < 10) ? 12 : 16), graph_baseline + 16 + 14);
    345       gfx->print('{');
    346       gfx->print(ap_count_list[idx]);
    347       gfx->print('}');
    348     }
    349   }
    350 
    351   // Wait a bit before scanning again
    352   delay(SCAN_INTERVAL);
    353 
    354 #if defined(SCAN_COUNT_SLEEP)
    355   // POWER SAVING
    356   if (++scan_count >= SCAN_COUNT_SLEEP)
    357   {
    358 #if defined(LCD_PWR_PIN)
    359     pinMode(LCD_PWR_PIN, INPUT); // disable pin
    360 #endif
    361 
    362 #if defined(GFX_BL)
    363     pinMode(GFX_BL, INPUT); // disable pin
    364 #endif
    365 
    366 #if defined(ESP32)
    367     esp_sleep_enable_ext0_wakeup(GPIO_NUM_36, LOW);
    368     esp_deep_sleep_start();
    369 #else
    370     ESP.deepSleep(0);
    371 #endif
    372   }
    373 #endif // defined(SCAN_COUNT_SLEEP)
    374 }