The Pico/W In C: Simple Web Client
Written by Harry Fairhead   
Monday, 31 October 2022
Article Index
The Pico/W In C: Simple Web Client

The Pico W has WiFi and getting started is easier than you might think from the documentation. Try our easy Web Client to see just how easy. This is an extract from our latest book all about the Pico/W in C.

Programming the Raspberry Pi Pico In C

By Harry Fairhead


Buy from Amazon.


  • Preface
  • Chapter 1 The Raspberry Pi Pico – Before We Begin
  • Chapter 2 Getting Started
  • Chapter 3 Getting Started With The GPIO
  • Chapter 4 Simple Output
  • Chapter 5 Some Electronics
  • Chapter 6 Simple Input
  • Chapter 7 Advanced Input – Events and Interrupts
  • Chapter 8 Pulse Width Modulation
        Extract: Basic PWM 
  • Chapter 9 Controlling Motors And Servos
  • Chapter 10 Getting Started With The SPI Bus
  • Chapter 11 A-To-D and The SPI Bus
  • Chapter 12 Using The I2C Bus
  • Chapter 13 Using The PIO
        Extract: A 1-Wire PIO Program  
  • Chapter 14 The DHT22 Sensor Implementing A Custom Protocol
  • Chapter 15 The 1‑Wire Bus And The DS1820
  • Chapter 16 The Serial Port
  • Chapter 17 Using the Pico W
       Extract: Simple Web Client ***NEW!
  • Chapter 18 Direct To The Hardware



The Pico and the Pico W are very similar and, with the exception of anything that uses the built-in LED, all of the programs presented so far work on both models. The important difference between them is that the Pico W has additional hardware that enables it to use WiFi. From the programming point of view, however, the task is to learn how to use the new WiFi driver and the LwIP library that provides higher-level networking. This is made more difficult than need be by the inadequate documentation provided for both. This will probably improve over time.

In chapter but not in this extract:

  • The Pico W
  • The WiFi Stack
  • The cyw43_arch Functions
  • Connecting To WiFi
  • A Better Connect


A Web Client

Now that we have managed to make the connection the WiFi, the next step is to transfer data. There are lots of low-level LwIP functions concerned with data, but in most cases we need to work at a higher level with a well defined protocol. One of the most common is HTTP which is used to transfer HTML web pages and this is easy enough to implement using LwIP. You can use raw low-level functions to implement an HTTP client and this is what the example in the SDK does, but there is a much simpler way to achieve the same result. LwIP has a ready built HTTP client that you can use to download any file from a web server. The HTTP client makes use of the raw API, so it can be used without the need for freeRTOS.

The HTTP client has two functions:

err_t httpc_get_file (
   const ip_addr_t *server_addr,
   u16_t port, 
   const char *uri, 
   const httpc_connection_t *settings, 
   altcp_recv_fn recv_fn,
   void *callback_arg, 
   httpc_state_t **connection)
err_t 	 httpc_get_file_dns (
   const char *server_name, 
   u16_t port, 
   const char *uri, 
   const httpc_connection_t *settings,
   altcp_recv_fn recv_fn, 
   void *callback_arg, 
   httpc_state_t **connection)

As you can see they are very similar. The only real difference is that the first makes the connection using an IP address and the second uses a URL or an IP address and performs a DNS lookup if necessary.

Both functions are asynchronous and you need to define three callback functions to accept the results. Notice that this means you could initiate multiple file downloads that would proceed in parallel.

The first three parameters specify the server and the file to be downloaded. The settings parameter specifies callbacks etc to be used as the connection proceeds. The recv_fn callback is called with the body of the web page, i.e. minus any headers. The callback_arg is passed to the callbacks and the connection parameter can be used to identify the connection if the callbacks are used to download multiple files.

The recv_fn callback provides access to the data:

err_t tcp_recv_fn(void *arg, struct tcp_pcb *tpcb, 
                           struct pbuf *p, err_t err);

The first parameter is the argument specified in the original call. The tpcb parameter gives the TCP control block which provides information about the connection which generated the data. The p parameter is a pointer to a pbuf linked list which contains the data, the contents of the requested file. How to make use of pbuf is described later. The final parameter gives the code for any error that has occurred.

A simplified definition of the settings type is:

typedef struct _httpc_connection {
  ip_addr_t proxy_addr;
  u16_t proxy_port;
  u8_t use_proxy;
httpc_result_fn result_fn; httpc_headers_done_fn headers_done_fn; } httpc_connection_t;

The first three fields are used to set a web proxy and you can ignore them unless you need to use a proxy. The final two define callbacks. The first result_fn is called when the file transfer is over and it is given the results of the transfer:

void httpc_result_fn(
   void *arg, 
   httpc_result_t httpc_result,
   u32_t rx_content_len,
   u32_t srv_res,
   err_t err)

The first parameter is the argument specified in the call that started the transfer. There are three parameters concerned with reporting the status of the transfer. The httpc_result parameter gives you the status of the HTTP connection e.g. HTTPC_RESULT_OK or HTTPC_RESULT_ERR_HOSTNAME.
The srv_res parameter gives you the status code from the web server – usually 200 if the file was found and downloaded and 404 if it wasn’t. The err parameter gives you any errors generated by the LwIP functions themselves.

The rx_content_len parameter gives you the number of characters downloaded, but notice you don’t have access to the data in this callback, just the final status of the transaction.

Last Updated ( Wednesday, 02 November 2022 )