本篇文章介紹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;
}

沒有留言:
張貼留言