tcp port send stdio
This commit is contained in:
@@ -44,6 +44,7 @@ if (TARGET tinyusb_host)
|
|||||||
command_processor.cpp
|
command_processor.cpp
|
||||||
epaper_manager.cpp
|
epaper_manager.cpp
|
||||||
wifi_manager.cpp
|
wifi_manager.cpp
|
||||||
|
tcp_debug.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(pico-ssd1306 commands)
|
add_subdirectory(pico-ssd1306 commands)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "epaper_manager.h"
|
#include "epaper_manager.h"
|
||||||
#include "wifi_manager.h"
|
#include "wifi_manager.h"
|
||||||
|
#include "tcp_debug.h"
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
#include "pico/multicore.h"
|
#include "pico/multicore.h"
|
||||||
#include "pico/flash.h"
|
#include "pico/flash.h"
|
||||||
@@ -94,6 +95,9 @@ static void init_epaper_display() {
|
|||||||
bool connected = wifi_try_auto_connect();
|
bool connected = wifi_try_auto_connect();
|
||||||
printf("[Core 1] Connected: %d\r\n", connected);
|
printf("[Core 1] Connected: %d\r\n", connected);
|
||||||
|
|
||||||
|
if (connected) {
|
||||||
|
tcp_debug_init();
|
||||||
|
}
|
||||||
|
|
||||||
Paint_SelectImage(g_epd_red);
|
Paint_SelectImage(g_epd_red);
|
||||||
printf("[Core 1] Drawing header\r\n");
|
printf("[Core 1] Drawing header\r\n");
|
||||||
|
|||||||
@@ -22,8 +22,13 @@
|
|||||||
// Holds last echoed line for display
|
// Holds last echoed line for display
|
||||||
static char g_last_echo[128] = "";
|
static char g_last_echo[128] = "";
|
||||||
|
|
||||||
// Global DisplayManager pointer
|
#include "command_processor.h"
|
||||||
static DisplayManager* g_display_manager = nullptr;
|
#include "epaper_manager.h"
|
||||||
|
#include "wifi_manager.h"
|
||||||
|
#include "tcp_debug.h"
|
||||||
|
|
||||||
|
// Global display manager instance
|
||||||
|
DisplayManager* g_display_manager = nullptr;
|
||||||
|
|
||||||
// Keyboard buffer
|
// Keyboard buffer
|
||||||
#define MAX_INPUT_LEN 64
|
#define MAX_INPUT_LEN 64
|
||||||
@@ -75,6 +80,7 @@ static bool execute_command(CommandAction action, const char* input) {
|
|||||||
epaper_send_update(err_msg, true);
|
epaper_send_update(err_msg, true);
|
||||||
} else {
|
} else {
|
||||||
epaper_send_update("Connected!", true);
|
epaper_send_update("Connected!", true);
|
||||||
|
tcp_debug_init();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (g_display_manager) g_display_manager->refresh("Connection Failed", nullptr);
|
if (g_display_manager) g_display_manager->refresh("Connection Failed", nullptr);
|
||||||
@@ -148,7 +154,7 @@ static void process_kbd_report(hid_keyboard_report_t const *report) {
|
|||||||
g_buffer_index = 0;
|
g_buffer_index = 0;
|
||||||
g_input_buffer[0] = '\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) {
|
||||||
g_input_buffer[g_buffer_index++] = event.ascii;
|
g_input_buffer[g_buffer_index++] = event.ascii;
|
||||||
g_input_buffer[g_buffer_index] = '\0';
|
g_input_buffer[g_buffer_index] = '\0';
|
||||||
|
|||||||
137
tcp_debug.cpp
Normal file
137
tcp_debug.cpp
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
#include "tcp_debug.h"
|
||||||
|
#include "pico/cyw43_arch.h"
|
||||||
|
#include "lwip/tcp.h"
|
||||||
|
#include "pico/stdio/driver.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define TCP_PORT 4242
|
||||||
|
#define DEBUG_BUF_SIZE 2048
|
||||||
|
|
||||||
|
// Circular buffer for debug output
|
||||||
|
static char debug_buf[DEBUG_BUF_SIZE];
|
||||||
|
static volatile int write_idx = 0;
|
||||||
|
static volatile int read_idx = 0;
|
||||||
|
static struct tcp_pcb *server_pcb = NULL;
|
||||||
|
static struct tcp_pcb *client_pcb = NULL;
|
||||||
|
|
||||||
|
// Helper to write to buffer
|
||||||
|
static void buffer_write(const char *data, int len) {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
int next_write = (write_idx + 1) % DEBUG_BUF_SIZE;
|
||||||
|
if (next_write != read_idx) { // Only write if not full
|
||||||
|
debug_buf[write_idx] = data[i];
|
||||||
|
write_idx = next_write;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stdio driver callback
|
||||||
|
static void tcp_out_chars(const char *buf, int len) {
|
||||||
|
// Handle CRLF conversion manually if needed, or just write raw
|
||||||
|
// The issue is likely that \n is sent without \r, causing "staircase" effect in raw terminals
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
if (buf[i] == '\n') {
|
||||||
|
char cr = '\r';
|
||||||
|
buffer_write(&cr, 1);
|
||||||
|
}
|
||||||
|
buffer_write(&buf[i], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static stdio_driver_t tcp_driver = {
|
||||||
|
.out_chars = tcp_out_chars,
|
||||||
|
.out_flush = NULL,
|
||||||
|
.in_chars = NULL,
|
||||||
|
#if PICO_STDIO_ENABLE_CRLF_SUPPORT
|
||||||
|
.crlf_enabled = false
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// TCP callbacks
|
||||||
|
static err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb) {
|
||||||
|
if (tpcb != client_pcb) return ERR_OK;
|
||||||
|
|
||||||
|
// Check if there is data in the ring buffer to send
|
||||||
|
if (write_idx != read_idx) {
|
||||||
|
int len_to_send = 0;
|
||||||
|
char send_buf[256]; // Temporary buffer for one TCP write chunk
|
||||||
|
|
||||||
|
// Copy from ring buffer to linear buffer
|
||||||
|
while (write_idx != read_idx && len_to_send < sizeof(send_buf)) {
|
||||||
|
send_buf[len_to_send++] = debug_buf[read_idx];
|
||||||
|
read_idx = (read_idx + 1) % DEBUG_BUF_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len_to_send > 0) {
|
||||||
|
err_t err = tcp_write(tpcb, send_buf, len_to_send, TCP_WRITE_FLAG_COPY);
|
||||||
|
if (err == ERR_OK) {
|
||||||
|
tcp_output(tpcb);
|
||||||
|
} else {
|
||||||
|
// If write failed (e.g. buffer full), rewind read_idx (simple retry logic)
|
||||||
|
// Note: This is a simplification. In a real robust system we might drop data or handle partial writes.
|
||||||
|
// For now, we just lose the data if TCP is full to avoid blocking the system.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) {
|
||||||
|
if (!p) {
|
||||||
|
tcp_close(tpcb);
|
||||||
|
client_pcb = NULL;
|
||||||
|
printf("TCP debug client disconnected\n");
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
// We don't expect input, just discard it
|
||||||
|
tcp_recved(tpcb, p->tot_len);
|
||||||
|
pbuf_free(p);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t tcp_server_accept(void *arg, struct tcp_pcb *newpcb, err_t err) {
|
||||||
|
if (client_pcb) {
|
||||||
|
// Already have a client, reject or close old?
|
||||||
|
// Let's close the old one and accept the new one (last one wins)
|
||||||
|
tcp_abort(client_pcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
client_pcb = newpcb;
|
||||||
|
tcp_recv(newpcb, tcp_server_recv);
|
||||||
|
tcp_poll(newpcb, tcp_server_poll, 1); // Poll every 500ms (coarse grain) -> actually arg is interval in 500ms steps?
|
||||||
|
// Wait, poll interval is passed to tcp_poll. 1 means every 500ms.
|
||||||
|
// We might want faster polling for debug output.
|
||||||
|
// But we can't poll faster than the lwIP timer.
|
||||||
|
// However, we can also trigger writes from the main loop if we wanted, but polling is safer for threading.
|
||||||
|
|
||||||
|
printf("TCP debug client connected\n");
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tcp_debug_init(void) {
|
||||||
|
if (server_pcb) return true;
|
||||||
|
|
||||||
|
// Register stdio driver
|
||||||
|
stdio_set_driver_enabled(&tcp_driver, true);
|
||||||
|
|
||||||
|
cyw43_arch_lwip_begin();
|
||||||
|
server_pcb = tcp_new_ip_type(IPADDR_TYPE_ANY);
|
||||||
|
if (!server_pcb) {
|
||||||
|
cyw43_arch_lwip_end();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_t err = tcp_bind(server_pcb, IP_ANY_TYPE, TCP_PORT);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
cyw43_arch_lwip_end();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
server_pcb = tcp_listen(server_pcb);
|
||||||
|
tcp_accept(server_pcb, tcp_server_accept);
|
||||||
|
cyw43_arch_lwip_end();
|
||||||
|
|
||||||
|
printf("TCP debug server listening on port %d\n", TCP_PORT);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
13
tcp_debug.h
Normal file
13
tcp_debug.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef TCP_DEBUG_H
|
||||||
|
#define TCP_DEBUG_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the TCP debug server on port 4242.
|
||||||
|
* Registers a stdio driver that redirects printf output to connected TCP clients.
|
||||||
|
* Returns true on success.
|
||||||
|
*/
|
||||||
|
bool tcp_debug_init(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user