Raspberry Pi Pico W: HTTP Client Part I - Simple Client
Time to try some networking with Raspberry Pi Pico W. This example from the documentation works for me:
if (cyw43_arch_init_with_country(CYW43_COUNTRY_UK)) {
printf("failed to initialise\n");
return 1;
}
printf("initialised\n");
cyw43_arch_enable_sta_mode();
if (cyw43_arch_wifi_connect_timeout_ms(SSID, PASS, CYW43_AUTH_WPA2_AES_PSK, 10000)) {
printf("failed to connect\n");
return 1;
}
printf("connected\n");
But just connecting is not enough. So let’s try to make an HTTP request.
Adding:
target_link_libraries(<project>
pico_cyw43_arch_lwip_threadsafe_background
pico_lwip_http
pico_stdlib
)
to CMakeLists.txt to get the HTTP client. Then:
#include "lwip/apps/http_client.h"
But what’s next? The documentation, I guess: http://lwip.nongnu.org/2_1_x/group__httpc.html
First Attempt: httpc_get_file_dns
The simplest option seems to be httpc_get_file_dns
, which also resolves the hostname.
Added the following code:
httpc_connection_t settings = {
.use_proxy = 0,
.headers_done_fn = headers_done_fn,
.result_fn = result_fn
};
httpc_state_t *connection = NULL;
err_t err = httpc_get_file_dns("neverssl.com", HTTP_DEFAULT_PORT, "/", &settings, recv_fn, NULL, &connection);
printf("err = %d\n", err);
with some dummy callbacks:
static err_t headers_done_fn(httpc_state_t *connection, void *arg,
struct pbuf *hdr, u16_t hdr_len, u32_t content_len)
{
printf("in headers_done_fn\n");
return ERR_OK;
}
static void result_fn(void *arg, httpc_result_t httpc_result, u32_t rx_content_len, u32_t srv_res, err_t err)
{
printf("in result_fn\n");
}
static err_t recv_fn(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
printf("in recv_fn\n");
return ERR_OK;
}
Unfortunately, err
is 0 but nothing else is logged. The output:
initialised
Version: 7.95.49 (2271bb6 CY) CRC: b7a28ef3 Date: Mon 2021-11-29 22:50:27 PST Ucode Ver: 1043.2162 FWID 01-c51d9400
cyw43 loaded ok, mac 28:cd:c1:00:5f:62
API: 12.2
Data: RaspberryPi.PicoW
Compiler: 1.29.4
ClmImport: 1.47.1
Customization: v5 22/06/24
Creation: 2022-06-24 06:55:08
connect status: joining
connect status: no ip
connect status: link up
connected
err = 0
But it’s possible that the problem is that I’m not waiting long enough. It’s not a blocking request, but rather a “request start” call, and the callbacks are called when and if things are received. So let’s add a 10-second delay.
The result:
in headers_done_fn
in recv_fn
in recv_fn
in recv_fn
in result_fn
10 second timeout done
Lovely. Next we want to see what we’re getting.
static void result_fn(void *arg, httpc_result_t httpc_result, u32_t rx_content_len, u32_t srv_res, err_t err)
{
printf(">>> result_fn >>>\n");
printf("httpc_result: %s\n",
httpc_result == HTTPC_RESULT_OK ? "HTTPC_RESULT_OK"
: httpc_result == HTTPC_RESULT_ERR_UNKNOWN ? "HTTPC_RESULT_ERR_UNKNOWN"
: httpc_result == HTTPC_RESULT_ERR_CONNECT ? "HTTPC_RESULT_ERR_CONNECT"
: httpc_result == HTTPC_RESULT_ERR_HOSTNAME ? "HTTPC_RESULT_ERR_HOSTNAME"
: httpc_result == HTTPC_RESULT_ERR_CLOSED ? "HTTPC_RESULT_ERR_CLOSED"
: httpc_result == HTTPC_RESULT_ERR_TIMEOUT ? "HTTPC_RESULT_ERR_TIMEOUT"
: httpc_result == HTTPC_RESULT_ERR_SVR_RESP ? "HTTPC_RESULT_ERR_SVR_RESP"
: httpc_result == HTTPC_RESULT_ERR_MEM ? "HTTPC_RESULT_ERR_MEM"
: httpc_result == HTTPC_RESULT_LOCAL_ABORT ? "HTTPC_RESULT_LOCAL_ABORT"
: httpc_result == HTTPC_RESULT_ERR_CONTENT_LEN ? "HTTPC_RESULT_ERR_CONTENT_LEN"
: "*UNKNOWN*");
printf("received %ld bytes\n", rx_content_len);
printf("server response: %ld\n", srv_res);
printf("err: %d\n", err);
printf("<<< result_fn <<<\n");
}
All is well:
>>> result_fn >>>
httpc_result: HTTPC_RESULT_OK
received 3961 bytes
server response: 200
err: 0
<<< result_fn <<<
What about actual data? Added this:
static err_t recv_fn(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
printf(">>> recv_fn >>>\n");
if (p == NULL) {
printf("p is NULL\n");
} else {
printf("p: %p\n", p);
printf("next: %p\n", p->next);
printf("payload: %p\n", p->payload);
printf("len: %d\n", p->len);
}
printf("<<< recv_fn <<<\n");
return ERR_OK;
}
And the result:
>>> recv_fn >>>
p: 2000A704
next: 00000000
payload: 2000A87D
len: 1153
<<< recv_fn <<<
>>> recv_fn >>>
p: 2000A108
next: 00000000
payload: 2000A14E
len: 1460
<<< recv_fn <<<
>>> recv_fn >>>
p: 20009B0C
next: 00000000
payload: 20009B52
len: 1348
<<< recv_fn <<<
I’ll skip headers for now. I think that this is a good start. But of course, most of the internet is HTTPS.