Para começar o meu estudo das funções do SDK de C/C++ da Pi Pico para comunicação TCP/IP, eu resolvi implementar um cliente SNTP. É algo simples e que eu já tinha feito com as funções do Arduino. É um exercício, já que a biblioteca lwIP (que é usada no Pico W) inclui uma implementação disto. Os exemplos do SDK também incluem isso e foi por este exemplo (que você pode ver aqui) que eu comecei o meu estudo.
Uma primeira lida no código do exemplo não foi muito animador... Vamos ver parte por parte para entender, recomendo ler o texto abaixo junto com o fonte. Estou assumindo que vocês conhecem o básico de TCP/IP.
O exemplo funcionando |
A primeira parte a examinar é o main() que contém as seguintes chamadas à biblioteca cyw43_arch:
- cyw43_arch_init() - inicia as bibliotecas de comunicação WiFi
- cyw43_arch_enable_sta_mode() - coloca no modo "station" (vai se conectar a um AP WiFi)
- cyw43_arch_wifi_connect_timeout_ms() - tenta se conectar a um AP
- cyw43_arch_deinit() - encerra o uso das bibliotecas de comunicação WiFi
Até aqui, tranquilo. Vamos agora olhar run_ntp_test(), onde está o laço principal do programa. O primeiro passo desta rotina é chamar ntp_init(). O programa é construído em torno de uma estrutura que contém todo o seu estado (NTP_T). ntp_init() aloca esta estrutura e chama duas rotinas da biblioteca lwIP (cuja documentação está aqui):
- udp_new_ip_type() - esta rotina retorna um ponteiro para uma estrutura udp_pcb. Pcb corresponde a Protocol Control Block, as pcbs contém as informações necessárias para controle das comunicações (no caso UDP, existem pcbs para outros protocolos).
- udp_recv() - Aqui definimos a rotina que será chamada quando um pacote UDP for recebido. Como não definimos nenhuma porta no pcb, a rotina será chamada qualquer que seja a porta. Definimos também que a rotina receberá o estado como parâmetro.
- cyw43_arch_lwip_begin()
- dns_gethostbyname() - determina o endereço IP de um nome de host.
- cyw43_arch_lwip_end()
// Make an NTP request static void ntp_request(NTP_T *state) { cyw43_arch_lwip_begin(); struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, NTP_MSG_LEN, PBUF_RAM); uint8_t *req = (uint8_t *) p->payload; memset(req, 0, NTP_MSG_LEN); req[0] = 0x1b; udp_sendto(state->ntp_pcb, p, &state->ntp_server_address, NTP_PORT); pbuf_free(p); cyw43_arch_lwip_end(); }
- O pacote a transmitir é alocado por pbuf_alloc(), uma rotina da lwIP que aloca espaço para os cabeçalhos de protocolo e toma o cuidado de alocar na região correta da memória, conforme o sistema (no caso do RP2040 pode ser qualquer área da SRAM).
- O envio é feito por udp_sendto(), devidamente cercado por cw43_arch_lwip_begin/end.
- Quando udp_sendto() retorna, o buffer pode ser descartado
Nenhum comentário:
Postar um comentário