Using WiFi in the Raspberry Pi Pico (Part 4)

We will now take a look at TCP communication. There are client and server examples at pico-examples, let's see if we can understand what is done.

These two examples are written to talk one to the other. The clients connects to the server, that sends a message. The client receives this message and send it back to the server. This is repeated a few times and the test is concluded.

I will not analyze the code for the WiFi connection (we have looked at it before).

TCP Client

The code can be seem at https://github.com/raspberrypi/pico-examples/blob/master/pico_w/tcp_client/picow_tcp_client.c

Like in UDP, the communication state is stores in a "pcb" structure  (in this case tcp_pcb). The creation of this structure, the registering of the callbacks and the triggering of the connection are in the tcp_client_open function:

// Simplified and commented version
static bool tcp_client_open(void *arg) {
	
    // create the PCB PCB (Protocol Control Block)
    state->tcp_pcb = tcp_new_ip_type(IP_GET_TYPE(&state->remote_addr));

    // Define the callbacks argument
    tcp_arg(state->tcp_pcb, state);
	
    // Register a callback called periodic
    tcp_poll(state->tcp_pcb, tcp_client_poll, POLL_TIME_S * 2);
    
    // Register a callback that is called when a transmission is acknowledge by the receiver
    tcp_sent(state->tcp_pcb, tcp_client_sent);
    
    // Register a callback that is called when data is received
    tcp_recv(state->tcp_pcb, tcp_client_recv);
    
    // // Register a callback that is called when a fatal error occurs
    tcp_err(state->tcp_pcb, tcp_client_err);

    // Triggers the connection, tcp_client_connected will be called if and when a connection is successful
    cyw43_arch_lwip_begin();
    err_t err = tcp_connect(state->tcp_pcb, &state->remote_addr, 
                        TCP_PORT, tcp_client_connected);
    cyw43_arch_lwip_end();

    return err == ERR_OK;
}

OK, we can understand this. TCP communication works through the callbacks, lwIP will call your routines when something happens. Let's see what each callback does in the example:
  • tcp_client_poll(): just does a print to signal it was called
  • tcp_client_err(): prints an error message
  • tcp_client_connected(): updates the application state to wait data from the server
  • tcp_client_recv(): receives the data from the server and, optionally, prints it. The data is sent back to the server through a tcp_write()
  • tcp_client_sent(): checks if the test is finished, if not waits for more data
At the end of the test all callbacks are cancelled and the connection is closed.

TCP Server

The server initiation (at  tcp_server_open) is done by calling:
  • tcp_bind()  to set the port that will be monitored
  • tcp_listen_with_backlog(): to get ready for connection requests, return a pcb specific for this. All connection requests will be put in a queue (in this case with just one position)
  • tcp_accept(): start waiting for a connection and sets the callback that will be called when it is established
The next step in the server occurs in the tcp_server_accept() function that is called when a connection is established. This routine defines the poll, err, recv and sent callbacks (as in the client) and uses tcp_write() to send data to the client.

The sent callback readies the server to receive the answer from the client. When the answer is received (in the recv callback), it is checked. If everything is OK, and the test is not finished, another data message is sent.

At the end of the test all callbacks are cancelled and the connection is closed.

Some Comments

Once you get used to the examples code structure it is not hard to understand the programs. The lwIP TCP programming interface is not complex (if you are used to work with callbacks).

This examples are written to do a single test. At the end of a connection the server will not loop to the accept to wait for another client to connect.

Based on this example (and writing a good amount of code) should not be hard to write two applications that talk to each other using simple TCP messages. By today it all about using RESP APIs and that is what I gonna try in the next post.

Comments

Popular posts from this blog

Using the PIO to Interface a PS/2 Keyboard