Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pm:prj2025:avaduva:vlad_andrei.chira [2025/05/24 20:07]
vlad_andrei.chira [Introduction]
pm:prj2025:avaduva:vlad_andrei.chira [2025/05/24 21:37] (current)
vlad_andrei.chira [Hardware Design]
Line 34: Line 34:
    
 {{:​pm:​prj2025:​avaduva:​schematic1.png?​800|}} {{:​pm:​prj2025:​avaduva:​schematic1.png?​800|}}
 +
 +As seen above in the schematic, here are the pins I used
 +For the display:
 +    * Vcc --> 3.3V
 +    * Gnd --> Gnd
 +    * LED --> 3.3V
 +    * MOSI --> Port 23
 +    * SCK --> Port 18
 +    * CS --> Port 15
 +    * RESET --> Port 4
 +    * DC --> Port 2
 +The pin mapping does not really matter, as the mapping can be configured in the library used to control the display.
 +
 +For the encoder:
 +    * CLK --> Port 32
 +    * DT --> Port 35
 +    * + --> 3.3V
 +    * Gnd --> Gnd
 +
 +For the pushbutton: one side --> Gnd, other side --> Port 33
 +
 +The battery positive line goes into a switch that disables the battery when using the USB. Then it goes into the TP4056 charging module, who's output is then stepped up to 5V by the miniature boost converter.
 ===== Software Design ===== ===== Software Design =====
  
 +This project is more focused on software, so there will be a lot of code. Here are the features that must be implemented:​
 +    * Scan WiFi networks, store and display their information:​ SSID, channel, signal strength, authentication protocol, hidden SSID etc.
 +    * Graph channel occupancy: bar chart of how many networks are per channel
 +    * Signal strength graph: display signal strength over time for a particular network
 +    * MAC sniffing: use Promiscuous Mode to capture WiFi Management Frames by channel hopping, record the MAC addresses of all devices around (education purposes only)
 +    * <​del>​Deauth attack: Perform deauthentication attacks on nearby devices (own devices only)</​del>​ Due to a limitation of ESP32 firmaware, the ESP32 cannot send deauthentication management frames. Instead, this will be a //​monitoring//​ for deauthentication attacks only feature.
  
-<note tip> +To access all of these featuresa Main Menu will be provided on the display in the form of a 3x2 gridEach cell is a selectable button and will lead the user to a new window with the particular feature.
-Descrierea codului aplicaţiei (firmware):​ +
-  * mediu de dezvoltare (if any) (e.g. AVR StudioCodeVisionAVR) +
-  * librării şi surse 3rd-party (e.gProcyon AVRlib) +
-  * algoritmi şi structuri pe care plănuiţi să le implementaţi +
-  * (etapa 3) surse şi funcţii implementate +
-</​note>​+
  
-===== Rezultate Obţinute =====+To organize the code, the state of the application will be modeled using a Finite State Machine. For each state, there will be different elements drawn to the screen as well as conditions for transitioning into different states (for example, go back to Main Menu).
  
-<note tip> +For the code, I opted for Arduino IDE
-Care au fost rezultatele obţinute în urma realizării proiectului vostru+External libraries used : 
-</note>+    * TFT_eSPI by Bodmer 
 +    * <​del>​ImGui</del>
  
 +I really wanted to port ImGui library to embedded, because it is an amazing library and fantastic for this UI use case. It is hardware and OS agnostic, it just requires a way to draw triangles essentially. That means a software renderer drawing into a framebuffer is absolutely possible. The framebuffer is then passed to the TFT library and blit it to the screen. Alas, this ESP32 does not have external PSRAM, so it's not possible to store the entire framebuffer into memory. You don't need to store the entire framebuffer,​ especially if you write a wrapper on top of the TFT library and call those functions to draw the primitives. Due to time constraints,​ I gave up trying to port it. But I may come back one day and finish the port!
 +
 +**WiFi Controller**
 +
 +This class is used to scan for WiFi networks. Since the ESP only spends a few milliseconds per channel to capture access points, every scan will be different: some networks will be missing. Which is why this class caches networks and evicts them if they haven'​t been seen in more than 30 seconds. The cache is a map with bssid as keys and a custom data type made up of <​code>​MyNetwork</​code>​ and <​code>​lastSeen</​code>​ as values.
 +<code cpp>
 + // 1) Perform active scan (blocking)
 +int found = WiFi.scanNetworks(
 +  /​*async=*/​false,​
 +  /​*hidden=*/​showHiddenSSIDs,​
 +  /​*passive=*/​false,​
 +  /​*max_ms_per_channel=*/​scanTimePerChannelMs
 +    );
 +</​code>​
 +
 +<code cpp>
 +// write into cache (or update existing)
 +CacheEntry &entry = networkCache_[net.bssid];​
 +entry.net ​      = net;
 +entry.lastSeen ​ = now;
 +</​code>​
 +<code cpp>
 +// 3) Prune stale entries and build return vector
 +std::​vector<​MyNetwork>​ aggregated;
 +for (auto it = networkCache_.begin();​ it != networkCache_.end();​) {
 +    if (now - it->​second.lastSeen > aggregationTimeoutMs_) {
 +        // drop old
 +        it = networkCache_.erase(it);​
 +    } else {
 +        // include in output
 +        aggregated.push_back(it->​second.net);​
 +        ++it;
 +    }
 +}
 +</​code>​
 +
 +** Sniffer Controller **
 +
 +This class handles turning on Promiscuous Mode and sniffing all management frames by channel hopping around. It is responsible both for recording the MAC addresses it finds as well as monitoring for deauth frames.
 +
 +The way the ESP32 firmware handles this is by registering a callback function that will be called for every captured frame. It only provides the buffer, so I must define a custom data type that defines an IEEE 802.11 header and cast to it:
 +<code cpp>
 +typedef struct {
 +    uint16_t frame_ctrl;
 +    uint16_t duration_id;​
 +    uint8_t addr1[6];
 +    uint8_t addr2[6];
 +    uint8_t addr3[6];
 +    uint16_t seq_ctrl;
 +} __attribute__((packed)) ieee80211_hdr_t;​
 +</​code>​
 +
 +<code cpp>
 +
 +esp_wifi_stop(); ​              // tear down any previous mode  ​
 +delay(100);
 +wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();​
 +esp_wifi_init(&​cfg);​
 +esp_wifi_set_storage(WIFI_STORAGE_RAM);​
 +esp_wifi_set_mode(WIFI_MODE_NULL);​
 +esp_wifi_start();​
 +delay(100);
 +
 +esp_wifi_set_promiscuous_rx_cb(_promiscCallback);​
 +wifi_promiscuous_filter_t flt = {};
 +flt.filter_mask = WIFI_PROMIS_FILTER_MASK_MGMT;​
 +esp_wifi_set_promiscuous_filter(&​flt);​
 +
 +// Enable promiscuous mode
 +esp_wifi_set_promiscuous(true);​
 +</​code>​
 +
 +I can then retrieve the MAC address and the management frame type like this:
 +<code cpp>
 +// In 802.11 header: skip Frame Control (2), Duration (2), Addr1 (6) = offset 10
 +const uint8_t* srcMac = pkt->​payload + 10;
 +char macStr[18];
 +snprintf(macStr,​ sizeof(macStr),​
 +       "​%02X:​%02X:​%02X:​%02X:​%02X:​%02X",​
 +       ​srcMac[0],​ srcMac[1], srcMac[2],
 +       ​srcMac[3],​ srcMac[4], srcMac[5]);
 +
 +Serial.printf("​MAC:​ %s  RSSI: %d  CH: %u\n",
 +              macStr,
 +              pkt->​rx_ctrl.rssi,​
 +              pkt->​rx_ctrl.channel);​
 +</​code>​
 +
 +To channel hop, in the loop() function I must run:
 +<code cpp>
 +// Channel hop 1–13 every 200 ms to catch all APs
 +static uint8_t channel = 1;
 +esp_wifi_set_channel(channel,​ WIFI_SECOND_CHAN_NONE);​
 +channel = (channel % 13) + 1;
 +delay(200);
 +</​code>​
 +
 +** UI code **
 +
 +The TFT library only provides primitives and text, so drawing graphs means drawing them from scratch. The DisplayManager class handles the UI based on the state of the application (see Finite State Machine approach above).
 +
 +<code cpp>
 +void DisplayManager::​update(bool dirty) {
 +  if (currentState_ == lastState_ && !dirty) return;
 +
 +  switch (currentState_) {
 +    case State::​SplashScreen:​ drawSplashScreen();​ break;
 +    case State::​MainMenu:​ drawMainMenu();​ break;
 +    case State::​NetworkScan:​ drawNetworkScan();​ break;
 +    case State::​ChannelOccupancy:​ drawChannelOccupancy();​ break;
 +    case State::​SignalStrength:​ drawSignalStrength();​ break;
 +    case State::​MacSniffing:​ drawMacSniffing();​ break;
 +    case State::​DeauthMonitoring:​ drawDeauthMonitoring();​ break;
 +  }
 +  lastState_ = currentState_;​
 +}
 +</​code>​
 +
 +SPI is not fast enough to draw the entire screen continuously without flicker, so only if the state changed or the dirty flag is set manually will (re)rendering occur. Alternatively I can only draw things that will change, such as a graph curve, but keep all labels and axes untouched.
 +===== Results =====
 +
 +Here are some photos of the UI:
 +
 +{{:​pm:​prj2025:​avaduva:​splash.jpeg?​700|}}
 +
 +{{:​pm:​prj2025:​avaduva:​scan_list.jpeg?​700|}}
 +
 +{{:​pm:​prj2025:​avaduva:​main_menu.jpeg?​700|}}
 +
 +{{:​pm:​prj2025:​avaduva:​channel_occ.jpeg?​700|}}
 ===== Concluzii ===== ===== Concluzii =====
  
Line 61: Line 214:
 </​note>​ </​note>​
  
-===== Jurnal ===== 
- 
-<note tip> 
-Puteți avea și o secțiune de jurnal în care să poată urmări asistentul de proiect progresul proiectului. 
-</​note>​ 
  
 ===== Bibliografie/​Resurse ===== ===== Bibliografie/​Resurse =====
pm/prj2025/avaduva/vlad_andrei.chira.1748106478.txt.gz · Last modified: 2025/05/24 20:07 by vlad_andrei.chira
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0