本篇文章介紹Raspberry Pi Pico W使用lwIP TCP API上傳SD Card上的JPG 檔案到Node-RED TCP Server並透過Node-RED UI template即時顯示上傳的檔案。
- TCP Client 連線:
按下列步驟設定連線:
- create TCP PCB
- 設定TCP PCB的callback function:
tcp_sent: sent callback
tcp_recv: recv callback
tcp_err: err callback
tcp_poll: poll callback - tcp_connect連線server ip:port
於函式中設定connected callback。
如下圖。
- 透過TCP connection送出檔案:
tcp_write寫入data後呼叫tcp_output送出data,在sent callback回傳server已收到的資料。比對server已收到後再送出下一筆資料。
如下圖。
- Node-RED端:
程式碼:
#include <stdio.h> #include "pico/stdlib.h" #include "pico/cyw43_arch.h" #include "hardware/spi.h" #include "hardware/dma.h" #include "pico/cyw43_arch.h" #include "lwip/pbuf.h" #include "lwip/tcp.h" #include "modules/FatFs/ff.h" #include "modules/FatFs/diskio.h" #include "modules/ntp_time/ntp_time.h" #include "string.h" #include "inttypes.h" #define WIFI_SSID "your_SSID" #define WIFI_PASSWORD "your_PASSWORD" #define TCP_SERVER_IP "your_SERVER_IP" #define TCP_PORT 5656 #define BUF_SIZE (TCP_MSS*2) #define POLL_TIME_S 5 typedef struct TCP_CLIENT_T_ { struct tcp_pcb *tcp_pcb; ip_addr_t remote_addr; int sent_len; bool connected; } TCP_CLIENT_T; TCP_CLIENT_T *tcp_client=NULL; err_t tcp_client_connected_cb(void *arg, struct tcp_pcb *tpcb, err_t err) { if (err != ERR_OK) { printf("connect callback error\n"); return err; } TCP_CLIENT_T *tcp_client=(TCP_CLIENT_T *)arg; printf("connect to ip:%s\n", ip4addr_ntoa(&tcp_client->remote_addr)); tcp_client->connected = true; return ERR_OK; } err_t tcp_client_sent_cb(void *arg, struct tcp_pcb *tpcb, u16_t len){ err_t err = ERR_OK; //printf("tcp server received: %d\n", len); TCP_CLIENT_T *tcp_client = (TCP_CLIENT_T*)arg; tcp_client->sent_len -= len; return err; } err_t tcp_client_close(void *arg) { TCP_CLIENT_T *tcp_client = (TCP_CLIENT_T *)arg; err_t err = ERR_OK; if (tcp_client->tcp_pcb != NULL) { tcp_arg(tcp_client->tcp_pcb, NULL); tcp_poll(tcp_client->tcp_pcb, NULL, 0); tcp_sent(tcp_client->tcp_pcb, NULL); tcp_recv(tcp_client->tcp_pcb, NULL); tcp_err(tcp_client->tcp_pcb, NULL); err = tcp_close(tcp_client->tcp_pcb); if (err != ERR_OK) { printf("close failed %d, calling abort\n", err); tcp_abort(tcp_client->tcp_pcb); err = ERR_ABRT; } tcp_client->tcp_pcb = NULL; } return err; } err_t tcp_client_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { if (!p) { printf(" connect close\n"); tcp_client_close(arg); return err; } cyw43_arch_lwip_check(); uint8_t *buf = p->payload; buf[p->tot_len]='\0'; printf("received data:%s\n", buf); tcp_recved(tpcb, p->tot_len); pbuf_free(p); // * important return err; } void tcp_client_err_cb(void *arg, err_t err) { printf("tcp_client error: %d\n", err); tcp_client_close(arg); } err_t tcp_client_poll_cb(void *arg, struct tcp_pcb *tpcb) { printf("tcl_client_poll_cb\n"); return ERR_OK; } bool tcp_client_connect_server(uint8_t *addr, uint16_t port) { tcp_client = (TCP_CLIENT_T*) calloc(1, sizeof(TCP_CLIENT_T)); if (tcp_client == NULL) return false; if (! ip4addr_aton(addr, &tcp_client->remote_addr)) return false; tcp_client->tcp_pcb = tcp_new_ip_type(IP_GET_TYPE(&tcp_client->remote_addr)); tcp_client->connected=false; tcp_client->sent_len=0; tcp_arg(tcp_client->tcp_pcb, tcp_client); tcp_sent(tcp_client->tcp_pcb, tcp_client_sent_cb); tcp_recv(tcp_client->tcp_pcb, tcp_client_recv_cb); tcp_err(tcp_client->tcp_pcb, tcp_client_err_cb); tcp_poll(tcp_client->tcp_pcb, tcp_client_poll_cb, POLL_TIME_S*2); absolute_time_t timeout = make_timeout_time_ms(10000); err_t err = tcp_connect(tcp_client->tcp_pcb, &tcp_client->remote_addr, port, tcp_client_connected_cb); if (err != ERR_OK) { printf("connect to server error!\n"); return false; } while (absolute_time_diff_us(get_absolute_time(), timeout) > 0 && !tcp_client->connected) { sleep_ms(100); } if (!tcp_client->connected) { printf("connect time out\n"); return false; } return true; } void upload_file(uint8_t *filename) { FIL fil; FRESULT res; char path[100]; if (!tcp_client_connect_server(TCP_SERVER_IP, TCP_PORT)){ return; } sprintf(path, "%s/%s", SDMMC_PATH, filename); res = f_open(&fil, path, FA_READ); if (res != FR_OK) { printf("open file error:\n"); return; } uint8_t buff[BUF_SIZE]; UINT br; //absolute_time_t t1 = get_absolute_time(); do { res = f_read(&fil, buff, BUF_SIZE, &br); tcp_write(tcp_client->tcp_pcb, buff, br, TCP_WRITE_FLAG_COPY); tcp_client->sent_len += br; tcp_output(tcp_client->tcp_pcb); while(tcp_client->sent_len > 0) { sleep_us(1); } } while(br >0); //printf("tcp upload time=%"PRIu64"\n", absolute_time_diff_us(t1, get_absolute_time())); res=f_close(&fil); tcp_client_close(tcp_client); } int main() { stdio_init_all(); gpio_init(5); gpio_init(6); gpio_set_dir(5, 1); gpio_set_dir(6,1); gpio_put(5,1); gpio_put(6,0); if (cyw43_arch_init()) { printf("failed to initialise\n"); return 1; } cyw43_arch_enable_sta_mode(); if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000)) { printf("failed to connect\n"); return 1; } ntp_time_init(); get_ntp_time(); gpio_put(5,0); gpio_put(6,1); FIL fil; FATFS fs; FRESULT res; res = f_mount(&fs, SDMMC_PATH, 1); if (res != FR_OK) { printf(" mount error\n"); return 0; } uint8_t fname[15]; for (int j=0;j < 2;j++) for (int i=1; i <=8; i++) { sprintf(fname, "pic%d.jpg",i); printf("%s\n", fname); upload_file(fname); } gpio_put(6,0); printf("Finish\n"); if (tcp_client) free(tcp_client); return 0; }
沒有留言:
張貼留言