Files
pico-w-experiments/tcp-command-frame/main.c
2026-02-17 23:54:13 +01:00

186 lines
3.3 KiB
C

#include <string.h>
#include <stdlib.h>
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "lwip/netif.h"
#include "lwip/tcp.h"
#include "lwip/ip4_addr.h"
#include "wifi-settings.h"
#define MAX_PAYLOAD 256
#define TCP_PORT 5505
extern struct netif *netif_default;
enum {
READ_CMD,
READ_LEN0,
READ_LEN1,
READ_PAYLOAD
};
struct conn_state {
uint8_t state;
uint8_t cmd;
uint16_t len;
uint16_t received;
uint8_t buf[MAX_PAYLOAD];
};
static void handle_frame(struct tcp_pcb *pcb,
uint8_t cmd,
uint8_t *payload,
uint16_t len)
{
(void)cmd;
(void)payload;
(void)len;
const char reply_payload[] = "Hello";
const uint16_t reply_len = 5;
uint8_t frame[3 + reply_len];
frame[0] = 0x01; // ACK command
frame[1] = (uint8_t)(reply_len & 0xFF);
frame[2] = (uint8_t)(reply_len >> 8);
memcpy(&frame[3], reply_payload, reply_len);
tcp_write(pcb, frame, sizeof(frame), TCP_WRITE_FLAG_COPY);
tcp_output(pcb);
}
static err_t on_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) {
(void)err;
struct conn_state *st = (struct conn_state *)arg;
if (!p) {
free(st);
tcp_close(pcb);
return ERR_OK;
}
struct pbuf *q = p;
while (q) {
uint8_t *data = (uint8_t *)q->payload;
uint16_t i = 0;
while (i < q->len) {
uint8_t b = data[i++];
if (st->state == READ_CMD) {
st->cmd = b;
st->len = 0;
st->received = 0;
st->state = READ_LEN0;
}
else if (st->state == READ_LEN0) {
st->len = (uint16_t)b;
st->state = READ_LEN1;
}
else if (st->state == READ_LEN1) {
st->len |= ((uint16_t)b << 8);
if (st->len > MAX_PAYLOAD) {
pbuf_free(p);
free(st);
tcp_abort(pcb);
return ERR_ABRT;
}
st->received = 0;
st->state = (st->len == 0) ? READ_CMD : READ_PAYLOAD;
if (st->len == 0) {
handle_frame(pcb, st->cmd, st->buf, 0);
}
}
else { /* READ_PAYLOAD */
st->buf[st->received++] = b;
if (st->received == st->len) {
handle_frame(pcb, st->cmd, st->buf, st->len);
st->state = READ_CMD;
}
}
}
q = q->next;
}
tcp_recved(pcb, p->tot_len);
pbuf_free(p);
return ERR_OK;
}
static err_t on_accept(void *arg, struct tcp_pcb *newpcb, err_t err) {
(void)arg;
(void)err;
struct conn_state *st = (struct conn_state *)calloc(1, sizeof(struct conn_state));
if (!st) {
tcp_abort(newpcb);
return ERR_ABRT;
}
st->state = READ_CMD;
tcp_arg(newpcb, st);
tcp_recv(newpcb, on_recv);
return ERR_OK;
}
int main() {
stdio_init_all();
if (cyw43_arch_init()) {
return -1;
}
cyw43_arch_enable_sta_mode();
if (cyw43_arch_wifi_connect_timeout_ms(
WIFI_SSID,
WIFI_PASS,
CYW43_AUTH_WPA2_AES_PSK,
30000)) {
return -1;
}
struct tcp_pcb *listen_pcb = tcp_new_ip_type(IPADDR_TYPE_V4);
if (!listen_pcb) {
return -1;
}
if (tcp_bind(listen_pcb, IP_ADDR_ANY, TCP_PORT) != ERR_OK) {
tcp_close(listen_pcb);
return -1;
}
listen_pcb = tcp_listen(listen_pcb);
tcp_accept(listen_pcb, on_accept);
bool dhcp_done = false;
while (true) {
cyw43_arch_poll();
if (!dhcp_done) {
if (netif_default &&
netif_is_up(netif_default) &&
!ip4_addr_isany_val(*netif_ip4_addr(netif_default))) {
dhcp_done = true;
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
}
}
sleep_ms(1);
}
}