wifi working tested on hardware

This commit is contained in:
Adolfo Reyna
2025-12-10 08:09:38 -05:00
parent 47956bf64c
commit 65650a7b57
8 changed files with 305 additions and 25 deletions

View File

@@ -43,6 +43,7 @@ if (TARGET tinyusb_host)
keyboard_input.cpp keyboard_input.cpp
command_processor.cpp command_processor.cpp
epaper_manager.cpp epaper_manager.cpp
wifi_manager.cpp
) )
add_subdirectory(pico-ssd1306 commands) add_subdirectory(pico-ssd1306 commands)
@@ -61,7 +62,7 @@ if (TARGET tinyusb_host)
) )
# pull in common dependencies # pull in common dependencies
target_link_libraries(hello_usb pico_stdlib pico_ssd1306 hardware_i2c Config ePaper GUI Fonts hardware_spi pico_multicore tinyusb_host tinyusb_board) target_link_libraries(hello_usb pico_stdlib pico_ssd1306 hardware_i2c Config ePaper GUI Fonts hardware_spi pico_multicore tinyusb_host tinyusb_board pico_cyw43_arch_lwip_threadsafe_background)
# enable usb output, disable uart output # enable usb output, disable uart output
pico_enable_stdio_usb(hello_usb 0) pico_enable_stdio_usb(hello_usb 0)

View File

@@ -7,13 +7,11 @@ CommandAction parse_command(const char* input) {
return CMD_NONE; return CMD_NONE;
} }
if (strcmp(input, "/refresh") == 0) { if (strcmp(input, "/refresh") == 0) return CMD_REFRESH;
return CMD_REFRESH; if (strcmp(input, "/clear") == 0) return CMD_CLEAR;
} else if (strcmp(input, "/clear") == 0) { if (strcmp(input, "/scan") == 0) return CMD_SCAN;
return CMD_CLEAR; if (strncmp(input, "/connect ", 9) == 0 || strcmp(input, "/connect") == 0) return CMD_CONNECT;
} else if (strcmp(input, "/wifisetup") == 0) { if (strcmp(input, "/status") == 0) return CMD_STATUS;
return CMD_WIFI;
}
return CMD_UNKNOWN; return CMD_UNKNOWN;
} }

View File

@@ -5,7 +5,9 @@ enum CommandAction {
CMD_NONE, CMD_NONE,
CMD_REFRESH, CMD_REFRESH,
CMD_CLEAR, CMD_CLEAR,
CMD_WIFI, CMD_SCAN,
CMD_CONNECT,
CMD_STATUS,
CMD_UNKNOWN CMD_UNKNOWN
}; };

View File

@@ -1,4 +1,5 @@
#include "epaper_manager.h" #include "epaper_manager.h"
#include "wifi_manager.h"
#include "pico/stdlib.h" #include "pico/stdlib.h"
#include "pico/multicore.h" #include "pico/multicore.h"
#include <stdlib.h> #include <stdlib.h>
@@ -97,6 +98,9 @@ static void init_epaper_display() {
* Core 1 function: Runs display initialization and update handling * Core 1 function: Runs display initialization and update handling
*/ */
static void core1_display_init() { static void core1_display_init() {
// Initialize WiFi on Core 1 so IRQs are handled here
wifi_init();
init_epaper_display(); init_epaper_display();
g_display_ready = true; g_display_ready = true;

View File

@@ -10,12 +10,14 @@
#include <ctype.h> #include <ctype.h>
#include <cstring> #include <cstring>
#include <stdlib.h> #include <stdlib.h>
#include <malloc.h>
#include "display.h" #include "display.h"
#include "commands/echo.h" #include "commands/echo.h"
#include "keyboard_input.h" #include "keyboard_input.h"
#include "command_processor.h" #include "command_processor.h"
#include "epaper_manager.h" #include "epaper_manager.h"
#include "wifi_manager.h"
// Holds last echoed line for display // Holds last echoed line for display
static char g_last_echo[128] = ""; static char g_last_echo[128] = "";
@@ -28,7 +30,7 @@ static DisplayManager* g_display_manager = nullptr;
static char g_input_buffer[MAX_INPUT_LEN]; static char g_input_buffer[MAX_INPUT_LEN];
static int g_buffer_index = 0; static int g_buffer_index = 0;
static bool execute_command(CommandAction action) { static bool execute_command(CommandAction action, const char* input) {
switch (action) { switch (action) {
case CMD_REFRESH: case CMD_REFRESH:
printf("Command: /refresh\n"); printf("Command: /refresh\n");
@@ -38,9 +40,54 @@ static bool execute_command(CommandAction action) {
printf("Command: /clear\n"); printf("Command: /clear\n");
epaper_clear(); epaper_clear();
return true; return true;
case CMD_WIFI: case CMD_SCAN:
printf("Command: /wifisetup (Not implemented)\n"); printf("Command: /scan\n");
if (g_display_manager) g_display_manager->refresh("Scanning WiFi...", nullptr);
epaper_send_update("Scanning WiFi...", true);
wifi_scan();
return true; return true;
case CMD_CONNECT: {
printf("Command: /connect\n");
char ssid[33] = {0};
char password[64] = {0};
// Skip "/connect " (9 chars)
const char* args = input + 9;
// Simple parsing: first word is ssid, rest is password
int parsed = sscanf(args, "%32s %63s", ssid, password);
if (parsed < 2) {
printf("Usage: /connect <ssid> <password>\n");
if (g_display_manager) g_display_manager->refresh("Usage: /connect <ssid> <pass>", nullptr);
// epaper_send_update("Usage: /connect <ssid> <pass>", true);
return true;
}
if (g_display_manager) g_display_manager->refresh("Connecting...", ssid);
// epaper_send_update("Connecting...", true);
if (wifi_connect(ssid, password)) {
if (g_display_manager) g_display_manager->refresh("Connected!", ssid);
// epaper_send_update("Connected!", true);
// wifi_save_credentials(ssid, password);
} else {
if (g_display_manager) g_display_manager->refresh("Connection Failed", nullptr);
// epaper_send_update("Connection Failed", true);
}
return true;
}
case CMD_STATUS: {
printf("Command: /status\n");
struct mallinfo m = mallinfo();
char status_msg[64];
// fordblks is the free chunk size in the arena.
// Note: This might not account for the total available system RAM if the heap hasn't grown to fill it yet.
// But it gives an idea of fragmentation and available malloc-able memory within the current arena.
snprintf(status_msg, sizeof(status_msg), "Heap: %d B, IP: %s", m.fordblks, wifi_get_ip());
printf("%s\n", status_msg);
if (g_display_manager) g_display_manager->refresh(status_msg, nullptr);
epaper_send_update(status_msg, true);
return true;
}
default: default:
return false; return false;
} }
@@ -64,34 +111,35 @@ static void process_kbd_report(hid_keyboard_report_t const *report) {
} else if (event.is_enter) { } else if (event.is_enter) {
printf("\n"); printf("\n");
CommandAction action = parse_command(g_input_buffer); // Always commit the input line to e-Paper so commands are visible
if (execute_command(action)) { if (g_buffer_index > 0) {
// Command handled, clear buffer but don't commit line epaper_send_update(g_input_buffer, true);
g_buffer_index = 0; }
g_input_buffer[0] = '\0';
CommandAction action = parse_command(g_input_buffer);
if (execute_command(action, g_input_buffer)) {
// Command handled
if (g_display_manager) { if (g_display_manager) {
g_display_manager->set_last_echo("Command Executed"); g_display_manager->set_last_echo("Command Executed");
g_display_manager->refresh("", "Command Executed"); g_display_manager->refresh("", "Command Executed");
} }
} else { } else {
// Update e-Paper (commit line) // Not a command, just text (already committed to e-Paper above)
epaper_send_update(g_input_buffer, true);
// Save to last echo // Save to last echo
strncpy(g_last_echo, g_input_buffer, sizeof(g_last_echo) - 1); strncpy(g_last_echo, g_input_buffer, sizeof(g_last_echo) - 1);
g_last_echo[sizeof(g_last_echo) - 1] = '\0'; g_last_echo[sizeof(g_last_echo) - 1] = '\0';
// Clear buffer
g_buffer_index = 0;
g_input_buffer[0] = '\0';
// Update OLED // Update OLED
if (g_display_manager) { if (g_display_manager) {
g_display_manager->set_last_echo(g_last_echo); g_display_manager->set_last_echo(g_last_echo);
g_display_manager->refresh("", g_last_echo); g_display_manager->refresh("", g_last_echo);
} }
} }
// Clear buffer
g_buffer_index = 0;
g_input_buffer[0] = '\0';
} else if (event.is_printable) { } else if (event.is_printable) {
printf("%c", event.ascii); printf("%c", event.ascii);
if (g_buffer_index < MAX_INPUT_LEN - 1) { if (g_buffer_index < MAX_INPUT_LEN - 1) {
@@ -178,7 +226,12 @@ int main() {
display.init(); display.init();
g_display_manager = &display; g_display_manager = &display;
display.refresh("Waiting for Keyboard", nullptr); if (wifi_try_auto_connect()) {
display.refresh("WiFi Auto-Connected", nullptr);
epaper_send_update("WiFi Auto-Connected", true);
} else {
display.refresh("Waiting for Keyboard", nullptr);
}
printf("Initializing TinyUSB Host...\n"); printf("Initializing TinyUSB Host...\n");
tuh_init(BOARD_TUH_RHPORT); tuh_init(BOARD_TUH_RHPORT);

53
lwipopts.h Normal file
View File

@@ -0,0 +1,53 @@
#ifndef _LWIPOPTS_H
#define _LWIPOPTS_H
// Common settings used in most of the pico_w examples
#define NO_SYS 1
#define LWIP_SOCKET 0
#define MEM_LIBC_MALLOC 0
#define MEM_ALIGNMENT 4
#define MEM_SIZE 4000
#define MEMP_NUM_TCP_SEG 32
#define MEMP_NUM_ARP_QUEUE 10
#define PBUF_POOL_SIZE 24
#define LWIP_ARP 1
#define LWIP_ETHERNET 1
#define LWIP_ICMP 1
#define LWIP_RAW 1
#define TCP_WND (8 * TCP_MSS)
#define TCP_MSS 1460
#define TCP_SND_BUF (8 * TCP_MSS)
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
#define LWIP_NETIF_HOSTNAME 1
#define LWIP_NETCONN 0
#define MEM_STATS 0
#define SYS_STATS 0
#define MEMP_STATS 0
#define LINK_STATS 0
#define LWIP_CHKSUM_ALGORITHM 3
#define LWIP_DHCP 1
#define LWIP_IPV4 1
#define LWIP_TCP 1
#define LWIP_UDP 1
#define LWIP_DNS 1
#define LWIP_TCP_KEEPALIVE 1
#define LWIP_NETIF_TX_SINGLE_PBUF 1
#define DHCP_DOES_ARP_CHECK 0
#define LWIP_DHCP_DOES_ACD_CHECK 0
// Enable debugging
#ifndef NDEBUG
#define LWIP_DEBUG 1
#define LWIP_STATS 1
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#else
#define LWIP_DEBUG 0
#define LWIP_STATS 0
#define LWIP_PLATFORM_DIAG(x) do {} while(0)
#endif
#endif /* _LWIPOPTS_H */

125
wifi_manager.cpp Normal file
View File

@@ -0,0 +1,125 @@
#include "wifi_manager.h"
#include "pico/cyw43_arch.h"
#include "hardware/flash.h"
#include "hardware/sync.h"
#include <stdio.h>
#include <string.h>
// Use the last sector of the 2MB flash
#define FLASH_TARGET_OFFSET (2 * 1024 * 1024 - FLASH_SECTOR_SIZE)
#define WIFI_CREDS_MAGIC 0x42574946 // 'BWIF'
struct WifiCreds {
uint32_t magic;
char ssid[33];
char password[64];
};
static volatile bool g_wifi_initialized = false;
static bool g_wifi_connected = false;
bool wifi_init() {
if (g_wifi_initialized) return true;
if (cyw43_arch_init()) {
printf("WiFi init failed!\n");
return false;
}
cyw43_arch_enable_sta_mode();
g_wifi_initialized = true;
printf("WiFi initialized on Core %u\n", get_core_num());
return true;
}
static int scan_result(void *env, const cyw43_ev_scan_result_t *result) {
if (result) {
printf("SSID: %-32s RSSI: %4d Auth: %u\n", result->ssid, result->rssi, result->auth_mode);
}
return 0;
}
void wifi_scan() {
// Wait for initialization
int timeout = 500; // 5 seconds
while (!g_wifi_initialized && timeout > 0) {
sleep_ms(10);
timeout--;
}
if (!g_wifi_initialized) {
printf("WiFi not initialized!\n");
return;
}
printf("Starting WiFi scan...\n");
cyw43_wifi_scan_options_t scan_options = {0};
int err = cyw43_wifi_scan(&cyw43_state, &scan_options, NULL, scan_result);
if (err != 0) {
printf("Failed to start scan: %d\n", err);
}
}
void wifi_save_credentials(const char* ssid, const char* password) {
WifiCreds creds;
creds.magic = WIFI_CREDS_MAGIC;
strncpy(creds.ssid, ssid, sizeof(creds.ssid) - 1);
creds.ssid[sizeof(creds.ssid) - 1] = '\0';
strncpy(creds.password, password, sizeof(creds.password) - 1);
creds.password[sizeof(creds.password) - 1] = '\0';
uint32_t ints = save_and_disable_interrupts();
flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE);
flash_range_program(FLASH_TARGET_OFFSET, (const uint8_t*)&creds, sizeof(creds));
restore_interrupts(ints);
printf("WiFi credentials saved to flash.\n");
}
bool wifi_try_auto_connect() {
const WifiCreds* creds = (const WifiCreds*)(XIP_BASE + FLASH_TARGET_OFFSET);
if (creds->magic != WIFI_CREDS_MAGIC) {
printf("No saved WiFi credentials found.\n");
return false;
}
printf("Found saved credentials for SSID: %s\n", creds->ssid);
return wifi_connect(creds->ssid, creds->password);
}
bool wifi_connect(const char* ssid, const char* password) {
// Wait for initialization
int timeout = 500; // 5 seconds
while (!g_wifi_initialized && timeout > 0) {
sleep_ms(10);
timeout--;
}
if (!g_wifi_initialized) {
printf("WiFi not initialized!\n");
return false;
}
printf("Connecting to WiFi: %s...\n", ssid);
// Connect in blocking mode for simplicity
if (cyw43_arch_wifi_connect_timeout_ms(ssid, password, CYW43_AUTH_WPA2_AES_PSK, 30000)) {
printf("WiFi connection failed!\n");
g_wifi_connected = false;
return false;
}
printf("WiFi connected!\n");
g_wifi_connected = true;
return true;
}
bool wifi_is_connected() {
return g_wifi_connected;
}
const char* wifi_get_ip() {
if (!g_wifi_connected) return "Disconnected";
return ip4addr_ntoa(netif_ip4_addr(&cyw43_state.netif[0]));
}

44
wifi_manager.h Normal file
View File

@@ -0,0 +1,44 @@
#ifndef WIFI_MANAGER_H
#define WIFI_MANAGER_H
#include <stdbool.h>
/**
* Initializes the WiFi hardware.
* Returns true on success.
*/
bool wifi_init();
/**
* Scans for available WiFi networks and prints them to stdout.
*/
void wifi_scan();
/**
* Connects to the specified WiFi network.
* Returns true if connected successfully.
*/
bool wifi_connect(const char* ssid, const char* password);
/**
* Saves the WiFi credentials to flash memory for auto-connect.
*/
void wifi_save_credentials(const char* ssid, const char* password);
/**
* Attempts to connect using saved credentials.
* Returns true if connected.
*/
bool wifi_try_auto_connect();
/**
* Returns true if currently connected to WiFi.
*/
bool wifi_is_connected();
/**
* Returns the current IP address as a string, or "Disconnected".
*/
const char* wifi_get_ip();
#endif // WIFI_MANAGER_H