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

PicoWiFiAnalyzerUTF8.ino (10433B)

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