Connections

Connections are essential feature of WiFi device and middleware. It is developed with strong focus on its performance and since it may interact with huge amount of data, it tries to use zero-copy (when available) feature, to decrease processing time.

ESP AT Firmware by default supports up to 5 connections being active at the same time and supports:

  • Up to 5 TCP connections active at the same time

  • Up to 5 UDP connections active at the same time

  • Up to 1 SSL connection active at a time

Note

Client or server connections are available. Same API function call are used to send/receive data or close connection.

Architecture of the connection API is using callback event functions. This allows maximal optimization in terms of responsiveness on different kind of events.

Example below shows bare minimum implementation to:

  • Start a new connection to remote host

  • Send HTTP GET request to remote host

  • Process received data in event and print number of received bytes

Client connection minimum example
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
#include "client.h"
#include "lwesp/lwesp.h"

/* Host parameter */
#define CONN_HOST           "example.com"
#define CONN_PORT           80

static lwespr_t   conn_callback_func(lwesp_evt_t* evt);

/**
 * \brief           Request data for connection
 */
static const
uint8_t req_data[] = ""
                     "GET / HTTP/1.1\r\n"
                     "Host: " CONN_HOST "\r\n"
                     "Connection: close\r\n"
                     "\r\n";

/**
 * \brief           Start a new connection(s) as client
 */
void
client_connect(void) {
    lwespr_t res;

    /* Start a new connection as client in non-blocking mode */
    if ((res = lwesp_conn_start(NULL, LWESP_CONN_TYPE_TCP, "example.com", 80, NULL, conn_callback_func, 0)) == lwespOK) {
        printf("Connection to " CONN_HOST " started...\r\n");
    } else {
        printf("Cannot start connection to " CONN_HOST "!\r\n");
    }

    /* Start 2 more */
    lwesp_conn_start(NULL, LWESP_CONN_TYPE_TCP, CONN_HOST, CONN_PORT, NULL, conn_callback_func, 0);

    /*
     * An example of connection which should fail in connecting.
     * When this is the case, \ref LWESP_EVT_CONN_ERROR event should be triggered
     * in callback function processing
     */
    lwesp_conn_start(NULL, LWESP_CONN_TYPE_TCP, CONN_HOST, 10, NULL, conn_callback_func, 0);
}

/**
 * \brief           Event callback function for connection-only
 * \param[in]       evt: Event information with data
 * \return          \ref lwespOK on success, member of \ref lwespr_t otherwise
 */
static lwespr_t
conn_callback_func(lwesp_evt_t* evt) {
    lwesp_conn_p conn;
    lwespr_t res;
    uint8_t conn_num;

    conn = lwesp_conn_get_from_evt(evt);          /* Get connection handle from event */
    if (conn == NULL) {
        return lwespERR;
    }
    conn_num = lwesp_conn_getnum(conn);           /* Get connection number for identification */
    switch (lwesp_evt_get_type(evt)) {
        case LWESP_EVT_CONN_ACTIVE: {             /* Connection just active */
            printf("Connection %d active!\r\n", (int)conn_num);
            res = lwesp_conn_send(conn, req_data, sizeof(req_data) - 1, NULL, 0); /* Start sending data in non-blocking mode */
            if (res == lwespOK) {
                printf("Sending request data to server...\r\n");
            } else {
                printf("Cannot send request data to server. Closing connection manually...\r\n");
                lwesp_conn_close(conn, 0);        /* Close the connection */
            }
            break;
        }
        case LWESP_EVT_CONN_CLOSE: {              /* Connection closed */
            if (lwesp_evt_conn_close_is_forced(evt)) {
                printf("Connection %d closed by client!\r\n", (int)conn_num);
            } else {
                printf("Connection %d closed by remote side!\r\n", (int)conn_num);
            }
            break;
        }
        case LWESP_EVT_CONN_SEND: {               /* Data send event */
            lwespr_t res = lwesp_evt_conn_send_get_result(evt);
            if (res == lwespOK) {
                printf("Data sent successfully on connection %d...waiting to receive data from remote side...\r\n", (int)conn_num);
            } else {
                printf("Error while sending data on connection %d!\r\n", (int)conn_num);
            }
            break;
        }
        case LWESP_EVT_CONN_RECV: {               /* Data received from remote side */
            lwesp_pbuf_p pbuf = lwesp_evt_conn_recv_get_buff(evt);
            lwesp_conn_recved(conn, pbuf);        /* Notify stack about received pbuf */
            printf("Received %d bytes on connection %d..\r\n", (int)lwesp_pbuf_length(pbuf, 1), (int)conn_num);
            break;
        }
        case LWESP_EVT_CONN_ERROR: {              /* Error connecting to server */
            const char* host = lwesp_evt_conn_error_get_host(evt);
            lwesp_port_t port = lwesp_evt_conn_error_get_port(evt);
            printf("Error connecting to %s:%d\r\n", host, (int)port);
            break;
        }
        default:
            break;
    }
    return lwespOK;
}

Sending data

Receiving data flow is always the same. Whenever new data packet arrives, corresponding event is called to notify application layer. When it comes to sending data, application may decide between 2 options (*this is valid only for non-UDP connections):

  • Write data to temporary transmit buffer

  • Execute send command for every API function call

Temporary transmit buffer

By calling lwesp_conn_write() on active connection, temporary buffer is allocated and input data are copied to it. There is always up to 1 internal buffer active. When it is full (or if input data length is longer than maximal size), data are immediately send out and are not written to buffer.

ESP AT Firmware allows (current revision) to transmit up to 2048 bytes at a time with single command. When trying to send more than this, application would need to issue multiple send commands on AT commands level.

Write option is used mostly when application needs to write many different small chunks of data. Temporary buffer hence prevents many send command instructions as it is faster to send single command with big buffer, than many of them with smaller chunks of bytes.

Write data to connection output buffer
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
size_t rem_len;
lwesp_conn_p conn;
lwespr_t res;

/* ... other tasks to make sure connection is established */

/* We are connected to server at this point! */
/*
 * Call write function to write data to memory
 * and do not send immediately unless buffer is full after this write
 *
 * rem_len will give us response how much bytes
 * is available in memory after write
 */
res = lwesp_conn_write(conn, "My string", 9, 0, &rem_len);
if (rem_len == 0) {
    printf("No more memory available for next write!\r\n");
}
res = lwesp_conn_write(conn, "example.com", 11, 0, &rem_len);

/*
 * Data will stay in buffer until buffer is full,
 * except if user wants to force send,
 * call write function with flush mode enabled
 *
 * It will send out together 20 bytes
 */
lwesp_conn_write(conn, NULL, 0, 1, NULL);

Transmit packet manually

In some cases it is not possible to use temporary buffers, mostly because of memory constraints. Application can directly start send data instructions on AT level by using lwesp_conn_send() or lwesp_conn_sendto() functions.

group LWESP_CONN

Connection API functions.

Typedefs

typedef struct lwesp_conn *lwesp_conn_p

Pointer to lwesp_conn_t structure.

Enums

enum lwesp_conn_type_t

List of possible connection types.

Values:

enumerator LWESP_CONN_TYPE_TCP

Connection type is TCP

enumerator LWESP_CONN_TYPE_UDP

Connection type is UDP

enumerator LWESP_CONN_TYPE_SSL

Connection type is SSL

Functions

lwespr_t lwesp_conn_start(lwesp_conn_p *conn, lwesp_conn_type_t type, const char *const remote_host, lwesp_port_t remote_port, void *const arg, lwesp_evt_fn conn_evt_fn, const uint32_t blocking)

Start a new connection of specific type.

Return

lwespOK on success, member of lwespr_t enumeration otherwise

Parameters
  • [out] conn: Pointer to connection handle to set new connection reference in case of successfully connected

  • [in] type: Connection type. This parameter can be a value of lwesp_conn_type_t enumeration

  • [in] remote_host: Connection host. In case of IP, write it as string, ex. “192.168.1.1”

  • [in] remote_port: Connection port

  • [in] arg: Pointer to user argument passed to connection if successfully connected

  • [in] conn_evt_fn: Callback function for this connection

  • [in] blocking: Status whether command should be blocking or not

lwespr_t lwesp_conn_startex(lwesp_conn_p *conn, lwesp_conn_start_t *start_struct, void *const arg, lwesp_evt_fn conn_evt_fn, const uint32_t blocking)

Start a new connection of specific type in extended mode.

Return

lwespOK on success, member of lwespr_t enumeration otherwise

Parameters
  • [out] conn: Pointer to connection handle to set new connection reference in case of successfully connected

  • [in] start_struct: Connection information are handled by one giant structure

  • [in] arg: Pointer to user argument passed to connection if successfully connected

  • [in] conn_evt_fn: Callback function for this connection

  • [in] blocking: Status whether command should be blocking or not

lwespr_t lwesp_conn_close(lwesp_conn_p conn, const uint32_t blocking)

Close specific or all connections.

Return

lwespOK on success, member of lwespr_t enumeration otherwise

Parameters
  • [in] conn: Connection handle to close. Set to NULL if you want to close all connections.

  • [in] blocking: Status whether command should be blocking or not

lwespr_t lwesp_conn_send(lwesp_conn_p conn, const void *data, size_t btw, size_t *const bw, const uint32_t blocking)

Send data on already active connection either as client or server.

Return

lwespOK on success, member of lwespr_t enumeration otherwise

Parameters
  • [in] conn: Connection handle to send data

  • [in] data: Data to send

  • [in] btw: Number of bytes to send

  • [out] bw: Pointer to output variable to save number of sent data when successfully sent. Parameter value might not be accurate if you combine lwesp_conn_write and lwesp_conn_send functions

  • [in] blocking: Status whether command should be blocking or not

lwespr_t lwesp_conn_sendto(lwesp_conn_p conn, const lwesp_ip_t *const ip, lwesp_port_t port, const void *data, size_t btw, size_t *bw, const uint32_t blocking)

Send data on active connection of type UDP to specific remote IP and port.

Note

In case IP and port values are not set, it will behave as normal send function (suitable for TCP too)

Return

lwespOK on success, member of lwespr_t enumeration otherwise

Parameters
  • [in] conn: Connection handle to send data

  • [in] ip: Remote IP address for UDP connection

  • [in] port: Remote port connection

  • [in] data: Pointer to data to send

  • [in] btw: Number of bytes to send

  • [out] bw: Pointer to output variable to save number of sent data when successfully sent

  • [in] blocking: Status whether command should be blocking or not

lwespr_t lwesp_conn_set_arg(lwesp_conn_p conn, void *const arg)

Set argument variable for connection.

Return

lwespOK on success, member of lwespr_t enumeration otherwise

See

lwesp_conn_get_arg

Parameters
  • [in] conn: Connection handle to set argument

  • [in] arg: Pointer to argument

void *lwesp_conn_get_arg(lwesp_conn_p conn)

Get user defined connection argument.

Return

User argument

See

lwesp_conn_set_arg

Parameters
  • [in] conn: Connection handle to get argument

uint8_t lwesp_conn_is_client(lwesp_conn_p conn)

Check if connection type is client.

Return

1 on success, 0 otherwise

Parameters
  • [in] conn: Pointer to connection to check for status

uint8_t lwesp_conn_is_server(lwesp_conn_p conn)

Check if connection type is server.

Return

1 on success, 0 otherwise

Parameters
  • [in] conn: Pointer to connection to check for status

uint8_t lwesp_conn_is_active(lwesp_conn_p conn)

Check if connection is active.

Return

1 on success, 0 otherwise

Parameters
  • [in] conn: Pointer to connection to check for status

uint8_t lwesp_conn_is_closed(lwesp_conn_p conn)

Check if connection is closed.

Return

1 on success, 0 otherwise

Parameters
  • [in] conn: Pointer to connection to check for status

int8_t lwesp_conn_getnum(lwesp_conn_p conn)

Get the number from connection.

Return

Connection number in case of success or -1 on failure

Parameters
  • [in] conn: Connection pointer

lwespr_t lwesp_conn_set_ssl_buffersize(size_t size, const uint32_t blocking)

Set internal buffer size for SSL connection on ESP device.

Note

Use this function before you start first SSL connection

Return

lwespOK on success, member of lwespr_t enumeration otherwise

Parameters
  • [in] size: Size of buffer in units of bytes. Valid range is between 2048 and 4096 bytes

  • [in] blocking: Status whether command should be blocking or not

lwespr_t lwesp_get_conns_status(const uint32_t blocking)

Gets connections status.

Return

lwespOK on success, member of lwespr_t enumeration otherwise

Parameters
  • [in] blocking: Status whether command should be blocking or not

lwesp_conn_p lwesp_conn_get_from_evt(lwesp_evt_t *evt)

Get connection from connection based event.

Return

Connection pointer on success, NULL otherwise

Parameters
  • [in] evt: Event which happened for connection

lwespr_t lwesp_conn_write(lwesp_conn_p conn, const void *data, size_t btw, uint8_t flush, size_t *const mem_available)

Write data to connection buffer and if it is full, send it non-blocking way.

Note

This function may only be called from core (connection callbacks)

Return

lwespOK on success, member of lwespr_t enumeration otherwise

Parameters
  • [in] conn: Connection to write

  • [in] data: Data to copy to write buffer

  • [in] btw: Number of bytes to write

  • [in] flush: Flush flag. Set to 1 if you want to send data immediately after copying

  • [out] mem_available: Available memory size available in current write buffer. When the buffer length is reached, current one is sent and a new one is automatically created. If function returns lwespOK and *mem_available = 0, there was a problem allocating a new buffer for next operation

lwespr_t lwesp_conn_recved(lwesp_conn_p conn, lwesp_pbuf_p pbuf)

Notify connection about received data which means connection is ready to accept more data.

Once data reception is confirmed, stack will try to send more data to user.

Note

Since this feature is not supported yet by AT commands, function is only prototype and should be used in connection callback when data are received

Note

Function is not thread safe and may only be called from connection event function

Return

lwespOK on success, member of lwespr_t enumeration otherwise

Parameters
  • [in] conn: Connection handle

  • [in] pbuf: Packet buffer received on connection

size_t lwesp_conn_get_total_recved_count(lwesp_conn_p conn)

Get total number of bytes ever received on connection and sent to user.

Return

Total number of received bytes on connection

Parameters
  • [in] conn: Connection handle

uint8_t lwesp_conn_get_remote_ip(lwesp_conn_p conn, lwesp_ip_t *ip)

Get connection remote IP address.

Return

1 on success, 0 otherwise

Parameters
  • [in] conn: Connection handle

  • [out] ip: Pointer to IP output handle

lwesp_port_t lwesp_conn_get_remote_port(lwesp_conn_p conn)

Get connection remote port number.

Return

Port number on success, 0 otherwise

Parameters
  • [in] conn: Connection handle

lwesp_port_t lwesp_conn_get_local_port(lwesp_conn_p conn)

Get connection local port number.

Return

Port number on success, 0 otherwise

Parameters
  • [in] conn: Connection handle

lwespr_t lwesp_conn_ssl_set_config(uint8_t link_id, uint8_t auth_mode, uint8_t pki_number, uint8_t ca_number, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Configure SSL parameters.

Return

lwespOK on success, member of lwespr_t enumeration otherwise

Parameters
  • [in] link_id: ID of the connection (0~max), for multiple connections, if the value is max, it means all connections. By default, max is LWESP_CFG_MAX_CONNS.

  • [in] auth_mode: Authentication mode 0: no authorization 1: load cert and private key for server authorization 2: load CA for client authorize server cert and private key 3: both authorization

  • [in] pki_number: The index of cert and private key, if only one cert and private key, the value should be 0.

  • [in] ca_number: The index of CA, if only one CA, the value should be 0.

  • [in] evt_fn: Callback function called when command has finished. Set to NULL when not used

  • [in] evt_arg: Custom argument for event callback function

  • [in] blocking: Status whether command should be blocking or not

struct lwesp_conn_start_t
#include <lwesp_typedefs.h>

Connection start structure, used to start the connection in extended mode.

Public Members

lwesp_conn_type_t type

Connection type

const char *remote_host

Host name or IP address in string format

lwesp_port_t remote_port

Remote server port

const char *local_ip

Local IP. Optional parameter, set to NULL if not used (most cases)

uint16_t keep_alive

Keep alive parameter for TCP/SSL connection in units of seconds. Value can be between 0 - 7200 where 0 means no keep alive

struct lwesp_conn_start_t::[anonymous]::[anonymous] tcp_ssl

TCP/SSL specific features

lwesp_port_t local_port

Custom local port for UDP

uint8_t mode

UDP mode. Set to 0 by default. Check ESP AT commands instruction set for more info when needed

struct lwesp_conn_start_t::[anonymous]::[anonymous] udp

UDP specific features

union lwesp_conn_start_t::[anonymous] ext

Extended support union