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

PicoWiFiAnalyzer.ino (10251B)

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