LwESP branch-7c00ef1 documentation

Welcome to the documentation for version branch-7c00ef1.

LwESP is generic, platform independent, ESP-AT parser library to communicate with ESP8266 or ESP32 WiFi-based microcontrollers from Espressif systems using official AT Commands set running on ESP device. Its objective is to run on master system, while Espressif device runs official AT commands firmware developed and maintained by Espressif systems.

_images/logo.svg

Features

  • Supports latest ESP32, ESP32-C3 & ESP8266 AT software from Espressif system

  • Platform independent and easy to port, written in C99

    • Library is developed under Win32 platform

    • Provided examples for ARM Cortex-M or Win32 platforms

  • Allows different configurations to optimize user requirements

  • Optimized for systems with operating systems (or RTOS)

    • Currently only OS mode is supported

    • 2 different threads to process user inputs and received data

      • Producer thread to collect user commands from application threads and to start command execution

      • Process thread to process received data from ESP device

  • Allows sequential API for connections in client and server mode

  • Includes several applications built on top of library

    • HTTP server with dynamic files (file system) support

    • MQTT client for MQTT connection

    • MQTT client Cayenne API for Cayenne MQTT server

  • Embeds other AT features, such as WPS

  • User friendly MIT license

Requirements

  • C compiler

  • ESP8266 or ESP32 device with running AT-Commands firmware

Contribute

Fresh contributions are always welcome. Simple instructions to proceed:

  1. Fork Github repository

  2. Respect C style & coding rules used by the library

  3. Create a pull request to develop branch with new features or bug fixes

Alternatively you may:

  1. Report a bug

  2. Ask for a feature request

License

MIT License

Copyright (c) 2020 Tilen MAJERLE

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Table of contents

Getting started

Getting started may be the most challenging part of every new library. This guide is describing how to start with the library quickly and effectively

Download library

Library is primarly hosted on Github.

You can get it with:

  • Downloading latest release from releases area on Github

  • Clone master branch for latest stable version

  • Clone develop branch for latest development

Download from releases

All releases are available on Github releases area.

Clone from Github
First-time clone

This is used when you do not have yet local copy on your machine.

  • Make sure git is installed.

  • Open console and navigate to path in the system to clone repository to. Use command cd your_path

  • Clone repository with one of available 3 options

    • Run git clone --recurse-submodules https://github.com/MaJerle/lwesp command to clone entire repository, including submodules

    • Run git clone --recurse-submodules --branch develop https://github.com/MaJerle/lwesp to clone development branch, including submodules

    • Run git clone --recurse-submodules --branch master https://github.com/MaJerle/lwesp to clone latest stable branch, including submodules

  • Navigate to examples directory and run favourite example

Update cloned to latest version
  • Open console and navigate to path in the system where your repository is located. Use command cd your_path

  • Run git pull origin master command to get latest changes on master branch

  • Run git pull origin develop command to get latest changes on develop branch

  • Run git submodule update --init --remote to update submodules to latest version

Note

This is preferred option to use when you want to evaluate library and run prepared examples. Repository consists of multiple submodules which can be automatically downloaded when cloning and pulling changes from root repository.

Add library to project

At this point it is assumed that you have successfully download library, either cloned it or from releases page. Next step is to add the library to the project, by means of source files to compiler inputs and header files in search path

  • Copy lwesp folder to your project, it contains library files

  • Add lwesp/src/include folder to include path of your toolchain. This is where C/C++ compiler can find the files during compilation process. Usually using -I flag

  • Add source files from lwesp/src/ folder to toolchain build. These files are built by C/C++ compiler

  • Copy lwesp/src/include/lwesp/lwesp_opts_template.h to project folder and rename it to lwesp_opts.h

  • Build the project

Configuration file

Configuration file is used to overwrite default settings defined for the essential use case. Library comes with template config file, which can be modified according to needs. and it should be copied (or simply renamed in-place) and named lwesp_opts.h

Note

Default configuration template file location: lwesp/src/include/lwesp/lwesp_opts_template.h. File must be renamed to lwesp_opts.h first and then copied to the project directory where compiler include paths have access to it by using #include "lwesp_opts.h".

List of configuration options are available in the Configuration section. If any option is about to be modified, it should be done in configuration file

Template configuration file
 1/**
 2 * \file            lwesp_opts_template.h
 3 * \brief           Template config file
 4 */
 5
 6/*
 7 * Copyright (c) 2020 Tilen MAJERLE
 8 *
 9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so,
15 * subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 *
29 * This file is part of LwESP - Lightweight ESP-AT parser library.
30 *
31 * Author:          Tilen MAJERLE <tilen@majerle.eu>
32 * Version:         v1.1.2-dev
33 */
34#ifndef LWESP_HDR_OPTS_H
35#define LWESP_HDR_OPTS_H
36
37/* Rename this file to "lwesp_opts.h" for your application */
38
39/*
40 * Open "include/lwesp/lwesp_opt.h" and
41 * copy & replace here settings you want to change values
42 */
43
44#endif /* LWESP_HDR_OPTS_H */

Note

If you prefer to avoid using configuration file, application must define a global symbol LWESP_IGNORE_USER_OPTS, visible across entire application. This can be achieved with -D compiler option.

User manual

Overview

WiFi devices (focus on ESP8266 and ESP32) from Espressif Systems are low-cost and very useful for embedded projects. These are classic microcontrollers without embedded flash memory. Application needs to assure external Quad-SPI flash to execute code from it directly.

Espressif offers SDK to program these microcontrollers directly and run code from there. It is called RTOS-based SDK, written in C language, and allows customers to program MCU starting with main function. These devices have some basic peripherals, such as GPIO, ADC, SPI, I2C, UART, etc. Pretty basic though.

Wifi connectivity is often part of bigger system with more powerful MCU. There is usually bigger MCU + Wifi transceiver (usually module) aside with UART/SPI communication. MCU handles application, such as display & graphics, runs operating systems, drives motor and has additional external memories.

Typical application example with access to WiFi

Typical application example with access to WiFi

Espressif is not only developing RTOS SDK firmware, it also develops AT Slave firmware based on RTOS-SDK. This is a special application, which is running on ESP device and allows host MCU to send AT commands and get response for it. Now it is time to use LwESP you are reading this manual for.

LwESP has been developed to allow customers to:

  • Develop on single (host MCU) architecture at the same time and do not care about Espressif arch

  • Shorten time to market

Customers using LwESP do not need to take care about proper command for specific task, they can call API functions, such as lwesp_sta_join() to join WiFi network instead. Library will take the necessary steps in order to send right command to device via low-level driver (usually UART) and process incoming response from device before it will notify application layer if it was successfuly or not.

Note

LwESP offers efficient communication between host MCU at one side and Espressif wifi transceiver on another side.

To summarize:

  • ESP device runs official AT firmware, provided by Espressif systems

  • Host MCU runs custom application, together with LwESP library

  • Host MCU communicates with ESP device with UART or similar interface.

Architecture

Architecture of the library consists of 4 layers.

ESP-AT layer architecture overview

ESP-AT layer architecture overview

Application layer

User layer is the highest layer of the final application. This is the part where API functions are called to execute some command.

Middleware layer

Middleware part is actively developed and shall not be modified by customer by any means. If there is a necessity to do it, often it means that developer of the application uses it wrongly. This part is platform independent and does not use any specific compiler features for proper operation.

Note

There is no compiler specific features implemented in this layer.

System & low-level layer

Application needs to fully implement this part and resolve it with care. Functions are related to actual implementation with ESP device and are highly architecture oriented. Some examples for WIN32 and ARM Cortex-M are included with library.

Tip

Check Porting guide for detailed instructions and examples.

System functions

System functions are bridge between operating system running on embedded system and ESP-AT middleware. Functions need to provide:

  • Thread management

  • Binary semaphore management

  • Recursive mutex management

  • Message queue management

  • Current time status information

Tip

System function prototypes are available in System functions section.

Low-level implementation

Low-Level, or LWESP_LL, is part, dedicated for communication between ESP-AT middleware and ESP physical device. Application needs to implement output function to send necessary AT command instruction aswell as implement input module to send received data from ESP device to ESP-AT middleware.

Application must also assure memory assignment for Memory manager when default allocation is used.

Tip

Low level, input module & memory function prototypes are available in Low-Level functions, Input module and Memory manager respectfully.

ESP physical device

Inter thread communication

ESP-AT middleware is only available with operating system. For successful resources management, it uses 2 threads within library and allows multiple application threads to post new command to be processed.

Inter-thread architecture block diagram

Inter-thread architecture block diagram

Producing and Processing threads are part of library, its implementation is in lwesp_threads.c file.

Processing thread

Processing thread is in charge of processing each and every received character from ESP device. It can process URC messages which are received from ESP device without any command request. Some of them are:

  • +IPD indicating new data packet received from remote side on active connection

  • WIFI CONNECTED indicating ESP has been just connected to access point

  • and more others

Note

Received messages without any command (URC messages) are sent to application layer using events, where they can be processed and used in further steps

This thread also checks and processes specific received messages based on active command. As an example, when application tries to make a new connection to remote server, it starts command with AT+CIPSTART message. Thread understands that active command is to connect to remote side and will wait for potential +LINK_CONN:<...> message, indicating connection status. it will also wait for OK or ERROR, indicating command finished status before it unlocks sync_sem to unblock producing thread.

Tip

When thread tries to unlock sync_sem, it first checks if it has been locked by producing thread.

Producing thread

Producing thread waits for command messages posted from application thread. When new message has been received, it sends initial AT message over AT port.

  • It checks if command is valid and if it has corresponding initial AT sequence, such as AT+CIPSTART

  • It locks sync_sem semaphore and waits for processing thread to unlock it

    • Processing thread is in charge to read respone from ESP and react accordingly. See previous section for details.

  • If application uses blocking mode, it unlocks command sem semaphore and returns response

  • If application uses non-blocking mode, it frees memory for message and sends event with response message

Application thread

Application thread is considered any thread which calls API functions and therefore writes new messages to producing message queue, later processed by producing thread.

A new message memory is allocated in this thread and type of command is assigned to it, together with required input data for command. It also sets blocking or non-blocking mode, how command shall be executed.

When application tries to execute command in blocking mode, it creates new sync semaphore sem, locks it, writes message to producing queue and waits for sem to get unlocked. This effectively puts thread to blocked state by operating system and removes it from scheduler until semaphore is unlocked again. Semaphore sem gets unlocked in producing thread when response has been received for specific command.

Tip

sem semaphore is unlocked in producing thread after sync_sem is unlocked in processing thread

Note

Every command message uses its own sem semaphore to sync multiple application threads at the same time.

If message is to be executed in non-blocking mode, sem is not created as there is no need to block application thread. When this is the case, application thread will only write message command to producing queue and return status of writing to application.

Events and callback functions

Library uses events to notify application layer for (possible, but not limited to) unexpected events. This concept is used aswell for commands with longer executing time, such as scanning access points or when application starts new connection as client mode.

There are 3 types of events/callbacks available:

  • Global event callback function, assigned when initializing library

  • Connection specific event callback function, to process only events related to connection, such as connection error, data send, data receive, connection closed

  • API function call based event callback function

Every callback is always called from protected area of middleware (when exclusing access is granted to single thread only), and it can be called from one of these 3 threads:

Tip

Check Inter thread communication for more details about Producing and Processing thread.

Global event callback

Global event callback function is assigned at library initialization. It is used by the application to receive any kind of event, except the one related to connection:

  • ESP station successfully connected to access point

  • ESP physical device reset has been detected

  • Restore operation finished

  • New station has connected to access point

  • and many more..

Tip

Check Event management section for different kind of events

By default, global event function is single function. If the application tries to split different events with different callback functions, it is possible to do so by using lwesp_evt_register() function to register a new, custom, event function.

Tip

Implementation of Netconn API leverages lwesp_evt_register() to receive event when station disconnected from wifi access point. Check its source file for actual implementation.

Netconn API module actual implementation
  1/**
  2 * \file            lwesp_netconn.c
  3 * \brief           API functions for sequential calls
  4 */
  5
  6/*
  7 * Copyright (c) 2020 Tilen MAJERLE
  8 *
  9 * Permission is hereby granted, free of charge, to any person
 10 * obtaining a copy of this software and associated documentation
 11 * files (the "Software"), to deal in the Software without restriction,
 12 * including without limitation the rights to use, copy, modify, merge,
 13 * publish, distribute, sublicense, and/or sell copies of the Software,
 14 * and to permit persons to whom the Software is furnished to do so,
 15 * subject to the following conditions:
 16 *
 17 * The above copyright notice and this permission notice shall be
 18 * included in all copies or substantial portions of the Software.
 19 *
 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 23 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 27 * OTHER DEALINGS IN THE SOFTWARE.
 28 *
 29 * This file is part of LwESP - Lightweight ESP-AT parser library.
 30 *
 31 * Author:          Tilen MAJERLE <tilen@majerle.eu>
 32 * Version:         v1.1.2-dev
 33 */
 34#include "lwesp/lwesp_netconn.h"
 35#include "lwesp/lwesp_private.h"
 36#include "lwesp/lwesp_conn.h"
 37#include "lwesp/lwesp_mem.h"
 38
 39#if LWESP_CFG_NETCONN || __DOXYGEN__
 40
 41/* Check conditions */
 42#if LWESP_CFG_NETCONN_RECEIVE_QUEUE_LEN < 2
 43#error "LWESP_CFG_NETCONN_RECEIVE_QUEUE_LEN must be greater or equal to 2"
 44#endif /* LWESP_CFG_NETCONN_RECEIVE_QUEUE_LEN < 2 */
 45
 46#if LWESP_CFG_NETCONN_ACCEPT_QUEUE_LEN < 2
 47#error "LWESP_CFG_NETCONN_ACCEPT_QUEUE_LEN must be greater or equal to 2"
 48#endif /* LWESP_CFG_NETCONN_ACCEPT_QUEUE_LEN < 2 */
 49
 50/* Check for IP status */
 51#if LWESP_CFG_IPV6
 52#define NETCONN_IS_TCP(nc)          (nc->type == LWESP_NETCONN_TYPE_TCP || nc->type == LWESP_NETCONN_TYPE_TCPV6)
 53#define NETCONN_IS_SSL(nc)          (nc->type == LWESP_NETCONN_TYPE_SSL || nc->type == LWESP_NETCONN_TYPE_SSLV6)
 54#else
 55#define NETCONN_IS_TCP(nc)          (nc->type == LWESP_NETCONN_TYPE_TCP)
 56#define NETCONN_IS_SSL(nc)          (nc->type == LWESP_NETCONN_TYPE_SSL)
 57#endif /* LWESP_CFG_IPV6 */
 58
 59/**
 60 * \brief           Sequential API structure
 61 */
 62typedef struct lwesp_netconn {
 63    struct lwesp_netconn* next;                 /*!< Linked list entry */
 64
 65    lwesp_netconn_type_t type;                  /*!< Netconn type */
 66    lwesp_port_t listen_port;                   /*!< Port on which we are listening */
 67
 68    size_t rcv_packets;                         /*!< Number of received packets so far on this connection */
 69    lwesp_conn_p conn;                          /*!< Pointer to actual connection */
 70
 71    lwesp_sys_mbox_t mbox_accept;               /*!< List of active connections waiting to be processed */
 72    lwesp_sys_mbox_t mbox_receive;              /*!< Message queue for receive mbox */
 73    size_t mbox_receive_entries;                /*!< Number of entries written to receive mbox */
 74
 75    lwesp_linbuff_t buff;                       /*!< Linear buffer structure */
 76
 77    uint16_t conn_timeout;                      /*!< Connection timeout in units of seconds when
 78                                                    netconn is in server (listen) mode.
 79                                                    Connection will be automatically closed if there is no
 80                                                    data exchange in time. Set to `0` when timeout feature is disabled. */
 81
 82#if LWESP_CFG_NETCONN_RECEIVE_TIMEOUT || __DOXYGEN__
 83    uint32_t rcv_timeout;                       /*!< Receive timeout in unit of milliseconds */
 84#endif
 85} lwesp_netconn_t;
 86
 87static uint8_t recv_closed = 0xFF, recv_not_present = 0xFF;
 88static lwesp_netconn_t* listen_api;             /*!< Main connection in listening mode */
 89static lwesp_netconn_t* netconn_list;           /*!< Linked list of netconn entries */
 90
 91/**
 92 * \brief           Flush all mboxes and clear possible used memories
 93 * \param[in]       nc: Pointer to netconn to flush
 94 * \param[in]       protect: Set to 1 to protect against multi-thread access
 95 */
 96static void
 97flush_mboxes(lwesp_netconn_t* nc, uint8_t protect) {
 98    lwesp_pbuf_p pbuf;
 99    lwesp_netconn_t* new_nc;
100    if (protect) {
101        lwesp_core_lock();
102    }
103    if (lwesp_sys_mbox_isvalid(&nc->mbox_receive)) {
104        while (lwesp_sys_mbox_getnow(&nc->mbox_receive, (void**)&pbuf)) {
105            if (nc->mbox_receive_entries > 0) {
106                --nc->mbox_receive_entries;
107            }
108            if (pbuf != NULL && (uint8_t*)pbuf != (uint8_t*)&recv_closed) {
109                lwesp_pbuf_free(pbuf);          /* Free received data buffers */
110            }
111        }
112        lwesp_sys_mbox_delete(&nc->mbox_receive);   /* Delete message queue */
113        lwesp_sys_mbox_invalid(&nc->mbox_receive);  /* Invalid handle */
114    }
115    if (lwesp_sys_mbox_isvalid(&nc->mbox_accept)) {
116        while (lwesp_sys_mbox_getnow(&nc->mbox_accept, (void**)&new_nc)) {
117            if (new_nc != NULL
118                && (uint8_t*)new_nc != (uint8_t*)&recv_closed
119                && (uint8_t*)new_nc != (uint8_t*)&recv_not_present) {
120                lwesp_netconn_close(new_nc);    /* Close netconn connection */
121            }
122        }
123        lwesp_sys_mbox_delete(&nc->mbox_accept);/* Delete message queue */
124        lwesp_sys_mbox_invalid(&nc->mbox_accept);   /* Invalid handle */
125    }
126    if (protect) {
127        lwesp_core_unlock();
128    }
129}
130
131/**
132 * \brief           Callback function for every server connection
133 * \param[in]       evt: Pointer to callback structure
134 * \return          Member of \ref lwespr_t enumeration
135 */
136static lwespr_t
137netconn_evt(lwesp_evt_t* evt) {
138    lwesp_conn_p conn;
139    lwesp_netconn_t* nc = NULL;
140    uint8_t close = 0;
141
142    conn = lwesp_conn_get_from_evt(evt);        /* Get connection from event */
143    switch (lwesp_evt_get_type(evt)) {
144        /*
145         * A new connection has been active
146         * and should be handled by netconn API
147         */
148        case LWESP_EVT_CONN_ACTIVE: {           /* A new connection active is active */
149            if (lwesp_conn_is_client(conn)) {   /* Was connection started by us? */
150                nc = lwesp_conn_get_arg(conn);  /* Argument should be already set */
151                if (nc != NULL) {
152                    nc->conn = conn;            /* Save actual connection */
153                } else {
154                    close = 1;                  /* Close this connection, invalid netconn */
155                }
156
157            /* Is the connection server type and we have known listening API? */
158            } else if (lwesp_conn_is_server(conn) && listen_api != NULL) {
159                /*
160                 * Create a new netconn structure
161                 * and set it as connection argument.
162                 */
163                nc = lwesp_netconn_new(LWESP_NETCONN_TYPE_TCP); /* Create new API */
164                LWESP_DEBUGW(LWESP_CFG_DBG_NETCONN | LWESP_DBG_TYPE_TRACE | LWESP_DBG_LVL_WARNING,
165                           nc == NULL, "[NETCONN] Cannot create new structure for incoming server connection!\r\n");
166
167                if (nc != NULL) {
168                    nc->conn = conn;            /* Set connection handle */
169                    lwesp_conn_set_arg(conn, nc);   /* Set argument for connection */
170
171                    /*
172                     * In case there is no listening connection,
173                     * simply close the connection
174                     */
175                    if (!lwesp_sys_mbox_isvalid(&listen_api->mbox_accept)
176                        || !lwesp_sys_mbox_putnow(&listen_api->mbox_accept, nc)) {
177                        close = 1;
178                    }
179                } else {
180                    close = 1;
181                }
182            } else {
183                LWESP_DEBUGW(LWESP_CFG_DBG_NETCONN | LWESP_DBG_TYPE_TRACE | LWESP_DBG_LVL_WARNING, listen_api == NULL,
184                           "[NETCONN] Closing connection as there is no listening API in netconn!\r\n");
185                close = 1;                      /* Close the connection at this point */
186            }
187
188            /* Decide if some events want to close the connection */
189            if (close) {
190                if (nc != NULL) {
191                    lwesp_conn_set_arg(conn, NULL); /* Reset argument */
192                    lwesp_netconn_delete(nc);   /* Free memory for API */
193                }
194                lwesp_conn_close(conn, 0);      /* Close the connection */
195                close = 0;
196            }
197            break;
198        }
199
200        /*
201         * We have a new data received which
202         * should have netconn structure as argument
203         */
204        case LWESP_EVT_CONN_RECV: {
205            lwesp_pbuf_p pbuf;
206
207            nc = lwesp_conn_get_arg(conn);      /* Get API from connection */
208            pbuf = lwesp_evt_conn_recv_get_buff(evt);   /* Get received buff */
209
210#if !LWESP_CFG_CONN_MANUAL_TCP_RECEIVE
211            lwesp_conn_recved(conn, pbuf);      /* Notify stack about received data */
212#endif /* !LWESP_CFG_CONN_MANUAL_TCP_RECEIVE */
213
214            lwesp_pbuf_ref(pbuf);               /* Increase reference counter */
215            if (nc == NULL || !lwesp_sys_mbox_isvalid(&nc->mbox_receive)
216                || !lwesp_sys_mbox_putnow(&nc->mbox_receive, pbuf)) {
217                LWESP_DEBUGF(LWESP_CFG_DBG_NETCONN,
218                           "[NETCONN] Ignoring more data for receive!\r\n");
219                lwesp_pbuf_free(pbuf);          /* Free pbuf */
220                return lwespOKIGNOREMORE;       /* Return OK to free the memory and ignore further data */
221            }
222            ++nc->mbox_receive_entries;         /* Increase number of packets in receive mbox */
223#if LWESP_CFG_CONN_MANUAL_TCP_RECEIVE
224            /* Check against 1 less to still allow potential close event to be written to queue */
225            if (nc->mbox_receive_entries >= (LWESP_CFG_NETCONN_RECEIVE_QUEUE_LEN - 1)) {
226                conn->status.f.receive_blocked = 1; /* Block reading more data */
227            }
228#endif /* LWESP_CFG_CONN_MANUAL_TCP_RECEIVE */
229
230            ++nc->rcv_packets;                  /* Increase number of packets received */
231            LWESP_DEBUGF(LWESP_CFG_DBG_NETCONN | LWESP_DBG_TYPE_TRACE,
232                       "[NETCONN] Received pbuf contains %d bytes. Handle written to receive mbox\r\n",
233                       (int)lwesp_pbuf_length(pbuf, 0));
234            break;
235        }
236
237        /* Connection was just closed */
238        case LWESP_EVT_CONN_CLOSE: {
239            nc = lwesp_conn_get_arg(conn);      /* Get API from connection */
240
241            /*
242             * In case we have a netconn available,
243             * simply write pointer to received variable to indicate closed state
244             */
245            if (nc != NULL && lwesp_sys_mbox_isvalid(&nc->mbox_receive)) {
246                if (lwesp_sys_mbox_putnow(&nc->mbox_receive, (void*)&recv_closed)) {
247                    ++nc->mbox_receive_entries;
248                }
249            }
250
251            break;
252        }
253        default:
254            return lwespERR;
255    }
256    return lwespOK;
257}
258
259/**
260 * \brief           Global event callback function
261 * \param[in]       evt: Callback information and data
262 * \return          \ref lwespOK on success, member of \ref lwespr_t otherwise
263 */
264static lwespr_t
265lwesp_evt(lwesp_evt_t* evt) {
266    switch (lwesp_evt_get_type(evt)) {
267        case LWESP_EVT_WIFI_DISCONNECTED: {     /* Wifi disconnected event */
268            if (listen_api != NULL) {           /* Check if listen API active */
269                lwesp_sys_mbox_putnow(&listen_api->mbox_accept, &recv_closed);
270            }
271            break;
272        }
273        case LWESP_EVT_DEVICE_PRESENT: {        /* Device present event */
274            if (listen_api != NULL && !lwesp_device_is_present()) { /* Check if device present */
275                lwesp_sys_mbox_putnow(&listen_api->mbox_accept, &recv_not_present);
276            }
277        }
278        default:
279            break;
280    }
281    return lwespOK;
282}
283
284/**
285 * \brief           Create new netconn connection
286 * \param[in]       type: Netconn connection type
287 * \return          New netconn connection on success, `NULL` otherwise
288 */
289lwesp_netconn_p
290lwesp_netconn_new(lwesp_netconn_type_t type) {
291    lwesp_netconn_t* a;
292    static uint8_t first = 1;
293
294    /* Register only once! */
295    lwesp_core_lock();
296    if (first) {
297        first = 0;
298        lwesp_evt_register(lwesp_evt);          /* Register global event function */
299    }
300    lwesp_core_unlock();
301    a = lwesp_mem_calloc(1, sizeof(*a));        /* Allocate memory for core object */
302    if (a != NULL) {
303        a->type = type;                         /* Save netconn type */
304        a->conn_timeout = 0;                    /* Default connection timeout */
305        if (!lwesp_sys_mbox_create(&a->mbox_accept, LWESP_CFG_NETCONN_ACCEPT_QUEUE_LEN)) {  /* Allocate memory for accepting message box */
306            LWESP_DEBUGF(LWESP_CFG_DBG_NETCONN | LWESP_DBG_TYPE_TRACE | LWESP_DBG_LVL_DANGER,
307                       "[NETCONN] Cannot create accept MBOX\r\n");
308            goto free_ret;
309        }
310        if (!lwesp_sys_mbox_create(&a->mbox_receive, LWESP_CFG_NETCONN_RECEIVE_QUEUE_LEN)) {/* Allocate memory for receiving message box */
311            LWESP_DEBUGF(LWESP_CFG_DBG_NETCONN | LWESP_DBG_TYPE_TRACE | LWESP_DBG_LVL_DANGER,
312                       "[NETCONN] Cannot create receive MBOX\r\n");
313            goto free_ret;
314        }
315        lwesp_core_lock();
316        if (netconn_list == NULL) {             /* Add new netconn to the existing list */
317            netconn_list = a;
318        } else {
319            a->next = netconn_list;             /* Add it to beginning of the list */
320            netconn_list = a;
321        }
322        lwesp_core_unlock();
323    }
324    return a;
325free_ret:
326    if (lwesp_sys_mbox_isvalid(&a->mbox_accept)) {
327        lwesp_sys_mbox_delete(&a->mbox_accept);
328        lwesp_sys_mbox_invalid(&a->mbox_accept);
329    }
330    if (lwesp_sys_mbox_isvalid(&a->mbox_receive)) {
331        lwesp_sys_mbox_delete(&a->mbox_receive);
332        lwesp_sys_mbox_invalid(&a->mbox_receive);
333    }
334    if (a != NULL) {
335        lwesp_mem_free_s((void**)&a);
336    }
337    return NULL;
338}
339
340/**
341 * \brief           Delete netconn connection
342 * \param[in]       nc: Netconn handle
343 * \return          \ref lwespOK on success, member of \ref lwespr_t enumeration otherwise
344 */
345lwespr_t
346lwesp_netconn_delete(lwesp_netconn_p nc) {
347    LWESP_ASSERT("netconn != NULL", nc != NULL);
348
349    lwesp_core_lock();
350    flush_mboxes(nc, 0);                        /* Clear mboxes */
351
352    /* Stop listening on netconn */
353    if (nc == listen_api) {
354        listen_api = NULL;
355        lwesp_core_unlock();
356        lwesp_set_server(0, nc->listen_port, 0, 0, NULL, NULL, NULL, 1);
357        lwesp_core_lock();
358    }
359
360    /* Remove netconn from linkedlist */
361    if (nc == netconn_list) {
362        netconn_list = netconn_list->next;      /* Remove first from linked list */
363    } else if (netconn_list != NULL) {
364        lwesp_netconn_p tmp, prev;
365        /* Find element on the list */
366        for (prev = netconn_list, tmp = netconn_list->next;
367             tmp != NULL; prev = tmp, tmp = tmp->next) {
368            if (nc == tmp) {
369                prev->next = tmp->next;         /* Remove tmp from linked list */
370                break;
371            }
372        }
373    }
374    lwesp_core_unlock();
375
376    lwesp_mem_free_s((void**)&nc);
377    return lwespOK;
378}
379
380/**
381 * \brief           Connect to server as client
382 * \param[in]       nc: Netconn handle
383 * \param[in]       host: Pointer to host, such as domain name or IP address in string format
384 * \param[in]       port: Target port to use
385 * \return          \ref lwespOK if successfully connected, member of \ref lwespr_t otherwise
386 */
387lwespr_t
388lwesp_netconn_connect(lwesp_netconn_p nc, const char* host, lwesp_port_t port) {
389    lwespr_t res;
390
391    LWESP_ASSERT("nc != NULL", nc != NULL);
392    LWESP_ASSERT("host != NULL", host != NULL);
393    LWESP_ASSERT("port > 0", port > 0);
394
395    /*
396     * Start a new connection as client and:
397     *
398     *  - Set current netconn structure as argument
399     *  - Set netconn callback function for connection management
400     *  - Start connection in blocking mode
401     */
402    res = lwesp_conn_start(NULL, (lwesp_conn_type_t)nc->type, host, port, nc, netconn_evt, 1);
403    return res;
404}
405
406/**
407 * \brief           Connect to server as client, allow keep-alive option
408 * \param[in]       nc: Netconn handle
409 * \param[in]       host: Pointer to host, such as domain name or IP address in string format
410 * \param[in]       port: Target port to use
411 * \param[in]       keep_alive: Keep alive period seconds
412 * \param[in]       local_ip: Local ip in connected command
413 * \param[in]       local_port: Local port address
414 * \param[in]       mode: UDP mode
415 * \return          \ref lwespOK if successfully connected, member of \ref lwespr_t otherwise
416 */
417lwespr_t
418lwesp_netconn_connect_ex(lwesp_netconn_p nc, const char* host, lwesp_port_t port,
419                        uint16_t keep_alive, const char* local_ip, lwesp_port_t local_port, uint8_t mode) {
420    lwesp_conn_start_t cs = {0};
421    lwespr_t res;
422
423    LWESP_ASSERT("nc != NULL", nc != NULL);
424    LWESP_ASSERT("host != NULL", host != NULL);
425    LWESP_ASSERT("port > 0", port > 0);
426
427    /*
428     * Start a new connection as client and:
429     *
430     *  - Set current netconn structure as argument
431     *  - Set netconn callback function for connection management
432     *  - Start connection in blocking mode
433     */
434    cs.type = nc->type;
435    cs.remote_host = host;
436    cs.remote_port = port;
437    cs.local_ip = local_ip;
438    if (NETCONN_IS_TCP(nc) || NETCONN_IS_SSL(nc)) {
439        cs.ext.tcp_ssl.keep_alive = keep_alive;
440    } else {
441        cs.ext.udp.local_port = local_port;
442        cs.ext.udp.mode = mode;
443    }
444    res = lwesp_conn_startex(NULL, &cs, nc, netconn_evt, 1);
445    return res;
446}
447
448/**
449 * \brief           Bind a connection to specific port, can be only used for server connections
450 * \param[in]       nc: Netconn handle
451 * \param[in]       port: Port used to bind a connection to
452 * \return          \ref lwespOK on success, member of \ref lwespr_t enumeration otherwise
453 */
454lwespr_t
455lwesp_netconn_bind(lwesp_netconn_p nc, lwesp_port_t port) {
456    lwespr_t res = lwespOK;
457
458    LWESP_ASSERT("nc != NULL", nc != NULL);
459
460    /*
461     * Protection is not needed as it is expected
462     * that this function is called only from single
463     * thread for single netconn connection,
464     * thus it is considered reentrant
465     */
466
467    nc->listen_port = port;
468
469    return res;
470}
471
472/**
473 * \brief           Set timeout value in units of seconds when connection is in listening mode
474 *                  If new connection is accepted, it will be automatically closed after `seconds` elapsed
475 *                  without any data exchange.
476 * \note            Call this function before you put connection to listen mode with \ref lwesp_netconn_listen
477 * \param[in]       nc: Netconn handle used for listen mode
478 * \param[in]       timeout: Time in units of seconds. Set to `0` to disable timeout feature
479 * \return          \ref lwespOK on success, member of \ref lwespr_t otherwise
480 */
481lwespr_t
482lwesp_netconn_set_listen_conn_timeout(lwesp_netconn_p nc, uint16_t timeout) {
483    lwespr_t res = lwespOK;
484    LWESP_ASSERT("nc != NULL", nc != NULL);
485
486    /*
487     * Protection is not needed as it is expected
488     * that this function is called only from single
489     * thread for single netconn connection,
490     * thus it is reentrant in this case
491     */
492
493    nc->conn_timeout = timeout;
494
495    return res;
496}
497
498/**
499 * \brief           Listen on previously binded connection
500 * \param[in]       nc: Netconn handle used to listen for new connections
501 * \return          \ref lwespOK on success, member of \ref lwespr_t enumeration otherwise
502 */
503lwespr_t
504lwesp_netconn_listen(lwesp_netconn_p nc) {
505    return lwesp_netconn_listen_with_max_conn(nc, LWESP_CFG_MAX_CONNS);
506}
507
508/**
509 * \brief           Listen on previously binded connection with max allowed connections at a time
510 * \param[in]       nc: Netconn handle used to listen for new connections
511 * \param[in]       max_connections: Maximal number of connections server can accept at a time
512 *                      This parameter may not be larger than \ref LWESP_CFG_MAX_CONNS
513 * \return          \ref lwespOK on success, member of \ref lwespr_t otherwise
514 */
515lwespr_t
516lwesp_netconn_listen_with_max_conn(lwesp_netconn_p nc, uint16_t max_connections) {
517    lwespr_t res;
518
519    LWESP_ASSERT("nc != NULL", nc != NULL);
520    LWESP_ASSERT("nc->type must be TCP", NETCONN_IS_TCP(nc));
521
522    /* Enable server on port and set default netconn callback */
523    if ((res = lwesp_set_server(1, nc->listen_port,
524                              LWESP_U16(LWESP_MIN(max_connections, LWESP_CFG_MAX_CONNS)),
525                              nc->conn_timeout, netconn_evt, NULL, NULL, 1)) == lwespOK) {
526        lwesp_core_lock();
527        listen_api = nc;                        /* Set current main API in listening state */
528        lwesp_core_unlock();
529    }
530    return res;
531}
532
533/**
534 * \brief           Accept a new connection
535 * \param[in]       nc: Netconn handle used as base connection to accept new clients
536 * \param[out]      client: Pointer to netconn handle to save new connection to
537 * \return          \ref lwespOK on success, member of \ref lwespr_t enumeration otherwise
538 */
539lwespr_t
540lwesp_netconn_accept(lwesp_netconn_p nc, lwesp_netconn_p* client) {
541    lwesp_netconn_t* tmp;
542    uint32_t time;
543
544    LWESP_ASSERT("nc != NULL", nc != NULL);
545    LWESP_ASSERT("client != NULL", client != NULL);
546    LWESP_ASSERT("nc->type must be TCP", NETCONN_IS_TCP(nc));
547    LWESP_ASSERT("nc == listen_api", nc == listen_api);
548
549    *client = NULL;
550    time = lwesp_sys_mbox_get(&nc->mbox_accept, (void**)&tmp, 0);
551    if (time == LWESP_SYS_TIMEOUT) {
552        return lwespTIMEOUT;
553    }
554    if ((uint8_t*)tmp == (uint8_t*)&recv_closed) {
555        lwesp_core_lock();
556        listen_api = NULL;                      /* Disable listening at this point */
557        lwesp_core_unlock();
558        return lwespERRWIFINOTCONNECTED;        /* Wifi disconnected */
559    } else if ((uint8_t*)tmp == (uint8_t*)&recv_not_present) {
560        lwesp_core_lock();
561        listen_api = NULL;                      /* Disable listening at this point */
562        lwesp_core_unlock();
563        return lwespERRNODEVICE;                /* Device not present */
564    }
565    *client = tmp;                              /* Set new pointer */
566    return lwespOK;                             /* We have a new connection */
567}
568
569/**
570 * \brief           Write data to connection output buffers
571 * \note            This function may only be used on TCP or SSL connections
572 * \param[in]       nc: Netconn handle used to write data to
573 * \param[in]       data: Pointer to data to write
574 * \param[in]       btw: Number of bytes to write
575 * \return          \ref lwespOK on success, member of \ref lwespr_t enumeration otherwise
576 */
577lwespr_t
578lwesp_netconn_write(lwesp_netconn_p nc, const void* data, size_t btw) {
579    size_t len, sent;
580    const uint8_t* d = data;
581    lwespr_t res;
582
583    LWESP_ASSERT("nc != NULL", nc != NULL);
584    LWESP_ASSERT("nc->type must be TCP or SSL", NETCONN_IS_TCP(nc) || NETCONN_IS_SSL(nc));
585    LWESP_ASSERT("nc->conn must be active", lwesp_conn_is_active(nc->conn));
586
587    /*
588     * Several steps are done in write process
589     *
590     * 1. Check if buffer is set and check if there is something to write to it.
591     *    1. In case buffer will be full after copy, send it and free memory.
592     * 2. Check how many bytes we can write directly without need to copy
593     * 3. Try to allocate a new buffer and copy remaining input data to it
594     * 4. In case buffer allocation fails, send data directly (may have impact on speed and effectivenes)
595     */
596
597    /* Step 1 */
598    if (nc->buff.buff != NULL) {                /* Is there a write buffer ready to accept more data? */
599        len = LWESP_MIN(nc->buff.len - nc->buff.ptr, btw);  /* Get number of bytes we can write to buffer */
600        if (len > 0) {
601            LWESP_MEMCPY(&nc->buff.buff[nc->buff.ptr], data, len);  /* Copy memory to temporary write buffer */
602            d += len;
603            nc->buff.ptr += len;
604            btw -= len;
605        }
606
607        /* Step 1.1 */
608        if (nc->buff.ptr == nc->buff.len) {
609            res = lwesp_conn_send(nc->conn, nc->buff.buff, nc->buff.len, &sent, 1);
610
611            lwesp_mem_free_s((void**)&nc->buff.buff);
612            if (res != lwespOK) {
613                return res;
614            }
615        } else {
616            return lwespOK;                     /* Buffer is not full yet */
617        }
618    }
619
620    /* Step 2 */
621    if (btw >= LWESP_CFG_CONN_MAX_DATA_LEN) {
622        size_t rem;
623        rem = btw % LWESP_CFG_CONN_MAX_DATA_LEN;/* Get remaining bytes for max data length */
624        res = lwesp_conn_send(nc->conn, d, btw - rem, &sent, 1);/* Write data directly */
625        if (res != lwespOK) {
626            return res;
627        }
628        d += sent;                              /* Advance in data pointer */
629        btw -= sent;                            /* Decrease remaining data to send */
630    }
631
632    if (btw == 0) {                             /* Sent everything? */
633        return lwespOK;
634    }
635
636    /* Step 3 */
637    if (nc->buff.buff == NULL) {                /* Check if we should allocate a new buffer */
638        nc->buff.buff = lwesp_mem_malloc(sizeof(*nc->buff.buff) * LWESP_CFG_CONN_MAX_DATA_LEN);
639        nc->buff.len = LWESP_CFG_CONN_MAX_DATA_LEN; /* Save buffer length */
640        nc->buff.ptr = 0;                       /* Save buffer pointer */
641    }
642
643    /* Step 4 */
644    if (nc->buff.buff != NULL) {                /* Memory available? */
645        LWESP_MEMCPY(&nc->buff.buff[nc->buff.ptr], d, btw); /* Copy data to buffer */
646        nc->buff.ptr += btw;
647    } else {                                    /* Still no memory available? */
648        return lwesp_conn_send(nc->conn, data, btw, NULL, 1);   /* Simply send directly blocking */
649    }
650    return lwespOK;
651}
652
653/**
654 * \brief           Flush buffered data on netconn TCP/SSL connection
655 * \note            This function may only be used on TCP/SSL connection
656 * \param[in]       nc: Netconn handle to flush data
657 * \return          \ref lwespOK on success, member of \ref lwespr_t enumeration otherwise
658 */
659lwespr_t
660lwesp_netconn_flush(lwesp_netconn_p nc) {
661    LWESP_ASSERT("nc != NULL", nc != NULL);
662    LWESP_ASSERT("nc->type must be TCP or SSL", NETCONN_IS_TCP(nc) || NETCONN_IS_SSL(nc));
663    LWESP_ASSERT("nc->conn must be active", lwesp_conn_is_active(nc->conn));
664
665    /*
666     * In case we have data in write buffer,
667     * flush them out to network
668     */
669    if (nc->buff.buff != NULL) {                /* Check remaining data */
670        if (nc->buff.ptr > 0) {                 /* Do we have data in current buffer? */
671            lwesp_conn_send(nc->conn, nc->buff.buff, nc->buff.ptr, NULL, 1);/* Send data */
672        }
673        lwesp_mem_free_s((void**)&nc->buff.buff);
674    }
675    return lwespOK;
676}
677
678/**
679 * \brief           Send data on UDP connection to default IP and port
680 * \param[in]       nc: Netconn handle used to send
681 * \param[in]       data: Pointer to data to write
682 * \param[in]       btw: Number of bytes to write
683 * \return          \ref lwespOK on success, member of \ref lwespr_t enumeration otherwise
684 */
685lwespr_t
686lwesp_netconn_send(lwesp_netconn_p nc, const void* data, size_t btw) {
687    LWESP_ASSERT("nc != NULL", nc != NULL);
688    LWESP_ASSERT("nc->type must be UDP", nc->type == LWESP_NETCONN_TYPE_UDP);
689    LWESP_ASSERT("nc->conn must be active", lwesp_conn_is_active(nc->conn));
690
691    return lwesp_conn_send(nc->conn, data, btw, NULL, 1);
692}
693
694/**
695 * \brief           Send data on UDP connection to specific IP and port
696 * \note            Use this function in case of UDP type netconn
697 * \param[in]       nc: Netconn handle used to send
698 * \param[in]       ip: Pointer to IP address
699 * \param[in]       port: Port number used to send data
700 * \param[in]       data: Pointer to data to write
701 * \param[in]       btw: Number of bytes to write
702 * \return          \ref lwespOK on success, member of \ref lwespr_t enumeration otherwise
703 */
704lwespr_t
705lwesp_netconn_sendto(lwesp_netconn_p nc, const lwesp_ip_t* ip, lwesp_port_t port, const void* data, size_t btw) {
706    LWESP_ASSERT("nc != NULL", nc != NULL);
707    LWESP_ASSERT("nc->type must be UDP", nc->type == LWESP_NETCONN_TYPE_UDP);
708    LWESP_ASSERT("nc->conn must be active", lwesp_conn_is_active(nc->conn));
709
710    return lwesp_conn_sendto(nc->conn, ip, port, data, btw, NULL, 1);
711}
712
713/**
714 * \brief           Receive data from connection
715 * \param[in]       nc: Netconn handle used to receive from
716 * \param[in]       pbuf: Pointer to pointer to save new receive buffer to.
717 *                     When function returns, user must check for valid pbuf value `pbuf != NULL`
718 * \return          \ref lwespOK when new data ready
719 * \return          \ref lwespCLOSED when connection closed by remote side
720 * \return          \ref lwespTIMEOUT when receive timeout occurs
721 * \return          Any other member of \ref lwespr_t otherwise
722 */
723lwespr_t
724lwesp_netconn_receive(lwesp_netconn_p nc, lwesp_pbuf_p* pbuf) {
725    LWESP_ASSERT("nc != NULL", nc != NULL);
726    LWESP_ASSERT("pbuf != NULL", pbuf != NULL);
727
728    *pbuf = NULL;
729#if LWESP_CFG_NETCONN_RECEIVE_TIMEOUT
730    /*
731     * Wait for new received data for up to specific timeout
732     * or throw error for timeout notification
733     */
734    if (nc->rcv_timeout == LWESP_NETCONN_RECEIVE_NO_WAIT) {
735        if (!lwesp_sys_mbox_getnow(&nc->mbox_receive, (void**)pbuf)) {
736            return lwespTIMEOUT;
737        }
738    } else if (lwesp_sys_mbox_get(&nc->mbox_receive, (void**)pbuf, nc->rcv_timeout) == LWESP_SYS_TIMEOUT) {
739        return lwespTIMEOUT;
740    }
741#else /* LWESP_CFG_NETCONN_RECEIVE_TIMEOUT */
742    /* Forever wait for new receive packet */
743    lwesp_sys_mbox_get(&nc->mbox_receive, (void**)pbuf, 0);
744#endif /* !LWESP_CFG_NETCONN_RECEIVE_TIMEOUT */
745
746    lwesp_core_lock();
747    if (nc->mbox_receive_entries > 0) {
748        --nc->mbox_receive_entries;
749    }
750    lwesp_core_unlock();
751
752    /* Check if connection closed */
753    if ((uint8_t*)(*pbuf) == (uint8_t*)&recv_closed) {
754        *pbuf = NULL;                           /* Reset pbuf */
755        return lwespCLOSED;
756    }
757#if LWESP_CFG_CONN_MANUAL_TCP_RECEIVE
758    else {
759        lwesp_core_lock();
760        nc->conn->status.f.receive_blocked = 0; /* Resume reading more data */
761        lwesp_conn_recved(nc->conn, *pbuf);     /* Notify stack about received data */
762        lwesp_core_unlock();
763    }
764#endif /* LWESP_CFG_CONN_MANUAL_TCP_RECEIVE */
765    return lwespOK;                             /* We have data available */
766}
767
768/**
769 * \brief           Close a netconn connection
770 * \param[in]       nc: Netconn handle to close
771 * \return          \ref lwespOK on success, member of \ref lwespr_t enumeration otherwise
772 */
773lwespr_t
774lwesp_netconn_close(lwesp_netconn_p nc) {
775    lwesp_conn_p conn;
776
777    LWESP_ASSERT("nc != NULL", nc != NULL);
778    LWESP_ASSERT("nc->conn != NULL", nc->conn != NULL);
779    LWESP_ASSERT("nc->conn must be active", lwesp_conn_is_active(nc->conn));
780
781    lwesp_netconn_flush(nc);                    /* Flush data and ignore result */
782    conn = nc->conn;
783    nc->conn = NULL;
784
785    lwesp_conn_set_arg(conn, NULL);             /* Reset argument */
786    lwesp_conn_close(conn, 1);                  /* Close the connection */
787    flush_mboxes(nc, 1);                        /* Flush message queues */
788    return lwespOK;
789}
790
791/**
792 * \brief           Get connection number used for netconn
793 * \param[in]       nc: Netconn handle
794 * \return          `-1` on failure, connection number between `0` and \ref LWESP_CFG_MAX_CONNS otherwise
795 */
796int8_t
797lwesp_netconn_get_connnum(lwesp_netconn_p nc) {
798    if (nc != NULL && nc->conn != NULL) {
799        return lwesp_conn_getnum(nc->conn);
800    }
801    return -1;
802}
803
804#if LWESP_CFG_NETCONN_RECEIVE_TIMEOUT || __DOXYGEN__
805
806/**
807 * \brief           Set timeout value for receiving data.
808 *
809 * When enabled, \ref lwesp_netconn_receive will only block for up to
810 * `timeout` value and will return if no new data within this time
811 *
812 * \param[in]       nc: Netconn handle
813 * \param[in]       timeout: Timeout in units of milliseconds.
814 *                      Set to `0` to disable timeout feature
815 *                      Set to `> 0` to set maximum milliseconds to wait before timeout
816 *                      Set to \ref LWESP_NETCONN_RECEIVE_NO_WAIT to enable non-blocking receive
817 */
818void
819lwesp_netconn_set_receive_timeout(lwesp_netconn_p nc, uint32_t timeout) {
820    nc->rcv_timeout = timeout;
821}
822
823/**
824 * \brief           Get netconn receive timeout value
825 * \param[in]       nc: Netconn handle
826 * \return          Timeout in units of milliseconds.
827 *                  If value is `0`, timeout is disabled (wait forever)
828 */
829uint32_t
830lwesp_netconn_get_receive_timeout(lwesp_netconn_p nc) {
831    return nc->rcv_timeout;
832}
833
834#endif /* LWESP_CFG_NETCONN_RECEIVE_TIMEOUT || __DOXYGEN__ */
835
836/**
837 * \brief           Get netconn connection handle
838 * \param[in]       nc: Netconn handle
839 * \return          ESP connection handle
840 */
841lwesp_conn_p
842lwesp_netconn_get_conn(lwesp_netconn_p nc) {
843    return nc->conn;
844}
845
846/**
847 * \brief           Get netconn connection type
848 * \param[in]       nc: Netconn handle
849 * \return          ESP connection type
850 */
851lwesp_netconn_type_t
852lwesp_netconn_get_type(lwesp_netconn_p nc) {
853    return nc->type;
854}
855
856#endif /* LWESP_CFG_NETCONN || __DOXYGEN__ */
Connection specific event

This events are subset of global event callback. They work exactly the same way as global, but only receive events related to connections.

Tip

Connection related events start with LWESP_EVT_CONN_*, such as LWESP_EVT_CONN_RECV. Check Event management for list of all connection events.

Connection events callback function is set for 2 cases:

  • Each client (when application starts connection) sets event callback function when trying to connect with lwesp_conn_start() function

  • Application sets global event callback function when enabling server mode with lwesp_set_server() function

An example of client with its dedicated event callback function
  1#include "client.h"
  2#include "lwesp/lwesp.h"
  3
  4/* Host parameter */
  5#define CONN_HOST           "example.com"
  6#define CONN_PORT           80
  7
  8static lwespr_t   conn_callback_func(lwesp_evt_t* evt);
  9
 10/**
 11 * \brief           Request data for connection
 12 */
 13static const
 14uint8_t req_data[] = ""
 15                     "GET / HTTP/1.1\r\n"
 16                     "Host: " CONN_HOST "\r\n"
 17                     "Connection: close\r\n"
 18                     "\r\n";
 19
 20/**
 21 * \brief           Start a new connection(s) as client
 22 */
 23void
 24client_connect(void) {
 25    lwespr_t res;
 26
 27    /* Start a new connection as client in non-blocking mode */
 28    if ((res = lwesp_conn_start(NULL, LWESP_CONN_TYPE_TCP, "example.com", 80, NULL, conn_callback_func, 0)) == lwespOK) {
 29        printf("Connection to " CONN_HOST " started...\r\n");
 30    } else {
 31        printf("Cannot start connection to " CONN_HOST "!\r\n");
 32    }
 33
 34    /* Start 2 more */
 35    lwesp_conn_start(NULL, LWESP_CONN_TYPE_TCP, CONN_HOST, CONN_PORT, NULL, conn_callback_func, 0);
 36
 37    /*
 38     * An example of connection which should fail in connecting.
 39     * When this is the case, \ref LWESP_EVT_CONN_ERROR event should be triggered
 40     * in callback function processing
 41     */
 42    lwesp_conn_start(NULL, LWESP_CONN_TYPE_TCP, CONN_HOST, 10, NULL, conn_callback_func, 0);
 43}
 44
 45/**
 46 * \brief           Event callback function for connection-only
 47 * \param[in]       evt: Event information with data
 48 * \return          \ref lwespOK on success, member of \ref lwespr_t otherwise
 49 */
 50static lwespr_t
 51conn_callback_func(lwesp_evt_t* evt) {
 52    lwesp_conn_p conn;
 53    lwespr_t res;
 54    uint8_t conn_num;
 55
 56    conn = lwesp_conn_get_from_evt(evt);          /* Get connection handle from event */
 57    if (conn == NULL) {
 58        return lwespERR;
 59    }
 60    conn_num = lwesp_conn_getnum(conn);           /* Get connection number for identification */
 61    switch (lwesp_evt_get_type(evt)) {
 62        case LWESP_EVT_CONN_ACTIVE: {             /* Connection just active */
 63            printf("Connection %d active!\r\n", (int)conn_num);
 64            res = lwesp_conn_send(conn, req_data, sizeof(req_data) - 1, NULL, 0); /* Start sending data in non-blocking mode */
 65            if (res == lwespOK) {
 66                printf("Sending request data to server...\r\n");
 67            } else {
 68                printf("Cannot send request data to server. Closing connection manually...\r\n");
 69                lwesp_conn_close(conn, 0);        /* Close the connection */
 70            }
 71            break;
 72        }
 73        case LWESP_EVT_CONN_CLOSE: {              /* Connection closed */
 74            if (lwesp_evt_conn_close_is_forced(evt)) {
 75                printf("Connection %d closed by client!\r\n", (int)conn_num);
 76            } else {
 77                printf("Connection %d closed by remote side!\r\n", (int)conn_num);
 78            }
 79            break;
 80        }
 81        case LWESP_EVT_CONN_SEND: {               /* Data send event */
 82            lwespr_t res = lwesp_evt_conn_send_get_result(evt);
 83            if (res == lwespOK) {
 84                printf("Data sent successfully on connection %d...waiting to receive data from remote side...\r\n", (int)conn_num);
 85            } else {
 86                printf("Error while sending data on connection %d!\r\n", (int)conn_num);
 87            }
 88            break;
 89        }
 90        case LWESP_EVT_CONN_RECV: {               /* Data received from remote side */
 91            lwesp_pbuf_p pbuf = lwesp_evt_conn_recv_get_buff(evt);
 92            lwesp_conn_recved(conn, pbuf);        /* Notify stack about received pbuf */
 93            printf("Received %d bytes on connection %d..\r\n", (int)lwesp_pbuf_length(pbuf, 1), (int)conn_num);
 94            break;
 95        }
 96        case LWESP_EVT_CONN_ERROR: {              /* Error connecting to server */
 97            const char* host = lwesp_evt_conn_error_get_host(evt);
 98            lwesp_port_t port = lwesp_evt_conn_error_get_port(evt);
 99            printf("Error connecting to %s:%d\r\n", host, (int)port);
100            break;
101        }
102        default:
103            break;
104    }
105    return lwespOK;
106}
API call event

API function call event function is special type of event and is linked to command execution. It is especially useful when dealing with non-blocking commands to understand when specific command execution finished and when next operation could start.

Every API function, which directly operates with AT command on physical device layer, has optional 2 parameters for API call event:

  • Callback function, called when command finished

  • Custom user parameter for callback function

Below is an example code for DNS resolver. It uses custom API callback function with custom argument, used to distinguis domain name (when multiple domains are to be resolved).

Simple example for API call event, using DNS module
 1#include "dns.h"
 2#include "lwesp/lwesp.h"
 3
 4/* Host to resolve */
 5#define DNS_HOST1           "example.com"
 6#define DNS_HOST2           "example.net"
 7
 8/**
 9 * \brief           Variable to hold result of DNS resolver
10 */
11static lwesp_ip_t ip;
12
13/**
14 * \brief           Function to print actual resolved IP address
15 */
16static void
17prv_print_ip(void) {
18    if (0) {
19#if LWESP_CFG_IPV6
20    } else if (ip.type == LWESP_IPTYPE_V6) {
21        printf("IPv6: %04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X\r\n",
22            (unsigned)ip.addr.ip6.addr[0], (unsigned)ip.addr.ip6.addr[1], (unsigned)ip.addr.ip6.addr[2],
23            (unsigned)ip.addr.ip6.addr[3], (unsigned)ip.addr.ip6.addr[4], (unsigned)ip.addr.ip6.addr[5],
24            (unsigned)ip.addr.ip6.addr[6], (unsigned)ip.addr.ip6.addr[7]);
25#endif /* LWESP_CFG_IPV6 */
26    } else {
27        printf("IPv4: %d.%d.%d.%d\r\n",
28            (int)ip.addr.ip4.addr[0], (int)ip.addr.ip4.addr[1], (int)ip.addr.ip4.addr[2], (int)ip.addr.ip4.addr[3]);
29    }
30}
31
32/**
33 * \brief           Event callback function for API call,
34 *                  called when API command finished with execution
35 */
36static void
37prv_dns_resolve_evt(lwespr_t res, void* arg) {
38    /* Check result of command */
39    if (res == lwespOK) {
40        /* Print actual resolved IP */
41        prv_print_ip();
42    }
43}
44
45/**
46 * \brief           Start DNS resolver
47 */
48void
49dns_start(void) {
50    /* Use DNS protocol to get IP address of domain name */
51
52    /* Get IP with non-blocking mode */
53    if (lwesp_dns_gethostbyname(DNS_HOST2, &ip, prv_dns_resolve_evt, DNS_HOST2, 0) == lwespOK) {
54        printf("Request for DNS record for " DNS_HOST2 " has started\r\n");
55    } else {
56        printf("Could not start command for DNS\r\n");
57    }
58
59    /* Get IP with blocking mode */
60    if (lwesp_dns_gethostbyname(DNS_HOST1, &ip, prv_dns_resolve_evt, DNS_HOST1, 1) == lwespOK) {
61        /* Print actual resolved IP */
62        prv_print_ip();
63    } else {
64        printf("Could not retrieve IP address for " DNS_HOST1 "\r\n");
65    }
66}

Blocking or non-blocking API calls

API functions often allow application to set blocking parameter indicating if function shall be blocking or non-blocking.

Blocking mode

When the function is called in blocking mode blocking = 1, application thread gets suspended until response from ESP device is received. If there is a queue of multiple commands, thread may wait a while before receiving data.

When API function returns, application has valid response data and can react immediately.

  • Linear programming model may be used

  • Application may use multiple threads for real-time execution to prevent system stalling when running function call

Warning

Due to internal architecture, it is not allowed to call API functions in blocking mode from events or callbacks. Any attempt to do so will result in function returning error.

Example code:

Blocking command example
 1char hostname[20];
 2
 3/* Somewhere in thread function */
 4
 5/* Get device hostname in blocking mode */
 6/* Function returns actual result */
 7if (lwesp_hostname_get(hostname, sizeof(hostname), NULL, NULL, 1 /* 1 means blocking call */) == lwespOK) {
 8    /* At this point we have valid result and parameters from API function */
 9    printf("ESP hostname is %s\r\n", hostname);
10} else {
11    printf("Error reading ESP hostname..\r\n");
12}
Non-blocking mode

If the API function is called in non-blocking mode, function will return immediately with status indicating if command request has been successfully sent to internal command queue. Response has to be processed in event callback function.

Warning

Due to internal architecture, it is only allowed to call API functions in non-blocking mode from events or callbacks. Any attempt not to do so will result in function returning error.

Example code:

Non-blocking command example
 1char hostname[20];
 2
 3/* Hostname event function, called when lwesp_hostname_get() function finishes */
 4void
 5hostname_fn(lwespr_t res, void* arg) {
 6    /* Check actual result from device */
 7    if (res == lwespOK) {
 8        printf("ESP hostname is %s\r\n", hostname);
 9    } else {
10        printf("Error reading ESP hostname...\r\n");
11    }
12}
13
14/* Somewhere in thread and/or other ESP event function */
15
16/* Get device hostname in non-blocking mode */
17/* Function now returns if command has been sent to internal message queue */
18if (lwesp_hostname_get(hostname, sizeof(hostname), hostname_fn, NULL, 0 /* 0 means non-blocking call */) == lwespOK) {
19    /* At this point application knows that command has been sent to queue */
20    /* But it does not have yet valid data in "hostname" variable */
21    printf("ESP hostname get command sent to queue.\r\n");
22} else {
23    /* Error writing message to queue */
24    printf("Cannot send hostname get command to queue.\r\n");
25}

Warning

When using non-blocking API calls, do not use local variables as parameter. This may introduce undefined behavior and memory corruption if application function returns before command is executed.

Example of a bad code:

Example of bad usage of non-blocking command
 1char hostname[20];
 2
 3/* Hostname event function, called when lwesp_hostname_get() function finishes */
 4void
 5hostname_fn(lwespr_t res, void* arg) {
 6    /* Check actual result from device */
 7    if (res == lwespOK) {
 8        printf("ESP hostname is %s\r\n", hostname);
 9    } else {
10        printf("Error reading ESP hostname...\r\n");
11    }
12}
13
14/* Check hostname */
15void
16check_hostname(void) {
17    char hostname[20];
18
19    /* Somewhere in thread and/or other ESP event function */
20
21    /* Get device hostname in non-blocking mode */
22    /* Function now returns if command has been sent to internal message queue */
23    /* Function will use local "hostname" variable and will write to undefined memory */
24    if (lwesp_hostname_get(hostname, sizeof(hostname), hostname_fn, NULL, 0 /* 0 means non-blocking call */) == lwespOK) {
25        /* At this point application knows that command has been sent to queue */
26        /* But it does not have yet valid data in "hostname" variable */
27        printf("ESP hostname get command sent to queue.\r\n");
28    } else {
29        /* Error writing message to queue */
30        printf("Cannot send hostname get command to queue.\r\n");
31    }
32}

Porting guide

High level of ESP-AT library is platform independent, written in ANSI C99, however there is an important part where middleware needs to communicate with target ESP device and it must work under different optional operating systems selected by final customer.

Porting consists of:

  • Implementation of low-level part, for actual communication between host device and ESP device

  • Implementation of system functions, link between target operating system and middleware functions

  • Assignment of memory for allocation manager

Implement low-level driver

To successfully prepare all parts of low-level driver, application must take care of:

  • Implementing lwesp_ll_init() and lwesp_ll_deinit() callback functions

  • Implement and assign send data and optional hardware reset function callbacks

  • Assign memory for allocation manager when using default allocator or use custom allocator

  • Process received data from ESP device and send it to input module for further processing

Tip

Port examples are available for STM32 and WIN32 architectures. Both actual working and up-to-date implementations are available within the library.

Note

Check Input module for more information about direct & indirect input processing.

Implement system functions

System functions are bridge between operating system calls and ESP middleware. ESP library relies on stable operating system features and its implementation and does not require any special features which do not normally come with operating systems.

Operating system must support:

  • Thread management functions

  • Mutex management functions

  • Binary semaphores only, no need for counting semaphores

  • Message queue management functions

Warning

If any of the features are not available within targeted operating system, customer needs to resolve it with care. As an example, message queue is not available in WIN32 OS API therefore custom message queue has been implemented using binary semaphores

Application needs to implement all system call functions, starting with lwesp_sys_. It must also prepare header file for standard types in order to support OS types within ESP middleware.

An example code is provided latter section of this page for WIN32 and STM32.

Steps to follow
  • Copy lwesp/src/system/lwesp_sys_template.c to the same folder and rename it to application port, eg. lwesp_sys_win32.c

  • Open newly created file and implement all system functions

  • Copy folder lwesp/src/include/system/port/template/* to the same folder and rename folder name to application port, eg. cmsis_os

  • Open lwesp_sys_port.h file from newly created folder and implement all typedefs and macros for specific target

  • Add source file to compiler sources and add path to header file to include paths in compiler options

Note

Check System functions for function prototypes.

Example: Low-level driver for WIN32

Example code for low-level porting on WIN32 platform. It uses native Windows features to open COM port and read/write from/to it.

Notes:

  • It uses separate thread for received data processing. It uses lwesp_input_process() or lwesp_input() functions, based on application configuration of LWESP_CFG_INPUT_USE_PROCESS parameter.

    • When LWESP_CFG_INPUT_USE_PROCESS is disabled, dedicated receive buffer is created by ESP-AT library and lwesp_input() function just writes data to it and does not process received characters immediately. This is handled by Processing thread at later stage instead.

    • When LWESP_CFG_INPUT_USE_PROCESS is enabled, lwesp_input_process() is used, which directly processes input data and sends potential callback/event functions to application layer.

  • Memory manager has been assigned to 1 region of LWESP_MEM_SIZE size

  • It sets send and reset callback functions for ESP-AT library

Actual implementation of low-level driver for WIN32
  1/**
  2 * \file            lwesp_ll_win32.c
  3 * \brief           Low-level communication with ESP device for WIN32
  4 */
  5
  6/*
  7 * Copyright (c) 2020 Tilen MAJERLE
  8 *
  9 * Permission is hereby granted, free of charge, to any person
 10 * obtaining a copy of this software and associated documentation
 11 * files (the "Software"), to deal in the Software without restriction,
 12 * including without limitation the rights to use, copy, modify, merge,
 13 * publish, distribute, sublicense, and/or sell copies of the Software,
 14 * and to permit persons to whom the Software is furnished to do so,
 15 * subject to the following conditions:
 16 *
 17 * The above copyright notice and this permission notice shall be
 18 * included in all copies or substantial portions of the Software.
 19 *
 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 23 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 27 * OTHER DEALINGS IN THE SOFTWARE.
 28 *
 29 * This file is part of LwESP - Lightweight ESP-AT parser library.
 30 *
 31 * Author:          Tilen MAJERLE <tilen@majerle.eu>
 32 * Version:         v1.1.2-dev
 33 */
 34#include "system/lwesp_ll.h"
 35#include "lwesp/lwesp.h"
 36#include "lwesp/lwesp_mem.h"
 37#include "lwesp/lwesp_input.h"
 38
 39#if !__DOXYGEN__
 40
 41volatile uint8_t lwesp_ll_win32_driver_ignore_data;
 42static uint8_t initialized = 0;
 43static HANDLE thread_handle;
 44static volatile HANDLE com_port;                /*!< COM port handle */
 45static uint8_t data_buffer[0x1000];             /*!< Received data array */
 46
 47static void uart_thread(void* param);
 48
 49/**
 50 * \brief           Send data to ESP device, function called from ESP stack when we have data to send
 51 */
 52static size_t
 53send_data(const void* data, size_t len) {
 54    DWORD written;
 55    if (com_port != NULL) {
 56#if !LWESP_CFG_AT_ECHO
 57        const uint8_t* d = data;
 58        HANDLE hConsole;
 59
 60        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
 61        SetConsoleTextAttribute(hConsole, FOREGROUND_RED);
 62        for (DWORD i = 0; i < len; ++i) {
 63            printf("%c", d[i]);
 64        }
 65        SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
 66#endif /* !LWESP_CFG_AT_ECHO */
 67
 68        WriteFile(com_port, data, len, &written, NULL);
 69        FlushFileBuffers(com_port);
 70        return written;
 71    }
 72    return 0;
 73}
 74
 75/**
 76 * \brief           Configure UART (USB to UART)
 77 */
 78static uint8_t
 79configure_uart(uint32_t baudrate) {
 80    DCB dcb = { 0 };
 81    dcb.DCBlength = sizeof(dcb);
 82    size_t i;
 83
 84    /* List of COM ports to probe */
 85    static const char* com_port_names[] = {
 86        "\\\\.\\COM16",
 87        "\\\\.\\COM4"
 88    };
 89
 90    /* TODO: Needs proper work to run for loop only if not initialized */
 91
 92    for (i = 0; i < LWESP_ARRAYSIZE(com_port_names); ++i) {
 93        /*
 94         * On first call,
 95         * create virtual file on selected COM port and open it
 96         * as generic read and write
 97         */
 98        if (!initialized) {
 99            printf("Probing COM port %s\r\n", com_port_names[i]);
100            com_port = CreateFileA(com_port_names[i], GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, NULL);
101        }
102
103        /* Configure COM port parameters */
104        if (GetCommState(com_port, &dcb)) {
105            COMMTIMEOUTS timeouts;
106
107            dcb.BaudRate = baudrate;
108            dcb.ByteSize = 8;
109            dcb.Parity = NOPARITY;
110            dcb.StopBits = ONESTOPBIT;
111
112            if (!SetCommState(com_port, &dcb)) {
113                printf("Cannot set COM PORT info for port: %s\r\n", com_port_names[i]);
114                continue;
115            }
116            if (GetCommTimeouts(com_port, &timeouts)) {
117                /* Set timeout to return immediately from ReadFile function */
118                timeouts.ReadIntervalTimeout = MAXDWORD;
119                timeouts.ReadTotalTimeoutConstant = 0;
120                timeouts.ReadTotalTimeoutMultiplier = 0;
121                if (!SetCommTimeouts(com_port, &timeouts)) {
122                    printf("Cannot set COM PORT timeouts: %s\r\n", com_port_names[i]);
123                }
124                GetCommTimeouts(com_port, &timeouts);
125                break;
126            } else {
127                printf("Cannot get COM PORT timeouts: %s\r\n", com_port_names[i]);
128            }
129        } else {
130            printf("Cannot get COM PORT info: %s\r\n", com_port_names[i]);
131        }
132    }
133    if (i == LWESP_ARRAYSIZE(com_port_names)) {
134        printf("Failed to open any COM port\r\n");
135        return 0;
136    }
137
138    /* On first function call, create a thread to read data from COM port */
139    if (!initialized) {
140        lwesp_sys_thread_create(&thread_handle, "lwesp_ll_thread", uart_thread, NULL, 0, 0);
141    }
142    return 1;
143}
144
145/**
146 * \brief           UART thread
147 */
148static void
149uart_thread(void* param) {
150    DWORD bytes_read;
151    lwesp_sys_sem_t sem;
152    FILE* file = NULL;
153
154    lwesp_sys_sem_create(&sem, 0);              /* Create semaphore for delay functions */
155
156    while (com_port == NULL) {
157        lwesp_sys_sem_wait(&sem, 1);            /* Add some delay with yield */
158    }
159
160    fopen_s(&file, "log_file.txt", "w+");       /* Open debug file in write mode */
161    while (1) {
162        /*
163         * Try to read data from COM port
164         * and send it to upper layer for processing
165         */
166        do {
167            ReadFile(com_port, data_buffer, sizeof(data_buffer), &bytes_read, NULL);
168            if (bytes_read > 0) {
169                HANDLE hConsole;
170                hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
171                SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN);
172                for (DWORD i = 0; i < bytes_read; ++i) {
173                    printf("%c", data_buffer[i]);
174                }
175                SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
176
177                if (lwesp_ll_win32_driver_ignore_data) {
178                    printf("IGNORING..\r\n");
179                    continue;
180                }
181
182                /* Send received data to input processing module */
183#if LWESP_CFG_INPUT_USE_PROCESS
184                lwesp_input_process(data_buffer, (size_t)bytes_read);
185#else /* LWESP_CFG_INPUT_USE_PROCESS */
186                lwesp_input(data_buffer, (size_t)bytes_read);
187#endif /* !LWESP_CFG_INPUT_USE_PROCESS */
188
189                /* Write received data to output debug file */
190                if (file != NULL) {
191                    fwrite(data_buffer, 1, bytes_read, file);
192                    fflush(file);
193                }
194            }
195        } while (bytes_read == (DWORD)sizeof(data_buffer));
196
197        /* Implement delay to allow other tasks processing */
198        lwesp_sys_sem_wait(&sem, 1);
199    }
200}
201
202/**
203 * \brief           Reset device GPIO management
204 */
205static uint8_t
206reset_device(uint8_t state) {
207    return 0;                                   /* Hardware reset was not successful */
208}
209
210/**
211 * \brief           Callback function called from initialization process
212 */
213lwespr_t
214lwesp_ll_init(lwesp_ll_t* ll) {
215#if !LWESP_CFG_MEM_CUSTOM
216    /* Step 1: Configure memory for dynamic allocations */
217    static uint8_t memory[0x10000];             /* Create memory for dynamic allocations with specific size */
218
219    /*
220     * Create memory region(s) of memory.
221     * If device has internal/external memory available,
222     * multiple memories may be used
223     */
224    lwesp_mem_region_t mem_regions[] = {
225        { memory, sizeof(memory) }
226    };
227    if (!initialized) {
228        lwesp_mem_assignmemory(mem_regions, LWESP_ARRAYSIZE(mem_regions));  /* Assign memory for allocations to ESP library */
229    }
230#endif /* !LWESP_CFG_MEM_CUSTOM */
231
232    /* Step 2: Set AT port send function to use when we have data to transmit */
233    if (!initialized) {
234        ll->send_fn = send_data;                /* Set callback function to send data */
235        ll->reset_fn = reset_device;
236    }
237
238    /* Step 3: Configure AT port to be able to send/receive data to/from ESP device */
239    if (!configure_uart(ll->uart.baudrate)) {   /* Initialize UART for communication */
240        return lwespERR;
241    }
242    initialized = 1;
243    return lwespOK;
244}
245
246/**
247 * \brief           Callback function to de-init low-level communication part
248 */
249lwespr_t
250lwesp_ll_deinit(lwesp_ll_t* ll) {
251    if (thread_handle != NULL) {
252        lwesp_sys_thread_terminate(&thread_handle);
253        thread_handle = NULL;
254    }
255    initialized = 0;                            /* Clear initialized flag */
256    return lwespOK;
257}
258
259#endif /* !__DOXYGEN__ */
Example: Low-level driver for STM32

Example code for low-level porting on STM32 platform. It uses CMSIS-OS based application layer functions for implementing threads & other OS dependent features.

Notes:

  • It uses separate thread for received data processing. It uses lwesp_input_process() function to directly process received data without using intermediate receive buffer

  • Memory manager has been assigned to 1 region of LWESP_MEM_SIZE size

  • It sets send and reset callback functions for ESP-AT library

Actual implementation of low-level driver for STM32
  1/**
  2 * \file            lwesp_ll_stm32.c
  3 * \brief           Generic STM32 driver, included in various STM32 driver variants
  4 */
  5
  6/*
  7 * Copyright (c) 2020 Tilen MAJERLE
  8 *
  9 * Permission is hereby granted, free of charge, to any person
 10 * obtaining a copy of this software and associated documentation
 11 * files (the "Software"), to deal in the Software without restriction,
 12 * including without limitation the rights to use, copy, modify, merge,
 13 * publish, distribute, sublicense, and/or sell copies of the Software,
 14 * and to permit persons to whom the Software is furnished to do so,
 15 * subject to the following conditions:
 16 *
 17 * The above copyright notice and this permission notice shall be
 18 * included in all copies or substantial portions of the Software.
 19 *
 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 23 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 27 * OTHER DEALINGS IN THE SOFTWARE.
 28 *
 29 * This file is part of LwESP - Lightweight ESP-AT parser library.
 30 *
 31 * Author:          Tilen MAJERLE <tilen@majerle.eu>
 32 * Version:         v1.1.2-dev
 33 */
 34
 35/*
 36 * How it works
 37 *
 38 * On first call to \ref lwesp_ll_init, new thread is created and processed in usart_ll_thread function.
 39 * USART is configured in RX DMA mode and any incoming bytes are processed inside thread function.
 40 * DMA and USART implement interrupt handlers to notify main thread about new data ready to send to upper layer.
 41 *
 42 * More about UART + RX DMA: https://github.com/MaJerle/stm32-usart-dma-rx-tx
 43 *
 44 * \ref LWESP_CFG_INPUT_USE_PROCESS must be enabled in `lwesp_config.h` to use this driver.
 45 */
 46#include "lwesp/lwesp.h"
 47#include "lwesp/lwesp_mem.h"
 48#include "lwesp/lwesp_input.h"
 49#include "system/lwesp_ll.h"
 50
 51#if !__DOXYGEN__
 52
 53#if !LWESP_CFG_INPUT_USE_PROCESS
 54#error "LWESP_CFG_INPUT_USE_PROCESS must be enabled in `lwesp_config.h` to use this driver."
 55#endif /* LWESP_CFG_INPUT_USE_PROCESS */
 56
 57#if !defined(LWESP_USART_DMA_RX_BUFF_SIZE)
 58#define LWESP_USART_DMA_RX_BUFF_SIZE      0x1000
 59#endif /* !defined(LWESP_USART_DMA_RX_BUFF_SIZE) */
 60
 61#if !defined(LWESP_MEM_SIZE)
 62#define LWESP_MEM_SIZE                    0x1000
 63#endif /* !defined(LWESP_MEM_SIZE) */
 64
 65#if !defined(LWESP_USART_RDR_NAME)
 66#define LWESP_USART_RDR_NAME              RDR
 67#endif /* !defined(LWESP_USART_RDR_NAME) */
 68
 69/* USART memory */
 70static uint8_t      usart_mem[LWESP_USART_DMA_RX_BUFF_SIZE];
 71static uint8_t      is_running, initialized;
 72static size_t       old_pos;
 73
 74/* USART thread */
 75static void usart_ll_thread(void* arg);
 76static osThreadId_t usart_ll_thread_id;
 77
 78/* Message queue */
 79static osMessageQueueId_t usart_ll_mbox_id;
 80
 81/**
 82 * \brief           USART data processing
 83 */
 84static void
 85usart_ll_thread(void* arg) {
 86    size_t pos;
 87
 88    LWESP_UNUSED(arg);
 89
 90    while (1) {
 91        void* d;
 92        /* Wait for the event message from DMA or USART */
 93        osMessageQueueGet(usart_ll_mbox_id, &d, NULL, osWaitForever);
 94
 95        /* Read data */
 96#if defined(LWESP_USART_DMA_RX_STREAM)
 97        pos = sizeof(usart_mem) - LL_DMA_GetDataLength(LWESP_USART_DMA, LWESP_USART_DMA_RX_STREAM);
 98#else
 99        pos = sizeof(usart_mem) - LL_DMA_GetDataLength(LWESP_USART_DMA, LWESP_USART_DMA_RX_CH);
100#endif /* defined(LWESP_USART_DMA_RX_STREAM) */
101        if (pos != old_pos && is_running) {
102            if (pos > old_pos) {
103                lwesp_input_process(&usart_mem[old_pos], pos - old_pos);
104            } else {
105                lwesp_input_process(&usart_mem[old_pos], sizeof(usart_mem) - old_pos);
106                if (pos > 0) {
107                    lwesp_input_process(&usart_mem[0], pos);
108                }
109            }
110            old_pos = pos;
111            if (old_pos == sizeof(usart_mem)) {
112                old_pos = 0;
113            }
114        }
115    }
116}
117
118/**
119 * \brief           Configure UART using DMA for receive in double buffer mode and IDLE line detection
120 */
121static void
122configure_uart(uint32_t baudrate) {
123    static LL_USART_InitTypeDef usart_init;
124    static LL_DMA_InitTypeDef dma_init;
125    LL_GPIO_InitTypeDef gpio_init;
126
127    if (!initialized) {
128        /* Enable peripheral clocks */
129        LWESP_USART_CLK;
130        LWESP_USART_DMA_CLK;
131        LWESP_USART_TX_PORT_CLK;
132        LWESP_USART_RX_PORT_CLK;
133
134#if defined(LWESP_RESET_PIN)
135        LWESP_RESET_PORT_CLK;
136#endif /* defined(LWESP_RESET_PIN) */
137
138#if defined(LWESP_GPIO0_PIN)
139        LWESP_GPIO0_PORT_CLK;
140#endif /* defined(LWESP_GPIO0_PIN) */
141
142#if defined(LWESP_GPIO2_PIN)
143        LWESP_GPIO2_PORT_CLK;
144#endif /* defined(LWESP_GPIO2_PIN) */
145
146#if defined(LWESP_CH_PD_PIN)
147        LWESP_CH_PD_PORT_CLK;
148#endif /* defined(LWESP_CH_PD_PIN) */
149
150        /* Global pin configuration */
151        LL_GPIO_StructInit(&gpio_init);
152        gpio_init.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
153        gpio_init.Pull = LL_GPIO_PULL_UP;
154        gpio_init.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
155        gpio_init.Mode = LL_GPIO_MODE_OUTPUT;
156
157#if defined(LWESP_RESET_PIN)
158        /* Configure RESET pin */
159        gpio_init.Pin = LWESP_RESET_PIN;
160        LL_GPIO_Init(LWESP_RESET_PORT, &gpio_init);
161#endif /* defined(LWESP_RESET_PIN) */
162
163#if defined(LWESP_GPIO0_PIN)
164        /* Configure GPIO0 pin */
165        gpio_init.Pin = LWESP_GPIO0_PIN;
166        LL_GPIO_Init(LWESP_GPIO0_PORT, &gpio_init);
167        LL_GPIO_SetOutputPin(LWESP_GPIO0_PORT, LWESP_GPIO0_PIN);
168#endif /* defined(LWESP_GPIO0_PIN) */
169
170#if defined(LWESP_GPIO2_PIN)
171        /* Configure GPIO2 pin */
172        gpio_init.Pin = LWESP_GPIO2_PIN;
173        LL_GPIO_Init(LWESP_GPIO2_PORT, &gpio_init);
174        LL_GPIO_SetOutputPin(LWESP_GPIO2_PORT, LWESP_GPIO2_PIN);
175#endif /* defined(LWESP_GPIO2_PIN) */
176
177#if defined(LWESP_CH_PD_PIN)
178        /* Configure CH_PD pin */
179        gpio_init.Pin = LWESP_CH_PD_PIN;
180        LL_GPIO_Init(LWESP_CH_PD_PORT, &gpio_init);
181        LL_GPIO_SetOutputPin(LWESP_CH_PD_PORT, LWESP_CH_PD_PIN);
182#endif /* defined(LWESP_CH_PD_PIN) */
183
184        /* Configure USART pins */
185        gpio_init.Mode = LL_GPIO_MODE_ALTERNATE;
186
187        /* TX PIN */
188        gpio_init.Alternate = LWESP_USART_TX_PIN_AF;
189        gpio_init.Pin = LWESP_USART_TX_PIN;
190        LL_GPIO_Init(LWESP_USART_TX_PORT, &gpio_init);
191
192        /* RX PIN */
193        gpio_init.Alternate = LWESP_USART_RX_PIN_AF;
194        gpio_init.Pin = LWESP_USART_RX_PIN;
195        LL_GPIO_Init(LWESP_USART_RX_PORT, &gpio_init);
196
197        /* Configure UART */
198        LL_USART_DeInit(LWESP_USART);
199        LL_USART_StructInit(&usart_init);
200        usart_init.BaudRate = baudrate;
201        usart_init.DataWidth = LL_USART_DATAWIDTH_8B;
202        usart_init.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
203        usart_init.OverSampling = LL_USART_OVERSAMPLING_16;
204        usart_init.Parity = LL_USART_PARITY_NONE;
205        usart_init.StopBits = LL_USART_STOPBITS_1;
206        usart_init.TransferDirection = LL_USART_DIRECTION_TX_RX;
207        LL_USART_Init(LWESP_USART, &usart_init);
208
209        /* Enable USART interrupts and DMA request */
210        LL_USART_EnableIT_IDLE(LWESP_USART);
211        LL_USART_EnableIT_PE(LWESP_USART);
212        LL_USART_EnableIT_ERROR(LWESP_USART);
213        LL_USART_EnableDMAReq_RX(LWESP_USART);
214
215        /* Enable USART interrupts */
216        NVIC_SetPriority(LWESP_USART_IRQ, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0x07, 0x00));
217        NVIC_EnableIRQ(LWESP_USART_IRQ);
218
219        /* Configure DMA */
220        is_running = 0;
221#if defined(LWESP_USART_DMA_RX_STREAM)
222        LL_DMA_DeInit(LWESP_USART_DMA, LWESP_USART_DMA_RX_STREAM);
223        dma_init.Channel = LWESP_USART_DMA_RX_CH;
224#else
225        LL_DMA_DeInit(LWESP_USART_DMA, LWESP_USART_DMA_RX_CH);
226        dma_init.PeriphRequest = LWESP_USART_DMA_RX_REQ_NUM;
227#endif /* defined(LWESP_USART_DMA_RX_STREAM) */
228        dma_init.PeriphOrM2MSrcAddress = (uint32_t)&LWESP_USART->LWESP_USART_RDR_NAME;
229        dma_init.MemoryOrM2MDstAddress = (uint32_t)usart_mem;
230        dma_init.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
231        dma_init.Mode = LL_DMA_MODE_CIRCULAR;
232        dma_init.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
233        dma_init.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
234        dma_init.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_BYTE;
235        dma_init.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE;
236        dma_init.NbData = sizeof(usart_mem);
237        dma_init.Priority = LL_DMA_PRIORITY_MEDIUM;
238#if defined(LWESP_USART_DMA_RX_STREAM)
239        LL_DMA_Init(LWESP_USART_DMA, LWESP_USART_DMA_RX_STREAM, &dma_init);
240#else
241        LL_DMA_Init(LWESP_USART_DMA, LWESP_USART_DMA_RX_CH, &dma_init);
242#endif /* defined(LWESP_USART_DMA_RX_STREAM) */
243
244        /* Enable DMA interrupts */
245#if defined(LWESP_USART_DMA_RX_STREAM)
246        LL_DMA_EnableIT_HT(LWESP_USART_DMA, LWESP_USART_DMA_RX_STREAM);
247        LL_DMA_EnableIT_TC(LWESP_USART_DMA, LWESP_USART_DMA_RX_STREAM);
248        LL_DMA_EnableIT_TE(LWESP_USART_DMA, LWESP_USART_DMA_RX_STREAM);
249        LL_DMA_EnableIT_FE(LWESP_USART_DMA, LWESP_USART_DMA_RX_STREAM);
250        LL_DMA_EnableIT_DME(LWESP_USART_DMA, LWESP_USART_DMA_RX_STREAM);
251#else
252        LL_DMA_EnableIT_HT(LWESP_USART_DMA, LWESP_USART_DMA_RX_CH);
253        LL_DMA_EnableIT_TC(LWESP_USART_DMA, LWESP_USART_DMA_RX_CH);
254        LL_DMA_EnableIT_TE(LWESP_USART_DMA, LWESP_USART_DMA_RX_CH);
255#endif /* defined(LWESP_USART_DMA_RX_STREAM) */
256
257        /* Enable DMA interrupts */
258        NVIC_SetPriority(LWESP_USART_DMA_RX_IRQ, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0x07, 0x00));
259        NVIC_EnableIRQ(LWESP_USART_DMA_RX_IRQ);
260
261        old_pos = 0;
262        is_running = 1;
263
264        /* Start DMA and USART */
265#if defined(LWESP_USART_DMA_RX_STREAM)
266        LL_DMA_EnableStream(LWESP_USART_DMA, LWESP_USART_DMA_RX_STREAM);
267#else
268        LL_DMA_EnableChannel(LWESP_USART_DMA, LWESP_USART_DMA_RX_CH);
269#endif /* defined(LWESP_USART_DMA_RX_STREAM) */
270        LL_USART_Enable(LWESP_USART);
271    } else {
272        osDelay(10);
273        LL_USART_Disable(LWESP_USART);
274        usart_init.BaudRate = baudrate;
275        LL_USART_Init(LWESP_USART, &usart_init);
276        LL_USART_Enable(LWESP_USART);
277    }
278
279    /* Create mbox and start thread */
280    if (usart_ll_mbox_id == NULL) {
281        usart_ll_mbox_id = osMessageQueueNew(10, sizeof(void*), NULL);
282    }
283    if (usart_ll_thread_id == NULL) {
284        const osThreadAttr_t attr = {
285            .stack_size = 1024
286        };
287        usart_ll_thread_id = osThreadNew(usart_ll_thread, usart_ll_mbox_id, &attr);
288    }
289}
290
291#if defined(LWESP_RESET_PIN)
292/**
293 * \brief           Hardware reset callback
294 */
295static uint8_t
296reset_device(uint8_t state) {
297    if (state) {                                /* Activate reset line */
298        LL_GPIO_ResetOutputPin(LWESP_RESET_PORT, LWESP_RESET_PIN);
299    } else {
300        LL_GPIO_SetOutputPin(LWESP_RESET_PORT, LWESP_RESET_PIN);
301    }
302    return 1;
303}
304#endif /* defined(LWESP_RESET_PIN) */
305
306/**
307 * \brief           Send data to ESP device
308 * \param[in]       data: Pointer to data to send
309 * \param[in]       len: Number of bytes to send
310 * \return          Number of bytes sent
311 */
312static size_t
313send_data(const void* data, size_t len) {
314    const uint8_t* d = data;
315
316    for (size_t i = 0; i < len; ++i, ++d) {
317        LL_USART_TransmitData8(LWESP_USART, *d);
318        while (!LL_USART_IsActiveFlag_TXE(LWESP_USART)) {}
319    }
320    return len;
321}
322
323/**
324 * \brief           Callback function called from initialization process
325 */
326lwespr_t
327lwesp_ll_init(lwesp_ll_t* ll) {
328#if !LWESP_CFG_MEM_CUSTOM
329    static uint8_t memory[LWESP_MEM_SIZE];
330    lwesp_mem_region_t mem_regions[] = {
331        { memory, sizeof(memory) }
332    };
333
334    if (!initialized) {
335        lwesp_mem_assignmemory(mem_regions, LWESP_ARRAYSIZE(mem_regions));  /* Assign memory for allocations */
336    }
337#endif /* !LWESP_CFG_MEM_CUSTOM */
338
339    if (!initialized) {
340        ll->send_fn = send_data;                /* Set callback function to send data */
341#if defined(LWESP_RESET_PIN)
342        ll->reset_fn = reset_device;            /* Set callback for hardware reset */
343#endif /* defined(LWESP_RESET_PIN) */
344    }
345
346    configure_uart(ll->uart.baudrate);          /* Initialize UART for communication */
347    initialized = 1;
348    return lwespOK;
349}
350
351/**
352 * \brief           Callback function to de-init low-level communication part
353 */
354lwespr_t
355lwesp_ll_deinit(lwesp_ll_t* ll) {
356    if (usart_ll_mbox_id != NULL) {
357        osMessageQueueId_t tmp = usart_ll_mbox_id;
358        usart_ll_mbox_id = NULL;
359        osMessageQueueDelete(tmp);
360    }
361    if (usart_ll_thread_id != NULL) {
362        osThreadId_t tmp = usart_ll_thread_id;
363        usart_ll_thread_id = NULL;
364        osThreadTerminate(tmp);
365    }
366    initialized = 0;
367    LWESP_UNUSED(ll);
368    return lwespOK;
369}
370
371/**
372 * \brief           UART global interrupt handler
373 */
374void
375LWESP_USART_IRQHANDLER(void) {
376    LL_USART_ClearFlag_IDLE(LWESP_USART);
377    LL_USART_ClearFlag_PE(LWESP_USART);
378    LL_USART_ClearFlag_FE(LWESP_USART);
379    LL_USART_ClearFlag_ORE(LWESP_USART);
380    LL_USART_ClearFlag_NE(LWESP_USART);
381
382    if (usart_ll_mbox_id != NULL) {
383        void* d = (void*)1;
384        osMessageQueuePut(usart_ll_mbox_id, &d, 0, 0);
385    }
386}
387
388/**
389 * \brief           UART DMA stream/channel handler
390 */
391void
392LWESP_USART_DMA_RX_IRQHANDLER(void) {
393    LWESP_USART_DMA_RX_CLEAR_TC;
394    LWESP_USART_DMA_RX_CLEAR_HT;
395
396    if (usart_ll_mbox_id != NULL) {
397        void* d = (void*)1;
398        osMessageQueuePut(usart_ll_mbox_id, &d, 0, 0);
399    }
400}
401
402#endif /* !__DOXYGEN__ */
Example: System functions for WIN32
Actual header implementation of system functions for WIN32
 1/**
 2 * \file            lwesp_sys_port.h
 3 * \brief           WIN32 based system file implementation
 4 */
 5
 6/*
 7 * Copyright (c) 2020 Tilen MAJERLE
 8 *
 9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so,
15 * subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 *
29 * This file is part of LwESP - Lightweight ESP-AT parser library.
30 *
31 * Author:          Tilen MAJERLE <tilen@majerle.eu>
32 * Version:         v1.1.2-dev
33 */
34#ifndef LWESP_HDR_SYSTEM_PORT_H
35#define LWESP_HDR_SYSTEM_PORT_H
36
37#include <stdint.h>
38#include <stdlib.h>
39#include "lwesp/lwesp_opt.h"
40#include "windows.h"
41
42#ifdef __cplusplus
43extern "C" {
44#endif /* __cplusplus */
45
46#if LWESP_CFG_OS && !__DOXYGEN__
47
48typedef HANDLE                      lwesp_sys_mutex_t;
49typedef HANDLE                      lwesp_sys_sem_t;
50typedef HANDLE                      lwesp_sys_mbox_t;
51typedef HANDLE                      lwesp_sys_thread_t;
52typedef int                         lwesp_sys_thread_prio_t;
53
54#define LWESP_SYS_MBOX_NULL           ((HANDLE)0)
55#define LWESP_SYS_SEM_NULL            ((HANDLE)0)
56#define LWESP_SYS_MUTEX_NULL          ((HANDLE)0)
57#define LWESP_SYS_TIMEOUT             (INFINITE)
58#define LWESP_SYS_THREAD_PRIO         (0)
59#define LWESP_SYS_THREAD_SS           (1024)
60
61#endif /* LWESP_CFG_OS && !__DOXYGEN__ */
62
63#ifdef __cplusplus
64}
65#endif /* __cplusplus */
66
67#endif /* LWESP_HDR_SYSTEM_PORT_H */
Actual implementation of system functions for WIN32
  1/**
  2 * \file            lwesp_sys_win32.c
  3 * \brief           System dependant functions for WIN32
  4 */
  5
  6/*
  7 * Copyright (c) 2020 Tilen MAJERLE
  8 *
  9 * Permission is hereby granted, free of charge, to any person
 10 * obtaining a copy of this software and associated documentation
 11 * files (the "Software"), to deal in the Software without restriction,
 12 * including without limitation the rights to use, copy, modify, merge,
 13 * publish, distribute, sublicense, and/or sell copies of the Software,
 14 * and to permit persons to whom the Software is furnished to do so,
 15 * subject to the following conditions:
 16 *
 17 * The above copyright notice and this permission notice shall be
 18 * included in all copies or substantial portions of the Software.
 19 *
 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 23 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 27 * OTHER DEALINGS IN THE SOFTWARE.
 28 *
 29 * This file is part of LwESP - Lightweight ESP-AT parser library.
 30 *
 31 * Author:          Tilen MAJERLE <tilen@majerle.eu>
 32 * Version:         v1.1.2-dev
 33 */
 34#include <string.h>
 35#include <stdlib.h>
 36#include "system/lwesp_sys.h"
 37#include "windows.h"
 38
 39#if !__DOXYGEN__
 40
 41/**
 42 * \brief           Custom message queue implementation for WIN32
 43 */
 44typedef struct {
 45    lwesp_sys_sem_t sem_not_empty;              /*!< Semaphore indicates not empty */
 46    lwesp_sys_sem_t sem_not_full;               /*!< Semaphore indicates not full */
 47    lwesp_sys_sem_t sem;                        /*!< Semaphore to lock access */
 48    size_t in, out, size;
 49    void* entries[1];
 50} win32_mbox_t;
 51
 52static LARGE_INTEGER freq, sys_start_time;
 53static lwesp_sys_mutex_t sys_mutex;             /* Mutex ID for main protection */
 54
 55/**
 56 * \brief           Check if message box is full
 57 * \param[in]       m: Message box handle
 58 * \return          1 if full, 0 otherwise
 59 */
 60static uint8_t
 61mbox_is_full(win32_mbox_t* m) {
 62    size_t size = 0;
 63    if (m->in > m->out) {
 64        size = (m->in - m->out);
 65    } else if (m->out > m->in) {
 66        size = m->size - m->out + m->in;
 67    }
 68    return size == m->size - 1;
 69}
 70
 71/**
 72 * \brief           Check if message box is empty
 73 * \param[in]       m: Message box handle
 74 * \return          1 if empty, 0 otherwise
 75 */
 76static uint8_t
 77mbox_is_empty(win32_mbox_t* m) {
 78    return m->in == m->out;
 79}
 80
 81/**
 82 * \brief           Get current kernel time in units of milliseconds
 83 */
 84static uint32_t
 85osKernelSysTick(void) {
 86    LONGLONG ret;
 87    LARGE_INTEGER now;
 88
 89    QueryPerformanceFrequency(&freq);           /* Get frequency */
 90    QueryPerformanceCounter(&now);              /* Get current time */
 91    ret = now.QuadPart - sys_start_time.QuadPart;
 92    return (uint32_t)(((ret) * 1000) / freq.QuadPart);
 93}
 94
 95uint8_t
 96lwesp_sys_init(void) {
 97    QueryPerformanceFrequency(&freq);
 98    QueryPerformanceCounter(&sys_start_time);
 99
100    lwesp_sys_mutex_create(&sys_mutex);
101    return 1;
102}
103
104uint32_t
105lwesp_sys_now(void) {
106    return osKernelSysTick();
107}
108
109#if LWESP_CFG_OS
110uint8_t
111lwesp_sys_protect(void) {
112    lwesp_sys_mutex_lock(&sys_mutex);
113    return 1;
114}
115
116uint8_t
117lwesp_sys_unprotect(void) {
118    lwesp_sys_mutex_unlock(&sys_mutex);
119    return 1;
120}
121
122uint8_t
123lwesp_sys_mutex_create(lwesp_sys_mutex_t* p) {
124    *p = CreateMutex(NULL, FALSE, NULL);
125    return *p != NULL;
126}
127
128uint8_t
129lwesp_sys_mutex_delete(lwesp_sys_mutex_t* p) {
130    return CloseHandle(*p);
131}
132
133uint8_t
134lwesp_sys_mutex_lock(lwesp_sys_mutex_t* p) {
135    DWORD ret;
136    ret = WaitForSingleObject(*p, INFINITE);
137    if (ret != WAIT_OBJECT_0) {
138        return 0;
139    }
140    return 1;
141}
142
143uint8_t
144lwesp_sys_mutex_unlock(lwesp_sys_mutex_t* p) {
145    return ReleaseMutex(*p);
146}
147
148uint8_t
149lwesp_sys_mutex_isvalid(lwesp_sys_mutex_t* p) {
150    return p != NULL && *p != NULL;
151}
152
153uint8_t
154lwesp_sys_mutex_invalid(lwesp_sys_mutex_t* p) {
155    *p = LWESP_SYS_MUTEX_NULL;
156    return 1;
157}
158
159uint8_t
160lwesp_sys_sem_create(lwesp_sys_sem_t* p, uint8_t cnt) {
161    HANDLE h;
162    h = CreateSemaphore(NULL, !!cnt, 1, NULL);
163    *p = h;
164    return *p != NULL;
165}
166
167uint8_t
168lwesp_sys_sem_delete(lwesp_sys_sem_t* p) {
169    return CloseHandle(*p);
170}
171
172uint32_t
173lwesp_sys_sem_wait(lwesp_sys_sem_t* p, uint32_t timeout) {
174    DWORD ret;
175    uint32_t tick = osKernelSysTick();
176
177    if (timeout == 0) {
178        ret = WaitForSingleObject(*p, INFINITE);
179        return 1;
180    } else {
181        ret = WaitForSingleObject(*p, timeout);
182        if (ret == WAIT_OBJECT_0) {
183            return 1;
184        } else {
185            return LWESP_SYS_TIMEOUT;
186        }
187    }
188}
189
190uint8_t
191lwesp_sys_sem_release(lwesp_sys_sem_t* p) {
192    return ReleaseSemaphore(*p, 1, NULL);
193}
194
195uint8_t
196lwesp_sys_sem_isvalid(lwesp_sys_sem_t* p) {
197    return p != NULL && *p != NULL;
198}
199
200uint8_t
201lwesp_sys_sem_invalid(lwesp_sys_sem_t* p) {
202    *p = LWESP_SYS_SEM_NULL;
203    return 1;
204}
205
206uint8_t
207lwesp_sys_mbox_create(lwesp_sys_mbox_t* b, size_t size) {
208    win32_mbox_t* mbox;
209
210    *b = 0;
211
212    mbox = malloc(sizeof(*mbox) + size * sizeof(void*));
213    if (mbox != NULL) {
214        memset(mbox, 0x00, sizeof(*mbox));
215        mbox->size = size + 1;                  /* Set it to 1 more as cyclic buffer has only one less than size */
216        lwesp_sys_sem_create(&mbox->sem, 1);
217        lwesp_sys_sem_create(&mbox->sem_not_empty, 0);
218        lwesp_sys_sem_create(&mbox->sem_not_full, 0);
219        *b = mbox;
220    }
221    return *b != NULL;
222}
223
224uint8_t
225lwesp_sys_mbox_delete(lwesp_sys_mbox_t* b) {
226    win32_mbox_t* mbox = *b;
227    lwesp_sys_sem_delete(&mbox->sem);
228    lwesp_sys_sem_delete(&mbox->sem_not_full);
229    lwesp_sys_sem_delete(&mbox->sem_not_empty);
230    free(mbox);
231    return 1;
232}
233
234uint32_t
235lwesp_sys_mbox_put(lwesp_sys_mbox_t* b, void* m) {
236    win32_mbox_t* mbox = *b;
237    uint32_t time = osKernelSysTick();          /* Get start time */
238
239    lwesp_sys_sem_wait(&mbox->sem, 0);          /* Wait for access */
240
241    /*
242     * Since function is blocking until ready to write something to queue,
243     * wait and release the semaphores to allow other threads
244     * to process the queue before we can write new value.
245     */
246    while (mbox_is_full(mbox)) {
247        lwesp_sys_sem_release(&mbox->sem);      /* Release semaphore */
248        lwesp_sys_sem_wait(&mbox->sem_not_full, 0); /* Wait for semaphore indicating not full */
249        lwesp_sys_sem_wait(&mbox->sem, 0);      /* Wait availability again */
250    }
251    mbox->entries[mbox->in] = m;
252    if (++mbox->in >= mbox->size) {
253        mbox->in = 0;
254    }
255    lwesp_sys_sem_release(&mbox->sem_not_empty);/* Signal non-empty state */
256    lwesp_sys_sem_release(&mbox->sem);          /* Release access for other threads */
257    return osKernelSysTick() - time;
258}
259
260uint32_t
261lwesp_sys_mbox_get(lwesp_sys_mbox_t* b, void** m, uint32_t timeout) {
262    win32_mbox_t* mbox = *b;
263    uint32_t time;
264
265    time = osKernelSysTick();
266
267    /* Get exclusive access to message queue */
268    if (lwesp_sys_sem_wait(&mbox->sem, timeout) == LWESP_SYS_TIMEOUT) {
269        return LWESP_SYS_TIMEOUT;
270    }
271    while (mbox_is_empty(mbox)) {
272        lwesp_sys_sem_release(&mbox->sem);
273        if (lwesp_sys_sem_wait(&mbox->sem_not_empty, timeout) == LWESP_SYS_TIMEOUT) {
274            return LWESP_SYS_TIMEOUT;
275        }
276        lwesp_sys_sem_wait(&mbox->sem, timeout);
277    }
278    *m = mbox->entries[mbox->out];
279    if (++mbox->out >= mbox->size) {
280        mbox->out = 0;
281    }
282    lwesp_sys_sem_release(&mbox->sem_not_full);
283    lwesp_sys_sem_release(&mbox->sem);
284
285    return osKernelSysTick() - time;
286}
287
288uint8_t
289lwesp_sys_mbox_putnow(lwesp_sys_mbox_t* b, void* m) {
290    win32_mbox_t* mbox = *b;
291
292    lwesp_sys_sem_wait(&mbox->sem, 0);
293    if (mbox_is_full(mbox)) {
294        lwesp_sys_sem_release(&mbox->sem);
295        return 0;
296    }
297    mbox->entries[mbox->in] = m;
298    if (mbox->in == mbox->out) {
299        lwesp_sys_sem_release(&mbox->sem_not_empty);
300    }
301    if (++mbox->in >= mbox->size) {
302        mbox->in = 0;
303    }
304    lwesp_sys_sem_release(&mbox->sem);
305    return 1;
306}
307
308uint8_t
309lwesp_sys_mbox_getnow(lwesp_sys_mbox_t* b, void** m) {
310    win32_mbox_t* mbox = *b;
311
312    lwesp_sys_sem_wait(&mbox->sem, 0);          /* Wait exclusive access */
313    if (mbox->in == mbox->out) {
314        lwesp_sys_sem_release(&mbox->sem);      /* Release access */
315        return 0;
316    }
317
318    *m = mbox->entries[mbox->out];
319    if (++mbox->out >= mbox->size) {
320        mbox->out = 0;
321    }
322    lwesp_sys_sem_release(&mbox->sem_not_full); /* Queue not full anymore */
323    lwesp_sys_sem_release(&mbox->sem);          /* Release semaphore */
324    return 1;
325}
326
327uint8_t
328lwesp_sys_mbox_isvalid(lwesp_sys_mbox_t* b) {
329    return b != NULL && *b != NULL;
330}
331
332uint8_t
333lwesp_sys_mbox_invalid(lwesp_sys_mbox_t* b) {
334    *b = LWESP_SYS_MBOX_NULL;
335    return 1;
336}
337
338uint8_t
339lwesp_sys_thread_create(lwesp_sys_thread_t* t, const char* name, lwesp_sys_thread_fn thread_func, void* const arg, size_t stack_size, lwesp_sys_thread_prio_t prio) {
340    HANDLE h;
341    DWORD id;
342    h = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)thread_func, arg, 0, &id);
343    if (t != NULL) {
344        *t = h;
345    }
346    return h != NULL;
347}
348
349uint8_t
350lwesp_sys_thread_terminate(lwesp_sys_thread_t* t) {
351    if (t == NULL) {                            /* Shall we terminate ourself? */
352        ExitThread(0);
353    } else {
354        /* We have known thread, find handle by looking at ID */
355        TerminateThread(*t, 0);
356    }
357    return 1;
358}
359
360uint8_t
361lwesp_sys_thread_yield(void) {
362    /* Not implemented */
363    return 1;
364}
365
366#endif /* LWESP_CFG_OS */
367#endif /* !__DOXYGEN__ */
Example: System functions for CMSIS-OS
Actual header implementation of system functions for CMSIS-OS based operating systems
 1/**
 2 * \file            lwesp_sys_port.h
 3 * \brief           CMSIS-OS based system file
 4 */
 5
 6/*
 7 * Copyright (c) 2020 Tilen MAJERLE
 8 *
 9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so,
15 * subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 *
29 * This file is part of LwESP - Lightweight ESP-AT parser library.
30 *
31 * Author:          Tilen MAJERLE <tilen@majerle.eu>
32 * Version:         v1.1.2-dev
33 */
34#ifndef LWESP_HDR_SYSTEM_PORT_H
35#define LWESP_HDR_SYSTEM_PORT_H
36
37#include <stdint.h>
38#include <stdlib.h>
39#include "lwesp/lwesp_opt.h"
40#include "cmsis_os.h"
41
42#ifdef __cplusplus
43extern "C" {
44#endif /* __cplusplus */
45
46#if LWESP_CFG_OS && !__DOXYGEN__
47
48typedef osMutexId_t                 lwesp_sys_mutex_t;
49typedef osSemaphoreId_t             lwesp_sys_sem_t;
50typedef osMessageQueueId_t          lwesp_sys_mbox_t;
51typedef osThreadId_t                lwesp_sys_thread_t;
52typedef osPriority_t                lwesp_sys_thread_prio_t;
53
54#define LWESP_SYS_MUTEX_NULL          ((lwesp_sys_mutex_t)0)
55#define LWESP_SYS_SEM_NULL            ((lwesp_sys_sem_t)0)
56#define LWESP_SYS_MBOX_NULL           ((lwesp_sys_mbox_t)0)
57#define LWESP_SYS_TIMEOUT             ((uint32_t)osWaitForever)
58#define LWESP_SYS_THREAD_PRIO         (osPriorityNormal)
59#define LWESP_SYS_THREAD_SS           (512)
60
61#endif /* LWESP_CFG_OS && !__DOXYGEN__ */
62
63#ifdef __cplusplus
64}
65#endif /* __cplusplus */
66
67#endif /* LWESP_HDR_SYSTEM_PORT_H */
Actual implementation of system functions for CMSIS-OS based operating systems
  1/**
  2 * \file            lwesp_sys_cmsis_os.c
  3 * \brief           System dependent functions for CMSIS based operating system
  4 */
  5
  6/*
  7 * Copyright (c) 2020 Tilen MAJERLE
  8 *
  9 * Permission is hereby granted, free of charge, to any person
 10 * obtaining a copy of this software and associated documentation
 11 * files (the "Software"), to deal in the Software without restriction,
 12 * including without limitation the rights to use, copy, modify, merge,
 13 * publish, distribute, sublicense, and/or sell copies of the Software,
 14 * and to permit persons to whom the Software is furnished to do so,
 15 * subject to the following conditions:
 16 *
 17 * The above copyright notice and this permission notice shall be
 18 * included in all copies or substantial portions of the Software.
 19 *
 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 23 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 27 * OTHER DEALINGS IN THE SOFTWARE.
 28 *
 29 * This file is part of LwESP - Lightweight ESP-AT parser library.
 30 *
 31 * Author:          Tilen MAJERLE <tilen@majerle.eu>
 32 * Version:         v1.1.2-dev
 33 */
 34#include "system/lwesp_sys.h"
 35#include "cmsis_os.h"
 36
 37#if !__DOXYGEN__
 38
 39static osMutexId_t sys_mutex;
 40
 41uint8_t
 42lwesp_sys_init(void) {
 43    lwesp_sys_mutex_create(&sys_mutex);
 44    return 1;
 45}
 46
 47uint32_t
 48lwesp_sys_now(void) {
 49    return osKernelSysTick();
 50}
 51
 52uint8_t
 53lwesp_sys_protect(void) {
 54    lwesp_sys_mutex_lock(&sys_mutex);
 55    return 1;
 56}
 57
 58uint8_t
 59lwesp_sys_unprotect(void) {
 60    lwesp_sys_mutex_unlock(&sys_mutex);
 61    return 1;
 62}
 63
 64uint8_t
 65lwesp_sys_mutex_create(lwesp_sys_mutex_t* p) {
 66    const osMutexAttr_t attr = {
 67        .attr_bits = osMutexRecursive,
 68        .name = "lwesp_mutex",
 69    };
 70    return (*p = osMutexNew(&attr)) != NULL;
 71}
 72
 73uint8_t
 74lwesp_sys_mutex_delete(lwesp_sys_mutex_t* p) {
 75    return osMutexDelete(*p) == osOK;
 76}
 77
 78uint8_t
 79lwesp_sys_mutex_lock(lwesp_sys_mutex_t* p) {
 80    return osMutexAcquire(*p, osWaitForever) == osOK;
 81}
 82
 83uint8_t
 84lwesp_sys_mutex_unlock(lwesp_sys_mutex_t* p) {
 85    return osMutexRelease(*p) == osOK;
 86}
 87
 88uint8_t
 89lwesp_sys_mutex_isvalid(lwesp_sys_mutex_t* p) {
 90    return p != NULL && *p != NULL;
 91}
 92
 93uint8_t
 94lwesp_sys_mutex_invalid(lwesp_sys_mutex_t* p) {
 95    *p = LWESP_SYS_MUTEX_NULL;
 96    return 1;
 97}
 98
 99uint8_t
100lwesp_sys_sem_create(lwesp_sys_sem_t* p, uint8_t cnt) {
101    const osSemaphoreAttr_t attr = {
102        .name = "lwesp_sem",
103    };
104    return (*p = osSemaphoreNew(1, cnt > 0 ? 1 : 0, &attr)) != NULL;
105}
106
107uint8_t
108lwesp_sys_sem_delete(lwesp_sys_sem_t* p) {
109    return osSemaphoreDelete(*p) == osOK;
110}
111
112uint32_t
113lwesp_sys_sem_wait(lwesp_sys_sem_t* p, uint32_t timeout) {
114    uint32_t tick = osKernelSysTick();
115    return (osSemaphoreAcquire(*p, timeout == 0 ? osWaitForever : timeout) == osOK) ? (osKernelSysTick() - tick) : LWESP_SYS_TIMEOUT;
116}
117
118uint8_t
119lwesp_sys_sem_release(lwesp_sys_sem_t* p) {
120    return osSemaphoreRelease(*p) == osOK;
121}
122
123uint8_t
124lwesp_sys_sem_isvalid(lwesp_sys_sem_t* p) {
125    return p != NULL && *p != NULL;
126}
127
128uint8_t
129lwesp_sys_sem_invalid(lwesp_sys_sem_t* p) {
130    *p = LWESP_SYS_SEM_NULL;
131    return 1;
132}
133
134uint8_t
135lwesp_sys_mbox_create(lwesp_sys_mbox_t* b, size_t size) {
136    const osMessageQueueAttr_t attr = {
137        .name = "lwesp_mbox",
138    };
139    return (*b = osMessageQueueNew(size, sizeof(void*), &attr)) != NULL;
140}
141
142uint8_t
143lwesp_sys_mbox_delete(lwesp_sys_mbox_t* b) {
144    if (osMessageQueueGetCount(*b) > 0) {
145        return 0;
146    }
147    return osMessageQueueDelete(*b) == osOK;
148}
149
150uint32_t
151lwesp_sys_mbox_put(lwesp_sys_mbox_t* b, void* m) {
152    uint32_t tick = osKernelSysTick();
153    return osMessageQueuePut(*b, &m, 0, osWaitForever) == osOK ? (osKernelSysTick() - tick) : LWESP_SYS_TIMEOUT;
154}
155
156uint32_t
157lwesp_sys_mbox_get(lwesp_sys_mbox_t* b, void** m, uint32_t timeout) {
158    uint32_t tick = osKernelSysTick();
159    return (osMessageQueueGet(*b, m, NULL, timeout == 0 ? osWaitForever : timeout) == osOK) ? (osKernelSysTick() - tick) : LWESP_SYS_TIMEOUT;
160}
161
162uint8_t
163lwesp_sys_mbox_putnow(lwesp_sys_mbox_t* b, void* m) {
164    return osMessageQueuePut(*b, &m, 0, 0) == osOK;
165}
166
167uint8_t
168lwesp_sys_mbox_getnow(lwesp_sys_mbox_t* b, void** m) {
169    return osMessageQueueGet(*b, m, NULL, 0) == osOK;
170}
171
172uint8_t
173lwesp_sys_mbox_isvalid(lwesp_sys_mbox_t* b) {
174    return b != NULL && *b != NULL;
175}
176
177uint8_t
178lwesp_sys_mbox_invalid(lwesp_sys_mbox_t* b) {
179    *b = LWESP_SYS_MBOX_NULL;
180    return 1;
181}
182
183uint8_t
184lwesp_sys_thread_create(lwesp_sys_thread_t* t, const char* name, lwesp_sys_thread_fn thread_func, void* const arg, size_t stack_size, lwesp_sys_thread_prio_t prio) {
185    lwesp_sys_thread_t id;
186    const osThreadAttr_t thread_attr = {
187        .name = (char*)name,
188        .priority = (osPriority)prio,
189        .stack_size = stack_size > 0 ? stack_size : LWESP_SYS_THREAD_SS
190    };
191
192    id = osThreadNew(thread_func, arg, &thread_attr);
193    if (t != NULL) {
194        *t = id;
195    }
196    return id != NULL;
197}
198
199uint8_t
200lwesp_sys_thread_terminate(lwesp_sys_thread_t* t) {
201    if (t != NULL) {
202        osThreadTerminate(*t);
203    } else {
204        osThreadExit();
205    }
206    return 1;
207}
208
209uint8_t
210lwesp_sys_thread_yield(void) {
211    osThreadYield();
212    return 1;
213}
214
215#endif /* !__DOXYGEN__ */

API reference

List of all the modules:

LwESP

Access point
group LWESP_AP

Access point.

Functions to manage access point (AP) on ESP device.

In order to be able to use AP feature, LWESP_CFG_MODE_ACCESS_POINT must be enabled.

Functions

lwespr_t lwesp_ap_getip(lwesp_ip_t *ip, lwesp_ip_t *gw, lwesp_ip_t *nm, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get IP of access point.

Parameters
  • ip[out] Pointer to variable to write IP address

  • gw[out] Pointer to variable to write gateway address

  • nm[out] Pointer to variable to write netmask address

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_ap_setip(const lwesp_ip_t *ip, const lwesp_ip_t *gw, const lwesp_ip_t *nm, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Set IP of access point.

Configuration changes will be saved in the NVS area of ESP device.

Parameters
  • ip[in] Pointer to IP address

  • gw[in] Pointer to gateway address. Set to NULL to use default gateway

  • nm[in] Pointer to netmask address. Set to NULL to use default netmask

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_ap_getmac(lwesp_mac_t *mac, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get MAC of access point.

Parameters
  • mac[out] Pointer to output variable to save MAC address

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_ap_setmac(const lwesp_mac_t *mac, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Set MAC of access point.

Configuration changes will be saved in the NVS area of ESP device.

Parameters
  • mac[in] Pointer to variable with MAC address. Memory of at least 6 bytes is required

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_ap_get_config(lwesp_ap_conf_t *ap_conf, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get configuration of Soft Access Point.

Note

Before you can get configuration access point, ESP device must be in AP mode. Check lwesp_set_wifi_mode for more information

Parameters
  • ap_conf[out] soft access point configuration

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_ap_set_config(const char *ssid, const char *pwd, uint8_t ch, lwesp_ecn_t ecn, uint8_t max_sta, uint8_t hid, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Configure access point.

Configuration changes will be saved in the NVS area of ESP device.

Note

Before you can configure access point, ESP device must be in AP mode. Check lwesp_set_wifi_mode for more information

Parameters
  • ssid[in] SSID name of access point

  • pwd[in] Password for network. Either set it to NULL or less than 64 characters

  • ch[in] Wifi RF channel

  • ecn[in] Encryption type. Valid options are OPEN, WPA_PSK, WPA2_PSK and WPA_WPA2_PSK

  • max_sta[in] Maximal number of stations access point can accept. Valid between 1 and 10 stations

  • hid[in] Set to 1 to hide access point from public access

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_ap_list_sta(lwesp_sta_t *sta, size_t stal, size_t *staf, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

List stations connected to access point.

Parameters
  • sta[in] Pointer to array of lwesp_sta_t structure to fill with stations

  • stal[in] Number of array entries of sta parameter

  • staf[out] Number of stations connected to access point

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_ap_disconn_sta(const lwesp_mac_t *mac, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Disconnects connected station from SoftAP access point.

Parameters
  • mac[in] Device MAC address to disconnect. Application may use lwesp_ap_list_sta to obtain list of connected stations to SoftAP. Set to NULL to disconnect all stations.

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

struct lwesp_ap_t
#include <lwesp_typedefs.h>

Access point data structure.

Public Members

lwesp_ecn_t ecn

Encryption mode

char ssid[LWESP_CFG_MAX_SSID_LENGTH]

Access point name

int16_t rssi

Received signal strength indicator

lwesp_mac_t mac

MAC physical address

uint8_t ch

WiFi channel used on access point

uint8_t scan_type

Scan type, 0 = active, 1 = passive

uint16_t scan_time_min

Minimum active scan time per channel in units of milliseconds

uint16_t scan_time_max

maximum active scan time per channel in units of milliseconds

int16_t freq_offset

Frequency offset

int16_t freq_cal

Frequency calibration

lwesp_ap_cipher_t pairwise_cipher

Pairwise cipher mode

lwesp_ap_cipher_t group_cipher

Group cipher mode

uint8_t bgn

Information about 802.11[b|g|n] support

uint8_t wps

Status if WPS function is supported

struct lwesp_sta_info_ap_t
#include <lwesp_typedefs.h>

Access point information on which station is connected to.

Public Members

char ssid[LWESP_CFG_MAX_SSID_LENGTH]

Access point name

int16_t rssi

RSSI

lwesp_mac_t mac

MAC address

uint8_t ch

Channel information

struct lwesp_ap_conf_t
#include <lwesp_typedefs.h>

Soft access point data structure.

Public Members

char ssid[LWESP_CFG_MAX_SSID_LENGTH]

Access point name

char pwd[LWESP_CFG_MAX_PWD_LENGTH]

Access point password/passphrase

uint8_t ch

WiFi channel used on access point

lwesp_ecn_t ecn

Encryption mode

uint8_t max_cons

Maximum number of stations allowed connected to this AP

uint8_t hidden

broadcast the SSID, 0 No, 1 Yes

Ring buffer
group LWESP_BUFF

Generic ring buffer.

Defines

BUF_PREF(x)

Buffer function/typedef prefix string.

It is used to change function names in zero time to easily re-use same library between applications. Use #define BUF_PREF(x) my_prefix_ ## x to change all function names to (for example) my_prefix_buff_init

Note

Modification of this macro must be done in header and source file aswell

Functions

uint8_t lwesp_buff_init(lwesp_buff_t *buff, size_t size)

Initialize buffer.

Parameters
  • buff[in] Pointer to buffer structure

  • size[in] Size of buffer in units of bytes

Returns

1 on success, 0 otherwise

void lwesp_buff_free(lwesp_buff_t *buff)

Free dynamic allocation if used on memory.

Parameters

buff[in] Pointer to buffer structure

void lwesp_buff_reset(lwesp_buff_t *buff)

Resets buffer to default values. Buffer size is not modified.

Parameters

buff[in] Buffer handle

size_t lwesp_buff_write(lwesp_buff_t *buff, const void *data, size_t btw)

Write data to buffer Copies data from data array to buffer and marks buffer as full for maximum count number of bytes.

Parameters
  • buff[in] Buffer handle

  • data[in] Pointer to data to write into buffer

  • btw[in] Number of bytes to write

Returns

Number of bytes written to buffer. When returned value is less than btw, there was no enough memory available to copy full data array

size_t lwesp_buff_read(lwesp_buff_t *buff, void *data, size_t btr)

Read data from buffer Copies data from buffer to data array and marks buffer as free for maximum btr number of bytes.

Parameters
  • buff[in] Buffer handle

  • data[out] Pointer to output memory to copy buffer data to

  • btr[in] Number of bytes to read

Returns

Number of bytes read and copied to data array

size_t lwesp_buff_peek(lwesp_buff_t *buff, size_t skip_count, void *data, size_t btp)

Read from buffer without changing read pointer (peek only)

Parameters
  • buff[in] Buffer handle

  • skip_count[in] Number of bytes to skip before reading data

  • data[out] Pointer to output memory to copy buffer data to

  • btp[in] Number of bytes to peek

Returns

Number of bytes peeked and written to output array

size_t lwesp_buff_get_free(lwesp_buff_t *buff)

Get number of bytes in buffer available to write.

Parameters

buff[in] Buffer handle

Returns

Number of free bytes in memory

size_t lwesp_buff_get_full(lwesp_buff_t *buff)

Get number of bytes in buffer available to read.

Parameters

buff[in] Buffer handle

Returns

Number of bytes ready to be read

void *lwesp_buff_get_linear_block_read_address(lwesp_buff_t *buff)

Get linear address for buffer for fast read.

Parameters

buff[in] Buffer handle

Returns

Linear buffer start address

size_t lwesp_buff_get_linear_block_read_length(lwesp_buff_t *buff)

Get length of linear block address before it overflows for read operation.

Parameters

buff[in] Buffer handle

Returns

Linear buffer size in units of bytes for read operation

size_t lwesp_buff_skip(lwesp_buff_t *buff, size_t len)

Skip (ignore; advance read pointer) buffer data Marks data as read in the buffer and increases free memory for up to len bytes.

Note

Useful at the end of streaming transfer such as DMA

Parameters
  • buff[in] Buffer handle

  • len[in] Number of bytes to skip and mark as read

Returns

Number of bytes skipped

void *lwesp_buff_get_linear_block_write_address(lwesp_buff_t *buff)

Get linear address for buffer for fast read.

Parameters

buff[in] Buffer handle

Returns

Linear buffer start address

size_t lwesp_buff_get_linear_block_write_length(lwesp_buff_t *buff)

Get length of linear block address before it overflows for write operation.

Parameters

buff[in] Buffer handle

Returns

Linear buffer size in units of bytes for write operation

size_t lwesp_buff_advance(lwesp_buff_t *buff, size_t len)

Advance write pointer in the buffer. Similar to skip function but modifies write pointer instead of read.

Note

Useful when hardware is writing to buffer and application needs to increase number of bytes written to buffer by hardware

Parameters
  • buff[in] Buffer handle

  • len[in] Number of bytes to advance

Returns

Number of bytes advanced for write operation

struct lwesp_buff_t
#include <lwesp_typedefs.h>

Buffer structure.

Public Members

uint8_t *buff

Pointer to buffer data. Buffer is considered initialized when buff != NULL

size_t size

Size of buffer data. Size of actual buffer is 1 byte less than this value

size_t r

Next read pointer. Buffer is considered empty when r == w and full when w == r - 1

size_t w

Next write pointer. Buffer is considered empty when r == w and full when w == r - 1

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#include "client.h"
  2#include "lwesp/lwesp.h"
  3
  4/* Host parameter */
  5#define CONN_HOST           "example.com"
  6#define CONN_PORT           80
  7
  8static lwespr_t   conn_callback_func(lwesp_evt_t* evt);
  9
 10/**
 11 * \brief           Request data for connection
 12 */
 13static const
 14uint8_t req_data[] = ""
 15                     "GET / HTTP/1.1\r\n"
 16                     "Host: " CONN_HOST "\r\n"
 17                     "Connection: close\r\n"
 18                     "\r\n";
 19
 20/**
 21 * \brief           Start a new connection(s) as client
 22 */
 23void
 24client_connect(void) {
 25    lwespr_t res;
 26
 27    /* Start a new connection as client in non-blocking mode */
 28    if ((res = lwesp_conn_start(NULL, LWESP_CONN_TYPE_TCP, "example.com", 80, NULL, conn_callback_func, 0)) == lwespOK) {
 29        printf("Connection to " CONN_HOST " started...\r\n");
 30    } else {
 31        printf("Cannot start connection to " CONN_HOST "!\r\n");
 32    }
 33
 34    /* Start 2 more */
 35    lwesp_conn_start(NULL, LWESP_CONN_TYPE_TCP, CONN_HOST, CONN_PORT, NULL, conn_callback_func, 0);
 36
 37    /*
 38     * An example of connection which should fail in connecting.
 39     * When this is the case, \ref LWESP_EVT_CONN_ERROR event should be triggered
 40     * in callback function processing
 41     */
 42    lwesp_conn_start(NULL, LWESP_CONN_TYPE_TCP, CONN_HOST, 10, NULL, conn_callback_func, 0);
 43}
 44
 45/**
 46 * \brief           Event callback function for connection-only
 47 * \param[in]       evt: Event information with data
 48 * \return          \ref lwespOK on success, member of \ref lwespr_t otherwise
 49 */
 50static lwespr_t
 51conn_callback_func(lwesp_evt_t* evt) {
 52    lwesp_conn_p conn;
 53    lwespr_t res;
 54    uint8_t conn_num;
 55
 56    conn = lwesp_conn_get_from_evt(evt);          /* Get connection handle from event */
 57    if (conn == NULL) {
 58        return lwespERR;
 59    }
 60    conn_num = lwesp_conn_getnum(conn);           /* Get connection number for identification */
 61    switch (lwesp_evt_get_type(evt)) {
 62        case LWESP_EVT_CONN_ACTIVE: {             /* Connection just active */
 63            printf("Connection %d active!\r\n", (int)conn_num);
 64            res = lwesp_conn_send(conn, req_data, sizeof(req_data) - 1, NULL, 0); /* Start sending data in non-blocking mode */
 65            if (res == lwespOK) {
 66                printf("Sending request data to server...\r\n");
 67            } else {
 68                printf("Cannot send request data to server. Closing connection manually...\r\n");
 69                lwesp_conn_close(conn, 0);        /* Close the connection */
 70            }
 71            break;
 72        }
 73        case LWESP_EVT_CONN_CLOSE: {              /* Connection closed */
 74            if (lwesp_evt_conn_close_is_forced(evt)) {
 75                printf("Connection %d closed by client!\r\n", (int)conn_num);
 76            } else {
 77                printf("Connection %d closed by remote side!\r\n", (int)conn_num);
 78            }
 79            break;
 80        }
 81        case LWESP_EVT_CONN_SEND: {               /* Data send event */
 82            lwespr_t res = lwesp_evt_conn_send_get_result(evt);
 83            if (res == lwespOK) {
 84                printf("Data sent successfully on connection %d...waiting to receive data from remote side...\r\n", (int)conn_num);
 85            } else {
 86                printf("Error while sending data on connection %d!\r\n", (int)conn_num);
 87            }
 88            break;
 89        }
 90        case LWESP_EVT_CONN_RECV: {               /* Data received from remote side */
 91            lwesp_pbuf_p pbuf = lwesp_evt_conn_recv_get_buff(evt);
 92            lwesp_conn_recved(conn, pbuf);        /* Notify stack about received pbuf */
 93            printf("Received %d bytes on connection %d..\r\n", (int)lwesp_pbuf_length(pbuf, 1), (int)conn_num);
 94            break;
 95        }
 96        case LWESP_EVT_CONN_ERROR: {              /* Error connecting to server */
 97            const char* host = lwesp_evt_conn_error_get_host(evt);
 98            lwesp_port_t port = lwesp_evt_conn_error_get_port(evt);
 99            printf("Error connecting to %s:%d\r\n", host, (int)port);
100            break;
101        }
102        default:
103            break;
104    }
105    return lwespOK;
106}
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
 1size_t rem_len;
 2lwesp_conn_p conn;
 3lwespr_t res;
 4
 5/* ... other tasks to make sure connection is established */
 6
 7/* We are connected to server at this point! */
 8/*
 9 * Call write function to write data to memory
10 * and do not send immediately unless buffer is full after this write
11 *
12 * rem_len will give us response how much bytes
13 * is available in memory after write
14 */
15res = lwesp_conn_write(conn, "My string", 9, 0, &rem_len);
16if (rem_len == 0) {
17    printf("No more memory available for next write!\r\n");
18}
19res = lwesp_conn_write(conn, "example.com", 11, 0, &rem_len);
20
21/*
22 * Data will stay in buffer until buffer is full,
23 * except if user wants to force send,
24 * call write function with flush mode enabled
25 *
26 * It will send out together 20 bytes
27 */
28lwesp_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

enumerator LWESP_CONN_TYPE_TCPV6

Connection type is TCP over IPV6

enumerator LWESP_CONN_TYPE_SSLV6

Connection type is SSL over IPV6

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.

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

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

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

  • remote_port[in] Connection port

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

  • conn_evt_fn[in] Callback function for this connection

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

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.

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

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

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

  • conn_evt_fn[in] Callback function for this connection

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_conn_close(lwesp_conn_p conn, const uint32_t blocking)

Close specific or all connections.

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

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

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.

Parameters
  • conn[in] Connection handle to send data

  • data[in] Data to send

  • btw[in] Number of bytes to send

  • bw[out] 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

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

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)

Parameters
  • conn[in] Connection handle to send data

  • ip[in] Remote IP address for UDP connection

  • port[in] Remote port connection

  • data[in] Pointer to data to send

  • btw[in] Number of bytes to send

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

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_conn_set_arg(lwesp_conn_p conn, void *const arg)

Set argument variable for connection.

See

lwesp_conn_get_arg

Parameters
  • conn[in] Connection handle to set argument

  • arg[in] Pointer to argument

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

void *lwesp_conn_get_arg(lwesp_conn_p conn)

Get user defined connection argument.

See

lwesp_conn_set_arg

Parameters

conn[in] Connection handle to get argument

Returns

User argument

uint8_t lwesp_conn_is_client(lwesp_conn_p conn)

Check if connection type is client.

Parameters

conn[in] Pointer to connection to check for status

Returns

1 on success, 0 otherwise

uint8_t lwesp_conn_is_server(lwesp_conn_p conn)

Check if connection type is server.

Parameters

conn[in] Pointer to connection to check for status

Returns

1 on success, 0 otherwise

uint8_t lwesp_conn_is_active(lwesp_conn_p conn)

Check if connection is active.

Parameters

conn[in] Pointer to connection to check for status

Returns

1 on success, 0 otherwise

uint8_t lwesp_conn_is_closed(lwesp_conn_p conn)

Check if connection is closed.

Parameters

conn[in] Pointer to connection to check for status

Returns

1 on success, 0 otherwise

int8_t lwesp_conn_getnum(lwesp_conn_p conn)

Get the number from connection.

Parameters

conn[in] Connection pointer

Returns

Connection number in case of success or -1 on failure

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

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

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_get_conns_status(const uint32_t blocking)

Gets connections status.

Parameters

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwesp_conn_p lwesp_conn_get_from_evt(lwesp_evt_t *evt)

Get connection from connection based event.

Parameters

evt[in] Event which happened for connection

Returns

Connection pointer on success, NULL otherwise

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)

Parameters
  • conn[in] Connection to write

  • data[in] Data to copy to write buffer

  • btw[in] Number of bytes to write

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

  • mem_available[out] 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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

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

Parameters
  • conn[in] Connection handle

  • pbuf[in] Packet buffer received on connection

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

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.

Parameters

conn[in] Connection handle

Returns

Total number of received bytes on connection

uint8_t lwesp_conn_get_remote_ip(lwesp_conn_p conn, lwesp_ip_t *ip)

Get connection remote IP address.

Parameters
  • conn[in] Connection handle

  • ip[out] Pointer to IP output handle

Returns

1 on success, 0 otherwise

lwesp_port_t lwesp_conn_get_remote_port(lwesp_conn_p conn)

Get connection remote port number.

Parameters

conn[in] Connection handle

Returns

Port number on success, 0 otherwise

lwesp_port_t lwesp_conn_get_local_port(lwesp_conn_p conn)

Get connection local port number.

Parameters

conn[in] Connection handle

Returns

Port number on success, 0 otherwise

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.

Parameters
  • link_id[in] 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.

  • auth_mode[in] 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

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

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

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

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

Debug support

Middleware has extended debugging capabilities. These consist of different debugging levels and types of debug messages, allowing to track and catch different types of warnings, severe problems or simply output messages program flow messages (trace messages).

Module is highly configurable using library configuration methods. Application must enable some options to decide what type of messages and for which modules it would like to output messages.

With default configuration, printf is used as output function. This behavior can be changed with LWESP_CFG_DBG_OUT configuration.

For successful debugging, application must:

  • Enable global debugging by setting LWESP_CFG_DBG to LWESP_DBG_ON

  • Configure which types of messages to output

  • Configure debugging level, from all messages to severe only

  • Enable specific modules to debug, by setting its configuration value to LWESP_DBG_ON

Tip

Check Configuration for all modules with debug implementation.

An example code with config and latter usage:

Debug configuration setup
 1/* Modifications of lwesp_opts.h file for configuration */
 2
 3/* Enable global debug */
 4#define LWESP_CFG_DBG               LWESP_DBG_ON
 5
 6/*
 7 * Enable debug types.
 8 * Application may use bitwise OR | to use multiple types:
 9 *    LWESP_DBG_TYPE_TRACE | LWESP_DBG_TYPE_STATE
10 */
11#define LWESP_CFG_DBG_TYPES_ON      LWESP_DBG_TYPE_TRACE
12
13/* Enable debug on custom module */
14#define MY_DBG_MODULE               LWESP_DBG_ON
Debug usage within middleware
1#include "lwesp/lwesp_debug.h"
2
3/*
4 * Print debug message to the screen
5 * Trace message will be printed as it is enabled in types
6 * while state message will not be printed.
7 */
8LWESP_DEBUGF(MY_DBG_MODULE | LWESP_DBG_TYPE_TRACE, "This is trace message on my program\r\n");
9LWESP_DEBUGF(MY_DBG_MODULE | LWESP_DBG_TYPE_STATE, "This is state message on my program\r\n");
group LWESP_DEBUG

Debug support module to track library flow.

Debug levels

List of debug levels

LWESP_DBG_LVL_ALL

Print all messages of all types

LWESP_DBG_LVL_WARNING

Print warning and upper messages

LWESP_DBG_LVL_DANGER

Print danger errors

LWESP_DBG_LVL_SEVERE

Print severe problems affecting program flow

LWESP_DBG_LVL_MASK

Mask for getting debug level

Debug types

List of debug types

LWESP_DBG_TYPE_TRACE

Debug trace messages for program flow

LWESP_DBG_TYPE_STATE

Debug state messages (such as state machines)

LWESP_DBG_TYPE_ALL

All debug types

Defines

LWESP_DBG_ON

Indicates debug is enabled

LWESP_DBG_OFF

Indicates debug is disabled

LWESP_DEBUGF(c, fmt, ...)

Print message to the debug “window” if enabled.

Parameters
  • c[in] Condition if debug of specific type is enabled

  • fmt[in] Formatted string for debug

  • ...[in] Variable parameters for formatted string

LWESP_DEBUGW(c, cond, fmt, ...)

Print message to the debug “window” if enabled when specific condition is met.

Parameters
  • c[in] Condition if debug of specific type is enabled

  • cond[in] Debug only if this condition is true

  • fmt[in] Formatted string for debug

  • ...[in] Variable parameters for formatted string

Dynamic Host Configuration Protocol
group LWESP_DHCP

DHCP config.

Functions

lwespr_t lwesp_dhcp_set_config(uint8_t sta, uint8_t ap, uint8_t en, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Configure DHCP settings for station or access point (or both)

Configuration changes will be saved in the NVS area of ESP device.

Parameters
  • sta[in] Set to 1 to affect station DHCP configuration, set to 0 to keep current setup

  • ap[in] Set to 1 to affect access point DHCP configuration, set to 0 to keep current setup

  • en[in] Set to 1 to enable DHCP, or 0 to disable (static IP)

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

Domain Name System
group LWESP_DNS

Domain name server.

Functions

lwespr_t lwesp_dns_gethostbyname(const char *host, lwesp_ip_t *const ip, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get IP address from host name.

Parameters
  • host[in] Pointer to host name to get IP for

  • ip[out] Pointer to lwesp_ip_t variable to save IP

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_dns_get_config(lwesp_ip_t *s1, lwesp_ip_t *s2, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get the DNS server configuration.

Retrive configuration saved in the NVS area of ESP device.

Parameters
  • s1[out] First server IP address in lwesp_ip_t format, set to 0.0.0.0 if not used

  • s2[out] Second server IP address in lwesp_ip_t format, set to to 0.0.0.0 if not used. Address s1 cannot be the same as s2

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_dns_set_config(uint8_t en, const char *s1, const char *s2, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Enable or disable custom DNS server configuration.

Configuration changes will be saved in the NVS area of ESP device.

Parameters
  • en[in] Set to 1 to enable, 0 to disable custom DNS configuration. When disabled, default DNS servers are used as proposed by ESP AT commands firmware

  • s1[in] First server IP address in string format, set to NULL if not used

  • s2[in] Second server IP address in string format, set to NULL if not used. Address s1 cannot be the same as s2

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

Event management
group LWESP_EVT

Event helper functions.

Reset detected

Event helper functions for LWESP_EVT_RESET_DETECTED event

uint8_t lwesp_evt_reset_detected_is_forced(lwesp_evt_t *cc)

Check if detected reset was forced by user.

Parameters

cc[in] Event handle

Returns

1 if forced by user, 0 otherwise

Reset event

Event helper functions for LWESP_EVT_RESET event

lwespr_t lwesp_evt_reset_get_result(lwesp_evt_t *cc)

Get reset sequence operation status.

Parameters

cc[in] Event data

Returns

Member of lwespr_t enumeration

Restore event

Event helper functions for LWESP_EVT_RESTORE event

lwespr_t lwesp_evt_restore_get_result(lwesp_evt_t *cc)

Get restore sequence operation status.

Parameters

cc[in] Event data

Returns

Member of lwespr_t enumeration

Access point or station IP or MAC

Event helper functions for LWESP_EVT_AP_IP_STA event

lwesp_mac_t *lwesp_evt_ap_ip_sta_get_mac(lwesp_evt_t *cc)

Get MAC address from station.

Parameters

cc[in] Event handle

Returns

MAC address

lwesp_ip_t *lwesp_evt_ap_ip_sta_get_ip(lwesp_evt_t *cc)

Get IP address from station.

Parameters

cc[in] Event handle

Returns

IP address

Connected station to access point

Event helper functions for LWESP_EVT_AP_CONNECTED_STA event

lwesp_mac_t *lwesp_evt_ap_connected_sta_get_mac(lwesp_evt_t *cc)

Get MAC address from connected station.

Parameters

cc[in] Event handle

Returns

MAC address

Disconnected station from access point

Event helper functions for LWESP_EVT_AP_DISCONNECTED_STA event

lwesp_mac_t *lwesp_evt_ap_disconnected_sta_get_mac(lwesp_evt_t *cc)

Get MAC address from disconnected station.

Parameters

cc[in] Event handle

Returns

MAC address

Connection data received

Event helper functions for LWESP_EVT_CONN_RECV event

lwesp_pbuf_p lwesp_evt_conn_recv_get_buff(lwesp_evt_t *cc)

Get buffer from received data.

Parameters

cc[in] Event handle

Returns

Buffer handle

lwesp_conn_p lwesp_evt_conn_recv_get_conn(lwesp_evt_t *cc)

Get connection handle for receive.

Parameters

cc[in] Event handle

Returns

Connection handle

Connection data send

Event helper functions for LWESP_EVT_CONN_SEND event

lwesp_conn_p lwesp_evt_conn_send_get_conn(lwesp_evt_t *cc)

Get connection handle for data sent event.

Parameters

cc[in] Event handle

Returns

Connection handle

size_t lwesp_evt_conn_send_get_length(lwesp_evt_t *cc)

Get number of bytes sent on connection.

Parameters

cc[in] Event handle

Returns

Number of bytes sent

lwespr_t lwesp_evt_conn_send_get_result(lwesp_evt_t *cc)

Check if connection send was successful.

Parameters

cc[in] Event handle

Returns

Member of lwespr_t enumeration

Connection active

Event helper functions for LWESP_EVT_CONN_ACTIVE event

lwesp_conn_p lwesp_evt_conn_active_get_conn(lwesp_evt_t *cc)

Get connection handle.

Parameters

cc[in] Event handle

Returns

Connection handle

uint8_t lwesp_evt_conn_active_is_client(lwesp_evt_t *cc)

Check if new connection is client.

Parameters

cc[in] Event handle

Returns

1 if client, 0 otherwise

Connection close event

Event helper functions for LWESP_EVT_CONN_CLOSE event

lwesp_conn_p lwesp_evt_conn_close_get_conn(lwesp_evt_t *cc)

Get connection handle.

Parameters

cc[in] Event handle

Returns

Connection handle

uint8_t lwesp_evt_conn_close_is_client(lwesp_evt_t *cc)

Check if just closed connection was client.

Parameters

cc[in] Event handle

Returns

1 if client, 0 otherwise

uint8_t lwesp_evt_conn_close_is_forced(lwesp_evt_t *cc)

Check if connection close even was forced by user.

Parameters

cc[in] Event handle

Returns

1 if forced, 0 otherwise

lwespr_t lwesp_evt_conn_close_get_result(lwesp_evt_t *cc)

Get connection close event result.

Parameters

cc[in] Event handle

Returns

Member of lwespr_t enumeration

Connection poll

Event helper functions for LWESP_EVT_CONN_POLL event

lwesp_conn_p lwesp_evt_conn_poll_get_conn(lwesp_evt_t *cc)

Get connection handle.

Parameters

cc[in] Event handle

Returns

Connection handle

Connection error

Event helper functions for LWESP_EVT_CONN_ERROR event

lwespr_t lwesp_evt_conn_error_get_error(lwesp_evt_t *cc)

Get connection error type.

Parameters

cc[in] Event handle

Returns

Member of lwespr_t enumeration

lwesp_conn_type_t lwesp_evt_conn_error_get_type(lwesp_evt_t *cc)

Get connection type.

Parameters

cc[in] Event handle

Returns

Member of lwespr_t enumeration

const char *lwesp_evt_conn_error_get_host(lwesp_evt_t *cc)

Get connection host.

Parameters

cc[in] Event handle

Returns

Host name for connection

lwesp_port_t lwesp_evt_conn_error_get_port(lwesp_evt_t *cc)

Get connection port.

Parameters

cc[in] Event handle

Returns

Host port number

void *lwesp_evt_conn_error_get_arg(lwesp_evt_t *cc)

Get user argument.

Parameters

cc[in] Event handle

Returns

User argument

List access points

Event helper functions for LWESP_EVT_STA_LIST_AP event

lwespr_t lwesp_evt_sta_list_ap_get_result(lwesp_evt_t *cc)

Get command success result.

Parameters

cc[in] Event handle

Returns

Member of lwespr_t enumeration

lwesp_ap_t *lwesp_evt_sta_list_ap_get_aps(lwesp_evt_t *cc)

Get access points.

Parameters

cc[in] Event handle

Returns

Pointer to lwesp_ap_t with first access point description

size_t lwesp_evt_sta_list_ap_get_length(lwesp_evt_t *cc)

Get number of access points found.

Parameters

cc[in] Event handle

Returns

Number of access points found

Join access point

Event helper functions for LWESP_EVT_STA_JOIN_AP event

lwespr_t lwesp_evt_sta_join_ap_get_result(lwesp_evt_t *cc)

Get command success result.

Parameters

cc[in] Event handle

Returns

Member of lwespr_t enumeration

Get access point info

Event helper functions for LWESP_EVT_STA_INFO_AP event

lwespr_t lwesp_evt_sta_info_ap_get_result(lwesp_evt_t *cc)

Get command result.

Parameters

cc[in] Event handle

Returns

Member of lwespr_t enumeration

const char *lwesp_evt_sta_info_ap_get_ssid(lwesp_evt_t *cc)

Get current AP name.

Parameters

cc[in] Event handle

Returns

AP name

lwesp_mac_t lwesp_evt_sta_info_ap_get_mac(lwesp_evt_t *cc)

Get current AP MAC address.

Parameters

cc[in] Event handle

Returns

AP MAC address

uint8_t lwesp_evt_sta_info_ap_get_channel(lwesp_evt_t *cc)

Get current AP channel.

Parameters

cc[in] Event handle

Returns

AP channel

int16_t lwesp_evt_sta_info_ap_get_rssi(lwesp_evt_t *cc)

Get current AP rssi.

Parameters

cc[in] Event handle

Returns

AP rssi

Get host address by name

Event helper functions for LWESP_EVT_DNS_HOSTBYNAME event

lwespr_t lwesp_evt_dns_hostbyname_get_result(lwesp_evt_t *cc)

Get resolve result.

Parameters

cc[in] Event handle

Returns

Member of lwespr_t enumeration

const char *lwesp_evt_dns_hostbyname_get_host(lwesp_evt_t *cc)

Get hostname used to resolve IP address.

Parameters

cc[in] Event handle

Returns

Hostname

lwesp_ip_t *lwesp_evt_dns_hostbyname_get_ip(lwesp_evt_t *cc)

Get IP address from DNS function.

Parameters

cc[in] Event handle

Returns

IP address

Ping

Event helper functions for LWESP_EVT_PING event

lwespr_t lwesp_evt_ping_get_result(lwesp_evt_t *cc)

Get ping status.

Parameters

cc[in] Event handle

Returns

Member of lwespr_t enumeration

const char *lwesp_evt_ping_get_host(lwesp_evt_t *cc)

Get hostname used to ping.

Parameters

cc[in] Event handle

Returns

Hostname

uint32_t lwesp_evt_ping_get_time(lwesp_evt_t *cc)

Get time required for ping.

Parameters

cc[in] Event handle

Returns

Ping time

Web Server

Event helper functions for LWESP_EVT_WEBSERVER event

uint8_t lwesp_evt_webserver_get_status(lwesp_evt_t *cc)

Get web server status.

Parameters

cc[in] Event handle

Returns

Web server status code

Server

Event helper functions for LWESP_EVT_SERVER event

lwespr_t lwesp_evt_server_get_result(lwesp_evt_t *cc)

Get server command result.

Parameters

cc[in] Event handle

Returns

Member of lwespr_t enumeration

lwesp_port_t lwesp_evt_server_get_port(lwesp_evt_t *cc)

Get port for server operation.

Parameters

cc[in] Event handle

Returns

Server port

uint8_t lwesp_evt_server_is_enable(lwesp_evt_t *cc)

Check if operation was to enable or disable server.

Parameters

cc[in] Event handle

Returns

1 if enable, 0 otherwise

Typedefs

typedef lwespr_t (*lwesp_evt_fn)(struct lwesp_evt *evt)

Event function prototype.

Param evt

[in] Callback event data

Return

lwespOK on success, member of lwespr_t otherwise

Enums

enum lwesp_evt_type_t

List of possible callback types received to user.

Values:

enumerator LWESP_EVT_INIT_FINISH

Initialization has been finished at this point

enumerator LWESP_EVT_RESET_DETECTED

Device reset detected

enumerator LWESP_EVT_RESET

Device reset operation finished

enumerator LWESP_EVT_RESTORE

Device restore operation finished

enumerator LWESP_EVT_CMD_TIMEOUT

Timeout on command. When application receives this event, it may reset system as there was (maybe) a problem in device

enumerator LWESP_EVT_DEVICE_PRESENT

Notification when device present status changes

enumerator LWESP_EVT_AT_VERSION_NOT_SUPPORTED

Library does not support firmware version on ESP device.

enumerator LWESP_EVT_CONN_RECV

Connection data received

enumerator LWESP_EVT_CONN_SEND

Connection data send

enumerator LWESP_EVT_CONN_ACTIVE

Connection just became active

enumerator LWESP_EVT_CONN_ERROR

Client connection start was not successful

enumerator LWESP_EVT_CONN_CLOSE

Connection close event. Check status if successful

enumerator LWESP_EVT_CONN_POLL

Poll for connection if there are any changes

enumerator LWESP_EVT_SERVER

Server status changed

enumerator LWESP_EVT_KEEP_ALIVE

Generic keep-alive event type, used as periodic timeout. Optionally enabled with LWESP_CFG_KEEP_ALIVE

enumerator LWESP_EVT_WIFI_CONNECTED

Station just connected to AP

enumerator LWESP_EVT_WIFI_GOT_IP

Station has valid IP. When this event is received to application, no IP has been read from device. Stack will proceed with IP read from device and will later send LWESP_EVT_WIFI_IP_ACQUIRED event

enumerator LWESP_EVT_WIFI_DISCONNECTED

Station just disconnected from AP

enumerator LWESP_EVT_WIFI_IP_ACQUIRED

Station IP address acquired. At this point, valid IP address has been received from device. Application may use lwesp_sta_copy_ip function to read it

enumerator LWESP_EVT_STA_LIST_AP

Station listed APs event

enumerator LWESP_EVT_STA_JOIN_AP

Join to access point

enumerator LWESP_EVT_STA_INFO_AP

Station AP info (name, mac, channel, rssi)

enumerator LWESP_EVT_AP_CONNECTED_STA

New station just connected to ESP’s access point

enumerator LWESP_EVT_AP_DISCONNECTED_STA

New station just disconnected from ESP’s access point

enumerator LWESP_EVT_AP_IP_STA

New station just received IP from ESP’s access point

enumerator LWESP_EVT_DNS_HOSTBYNAME

DNS domain service finished

enumerator LWESP_EVT_PING

PING service finished

enumerator LWESP_EVT_WEBSERVER

Web server events

Functions

lwespr_t lwesp_evt_register(lwesp_evt_fn fn)

Register event function for global (non-connection based) events.

Parameters

fn[in] Callback function to call on specific event

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_evt_unregister(lwesp_evt_fn fn)

Unregister callback function for global (non-connection based) events.

Note

Function must be first registered using lwesp_evt_register

Parameters

fn[in] Callback function to remove from event list

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwesp_evt_type_t lwesp_evt_get_type(lwesp_evt_t *cc)

Get event type.

Parameters

cc[in] Event handle

Returns

Event type. Member of lwesp_evt_type_t enumeration

struct lwesp_evt_t
#include <lwesp_typedefs.h>

Global callback structure to pass as parameter to callback function.

Public Members

lwesp_evt_type_t type

Callback type

uint8_t forced

Set to 1 if reset forced by user

Set to 1 if connection action was forced when active: 1 = CLIENT, 0 = SERVER when closed, 1 = CMD, 0 = REMOTE

struct lwesp_evt_t::[anonymous]::[anonymous] reset_detected

Reset occurred. Use with LWESP_EVT_RESET_DETECTED event

lwespr_t res

Reset operation result

Restore operation result

Send data result

Result of close event. Set to lwespOK on success

Status of command

Result of command

struct lwesp_evt_t::[anonymous]::[anonymous] reset

Reset sequence finish. Use with LWESP_EVT_RESET event

struct lwesp_evt_t::[anonymous]::[anonymous] restore

Restore sequence finish. Use with LWESP_EVT_RESTORE event

lwesp_conn_p conn

Connection where data were received

Connection where data were sent

Pointer to connection

Set connection pointer

lwesp_pbuf_p buff

Pointer to received data

struct lwesp_evt_t::[anonymous]::[anonymous] conn_data_recv

Network data received. Use with LWESP_EVT_CONN_RECV event

size_t sent

Number of bytes sent on connection

struct lwesp_evt_t::[anonymous]::[anonymous] conn_data_send

Data send. Use with LWESP_EVT_CONN_SEND event

const char *host

Host to use for connection

Host name for DNS lookup

Host name for ping

lwesp_port_t port

Remote port used for connection

Server port number

lwesp_conn_type_t type

Connection type

void *arg

Connection user argument

lwespr_t err

Error value

struct lwesp_evt_t::[anonymous]::[anonymous] conn_error

Client connection start error. Use with LWESP_EVT_CONN_ERROR event

uint8_t client

Set to 1 if connection is/was client mode

struct lwesp_evt_t::[anonymous]::[anonymous] conn_active_close

Process active and closed statuses at the same time. Use with LWESP_EVT_CONN_ACTIVE or LWESP_EVT_CONN_CLOSE events

struct lwesp_evt_t::[anonymous]::[anonymous] conn_poll

Polling active connection to check for timeouts. Use with LWESP_EVT_CONN_POLL event

uint8_t en

Status to enable/disable server

struct lwesp_evt_t::[anonymous]::[anonymous] server

Server change event. Use with LWESP_EVT_SERVER event

lwesp_ap_t *aps

Pointer to access points

size_t len

Number of access points found

struct lwesp_evt_t::[anonymous]::[anonymous] sta_list_ap

Station list access points. Use with LWESP_EVT_STA_LIST_AP event

struct lwesp_evt_t::[anonymous]::[anonymous] sta_join_ap

Join to access point. Use with LWESP_EVT_STA_JOIN_AP event

lwesp_sta_info_ap_t *info

AP info of current station

struct lwesp_evt_t::[anonymous]::[anonymous] sta_info_ap

Current AP informations. Use with LWESP_EVT_STA_INFO_AP event

lwesp_mac_t *mac

Station MAC address

struct lwesp_evt_t::[anonymous]::[anonymous] ap_conn_disconn_sta

A new station connected or disconnected to ESP’s access point. Use with LWESP_EVT_AP_CONNECTED_STA or LWESP_EVT_AP_DISCONNECTED_STA events

lwesp_ip_t *ip

Station IP address

Pointer to IP result

struct lwesp_evt_t::[anonymous]::[anonymous] ap_ip_sta

Station got IP address from ESP’s access point. Use with LWESP_EVT_AP_IP_STA event

struct lwesp_evt_t::[anonymous]::[anonymous] dns_hostbyname

DNS domain service finished. Use with LWESP_EVT_DNS_HOSTBYNAME event

uint32_t time

Time required for ping. Valid only if operation succedded

struct lwesp_evt_t::[anonymous]::[anonymous] ping

Ping finished. Use with LWESP_EVT_PING event

uint8_t code

Result of command

struct lwesp_evt_t::[anonymous]::[anonymous] ws_status

Ping finished. Use with LWESP_EVT_PING event

union lwesp_evt_t::[anonymous] evt

Callback event union

Hostname
group LWESP_HOSTNAME

Hostname API.

Functions

lwespr_t lwesp_hostname_set(const char *hostname, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Set hostname of WiFi station.

Parameters
  • hostname[in] Name of ESP host

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_hostname_get(char *hostname, size_t size, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get hostname of WiFi station.

Parameters
  • hostname[in] Pointer to output variable holding memory to save hostname

  • size[in] Size of buffer for hostname. Size includes memory for NULL termination

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

Input module

Input module is used to input received data from ESP device to LwESP middleware part. 2 processing options are possible:

Tip

Direct or indirect processing mode is select by setting LWESP_CFG_INPUT_USE_PROCESS configuration value.

Indirect processing

With indirect processing mode, every received character from ESP physical device is written to intermediate buffer between low-level driver and processing thread.

Function lwesp_input() is used to write data to buffer, which is later processed by processing thread.

Indirect processing mode allows embedded systems to write received data to buffer from interrupt context (outside threads). As a drawback, its performance is decreased as it involves copying every receive character to intermediate buffer, and may also introduce RAM memory footprint increase.

Direct processing

Direct processing is targeting more advanced host controllers, like STM32 or WIN32 implementation use. It is developed with DMA support in mind, allowing low-level drivers to skip intermediate data buffer and process input bytes directly.

Note

When using this mode, function lwesp_input_process() must be used and it may only be called from thread context. Processing of input bytes is done in low-level input thread, started by application.

Tip

Check Porting guide for implementation examples.

group LWESP_INPUT

Input function for received data.

Functions

lwespr_t lwesp_input(const void *data, size_t len)

Write data to input buffer.

Note

LWESP_CFG_INPUT_USE_PROCESS must be disabled to use this function

Parameters
  • data[in] Pointer to data to write

  • len[in] Number of data elements in units of bytes

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_input_process(const void *data, size_t len)

Process input data directly without writing it to input buffer.

Note

This function may only be used when in OS mode, where single thread is dedicated for input read of AT receive

Note

LWESP_CFG_INPUT_USE_PROCESS must be enabled to use this function

Parameters
  • data[in] Pointer to received data to be processed

  • len[in] Length of data to process in units of bytes

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

Multicast DNS
group LWESP_MDNS

mDNS function

Functions

lwespr_t lwesp_mdns_set_config(uint8_t en, const char *host, const char *server, lwesp_port_t port, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Configure mDNS parameters with hostname and server.

Parameters
  • en[in] Status to enable 1 or disable 0 mDNS function

  • host[in] mDNS host name

  • server[in] mDNS server name

  • port[in] mDNS server port number

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

Memory manager
group LWESP_MEM

Dynamic memory manager.

Functions

uint8_t lwesp_mem_assignmemory(const lwesp_mem_region_t *regions, size_t size)

Assign memory region(s) for allocation functions.

Note

You can allocate multiple regions by assigning start address and region size in units of bytes

Note

Function is not available when LWESP_CFG_MEM_CUSTOM is 1

Parameters
  • regions[in] Pointer to list of regions to use for allocations

  • len[in] Number of regions to use

Returns

1 on success, 0 otherwise

void *lwesp_mem_malloc(size_t size)

Allocate memory of specific size.

Note

Function is not available when LWESP_CFG_MEM_CUSTOM is 1 and must be implemented by user

Parameters

size[in] Number of bytes to allocate

Returns

Memory address on success, NULL otherwise

void *lwesp_mem_realloc(void *ptr, size_t size)

Reallocate memory to specific size.

Note

After new memory is allocated, content of old one is copied to new memory

Note

Function is not available when LWESP_CFG_MEM_CUSTOM is 1 and must be implemented by user

Parameters
Returns

Memory address on success, NULL otherwise

void *lwesp_mem_calloc(size_t num, size_t size)

Allocate memory of specific size and set memory to zero.

Note

Function is not available when LWESP_CFG_MEM_CUSTOM is 1 and must be implemented by user

Parameters
  • num[in] Number of elements to allocate

  • size[in] Size of each element

Returns

Memory address on success, NULL otherwise

void lwesp_mem_free(void *ptr)

Free memory.

Note

Function is not available when LWESP_CFG_MEM_CUSTOM is 1 and must be implemented by user

Parameters

ptr[in] Pointer to memory previously returned using lwesp_mem_malloc, lwesp_mem_calloc or lwesp_mem_realloc functions

uint8_t lwesp_mem_free_s(void **ptr)

Free memory in safe way by invalidating pointer after freeing.

Parameters

ptr[in] Pointer to pointer to allocated memory to free

Returns

1 on success, 0 otherwise

struct lwesp_mem_region_t
#include <lwesp_mem.h>

Single memory region descriptor.

Public Members

void *start_addr

Start address of region

size_t size

Size in units of bytes of region

Packet buffer

Packet buffer (or pbuf) is buffer manager to handle received data from any connection. It is optimized to construct big buffer of smaller chunks of fragmented data as received bytes are not always coming as single packet.

Pbuf block diagram
Block diagram of pbuf chain

Block diagram of pbuf chain

Image above shows structure of pbuf chain. Each pbuf consists of:

  • Pointer to next pbuf, or NULL when it is last in chain

  • Length of current packet length

  • Length of current packet and all next in chain

    • If pbuf is last in chain, total length is the same as current packet length

  • Reference counter, indicating how many pointers point to current pbuf

  • Actual buffer data

Top image shows 3 pbufs connected to single chain. There are 2 custom pointer variables to point at different pbuf structures. Second pbuf has reference counter set to 2, as 2 variables point to it:

  • next of pbuf 1 is the first one

  • User variable 2 is the second one

Block structure

Block number

Next pbuf

Block size

Total size in chain

Reference counter

Block 1

Block 2

150

550

1

Block 2

Block 3

130

400

2

Block 3

NULL

270

270

1

Reference counter

Reference counter holds number of references (or variables) pointing to this block. It is used to properly handle memory free operation, especially when pbuf is used by lib core and application layer.

Note

If there would be no reference counter information and application would free memory while another part of library still uses its reference, application would invoke undefined behavior and system could crash instantly.

When application tries to free pbuf chain as on first image, it would normally call lwesp_pbuf_free() function. That would:

  • Decrease reference counter by 1

  • If reference counter == 0, it removes it from chain list and frees packet buffer memory

  • If reference counter != 0 after decrease, it stops free procedure

  • Go to next pbuf in chain and repeat steps

As per first example, result of freeing from user variable 1 would look similar to image and table below. First block (blue) had reference counter set to 1 prior freeing operation. It was successfully removed as user variable 1 was the only one pointing to it, while second (green) block had reference counter set to 2, preventing free operation.

Block diagram of pbuf chain after free from *user variable 1*

Block diagram of pbuf chain after free from user variable 1

Block diagram of pbuf chain after free from user variable 1

Block number

Next pbuf

Block size

Total size in chain

Reference counter

Block 2

Block 3

130

400

1

Block 3

NULL

270

270

1

Note

Block 1 has been successfully freed, but since block 2 had reference counter set to 2 before, it was only decreased by 1 to a new value 1 and free operation stopped instead. User variable 2 is still using pbuf starting at block 2 and must manually call lwesp_pbuf_free() to free it.

Concatenating vs chaining

This section will explain difference between concat and chain operations. Both operations link 2 pbufs together in a chain of pbufs, difference is that chain operation increases reference counter to linked pbuf, while concat keeps reference counter at its current status.

Different pbufs, each pointed to by its own variable

Different pbufs, each pointed to by its own variable

Concat operation

Concat operation shall be used when 2 pbufs are linked together and reference to second is no longer used.

Structure after pbuf concat

Structure after pbuf concat

After concating 2 pbufs together, reference counter of second is still set to 1, however we can see that 2 pointers point to second pbuf.

Note

After application calls lwesp_pbuf_cat(), it must not use pointer which points to second pbuf. This would invoke undefined behavior if one pointer tries to free memory while second still points to it.

An example code showing proper usage of concat operation:

Packet buffer concat example
 1lwesp_pbuf_p a, b;
 2
 3/* Create 2 pbufs of different sizes */
 4a = lwesp_pbuf_new(10);
 5b = lwesp_pbuf_new(20);
 6
 7/* Link them together with concat operation */
 8/* Reference on b will stay as is, won't be increased */
 9lwesp_pbuf_cat(a, b);
10
11/*
12 * Operating with b variable has from now on undefined behavior,
13 * application shall stop using variable b to access pbuf.
14 *
15 * The best way would be to set b reference to NULL
16 */
17b = NULL;
18
19/*
20 * When application doesn't need pbufs anymore,
21 * free a and it will also free b
22 */
23lwesp_pbuf_free(a);
Chain operation

Chain operation shall be used when 2 pbufs are linked together and reference to second is still required.

Structure after pbuf chain

Structure after pbuf chain

After chainin 2 pbufs together, reference counter of second is increased by 1, which allows application to reference second pbuf separatelly.

Note

After application calls lwesp_pbuf_chain(), it also has to manually free its reference using lwesp_pbuf_free() function. Forgetting to free pbuf invokes memory leak

An example code showing proper usage of chain operation:

Packet buffer chain example
 1lwesp_pbuf_p a, b;
 2
 3/* Create 2 pbufs of different sizes */
 4a = lwesp_pbuf_new(10);
 5b = lwesp_pbuf_new(20);
 6
 7/* Chain both pbufs together */
 8/* This will increase reference on b as 2 variables now point to it */
 9lwesp_pbuf_chain(a, b);
10
11/*
12 * When application does not need a anymore, it may free it
13
14 * This will free only pbuf a, as pbuf b has now 2 references:
15 *  - one from pbuf a
16 *  - one from variable b
17 */
18
19/* If application calls this, it will free only first pbuf */
20/* As there is link to b pbuf somewhere */
21lwesp_pbuf_free(a);
22
23/* Reset a variable, not used anymore */
24a = NULL;
25
26/*
27 * At this point, b is still valid memory block,
28 * but when application doesn't need it anymore,
29 * it should free it, otherwise memory leak appears
30 */
31lwesp_pbuf_free(b);
32
33/* Reset b variable */
34b = NULL;
Extract pbuf data

Each pbuf holds some amount of data bytes. When multiple pbufs are linked together (either chained or concated), blocks of raw data are not linked to contiguous memory block. It is necessary to process block by block manually.

An example code showing proper reading of any pbuf:

Packet buffer data extraction
 1const void* data;
 2size_t pos, len;
 3lwesp_pbuf_p a, b, c;
 4
 5const char str_a[] = "This is one long";
 6const char str_a[] = "string. We want to save";
 7const char str_a[] = "chain of pbufs to file";
 8
 9/* Create pbufs to hold these strings */
10a = lwesp_pbuf_new(strlen(str_a));
11b = lwesp_pbuf_new(strlen(str_b));
12c = lwesp_pbuf_new(strlen(str_c));
13
14/* Write data to pbufs */
15lwesp_pbuf_take(a, str_a, strlen(str_a), 0);
16lwesp_pbuf_take(b, str_b, strlen(str_b), 0);
17lwesp_pbuf_take(c, str_c, strlen(str_c), 0);
18
19/* Connect pbufs together */
20lwesp_pbuf_chain(a, b);
21lwesp_pbuf_chain(a, c);
22
23/*
24 * pbuf a now contains chain of b and c together
25 * and at this point application wants to print (or save) data from chained pbuf
26 *
27 * Process pbuf by pbuf with code below
28 */
29
30/*
31 * Get linear address of current pbuf at specific offset
32 * Function will return pointer to memory address at specific position
33 * and `len` will hold length of data block
34 */
35pos = 0;
36while ((data = lwesp_pbuf_get_linear_addr(a, pos, &len)) != NULL) {
37    /* Custom process function... */
38    /* Process data with data pointer and block length */
39    process_data(data, len);
40    printf("Str: %.*s", len, data);
41
42    /* Increase offset position for next block */
43    pos += len;
44}
45
46/* Call free only on a pbuf. Since it is chained, b and c will be freed too */
47lwesp_pbuf_free(a);
group LWESP_PBUF

Packet buffer manager.

Typedefs

typedef struct lwesp_pbuf *lwesp_pbuf_p

Pointer to lwesp_pbuf_t structure.

Functions

lwesp_pbuf_p lwesp_pbuf_new(size_t len)

Allocate packet buffer for network data of specific size.

Parameters

len[in] Length of payload memory to allocate

Returns

Pointer to allocated memory, NULL otherwise

size_t lwesp_pbuf_free(lwesp_pbuf_p pbuf)

Free previously allocated packet buffer.

Parameters

pbuf[in] Packet buffer to free

Returns

Number of freed pbufs from head

void *lwesp_pbuf_data(const lwesp_pbuf_p pbuf)

Get data pointer from packet buffer.

Parameters

pbuf[in] Packet buffer

Returns

Pointer to data buffer on success, NULL otherwise

size_t lwesp_pbuf_length(const lwesp_pbuf_p pbuf, uint8_t tot)

Get length of packet buffer.

Parameters
  • pbuf[in] Packet buffer to get length for

  • tot[in] Set to 1 to return total packet chain length or 0 to get only first packet length

Returns

Length of data in units of bytes

uint8_t lwesp_pbuf_set_length(lwesp_pbuf_p pbuf, size_t new_len)

Set new length of pbuf.

Note

New length can only be smaller than existing one. It has no effect when greater than existing one

Note

This function can be used on single-chain pbufs only, without next pbuf in chain

Parameters
  • pbuf[in] Pbuf to make it smaller

  • new_len[in] New length in units of bytes

Returns

1 on success, 0 otherwise

lwespr_t lwesp_pbuf_take(lwesp_pbuf_p pbuf, const void *data, size_t len, size_t offset)

Copy user data to chain of pbufs.

Parameters
  • pbuf[in] First pbuf in chain to start copying to

  • data[in] Input data to copy to pbuf memory

  • len[in] Length of input data to copy

  • offset[in] Start offset in pbuf where to start copying

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

size_t lwesp_pbuf_copy(lwesp_pbuf_p pbuf, void *data, size_t len, size_t offset)

Copy memory from pbuf to user linear memory.

Parameters
  • pbuf[in] Pbuf to copy from

  • data[out] User linear memory to copy to

  • len[in] Length of data in units of bytes

  • offset[in] Possible start offset in pbuf

Returns

Number of bytes copied

lwespr_t lwesp_pbuf_cat(lwesp_pbuf_p head, const lwesp_pbuf_p tail)

Concatenate 2 packet buffers together to one big packet.

See

lwesp_pbuf_chain

Note

After tail pbuf has been added to head pbuf chain, it must not be referenced by user anymore as it is now completely controlled by head pbuf. In simple words, when user calls this function, it should not call lwesp_pbuf_free function anymore, as it might make memory undefined for head pbuf.

Parameters
  • head[in] Head packet buffer to append new pbuf to

  • tail[in] Tail packet buffer to append to head pbuf

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_pbuf_chain(lwesp_pbuf_p head, lwesp_pbuf_p tail)

Chain 2 pbufs together. Similar to lwesp_pbuf_cat but now new reference is done from head pbuf to tail pbuf.

See

lwesp_pbuf_cat

Note

After this function call, user must call lwesp_pbuf_free to remove its reference to tail pbuf and allow control to head pbuf: lwesp_pbuf_free(tail)

Parameters
  • head[in] Head packet buffer to append new pbuf to

  • tail[in] Tail packet buffer to append to head pbuf

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwesp_pbuf_p lwesp_pbuf_unchain(lwesp_pbuf_p head)

Unchain first pbuf from list and return second one.

tot_len and len fields are adjusted to reflect new values and reference counter is as is

Note

After unchain, user must take care of both pbufs (head and new returned one)

Parameters

head[in] First pbuf in chain to remove from chain

Returns

Next pbuf after head

lwespr_t lwesp_pbuf_ref(lwesp_pbuf_p pbuf)

Increment reference count on pbuf.

Parameters

pbuf[in] pbuf to increase reference

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

uint8_t lwesp_pbuf_get_at(const lwesp_pbuf_p pbuf, size_t pos, uint8_t *el)

Get value from pbuf at specific position.

Parameters
  • pbuf[in] Pbuf used to get data from

  • pos[in] Position at which to get element

  • el[out] Output variable to save element value at desired position

Returns

1 on success, 0 otherwise

size_t lwesp_pbuf_memcmp(const lwesp_pbuf_p pbuf, const void *data, size_t len, size_t offset)

Compare pbuf memory with memory from data.

See

lwesp_pbuf_strcmp

Note

Compare is done on entire pbuf chain

Parameters
  • pbuf[in] Pbuf used to compare with data memory

  • data[in] Actual data to compare with

  • len[in] Length of input data in units of bytes

  • offset[in] Start offset to use when comparing data

Returns

0 if equal, LWESP_SIZET_MAX if memory/offset too big or anything between if not equal

size_t lwesp_pbuf_strcmp(const lwesp_pbuf_p pbuf, const char *str, size_t offset)

Compare pbuf memory with input string.

See

lwesp_pbuf_memcmp

Note

Compare is done on entire pbuf chain

Parameters
  • pbuf[in] Pbuf used to compare with data memory

  • str[in] String to be compared with pbuf

  • offset[in] Start memory offset in pbuf

Returns

0 if equal, LWESP_SIZET_MAX if memory/offset too big or anything between if not equal

size_t lwesp_pbuf_memfind(const lwesp_pbuf_p pbuf, const void *data, size_t len, size_t off)

Find desired needle in a haystack.

See

lwesp_pbuf_strfind

Parameters
  • pbuf[in] Pbuf used as haystack

  • needle[in] Data memory used as needle

  • len[in] Length of needle memory

  • off[in] Starting offset in pbuf memory

Returns

LWESP_SIZET_MAX if no match or position where in pbuf we have a match

size_t lwesp_pbuf_strfind(const lwesp_pbuf_p pbuf, const char *str, size_t off)

Find desired needle (str) in a haystack (pbuf)

See

lwesp_pbuf_memfind

Parameters
  • pbuf[in] Pbuf used as haystack

  • str[in] String to search for in pbuf

  • off[in] Starting offset in pbuf memory

Returns

LWESP_SIZET_MAX if no match or position where in pbuf we have a match

uint8_t lwesp_pbuf_advance(lwesp_pbuf_p pbuf, int len)

Advance pbuf payload pointer by number of len bytes. It can only advance single pbuf in a chain.

Note

When other pbufs are referencing current one, they are not adjusted in length and total length

Parameters
  • pbuf[in] Pbuf to advance

  • len[in] Number of bytes to advance. when negative is used, buffer size is increased only if it was decreased before

Returns

1 on success, 0 otherwise

lwesp_pbuf_p lwesp_pbuf_skip(lwesp_pbuf_p pbuf, size_t offset, size_t *new_offset)

Skip a list of pbufs for desired offset.

Note

Reference is not changed after return and user must not free the memory of new pbuf directly

Parameters
  • pbuf[in] Start of pbuf chain

  • offset[in] Offset in units of bytes to skip

  • new_offset[out] Pointer to output variable to save new offset in returned pbuf

Returns

New pbuf on success, NULL otherwise

void *lwesp_pbuf_get_linear_addr(const lwesp_pbuf_p pbuf, size_t offset, size_t *new_len)

Get linear offset address for pbuf from specific offset.

Note

Since pbuf memory can be fragmented in chain, you may need to call function multiple times to get memory for entire pbuf chain

Parameters
  • pbuf[in] Pbuf to get linear address

  • offset[in] Start offset from where to start

  • new_len[out] Length of memory returned by function

Returns

Pointer to memory on success, NULL otherwise

void lwesp_pbuf_set_ip(lwesp_pbuf_p pbuf, const lwesp_ip_t *ip, lwesp_port_t port)

Set IP address and port number for received data.

Parameters
  • pbuf[in] Packet buffer

  • ip[in] IP to assing to packet buffer

  • port[in] Port number to assign to packet buffer

void lwesp_pbuf_dump(lwesp_pbuf_p p, uint8_t seq)

Dump and debug pbuf chain.

Parameters
  • p[in] Head pbuf to dump

  • seq[in] Set to 1 to dump all pbufs in linked list or 0 to dump first one only

struct lwesp_pbuf_t
#include <lwesp_private.h>

Packet buffer structure.

Public Members

struct lwesp_pbuf *next

Next pbuf in chain list

size_t tot_len

Total length of pbuf chain

size_t len

Length of payload

size_t ref

Number of references to this structure

uint8_t *payload

Pointer to payload memory

lwesp_ip_t ip

Remote address for received IPD data

lwesp_port_t port

Remote port for received IPD data

Ping support
group LWESP_PING

Ping server and get response time.

Functions

lwespr_t lwesp_ping(const char *host, uint32_t *time, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Ping server and get response time from it.

Parameters
  • host[in] Host name to ping

  • time[out] Pointer to output variable to save ping time in units of milliseconds

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

Server
group LWESP_SERVER

Server mode.

Functions

lwespr_t lwesp_set_server(uint8_t en, lwesp_port_t port, uint16_t max_conn, uint16_t timeout, lwesp_evt_fn cb, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Enables or disables server mode.

Parameters
  • en[in] Set to 1 to enable server, 0 otherwise

  • port[in] Port number used to listen on. Must also be used when disabling server mode

  • max_conn[in] Number of maximal connections populated by server

  • timeout[in] Time used to automatically close the connection in units of seconds. Set to 0 to disable timeout feature (not recommended)

  • server_evt_fn[in] Connection callback function for new connections started as server

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

Smart config
group LWESP_SMART

SMART function on ESP device.

Functions

lwespr_t lwesp_smart_set_config(uint8_t en, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Configure SMART function on ESP device.

Parameters
  • en[in] Set to 1 to start SMART or 0 to stop SMART

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

Simple Network Time Protocol

ESP has built-in support for Simple Network Time Protocol (SNTP). It is support through middleware API calls for configuring servers and reading actual date and time.

Minimum SNTP example
 1#include "sntp.h"
 2#include "lwesp/lwesp.h"
 3
 4/**
 5 * \brief           Run SNTP
 6 */
 7void
 8sntp_gettime(void) {
 9    lwesp_datetime_t dt;
10
11    /* Enable SNTP with default configuration for NTP servers */
12    if (lwesp_sntp_set_config(1, 1, NULL, NULL, NULL, NULL, NULL, 1) == lwespOK) {
13        lwesp_delay(5000);
14
15        /* Get actual time and print it */
16        if (lwesp_sntp_gettime(&dt, NULL, NULL, 1) == lwespOK) {
17            printf("Date & time: %d.%d.%d, %d:%d:%d\r\n",
18                   (int)dt.date, (int)dt.month, (int)dt.year,
19                   (int)dt.hours, (int)dt.minutes, (int)dt.seconds);
20        }
21    }
22}
group LWESP_SNTP

Simple network time protocol supported by AT commands.

Functions

lwespr_t lwesp_sntp_set_config(uint8_t en, int8_t tz, const char *h1, const char *h2, const char *h3, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Configure SNTP mode parameters.

Parameters
  • en[in] Status whether SNTP mode is enabled or disabled on ESP device

  • tz[in] Timezone to use when SNTP acquires time, between -11 and 13

  • h1[in] Optional first SNTP server for time. Set to NULL if not used

  • h2[in] Optional second SNTP server for time. Set to NULL if not used

  • h3[in] Optional third SNTP server for time. Set to NULL if not used

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sntp_gettime(lwesp_datetime_t *dt, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get time from SNTP servers.

Parameters
  • dt[out] Pointer to lwesp_datetime_t structure to fill with date and time values

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

Station API

Station API is used to work with ESP acting in station mode. It allows to join other access point, scan for available access points or simply disconnect from it.

An example below is showing how all examples (coming with this library) scan for access point and then try to connect to AP from list of preferred one.

Station manager used with all examples
  1#include "station_manager.h"
  2#include "utils.h"
  3#include "lwesp/lwesp.h"
  4
  5/**
  6 * \brief           Private access-point and station management system
  7 * 
  8 * This is used for asynchronous connection to access point
  9 */
 10typedef struct {
 11    size_t index_preferred_list;                /*!< Current index position of preferred array */
 12    size_t index_scanned_list;                  /*!< Current index position in array of scanned APs */
 13
 14    uint8_t command_is_running;                 /*!< Indicating if command is currently in progress */
 15} prv_ap_data_t;
 16
 17/* Arguments for callback function */
 18#define ARG_SCAN                (void*)1
 19#define ARG_CONNECT             (void*)2
 20
 21/* Function declaration */
 22static void prv_cmd_event_fn(lwespr_t status, void* arg);
 23static void prv_try_next_access_point(void);
 24
 25/*
 26 * List of preferred access points for ESP device
 27 * SSID and password
 28 *
 29 * ESP will try to scan for access points
 30 * and then compare them with the one on the list below
 31 */
 32static const ap_entry_t ap_list_preferred[] = {
 33    //{ .ssid = "SSID name", .pass = "SSID password" },
 34    { .ssid = "TilenM_ST", .pass = "its private" },
 35    { .ssid = "Kaja", .pass = "kajagin2021" },
 36    { .ssid = "Majerle WIFI", .pass = "majerle_internet_private" },
 37    { .ssid = "Majerle AMIS", .pass = "majerle_internet_private" },
 38};
 39static lwesp_ap_t ap_list_scanned[100];         /* Scanned access points information */
 40static size_t ap_list_scanned_len = 0;          /* Number of scanned access points */
 41static prv_ap_data_t ap_async_data;             /* Asynchronous data structure */
 42
 43/* Command to execute to start scanning access points */
 44#define prv_scan_ap_command_ex(blocking)        lwesp_sta_list_ap(NULL, ap_list_scanned, LWESP_ARRAYSIZE(ap_list_scanned), &ap_list_scanned_len, NULL, NULL, (blocking))
 45#define prv_scan_ap_command()                   do {\
 46    if (!ap_async_data.command_is_running) {    \
 47        printf("Starting scan command on line %d\r\n", __LINE__);\
 48        ap_async_data.command_is_running = lwesp_sta_list_ap(NULL, ap_list_scanned, LWESP_ARRAYSIZE(ap_list_scanned), &ap_list_scanned_len, prv_cmd_event_fn, ARG_SCAN, 0) == lwespOK;   \
 49    }       \
 50} while (0)
 51
 52/**
 53 * \brief           Every internal command execution callback
 54 * \param[in]       status: Execution status result
 55 * \param[in]       arg: Custom user argument
 56 */
 57static void
 58prv_cmd_event_fn(lwespr_t status, void* arg) {
 59    /*
 60     * Command has now successfully finish
 61     * and callbacks have been properly processed
 62     */
 63    ap_async_data.command_is_running = 0;
 64
 65    if (arg == ARG_SCAN) {
 66        /* Immediately try to connect to access point after successful scan*/
 67        prv_try_next_access_point();
 68    }
 69}
 70
 71/**
 72 * \brief           Try to connect to next access point on a list 
 73 */
 74static void
 75prv_try_next_access_point(void) {
 76    uint8_t tried = 0;
 77
 78    /* No action to be done if command is currently in progress or already connected to network */
 79    if (ap_async_data.command_is_running
 80        || lwesp_sta_has_ip()) {
 81        return;
 82    }
 83
 84    /*
 85     * Process complete list and try to find suitable match
 86     *
 87     * Use global variable for indexes to be able to call function multiple times
 88     * and continue where it finished previously
 89     */
 90
 91    /* List all preferred access points */
 92    for (; ap_async_data.index_preferred_list < LWESP_ARRAYSIZE(ap_list_preferred);
 93            ap_async_data.index_preferred_list++, ap_async_data.index_scanned_list = 0) {
 94
 95        /* List all scanned access points */
 96        for (; ap_async_data.index_scanned_list < ap_list_scanned_len; ap_async_data.index_scanned_list++) {
 97
 98            /* Find a match if available */
 99            if (strncmp(ap_list_scanned[ap_async_data.index_scanned_list].ssid,
100                        ap_list_preferred[ap_async_data.index_preferred_list].ssid,
101                        strlen(ap_list_preferred[ap_async_data.index_preferred_list].ssid)) == 0) {
102
103                /* Try to connect to the network */
104                if (!ap_async_data.command_is_running
105                    && lwesp_sta_join(ap_list_preferred[ap_async_data.index_preferred_list].ssid,
106                                    ap_list_preferred[ap_async_data.index_preferred_list].pass,
107                                    NULL, prv_cmd_event_fn, ARG_CONNECT, 0) == lwespOK) {
108                    ap_async_data.command_is_running = 1;
109
110                    /* Go to next index for sub-for loop and exit */
111                    ap_async_data.index_scanned_list++;
112                    tried = 1;
113                    goto stp;
114                } else {
115                    /* We have a problem, needs to resume action in next run */
116                }
117            }
118        }
119    }
120
121    /* Restart scan operation if there was no try to connect and station has no IP */
122    if (!tried && !lwesp_sta_has_ip()) {
123        prv_scan_ap_command();
124    }
125stp:
126    return;
127}
128
129/**
130 * \brief           Private event function for asynchronous scanning
131 * \param[in]       evt: Event information
132 * \return          \ref lwespOK on success, member of \ref lwespr_t otherwise
133 */
134static lwespr_t
135prv_evt_fn(lwesp_evt_t* evt) {
136    switch (evt->type) {
137        case LWESP_EVT_KEEP_ALIVE:
138        case LWESP_EVT_WIFI_DISCONNECTED: {
139            /* Try to connect to next access point */
140            prv_try_next_access_point();
141            break;
142        }
143        case LWESP_EVT_STA_LIST_AP: {
144            /*
145             * After scanning gets completed
146             * manually reset all indexes for comparison purposes
147             */
148            ap_async_data.index_scanned_list = 0;
149            ap_async_data.index_preferred_list = 0;
150
151            /* Actual connection try is done in function callback */
152            break;
153        }
154        default: break;
155    }
156    return lwespOK;
157}
158
159/**
160 * \brief           Initialize asynchronous mode to connect to preferred access point
161 *
162 * Asynchronous mode relies on system events received by the application,
163 * to determine current device status if station is being, or not, connected to access point.
164 *
165 * When used, async acts only upon station connection change through callbacks,
166 * therefore it does not require additional system thread or user code,
167 * to be able to properly handle preferred access points.
168 * This certainly decreases memory consumption of the complete system.
169 *
170 * \ref LWESP_CFG_KEEP_ALIVE feature must be enable to properly handle all events
171 * \return          \ref lwespOK on success, member of \ref lwespr_t otherwise
172 */
173lwespr_t
174station_manager_connect_to_access_point_async_init(void) {
175    /* Register system event function */
176    lwesp_evt_register(prv_evt_fn);
177
178    /*
179     * Start scanning process in non-blocking mode
180     *
181     * This is the only command being executed from non-callback mode,
182     * therefore it must be protected against other threads trying to access the same core
183     */
184    lwesp_core_lock();
185    prv_scan_ap_command();
186    lwesp_core_unlock();
187
188    /* Return all good, things will progress (from now-on) asynchronously */
189    return lwespOK;
190}
191
192/**
193 * \brief           Connect to preferred access point in blocking mode
194 * 
195 * This functionality can only be used if non-blocking approach is not used
196 * 
197 * \note            List of access points should be set by user in \ref ap_list structure
198 * \param[in]       unlimited: When set to 1, function will block until SSID is found and connected
199 * \return          \ref lwespOK on success, member of \ref lwespr_t enumeration otherwise
200 */
201lwespr_t
202connect_to_preferred_access_point(uint8_t unlimited) {
203    lwespr_t eres;
204    uint8_t tried;
205
206    /*
207     * Scan for network access points
208     * In case we have access point,
209     * try to connect to known AP
210     */
211    do {
212        if (lwesp_sta_has_ip()) {
213            return lwespOK;
214        }
215
216        /* Scan for access points visible to ESP device */
217        printf("Scanning access points...\r\n");
218        if ((eres = prv_scan_ap_command_ex(1)) == lwespOK) {
219            tried = 0;
220
221            /* Print all access points found by ESP */
222            for (size_t i = 0; i < ap_list_scanned_len; i++) {
223                printf("AP found: %s, CH: %d, RSSI: %d\r\n", ap_list_scanned[i].ssid, ap_list_scanned[i].ch, ap_list_scanned[i].rssi);
224            }
225
226            /* Process array of preferred access points with array of found points */
227            for (size_t j = 0; j < LWESP_ARRAYSIZE(ap_list_preferred); j++) {
228
229                /* Go through all scanned list */
230                for (size_t i = 0; i < ap_list_scanned_len; i++) {
231
232                    /* Try to find a match between preferred and scanned */
233                    if (strncmp(ap_list_scanned[i].ssid, ap_list_preferred[j].ssid, strlen(ap_list_scanned[i].ssid)) == 0) {
234                        tried = 1;
235                        printf("Connecting to \"%s\" network...\r\n", ap_list_preferred[j].ssid);
236
237                        /* Try to join to access point */
238                        if ((eres = lwesp_sta_join(ap_list_preferred[j].ssid, ap_list_preferred[j].pass, NULL, NULL, NULL, 1)) == lwespOK) {
239                            lwesp_ip_t ip;
240                            uint8_t is_dhcp;
241
242                            printf("Connected to %s network!\r\n", ap_list_preferred[j].ssid);
243
244                            lwesp_sta_copy_ip(&ip, NULL, NULL, &is_dhcp);
245                            utils_print_ip("Station IP address: ", &ip, "\r\n");
246                            printf("; Is DHCP: %d\r\n", (int)is_dhcp);
247                            return lwespOK;
248                        } else {
249                            printf("Connection error: %d\r\n", (int)eres);
250                        }
251                    }
252                }
253            }
254            if (!tried) {
255                printf("No access points available with preferred SSID!\r\nPlease check station_manager.c file and edit preferred SSID access points!\r\n");
256            }
257        } else if (eres == lwespERRNODEVICE) {
258            printf("Device is not present!\r\n");
259            break;
260        } else {
261            printf("Error on WIFI scan procedure!\r\n");
262        }
263        if (!unlimited) {
264            break;
265        }
266    } while (1);
267    return lwespERR;
268}
group LWESP_STA

Station API.

Functions

lwespr_t lwesp_sta_join(const char *name, const char *pass, const lwesp_mac_t *mac, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Join as station to access point.

Configuration changes will be saved in the NVS area of ESP device.

Parameters
  • name[in] SSID of access point to connect to

  • pass[in] Password of access point. Use NULL if AP does not have password

  • mac[in] Pointer to MAC address of AP. If multiple APs with same name exist, MAC may help to select proper one. Set to NULL if not needed

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_quit(const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Quit (disconnect) from access point.

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_autojoin(uint8_t en, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Configure auto join to access point on startup.

Note

For auto join feature, you need to do a join to access point with default mode. Check lwesp_sta_join for more information

Parameters
  • en[in] Set to 1 to enable or 0 to disable

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_reconnect_set_config(uint16_t interval, uint16_t rep_cnt, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Set reconnect interval and maximum tries when connection drops.

Parameters
  • interval[in] Interval in units of seconds. Valid numbers are 1-7200 or 0 to disable reconnect feature

  • rep_cnt[in] Repeat counter. Number of maximum tries for reconnect. Valid entries are 1-1000 or 0 to always try. This parameter is only valid if interval is not 0

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_getip(lwesp_ip_t *ip, lwesp_ip_t *gw, lwesp_ip_t *nm, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get station IP address.

Parameters
  • ip[out] Pointer to variable to save IP address

  • gw[out] Pointer to output variable to save gateway address

  • nm[out] Pointer to output variable to save netmask address

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_setip(const lwesp_ip_t *ip, const lwesp_ip_t *gw, const lwesp_ip_t *nm, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Set station IP address.

Application may manually set IP address. When this happens, stack will check for DHCP settings and will read actual IP address from device. Once procedure is finished, LWESP_EVT_WIFI_IP_ACQUIRED event will be sent to application where user may read the actual new IP and DHCP settings.

Configuration changes will be saved in the NVS area of ESP device.

Note

DHCP is automatically disabled when using static IP address

Parameters
  • ip[in] Pointer to IP address

  • gw[in] Pointer to gateway address. Set to NULL to use default gateway

  • nm[in] Pointer to netmask address. Set to NULL to use default netmask

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_getmac(lwesp_mac_t *mac, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get station MAC address.

Parameters
  • mac[out] Pointer to output variable to save MAC address

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_setmac(const lwesp_mac_t *mac, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Set station MAC address.

Configuration changes will be saved in the NVS area of ESP device.

Parameters
  • mac[in] Pointer to variable with MAC address

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

uint8_t lwesp_sta_has_ip(void)

Check if ESP got IP from access point.

Returns

1 on success, 0 otherwise

uint8_t lwesp_sta_is_joined(void)

Check if station is connected to WiFi network.

Returns

1 on success, 0 otherwise

lwespr_t lwesp_sta_copy_ip(lwesp_ip_t *ip, lwesp_ip_t *gw, lwesp_ip_t *nm, uint8_t *is_dhcp)

Copy IP address from internal value to user variable.

Note

Use lwesp_sta_getip to refresh actual IP value from device

Parameters
  • ip[out] Pointer to output IP variable. Set to NULL if not interested in IP address

  • gw[out] Pointer to output gateway variable. Set to NULL if not interested in gateway address

  • nm[out] Pointer to output netmask variable. Set to NULL if not interested in netmask address

  • is_dhcp[out] Pointer to output DHCP status variable. Set to NULL if not interested

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_list_ap(const char *ssid, lwesp_ap_t *aps, size_t apsl, size_t *apf, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

List for available access points ESP can connect to.

Parameters
  • ssid[in] Optional SSID name to search for. Set to NULL to disable filter

  • aps[in] Pointer to array of available access point parameters

  • apsl[in] Length of aps array

  • apf[out] Pointer to output variable to save number of access points found

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_sta_get_ap_info(lwesp_sta_info_ap_t *info, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get current access point information (name, mac, channel, rssi)

Note

Access point station is currently connected to

Parameters
  • info[in] Pointer to connected access point information

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

uint8_t lwesp_sta_is_ap_802_11b(lwesp_ap_t *ap)

Check if access point is 802.11b compatible.

Parameters

ap[in] Access point detailes acquired by lwesp_sta_list_ap

Returns

1 on success, 0 otherwise

uint8_t lwesp_sta_is_ap_802_11g(lwesp_ap_t *ap)

Check if access point is 802.11g compatible.

Parameters

ap[in] Access point detailes acquired by lwesp_sta_list_ap

Returns

1 on success, 0 otherwise

uint8_t lwesp_sta_is_ap_802_11n(lwesp_ap_t *ap)

Check if access point is 802.11n compatible.

Parameters

ap[in] Access point detailes acquired by lwesp_sta_list_ap

Returns

1 on success, 0 otherwise

uint8_t lwesp_sta_has_ipv6_local(void)

Check if station has local IPV6 IP Local IP is used between station and router.

Note

Defined as macro with 0 constant if LWESP_CFG_IPV6 is disabled

Returns

1 if local IPv6 is available, 0 otherwise

uint8_t lwesp_sta_has_ipv6_global(void)

Check if station has global IPV6 IP Global IP is used router and outside network.

Note

Defined as macro with 0 constant if LWESP_CFG_IPV6 is disabled

Returns

1 if global IPv6 is available, 0 otherwise

struct lwesp_sta_t
#include <lwesp_typedefs.h>

Station data structure.

Public Members

lwesp_ip_t ip

IP address of connected station

lwesp_mac_t mac

MAC address of connected station

Timeout manager

Timeout manager allows application to call specific function at desired time. It is used in middleware (and can be used by application too) to poll active connections.

Note

Callback function is called from processing thread. It is not allowed to call any blocking API function from it.

When application registers timeout, it needs to set timeout, callback function and optional user argument. When timeout elapses, ESP middleware will call timeout callback.

This feature can be considered as single-shot software timer.

group LWESP_TIMEOUT

Timeout manager.

Typedefs

typedef void (*lwesp_timeout_fn)(void *arg)

Timeout callback function prototype.

Param arg

[in] Custom user argument

Functions

lwespr_t lwesp_timeout_add(uint32_t time, lwesp_timeout_fn fn, void *arg)

Add new timeout to processing list.

Parameters
  • time[in] Time in units of milliseconds for timeout execution

  • fn[in] Callback function to call when timeout expires

  • arg[in] Pointer to user specific argument to call when timeout callback function is executed

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_timeout_remove(lwesp_timeout_fn fn)

Remove callback from timeout list.

Parameters

fn[in] Callback function to identify timeout to remove

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

struct lwesp_timeout_t
#include <lwesp_typedefs.h>

Timeout structure.

Public Members

struct lwesp_timeout *next

Pointer to next timeout entry

uint32_t time

Time difference from previous entry

void *arg

Argument to pass to callback function

lwesp_timeout_fn fn

Callback function for timeout

Structures and enumerations
group LWESP_TYPEDEFS

List of core structures and enumerations.

Typedefs

typedef uint16_t lwesp_port_t

Port variable.

typedef void (*lwesp_api_cmd_evt_fn)(lwespr_t res, void *arg)

Function declaration for API function command event callback function.

Param res

[in] Operation result, member of lwespr_t enumeration

Param arg

[in] Custom user argument

Enums

enum lwesp_cmd_t

List of possible messages.

Values:

enumerator LWESP_CMD_IDLE

IDLE mode

enumerator LWESP_CMD_RESET

Reset device

enumerator LWESP_CMD_ATE0

Disable ECHO mode on AT commands

enumerator LWESP_CMD_ATE1

Enable ECHO mode on AT commands

enumerator LWESP_CMD_GMR

Get AT commands version

enumerator LWESP_CMD_GSLP

Set ESP to sleep mode

enumerator LWESP_CMD_RESTORE

Restore ESP internal settings to default values

enumerator LWESP_CMD_UART
enumerator LWESP_CMD_SLEEP
enumerator LWESP_CMD_WAKEUPGPIO
enumerator LWESP_CMD_RFPOWER
enumerator LWESP_CMD_RFVDD
enumerator LWESP_CMD_RFAUTOTRACE
enumerator LWESP_CMD_SYSRAM
enumerator LWESP_CMD_SYSADC
enumerator LWESP_CMD_SYSMSG
enumerator LWESP_CMD_SYSLOG
enumerator LWESP_CMD_WIFI_CWMODE

Set wifi mode

enumerator LWESP_CMD_WIFI_CWMODE_GET

Get wifi mode

enumerator LWESP_CMD_WIFI_CWLAPOPT

Configure what is visible on CWLAP response

enumerator LWESP_CMD_WIFI_IPV6

Configure IPv6 support

enumerator LWESP_CMD_WIFI_CWJAP

Connect to access point

enumerator LWESP_CMD_WIFI_CWRECONNCFG

Setup reconnect interval and maximum tries

enumerator LWESP_CMD_WIFI_CWJAP_GET

Info of the connected access point

enumerator LWESP_CMD_WIFI_CWQAP

Disconnect from access point

enumerator LWESP_CMD_WIFI_CWLAP

List available access points

enumerator LWESP_CMD_WIFI_CIPSTAMAC_GET

Get MAC address of ESP station

enumerator LWESP_CMD_WIFI_CIPSTAMAC_SET

Set MAC address of ESP station

enumerator LWESP_CMD_WIFI_CIPSTA_GET

Get IP address of ESP station

enumerator LWESP_CMD_WIFI_CIPSTA_SET

Set IP address of ESP station

enumerator LWESP_CMD_WIFI_CWAUTOCONN

Configure auto connection to access point

enumerator LWESP_CMD_WIFI_CWDHCP_SET

Set DHCP config

enumerator LWESP_CMD_WIFI_CWDHCP_GET

Get DHCP config

enumerator LWESP_CMD_WIFI_CWDHCPS_SET

Set DHCP SoftAP IP config

enumerator LWESP_CMD_WIFI_CWDHCPS_GET

Get DHCP SoftAP IP config

enumerator LWESP_CMD_WIFI_CWSAP_GET

Get software access point configuration

enumerator LWESP_CMD_WIFI_CWSAP_SET

Set software access point configuration

enumerator LWESP_CMD_WIFI_CIPAPMAC_GET

Get MAC address of ESP access point

enumerator LWESP_CMD_WIFI_CIPAPMAC_SET

Set MAC address of ESP access point

enumerator LWESP_CMD_WIFI_CIPAP_GET

Get IP address of ESP access point

enumerator LWESP_CMD_WIFI_CIPAP_SET

Set IP address of ESP access point

enumerator LWESP_CMD_WIFI_CWLIF

Get connected stations on access point

enumerator LWESP_CMD_WIFI_CWQIF

Discnnect station from SoftAP

enumerator LWESP_CMD_WIFI_WPS

Set WPS option

enumerator LWESP_CMD_WIFI_MDNS

Configure MDNS function

enumerator LWESP_CMD_WIFI_CWHOSTNAME_SET

Set device hostname

enumerator LWESP_CMD_WIFI_CWHOSTNAME_GET

Get device hostname

enumerator LWESP_CMD_TCPIP_CIPDOMAIN

Get IP address from domain name = DNS function

enumerator LWESP_CMD_TCPIP_CIPDNS_SET

Configure user specific DNS servers

enumerator LWESP_CMD_TCPIP_CIPDNS_GET

Get DNS configuration

enumerator LWESP_CMD_TCPIP_CIPSTATUS

Get status of connections (deprecated, used on ESP8266 devices)

enumerator LWESP_CMD_TCPIP_CIPSTATE

Obtain connection state and information

enumerator LWESP_CMD_TCPIP_CIPSTART

Start client connection

enumerator LWESP_CMD_TCPIP_CIPSEND

Send network data

enumerator LWESP_CMD_TCPIP_CIPCLOSE

Close active connection

enumerator LWESP_CMD_TCPIP_CIPSSLSIZE

Set SSL buffer size for SSL connection

enumerator LWESP_CMD_TCPIP_CIPSSLCCONF

Set the SSL configuration

enumerator LWESP_CMD_TCPIP_CIFSR

Get local IP

enumerator LWESP_CMD_TCPIP_CIPMUX

Set single or multiple connections

enumerator LWESP_CMD_TCPIP_CIPSERVER

Enables/Disables server mode

enumerator LWESP_CMD_TCPIP_CIPSERVERMAXCONN

Sets maximal number of connections allowed for server population

enumerator LWESP_CMD_TCPIP_CIPMODE

Transmission mode, either transparent or normal one

enumerator LWESP_CMD_TCPIP_CIPSTO

Sets connection timeout

enumerator LWESP_CMD_TCPIP_CIPRECVMODE

Sets mode for TCP data receive (manual or automatic)

enumerator LWESP_CMD_TCPIP_CIPRECVDATA

Manually reads TCP data from device

enumerator LWESP_CMD_TCPIP_CIPRECVLEN

Gets number of available bytes in connection to be read

enumerator LWESP_CMD_TCPIP_CIUPDATE

Perform self-update

enumerator LWESP_CMD_TCPIP_CIPSNTPCFG

Configure SNTP servers

enumerator LWESP_CMD_TCPIP_CIPSNTPTIME

Get current time using SNTP

enumerator LWESP_CMD_TCPIP_CIPDINFO

Configure what data are received on +IPD statement

enumerator LWESP_CMD_TCPIP_PING

Ping domain

enumerator LWESP_CMD_WIFI_SMART_START

Start smart config

enumerator LWESP_CMD_WIFI_SMART_STOP

Stop smart config

enumerator LWESP_CMD_WEBSERVER

Start or Stop Web Server

enumerator LWESP_CMD_BLEINIT_GET

Get BLE status

enum lwespr_t

Result enumeration used across application functions.

Values:

enumerator lwespOK

Function succeeded

enumerator lwespOKIGNOREMORE

Function succedded, should continue as lwespOK but ignore sending more data. This result is possible on connection data receive callback

enumerator lwespERR

General error

enumerator lwespPARERR

Wrong parameters on function call

enumerator lwespERRMEM

Memory error occurred

enumerator lwespTIMEOUT

Timeout occurred on command

enumerator lwespCONT

There is still some command to be processed in current command

enumerator lwespCLOSED

Connection just closed

enumerator lwespINPROG

Operation is in progress

enumerator lwespERRNOIP

Station does not have IP address

enumerator lwespERRNOFREECONN

There is no free connection available to start

enumerator lwespERRCONNTIMEOUT

Timeout received when connection to access point

enumerator lwespERRPASS

Invalid password for access point

enumerator lwespERRNOAP

No access point found with specific SSID and MAC address

enumerator lwespERRCONNFAIL

Connection failed to access point

enumerator lwespERRWIFINOTCONNECTED

Wifi not connected to access point

enumerator lwespERRNODEVICE

Device is not present

enumerator lwespERRBLOCKING

Blocking mode command is not allowed

enum lwesp_device_t

List of support ESP devices by firmware.

Values:

enumerator LWESP_DEVICE_ESP8266

Device is ESP8266

enumerator LWESP_DEVICE_ESP32

Device is ESP32

enumerator LWESP_DEVICE_ESP32_C3

Device is ESP32-C3

enumerator LWESP_DEVICE_UNKNOWN

Unknown device

enum lwesp_ecn_t

List of encryptions of access point.

Values:

enumerator LWESP_ECN_OPEN

No encryption on access point

enumerator LWESP_ECN_WEP

WEP (Wired Equivalent Privacy) encryption

enumerator LWESP_ECN_WPA_PSK

WPA (Wifi Protected Access) encryption

enumerator LWESP_ECN_WPA2_PSK

WPA2 (Wifi Protected Access 2) encryption

enumerator LWESP_ECN_WPA_WPA2_PSK

WPA/2 (Wifi Protected Access 1/2) encryption

enumerator LWESP_ECN_WPA2_Enterprise

Enterprise encryption.

Note

ESP8266 is not able to connect to such device

enumerator LWESP_ECN_WPA3_PSK

WPA3 (Wifi Protected Access 3) encryption

enumerator LWESP_ECN_WPA2_WPA3_PSK

WPA2/3 (Wifi Protected Access 2/3) encryption, ESP32-C3 only mode

enumerator LWESP_ECN_END
enum lwesp_iptype_t

IP type.

Values:

enumerator LWESP_IPTYPE_V4

IP type is V4

enumerator LWESP_IPTYPE_V6

IP type is V6

enum lwesp_mode_t

List of possible WiFi modes.

Values:

enumerator LWESP_MODE_STA

Set WiFi mode to station only

enumerator LWESP_MODE_AP

Set WiFi mode to access point only

enumerator LWESP_MODE_STA_AP

Set WiFi mode to station and access point

enum lwesp_http_method_t

List of possible HTTP methods.

Values:

enumerator LWESP_HTTP_METHOD_GET

HTTP method GET

enumerator LWESP_HTTP_METHOD_HEAD

HTTP method HEAD

enumerator LWESP_HTTP_METHOD_POST

HTTP method POST

enumerator LWESP_HTTP_METHOD_PUT

HTTP method PUT

enumerator LWESP_HTTP_METHOD_DELETE

HTTP method DELETE

enumerator LWESP_HTTP_METHOD_CONNECT

HTTP method CONNECT

enumerator LWESP_HTTP_METHOD_OPTIONS

HTTP method OPTIONS

enumerator LWESP_HTTP_METHOD_TRACE

HTTP method TRACE

enumerator LWESP_HTTP_METHOD_PATCH

HTTP method PATCH

struct lwesp_conn_t
#include <lwesp_private.h>

Connection structure.

Public Members

lwesp_conn_type_t type

Connection type

uint8_t num

Connection number

lwesp_ip_t remote_ip

Remote IP address

lwesp_port_t remote_port

Remote port number

lwesp_port_t local_port

Local IP address

lwesp_evt_fn evt_func

Callback function for connection

void *arg

User custom argument

uint8_t val_id

Validation ID number. It is increased each time a new connection is established. It protects sending data to wrong connection in case we have data in send queue, and connection was closed and active again in between.

lwesp_linbuff_t buff

Linear buffer structure

size_t total_recved

Total number of bytes received

size_t tcp_available_bytes

Number of bytes in ESP ready to be read on connection. This variable always holds last known info from ESP device and is not decremented (or incremented) by application

size_t tcp_not_ack_bytes

Number of bytes not acknowledge by application done with processing This variable is increased everytime new packet is read to be sent to application and decreased when application acknowledges it

uint8_t active

Status whether connection is active

uint8_t client

Status whether connection is in client mode

uint8_t data_received

Status whether first data were received on connection

uint8_t in_closing

Status if connection is in closing mode. When in closing mode, ignore any possible received data from function

uint8_t receive_blocked

Status whether we should block manual receive for some time

uint8_t receive_is_command_queued

Status whether manual read command is in the queue already

struct lwesp_conn_t::[anonymous]::[anonymous] f

Connection flags

union lwesp_conn_t::[anonymous] status

Connection status union with flag bits

struct lwesp_pbuf_t
#include <lwesp_private.h>

Packet buffer structure.

Public Members

struct lwesp_pbuf *next

Next pbuf in chain list

size_t tot_len

Total length of pbuf chain

size_t len

Length of payload

size_t ref

Number of references to this structure

uint8_t *payload

Pointer to payload memory

lwesp_ip_t ip

Remote address for received IPD data

lwesp_port_t port

Remote port for received IPD data

struct lwesp_ipd_t
#include <lwesp_private.h>

Incoming network data read structure.

Public Members

uint8_t read

Set to 1 when we should process input data as connection data

size_t tot_len

Total length of packet

size_t rem_len

Remaining bytes to read in current +IPD statement

lwesp_conn_p conn

Pointer to connection for network data

lwesp_ip_t ip

Remote IP address on from IPD data

lwesp_port_t port

Remote port on IPD data

size_t buff_ptr

Buffer pointer to save data to. When set to NULL while read = 1, reading should ignore incoming data

lwesp_pbuf_p buff

Pointer to data buffer used for receiving data

struct lwesp_msg_t
#include <lwesp_private.h>

Message queue structure to share between threads.

Public Members

lwesp_cmd_t cmd_def

Default message type received from queue

lwesp_cmd_t cmd

Since some commands can have different subcommands, sub command is used here

uint8_t i

Variable to indicate order number of subcommands

lwesp_sys_sem_t sem

Semaphore for the message

uint8_t is_blocking

Status if command is blocking

uint32_t block_time

Maximal blocking time in units of milliseconds. Use 0 to for non-blocking call

lwespr_t res

Result of message operation

lwespr_t (*fn)(struct lwesp_msg*)

Processing callback function to process packet

uint32_t delay

Delay in units of milliseconds before executing first RESET command

struct lwesp_msg_t::[anonymous]::[anonymous] reset

Reset device

uint32_t baudrate

Baudrate for AT port

struct lwesp_msg_t::[anonymous]::[anonymous] uart

UART configuration

lwesp_mode_t mode

Mode of operation

lwesp_mode_t *mode_get

Get mode

struct lwesp_msg_t::[anonymous]::[anonymous] wifi_mode

When message type LWESP_CMD_WIFI_CWMODE is used

const char *name

AP name

const char *pass

AP password

const lwesp_mac_t *mac

Specific MAC address to use when connecting to AP

uint8_t error_num

Error number on connecting

struct lwesp_msg_t::[anonymous]::[anonymous] sta_join

Message for joining to access point

uint16_t interval

Interval in units of seconds

uint16_t rep_cnt

Repetition counter

struct lwesp_msg_t::[anonymous]::[anonymous] sta_reconn_set

Reconnect setup

uint8_t en

Status to enable/disable auto join feature

Enable/disable DHCP settings

Enable/Disable server status

Status if SNTP is enabled or not

Status if WPS is enabled or not

Set to 1 to enable or 0 to disable

Enable/Disable web server status

struct lwesp_msg_t::[anonymous]::[anonymous] sta_autojoin

Message for auto join procedure

lwesp_sta_info_ap_t *info

Information structure

struct lwesp_msg_t::[anonymous]::[anonymous] sta_info_ap

Message for reading the AP information

const char *ssid

Pointer to optional filter SSID name to search

Name of access point

lwesp_ap_t *aps

Pointer to array to save access points

size_t apsl

Length of input array of access points

size_t apsi

Current access point array

size_t *apf

Pointer to output variable holding number of access points found

struct lwesp_msg_t::[anonymous]::[anonymous] ap_list

List for available access points to connect to

const char *pwd

Password of access point

lwesp_ecn_t ecn

Ecryption used

uint8_t ch

RF Channel used

uint8_t max_sta

Max allowed connected stations

uint8_t hid

Configuration if network is hidden or visible

struct lwesp_msg_t::[anonymous]::[anonymous] ap_conf

Parameters to configure access point

lwesp_ap_conf_t *ap_conf

AP configuration

struct lwesp_msg_t::[anonymous]::[anonymous] ap_conf_get

Get the soft AP configuration

lwesp_sta_t *stas

Pointer to array to save access points

size_t stal

Length of input array of access points

size_t stai

Current access point array

size_t *staf

Pointer to output variable holding number of access points found

struct lwesp_msg_t::[anonymous]::[anonymous] sta_list

List for stations connected to SoftAP

uint8_t use_mac

Status if specific MAC is to be used

lwesp_mac_t mac

MAC address to disconnect from access point

Pointer to MAC variable

struct lwesp_msg_t::[anonymous]::[anonymous] ap_disconn_sta

Disconnect station from access point

lwesp_ip_t *ip

Pointer to IP variable

lwesp_ip_t *gw

Pointer to gateway variable

lwesp_ip_t *nm

Pointer to netmask variable

struct lwesp_msg_t::[anonymous]::[anonymous] sta_ap_getip

Message for reading station or access point IP

lwesp_mac_t *mac

Pointer to MAC variable

struct lwesp_msg_t::[anonymous]::[anonymous] sta_ap_getmac

Message for reading station or access point MAC address

lwesp_ip_t ip

IP variable

lwesp_ip_t gw

Gateway variable

lwesp_ip_t nm

Netmask variable

struct lwesp_msg_t::[anonymous]::[anonymous] sta_ap_setip

Message for setting station or access point IP

struct lwesp_msg_t::[anonymous]::[anonymous] sta_ap_setmac

Message for setting station or access point MAC address

uint8_t sta

Set station DHCP settings

uint8_t ap

Set access point DHCP settings

struct lwesp_msg_t::[anonymous]::[anonymous] wifi_cwdhcp

Set DHCP settings

const char *hostname_set

Hostname set value

char *hostname_get

Hostname get value

size_t length

Length of buffer when reading hostname

struct lwesp_msg_t::[anonymous]::[anonymous] wifi_hostname

Set or get hostname structure

lwesp_conn_t **conn

Pointer to pointer to save connection used

const char *remote_host

Host to use for connection

lwesp_port_t remote_port

Remote port used for connection

Remote port address for UDP connection

lwesp_conn_type_t type

Connection type

const char *local_ip

Local IP address. Normally set to NULL

uint16_t tcp_ssl_keep_alive

Keep alive parameter for TCP

uint8_t udp_mode

UDP mode

lwesp_port_t udp_local_port

UDP local port

void *arg

Connection custom argument

lwesp_evt_fn evt_func

Callback function to use on connection

uint8_t success

Status if connection AT+CIPSTART succedded

struct lwesp_msg_t::[anonymous]::[anonymous] conn_start

Structure for starting new connection

lwesp_conn_t *conn

Pointer to connection to close

Pointer to connection to send data

uint8_t val_id

Connection current validation ID when command was sent to queue

struct lwesp_msg_t::[anonymous]::[anonymous] conn_close

Close connection

size_t btw

Number of remaining bytes to write

size_t ptr

Current write pointer for data

const uint8_t *data

Data to send

size_t sent

Number of bytes sent in last packet

size_t sent_all

Number of bytes sent all together

uint8_t tries

Number of tries used for last packet

uint8_t wait_send_ok_err

Set to 1 when we wait for SEND OK or SEND ERROR

const lwesp_ip_t *remote_ip

Remote IP address for UDP connection

uint8_t fau

Free after use flag to free memory after data are sent (or not)

size_t *bw

Number of bytes written so far

struct lwesp_msg_t::[anonymous]::[anonymous] conn_send

Structure to send data on connection

lwesp_port_t port

Server port number

mDNS server port

uint16_t max_conn

Maximal number of connections available for server

uint16_t timeout

Connection timeout

lwesp_evt_fn cb

Server default callback function

struct lwesp_msg_t::[anonymous]::[anonymous] tcpip_server

Server configuration

size_t size

Size for SSL in uints of bytes

struct lwesp_msg_t::[anonymous]::[anonymous] tcpip_sslsize

TCP SSL size for SSL connections

const char *host

Hostname to ping

mDNS host name

uint32_t time

Time used for ping

uint32_t *time_out

Pointer to time output variable

struct lwesp_msg_t::[anonymous]::[anonymous] tcpip_ping

Pinging structure

int8_t tz

Timezone setup

const char *h1

Optional server 1

const char *h2

Optional server 2

const char *h3

Optional server 3

struct lwesp_msg_t::[anonymous]::[anonymous] tcpip_sntp_cfg

SNTP configuration

lwesp_datetime_t *dt

Pointer to datetime structure

struct lwesp_msg_t::[anonymous]::[anonymous] tcpip_sntp_time

SNTP get time

struct lwesp_msg_t::[anonymous]::[anonymous] wps_cfg

WPS configuration

const char *server

mDNS server

struct lwesp_msg_t::[anonymous]::[anonymous] mdns

mDNS configuration

uint8_t timeout

Connection timeout

struct lwesp_msg_t::[anonymous]::[anonymous] web_server

Web Server configuration

Link ID of connection to set SSL configuration for

uint8_t auth_mode

Timezone setup

uint8_t pki_number

The index of cert and private key, if only one cert and private key, the value should be 0.

uint8_t ca_number

The index of CA, if only one CA, the value should be 0.

struct lwesp_msg_t::[anonymous]::[anonymous] tcpip_ssl_cfg

SSl configuration for connection

union lwesp_msg_t::[anonymous] msg

Group of different message contents

struct lwesp_ip_mac_t
#include <lwesp_private.h>

IP and MAC structure with netmask and gateway addresses.

Public Members

lwesp_ip_t ip

IP address

lwesp_ip_t gw

Gateway address

lwesp_ip_t nm

Netmask address

lwesp_mac_t mac

MAC address

uint8_t dhcp

Flag indicating DHCP is enabled

uint8_t has_ip

Flag indicating IP is available

uint8_t is_connected

Flag indicating ESP is connected to wifi

struct lwesp_ip_mac_t::[anonymous] f

Flags structure

#include <lwesp_private.h>

Link connection active info.

Public Members

Status if connection successful

Connection number

Status if connection is client or server

Connection type

Remote IP address

Remote port

Local port number

struct lwesp_evt_func_t
#include <lwesp_private.h>

Callback function linked list prototype.

Public Members

struct lwesp_evt_func *next

Next function in the list

lwesp_evt_fn fn

Function pointer itself

struct lwesp_modules_t
#include <lwesp_private.h>

ESP modules structure.

Public Members

lwesp_device_t device

ESP device type

lwesp_sw_version_t version_at

Version of AT command software on ESP device

lwesp_sw_version_t version_sdk

Version of SDK used to build AT software

uint32_t active_conns

Bit field of currently active connections,

Todo:

: In case user has more than 32 connections, single variable is not enough

uint32_t active_conns_last

The same as previous but status before last check

Link connection handle

lwesp_ipd_t ipd

Connection incoming data structure

lwesp_conn_t conns[LWESP_CFG_MAX_CONNS]

Array of all connection structures

lwesp_ip_mac_t sta

Station IP and MAC addressed

lwesp_ip_mac_t ap

Access point IP and MAC addressed

struct lwesp_t
#include <lwesp_private.h>

ESP global structure.

Public Members

size_t locked_cnt

Counter how many times (recursive) stack is currently locked

lwesp_sys_sem_t sem_sync

Synchronization semaphore between threads

lwesp_sys_mbox_t mbox_producer

Producer message queue handle

lwesp_sys_mbox_t mbox_process

Consumer message queue handle

lwesp_sys_thread_t thread_produce

Producer thread handle

lwesp_sys_thread_t thread_process

Processing thread handle

lwesp_buff_t buff

Input processing buffer

lwesp_ll_t ll

Low level functions

lwesp_msg_t *msg

Pointer to current user message being executed

lwesp_evt_t evt

Callback processing structure

lwesp_evt_func_t *evt_func

Callback function linked list

lwesp_evt_fn evt_server

Default callback function for server connections

lwesp_modules_t m

All modules. When resetting, reset structure

uint8_t initialized

Flag indicating ESP library is initialized

uint8_t dev_present

Flag indicating if physical device is connected to host device

struct lwesp_t::[anonymous]::[anonymous] f

Flags structure

union lwesp_t::[anonymous] status

Status structure

uint8_t conn_val_id

Validation ID increased each time device connects to wifi network or on reset. It is used for connections

struct lwesp_unicode_t
#include <lwesp_private.h>

Unicode support structure.

Public Members

uint8_t ch[4]

UTF-8 max characters

uint8_t t

Total expected length in UTF-8 sequence

uint8_t r

Remaining bytes in UTF-8 sequence

lwespr_t res

Current result of processing

struct lwesp_ip4_addr_t
#include <lwesp_typedefs.h>

IPv4 address structure.

Public Members

uint8_t addr[4]

IP address data

struct lwesp_ip6_addr_t
#include <lwesp_typedefs.h>

IPv6 address structure.

Public Members

uint16_t addr[8]

IP address data

struct lwesp_ip_t
#include <lwesp_typedefs.h>

IP structure.

Public Members

lwesp_ip4_addr_t ip4

IPv4 address

union lwesp_ip_t::[anonymous] addr

Actual IP address

lwesp_iptype_t type

IP type, either V4 or V6

struct lwesp_mac_t
#include <lwesp_typedefs.h>

MAC address.

Public Members

uint8_t mac[6]

MAC address

struct lwesp_sw_version_t
#include <lwesp_typedefs.h>

SW version in semantic versioning format.

Public Members

uint8_t major

Major version

uint8_t minor

Minor version

uint8_t patch

Patch version

struct lwesp_datetime_t
#include <lwesp_typedefs.h>

Date and time structure.

Public Members

uint8_t date

Day in a month, from 1 to up to 31

uint8_t month

Month in a year, from 1 to 12

uint16_t year

Year

uint8_t day

Day in a week, from 1 to 7

uint8_t hours

Hours in a day, from 0 to 23

uint8_t minutes

Minutes in a hour, from 0 to 59

uint8_t seconds

Seconds in a minute, from 0 to 59

struct lwesp_linbuff_t
#include <lwesp_typedefs.h>

Linear buffer structure.

Public Members

uint8_t *buff

Pointer to buffer data array

size_t len

Length of buffer array

size_t ptr

Current buffer pointer

Unicode

Unicode decoder block. It can decode sequence of UTF-8 characters, between 1 and 4 bytes long.

Note

This is simple implementation and does not support string encoding.

group LWESP_UNICODE

Unicode support manager.

Functions

lwespr_t lwespi_unicode_decode(lwesp_unicode_t *uni, uint8_t ch)

Decode single character for unicode (UTF-8 only) format.

Parameters
  • s[inout] Pointer to unicode decode control structure

  • c[in] UTF-8 character sequence to test for device

Returns

lwespOK Function succedded, there is a valid UTF-8 sequence

Returns

lwespINPROG Function continues well but expects some more data to finish sequence

Returns

lwespERR Error in UTF-8 sequence

struct lwesp_unicode_t
#include <lwesp_private.h>

Unicode support structure.

Public Members

uint8_t ch[4]

UTF-8 max characters

uint8_t t

Total expected length in UTF-8 sequence

uint8_t r

Remaining bytes in UTF-8 sequence

lwespr_t res

Current result of processing

Utilities

Utility functions for various cases. These function are used across entire middleware and can also be used by application.

group LWESP_UTILS

Utilities.

Defines

LWESP_ASSERT(msg, c)

Assert an input parameter if in valid range.

Note

Since this is a macro, it may only be used on a functions where return status is of type lwespr_t enumeration

Parameters
  • msg[in] message to print to debug if test fails

  • c[in] Condition to test

LWESP_MEM_ALIGN(x)

Align x value to specific number of bytes, provided by LWESP_CFG_MEM_ALIGNMENT configuration.

Parameters
  • x[in] Input value to align

Returns

Input value aligned to specific number of bytes

LWESP_MIN(x, y)

Get minimal value between x and y inputs.

Parameters
  • x[in] First input to test

  • y[in] Second input to test

Returns

Minimal value between x and y parameters

LWESP_MAX(x, y)

Get maximal value between x and y inputs.

Parameters
  • x[in] First input to test

  • y[in] Second input to test

Returns

Maximal value between x and y parameters

LWESP_ARRAYSIZE(x)

Get size of statically declared array.

Parameters
  • x[in] Input array

Returns

Number of array elements

LWESP_UNUSED(x)

Unused argument in a function call.

Note

Use this on all parameters in a function which are not used to prevent compiler warnings complaining about “unused variables”

Parameters
  • x[in] Variable which is not used

LWESP_U32(x)

Get input value casted to unsigned 32-bit value.

Parameters
  • x[in] Input value

LWESP_U16(x)

Get input value casted to unsigned 16-bit value.

Parameters
  • x[in] Input value

LWESP_U8(x)

Get input value casted to unsigned 8-bit value.

Parameters
  • x[in] Input value

LWESP_I32(x)

Get input value casted to signed 32-bit value.

Parameters
  • x[in] Input value

LWESP_I16(x)

Get input value casted to signed 16-bit value.

Parameters
  • x[in] Input value

LWESP_I8(x)

Get input value casted to signed 8-bit value.

Parameters
  • x[in] Input value

LWESP_SZ(x)

Get input value casted to size_t value.

Parameters
  • x[in] Input value

lwesp_u32_to_str(num, out)

Convert unsigned 32-bit number to string.

Parameters
  • num[in] Number to convert

  • out[out] Output variable to save string

Returns

Pointer to output variable

lwesp_u32_to_hex_str(num, out, w)

Convert unsigned 32-bit number to HEX string.

Parameters
  • num[in] Number to convert

  • out[out] Output variable to save string

  • w[in] Width of output string. When number is shorter than width, leading 0 characters will apply

Returns

Pointer to output variable

lwesp_i32_to_str(num, out)

Convert signed 32-bit number to string.

Parameters
  • num[in] Number to convert

  • out[out] Output variable to save string

Returns

Pointer to output variable

lwesp_u16_to_str(num, out)

Convert unsigned 16-bit number to string.

Parameters
  • num[in] Number to convert

  • out[out] Output variable to save string

Returns

Pointer to output variable

lwesp_u16_to_hex_str(num, out, w)

Convert unsigned 16-bit number to HEX string.

Parameters
  • num[in] Number to convert

  • out[out] Output variable to save string

  • w[in] Width of output string. When number is shorter than width, leading 0 characters will apply.

Returns

Pointer to output variable

lwesp_i16_to_str(num, out)

Convert signed 16-bit number to string.

Parameters
  • num[in] Number to convert

  • out[out] Output variable to save string

Returns

Pointer to output variable

lwesp_u8_to_str(num, out)

Convert unsigned 8-bit number to string.

Parameters
  • num[in] Number to convert

  • out[out] Output variable to save string

Returns

Pointer to output variable

lwesp_u8_to_hex_str(num, out, w)

Convert unsigned 16-bit number to HEX string.

Parameters
  • num[in] Number to convert

  • out[out] Output variable to save string

  • w[in] Width of output string. When number is shorter than width, leading 0 characters will apply.

Returns

Pointer to output variable

lwesp_i8_to_str(num, out)

Convert signed 8-bit number to string.

Parameters
  • num[in] Number to convert

  • out[out] Output variable to save string

Returns

Pointer to output variable

Functions

char *lwesp_u32_to_gen_str(uint32_t num, char *out, uint8_t is_hex, uint8_t padding)

Convert unsigned 32-bit number to string.

Parameters
  • num[in] Number to convert

  • out[out] Output variable to save string

  • is_hex[in] Set to 1 to output hex, 0 otherwise

  • width[in] Width of output string. When number is shorter than width, leading 0 characters will apply. This parameter is valid only when formatting hex numbers

Returns

Pointer to output variable

char *lwesp_i32_to_gen_str(int32_t num, char *out)

Convert signed 32-bit number to string.

Parameters
  • num[in] Number to convert

  • out[out] Output variable to save string

Returns

Pointer to output variable

Web Server

Use ESP-AT’s built-in web server feature to help WiFi provisioning and/or Firmware Over-the-Air update.

Note

Web Server is not enabled in ESP-AT by default. Refer to ESP-AT User Guide to build a custom image from source.

group LWESP_WEBSERVER

Web Server function.

Functions

lwespr_t lwesp_set_webserver(uint8_t en, lwesp_port_t port, uint16_t timeout, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Enables or disables Web Server.

Parameters
  • en[in] Set to 1 to enable web server, 0 to disable web server.

  • port[in] The web server port number.

  • timeout[in] The timeout for the every connection. Unit: second. Range:[21,60].

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

Wi-Fi Protected Setup
group LWESP_WPS

WPS function on ESP device.

Functions

lwespr_t lwesp_wps_set_config(uint8_t en, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Configure WPS function on ESP device.

Parameters
  • en[in] Set to 1 to enable WPS or 0 to disable WPS

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

group LWESP

Lightweight ESP-AT parser.

Defines

lwesp_set_fw_version(v, major_, minor_, patch_)

Set and format major, minor and patch values to firmware version.

Parameters
  • v[in] Version output, pointer to lwesp_sw_version_t structure

  • major_[in] Major version

  • minor_[in] Minor version

  • patch_[in] Patch version

lwesp_get_min_at_fw_version(v)

Get minimal AT version supported by library.

Todo:

Convert to function and take care of different Espressif devices

Parameters

Functions

lwespr_t lwesp_init(lwesp_evt_fn cb_func, const uint32_t blocking)

Init and prepare ESP stack for device operation.

Note

Function must be called from operating system thread context. It creates necessary threads and waits them to start, thus running operating system is important.

Parameters
Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_reset(const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Execute reset and send default commands.

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_reset_with_delay(uint32_t delay, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Execute reset and send default commands with delay before first command.

Parameters
  • delay[in] Number of milliseconds to wait before initiating first command to device

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_restore(const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Execute restore command and set module to default values.

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_set_at_baudrate(uint32_t baud, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Sets baudrate of AT port (usually UART)

Parameters
  • baud[in] Baudrate in units of bits per second

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_set_wifi_mode(lwesp_mode_t mode, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Sets WiFi mode to either station only, access point only or both.

Configuration changes will be saved in the NVS area of ESP device.

Parameters
  • mode[in] Mode of operation. This parameter can be a value of lwesp_mode_t enumeration

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_get_wifi_mode(lwesp_mode_t *mode, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Gets WiFi mode of either station only, access point only or both.

Parameters
  • mode[in] point to space of Mode to get. This parameter can be a pointer of lwesp_mode_t enumeration

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_update_sw(const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Update ESP software remotely.

Note

ESP must be connected to access point to use this feature

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_core_lock(void)

Lock stack from multi-thread access, enable atomic access to core.

If lock was 0 prior function call, lock is enabled and increased

Note

Function may be called multiple times to increase locks. Application must take care to call lwesp_core_unlock the same amount of time to make sure lock gets back to 0

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_core_unlock(void)

Unlock stack for multi-thread access.

Used in conjunction with lwesp_core_lock function

If lock was non-zero before function call, lock is decreased. When lock == 0, protection is disabled and other threads may access to core

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_device_set_present(uint8_t present, const lwesp_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Notify stack if device is present or not.

Use this function to notify stack that device is not physically connected and not ready to communicate with host device

Parameters
  • present[in] Flag indicating device is present

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

  • evt_arg[in] Custom argument for event callback function

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

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

uint8_t lwesp_device_is_present(void)

Check if device is present.

Returns

1 on success, 0 otherwise

uint8_t lwesp_device_is_esp8266(void)

Check if modem device is ESP8266.

Returns

1 on success, 0 otherwise

uint8_t lwesp_device_is_esp32(void)

Check if modem device is ESP32.

Returns

1 on success, 0 otherwise

uint8_t lwesp_device_is_esp32_c3(void)

Check if modem device is ESP32-C3.

Returns

1 on success, 0 otherwise

uint8_t lwesp_delay(const uint32_t ms)

Delay for amount of milliseconds.

Delay is based on operating system semaphores. It locks semaphore and waits for timeout in ms time. Based on operating system, thread may be put to blocked list during delay and may improve execution speed

Parameters

ms[in] Milliseconds to delay

Returns

1 on success, 0 otherwise

uint8_t lwesp_get_current_at_fw_version(lwesp_sw_version_t *const version)

Get current AT firmware version of connected device.

Parameters

version[out] Output version variable

Returns

1 on success, 0 otherwise

Configuration

This is the default configuration of the middleware. When any of the settings shall be modified, it shall be done in dedicated application config lwesp_opts.h file.

Note

Check Getting started for guidelines on how to create and use configuration file.

group LWESP_OPT

ESP-AT options.

Defines

LWESP_CFG_ESP8266

Enables 1 or disables 0 support for ESP8266 AT commands.

LWESP_CFG_ESP32

Enables 1 or disables 0 support for ESP32 AT commands.

LWESP_CFG_ESP32_C3

Enables 1 or disables 0 support for ESP32-C3 AT commands.

LWESP_CFG_OS

Enables 1 or disables 0 operating system support for ESP library.

Note

Value must be set to 1 in the current revision

Note

Check OS configuration group for more configuration related to operating system

LWESP_CFG_MEM_CUSTOM

Enables 1 or disables 0 custom memory management functions.

When set to 1, Memory manager block must be provided manually. This includes implementation of functions lwesp_mem_malloc, lwesp_mem_calloc, lwesp_mem_realloc and lwesp_mem_free

Note

Function declaration follows standard C functions malloc, calloc, realloc, free. Declaration is available in lwesp/lwesp_mem.h file. Include this file to final implementation file

Note

When implementing custom memory allocation, it is necessary to take care of multiple threads accessing same resource for custom allocator

LWESP_CFG_MEM_ALIGNMENT

Memory alignment for dynamic memory allocations.

Note

Some CPUs can work faster if memory is aligned, usually to 4 or 8 bytes. To speed up this possibilities, you can set memory alignment and library will try to allocate memory on aligned boundaries.

Note

Some CPUs such ARM Cortex-M0 dont’t support unaligned memory access.

Note

This value must be power of 2

LWESP_CFG_USE_API_FUNC_EVT

Enables 1 or disables 0 callback function and custom parameter for API functions.

When enabled, 2 additional parameters are available in API functions. When command is executed, callback function with its parameter could be called when not set to NULL.

LWESP_CFG_MAX_SEND_RETRIES

Set number of retries for send data command.

Sometimes it may happen that AT+SEND command fails due to different problems. Trying to send the same data multiple times can raise chances for success.

LWESP_CFG_AT_PORT_BAUDRATE

Default baudrate used for AT port.

Note

User may call API function to change to desired baudrate if necessary

LWESP_CFG_MODE_STATION

Enables 1 or disables 0 ESP acting as station.

Note

When device is in station mode, it can connect to other access points

LWESP_CFG_MODE_ACCESS_POINT

Enables 1 or disables 0 ESP acting as access point.

Note

When device is in access point mode, it can accept connections from other stations

LWESP_CFG_ACCESS_POINT_STRUCT_FULL_FIELDS

Enables 1 or disables 0 full data info in lwesp_ap_t structure.

When enabled, advanced information is stored, and as a consequence, structure size is increased. Information such as scan type, min scan time, max scan time, frequency offset, frequency calibration are added

LWESP_CFG_KEEP_ALIVE

Enables 1 or disables 0 periodic keep-alive events to registered callbacks.

LWESP_CFG_KEEP_ALIVE_TIMEOUT

Timeout periodic time to trigger keep alive events to registered callbacks.

Feature must be enabled with LWESP_CFG_KEEP_ALIVE

LWESP_CFG_RCV_BUFF_SIZE

Buffer size for received data waiting to be processed.

Note

When server mode is active and a lot of connections are in queue this should be set high otherwise your buffer may overflow

Note

Buffer size also depends on TX user driver if it uses DMA or blocking mode. In case of DMA (CPU can work other tasks), buffer may be smaller as CPU will have more time to process all the incoming bytes

Note

This parameter has no meaning when LWESP_CFG_INPUT_USE_PROCESS is enabled

LWESP_CFG_RESET_ON_INIT

Enables 1 or disables 0 reset sequence after lwesp_init call.

Note

When this functionality is disabled, user must manually call lwesp_reset to send reset sequence to ESP device.

LWESP_CFG_RESTORE_ON_INIT

Enables 1 or disables 0 device restore after lwesp_init call.

Note

When this feature is enabled, it will automatically restore and clear any settings stored as default in ESP device

LWESP_CFG_RESET_ON_DEVICE_PRESENT

Enables 1 or disables 0 reset sequence after lwesp_device_set_present call.

Note

When this functionality is disabled, user must manually call lwesp_reset to send reset sequence to ESP device.

LWESP_CFG_RESET_DELAY_DEFAULT

Default delay (milliseconds unit) before sending first AT command on reset sequence.

LWESP_CFG_MAX_SSID_LENGTH

Maximum length of SSID for access point scan.

Note

This parameter must include trailling zero

LWESP_CFG_MAX_PWD_LENGTH

Maximum length of PWD for access point.

Note

This parameter must include trailling zero

LWESP_CFG_CONN_POLL_INTERVAL

Poll interval for connections in units of milliseconds.

Value indicates interval time to call poll event on active connections.

Note

Single poll interval applies for all connections

LWESP_CFG_CONN_MANUAL_TCP_RECEIVE

Enables 1 or disables 0 manual TCP data receive from ESP device.

Normally ESP automatically sends received TCP data to host device in async mode. When host device is slow or if there is memory constrain, it may happen that processing cannot handle all received data.

When feature is enabled, ESP will notify host device about new data available for read and then user may start read process

Note

This feature is only available for TCP connections.

group LWESP_OPT_DBG

Debugging configurations.

Defines

LWESP_CFG_DBG

Set global debug support.

Possible values are LWESP_DBG_ON or LWESP_DBG_OFF

Note

Set to LWESP_DBG_OFF to globally disable all debugs

LWESP_CFG_DBG_OUT(fmt, ...)

Debugging output function.

Called with format and optional parameters for printf-like debug

LWESP_CFG_DBG_LVL_MIN

Minimal debug level.

Check LWESP_DBG_LVL for possible values

LWESP_CFG_DBG_TYPES_ON

Enabled debug types.

When debug is globally enabled with LWESP_CFG_DBG parameter, user must enable debug types such as TRACE or STATE messages.

Check LWESP_DBG_TYPE for possible options. Separate values with bitwise OR operator

LWESP_CFG_DBG_INIT

Set debug level for init function.

Possible values are LWESP_DBG_ON or LWESP_DBG_OFF

LWESP_CFG_DBG_MEM

Set debug level for memory manager.

Possible values are LWESP_DBG_ON or LWESP_DBG_OFF

LWESP_CFG_DBG_INPUT

Set debug level for input module.

Possible values are LWESP_DBG_ON or LWESP_DBG_OFF

LWESP_CFG_DBG_THREAD

Set debug level for ESP threads.

Possible values are LWESP_DBG_ON or LWESP_DBG_OFF

LWESP_CFG_DBG_ASSERT

Set debug level for asserting of input variables.

Possible values are LWESP_DBG_ON or LWESP_DBG_OFF

LWESP_CFG_DBG_IPD

Set debug level for incoming data received from device.

Possible values are LWESP_DBG_ON or LWESP_DBG_OFF

LWESP_CFG_DBG_NETCONN

Set debug level for netconn sequential API.

Possible values are LWESP_DBG_ON or LWESP_DBG_OFF

LWESP_CFG_DBG_PBUF

Set debug level for packet buffer manager.

Possible values are LWESP_DBG_ON or LWESP_DBG_OFF

LWESP_CFG_DBG_CONN

Set debug level for connections.

Possible values are LWESP_DBG_ON or LWESP_DBG_OFF

LWESP_CFG_DBG_VAR

Set debug level for dynamic variable allocations.

Possible values are LWESP_DBG_ON or LWESP_DBG_OFF

LWESP_CFG_AT_ECHO

Enables 1 or disables 0 echo mode on AT commands sent to ESP device.

Note

This mode is useful when debugging ESP communication

group LWESP_OPT_OS

Operating system dependant configuration.

Defines

LWESP_CFG_THREAD_PRODUCER_MBOX_SIZE

Set number of message queue entries for procuder thread.

Message queue is used for storing memory address to command data

LWESP_CFG_THREAD_PROCESS_MBOX_SIZE

Set number of message queue entries for processing thread.

Message queue is used to notify processing thread about new received data on AT port

LWESP_CFG_INPUT_USE_PROCESS

Enables 1 or disables 0 direct support for processing input data.

When this mode is enabled, no overhead is included for copying data to receive buffer because bytes are processed directly by lwesp_input_process function

If this mode is not enabled, then user have to send every received byte via lwesp_input function to the internal buffer for future processing. This may introduce additional overhead with data copy and may decrease library performance

Note

This mode can only be used when LWESP_CFG_OS is enabled

Note

When using this mode, separate thread must be dedicated only for reading data on AT port. It is usually implemented in LL driver

Note

Best case for using this mode is if DMA receive is supported by host device

LWESP_THREAD_PRODUCER_HOOK()

Producer thread hook, called each time thread wakes-up and does the processing.

It can be used to check if thread is alive.

LWESP_THREAD_PROCESS_HOOK()

Process thread hook, called each time thread wakes-up and does the processing.

It can be used to check if thread is alive.

group LWESP_OPT_STD_LIB

Standard C library configuration.

Configuration allows you to overwrite default C language function in case of better implementation with hardware (for example DMA for data copy).

Defines

LWESP_MEMCPY(dst, src, len)

Memory copy function declaration.

User is able to change the memory function, in case hardware supports copy operation, it may implement its own

Function prototype must be similar to:

void *  my_memcpy(void* dst, const void* src, size_t len);

Parameters
  • dst[in] Destination memory start address

  • src[in] Source memory start address

  • len[in] Number of bytes to copy

Returns

Destination memory start address

LWESP_MEMSET(dst, b, len)

Memory set function declaration.

Function prototype must be similar to:

void *  my_memset(void* dst, int b, size_t len);

Parameters
  • dst[in] Destination memory start address

  • b[in] Value (byte) to set in memory

  • len[in] Number of bytes to set

Returns

Destination memory start address

group LWESP_OPT_MODULES

Configuration of specific modules.

Defines

LWESP_CFG_DNS

Enables 1 or disables 0 support for DNS functions.

LWESP_CFG_WPS

Enables 1 or disables 0 support for WPS functions.

LWESP_CFG_SNTP

Enables 1 or disables 0 support for SNTP protocol with AT commands.

LWESP_CFG_HOSTNAME

Enables 1 or disables 0 support for hostname with AT commands.

LWESP_CFG_PING

Enables 1 or disables 0 support for ping functions.

LWESP_CFG_MDNS

Enables 1 or disables 0 support for mDNS.

LWESP_CFG_SMART

Enables 1 or disables 0 support for SMART config.

LWESP_CFG_WEBSERVER

Enables 1 or disables 0 support for Web Server feature.

group LWESP_OPT_MODULES_NETCONN

Configuration of netconn API module.

Defines

LWESP_CFG_NETCONN

Enables 1 or disables 0 NETCONN sequential API support for OS systems.

See

LWESP_CFG_OS

Note

To use this feature, OS support is mandatory.

LWESP_CFG_NETCONN_RECEIVE_TIMEOUT

Enables 1 or disables 0 receive timeout feature.

When this option is enabled, user will get an option to set timeout value for receive data on netconn, before function returns timeout error.

Note

Even if this option is enabled, user must still manually set timeout, by default time will be set to 0 which means no timeout.

LWESP_CFG_NETCONN_ACCEPT_QUEUE_LEN

Accept queue length for new client when netconn server is used.

Defines number of maximal clients waiting in accept queue of server connection

LWESP_CFG_NETCONN_RECEIVE_QUEUE_LEN

Receive queue length for pbuf entries.

Defines maximal number of pbuf data packet references for receive

group LWESP_OPT_MODULES_MQTT

Configuration of MQTT and MQTT API client modules.

Defines

LWESP_CFG_MQTT_MAX_REQUESTS

Maximal number of open MQTT requests at a time.

LWESP_CFG_DBG_MQTT

Set debug level for MQTT client module.

Possible values are LWESP_DBG_ON or LWESP_DBG_OFF

LWESP_CFG_DBG_MQTT_API

Set debug level for MQTT API client module.

Possible values are LWESP_DBG_ON or LWESP_DBG_OFF

group LWESP_OPT_MODULES_CAYENNE

Configuration of Cayenne MQTT client.

Defines

LWESP_CFG_DBG_CAYENNE

Set debug level for Cayenne MQTT client module.

Possible values are LWESP_DBG_ON or LWESP_DBG_OFF

group LWESP_OPT_APP_HTTP

Configuration of HTTP server app.

Defines

LWESP_CFG_DBG_SERVER

Server debug default setting.

HTTP_SSI_TAG_START

SSI tag start string

HTTP_SSI_TAG_START_LEN

SSI tag start length

HTTP_SSI_TAG_END

SSI tag end string

HTTP_SSI_TAG_END_LEN

SSI tag end length

HTTP_SSI_TAG_MAX_LEN

Maximal length of tag name excluding start and end parts of tag.

HTTP_SUPPORT_POST

Enables 1 or disables 0 support for POST request.

HTTP_MAX_URI_LEN

Maximal length of allowed uri length including parameters in format /uri/sub/path?param=value

HTTP_MAX_PARAMS

Maximal number of parameters in URI.

HTTP_USE_METHOD_NOTALLOWED_RESP

Enables 1 or disables 0 method not allowed response.

Response is used in case user makes HTTP request with method which is not on the list of allowed methods. See http_req_method_t

Note

When disabled, connection will be closed without response

HTTP_USE_DEFAULT_STATIC_FILES

Enables 1 or disables 1 default static files.

To allow fast startup of server development, several static files are included by default:

  • /index.html

  • /index.shtml

  • /js/style.css

  • /js/js.js

HTTP_DYNAMIC_HEADERS

Enables 1 or disables 0 dynamic headers support.

With dynamic headers enabled, script will try to detect most common file extensions and will try to response with:

  • HTTP response code as first line

  • Server name as second line

  • Content type as third line including end of headers (empty line)

HTTP_DYNAMIC_HEADERS_CONTENT_LEN

Enables 1 or disables 0 content length header for response.

If response has fixed length without SSI tags, dynamic headers will try to include “Content-Length” header as part of response message sent to client

Note

In order to use this, HTTP_DYNAMIC_HEADERS must be enabled

HTTP_SERVER_NAME

Default server name for Server: x response dynamic header.

Platform specific

List of all the modules:

Low-Level functions

Low-level module consists of callback-only functions, which are called by middleware and must be implemented by final application.

Tip

Check Porting guide for actual implementation

group LWESP_LL

Low-level communication functions.

Typedefs

typedef size_t (*lwesp_ll_send_fn)(const void *data, size_t len)

Function prototype for AT output data.

Param data

[in] Pointer to data to send. This parameter can be set to NULL

Param len

[in] Number of bytes to send. This parameter can be set to 0 to indicate that internal buffer can be flushed to stream. This is implementation defined and feature might be ignored

Return

Number of bytes sent

typedef uint8_t (*lwesp_ll_reset_fn)(uint8_t state)

Function prototype for hardware reset of ESP device.

Param state

[in] State indicating reset. When set to 1, reset must be active (usually pin active low), or set to 0 when reset is cleared

Return

1 on successful action, 0 otherwise

Functions

lwespr_t lwesp_ll_init(lwesp_ll_t *ll)

Callback function called from initialization process.

Note

This function may be called multiple times if AT baudrate is changed from application. It is important that every configuration except AT baudrate is configured only once!

Note

This function may be called from different threads in ESP stack when using OS. When LWESP_CFG_INPUT_USE_PROCESS is set to 1, this function may be called from user UART thread.

Parameters

ll[inout] Pointer to lwesp_ll_t structure to fill data for communication functions

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_ll_deinit(lwesp_ll_t *ll)

Callback function to de-init low-level communication part.

Parameters

ll[inout] Pointer to lwesp_ll_t structure to fill data for communication functions

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

struct lwesp_ll_t
#include <lwesp_typedefs.h>

Low level user specific functions.

Public Members

lwesp_ll_send_fn send_fn

Callback function to transmit data

lwesp_ll_reset_fn reset_fn

Reset callback function

uint32_t baudrate

UART baudrate value

struct lwesp_ll_t::[anonymous] uart

UART communication parameters

System functions

System functions are bridge between operating system system calls and middleware system calls. Middleware is tightly coupled with operating system features hence it is important to include OS features directly.

It includes support for:

  • Thread management, to start/stop threads

  • Mutex management for recursive mutexes

  • Semaphore management for binary-only semaphores

  • Message queues for thread-safe data exchange between threads

  • Core system protection for mutual exclusion to access shared resources

Tip

Check Porting guide for actual implementation guidelines.

group LWESP_SYS

System based function for OS management, timings, etc.

Main

uint8_t lwesp_sys_init(void)

Init system dependant parameters.

After this function is called, all other system functions must be fully ready.

Returns

1 on success, 0 otherwise

uint32_t lwesp_sys_now(void)

Get current time in units of milliseconds.

Returns

Current time in units of milliseconds

uint8_t lwesp_sys_protect(void)

Protect middleware core.

Stack protection must support recursive mode. This function may be called multiple times, even if access has been granted before.

Note

Most operating systems support recursive mutexes.

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_unprotect(void)

Unprotect middleware core.

This function must follow number of calls of lwesp_sys_protect and unlock access only when counter reached back zero.

Note

Most operating systems support recursive mutexes.

Returns

1 on success, 0 otherwise

Mutex

uint8_t lwesp_sys_mutex_create(lwesp_sys_mutex_t *p)

Create new recursive mutex.

Note

Recursive mutex has to be created as it may be locked multiple times before unlocked

Parameters

p[out] Pointer to mutex structure to allocate

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_mutex_delete(lwesp_sys_mutex_t *p)

Delete recursive mutex from system.

Parameters

p[in] Pointer to mutex structure

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_mutex_lock(lwesp_sys_mutex_t *p)

Lock recursive mutex, wait forever to lock.

Parameters

p[in] Pointer to mutex structure

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_mutex_unlock(lwesp_sys_mutex_t *p)

Unlock recursive mutex.

Parameters

p[in] Pointer to mutex structure

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_mutex_isvalid(lwesp_sys_mutex_t *p)

Check if mutex structure is valid system.

Parameters

p[in] Pointer to mutex structure

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_mutex_invalid(lwesp_sys_mutex_t *p)

Set recursive mutex structure as invalid.

Parameters

p[in] Pointer to mutex structure

Returns

1 on success, 0 otherwise

Semaphores

uint8_t lwesp_sys_sem_create(lwesp_sys_sem_t *p, uint8_t cnt)

Create a new binary semaphore and set initial state.

Note

Semaphore may only have 1 token available

Parameters
  • p[out] Pointer to semaphore structure to fill with result

  • cnt[in] Count indicating default semaphore state: 0: Take semaphore token immediately 1: Keep token available

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_sem_delete(lwesp_sys_sem_t *p)

Delete binary semaphore.

Parameters

p[in] Pointer to semaphore structure

Returns

1 on success, 0 otherwise

uint32_t lwesp_sys_sem_wait(lwesp_sys_sem_t *p, uint32_t timeout)

Wait for semaphore to be available.

Parameters
  • p[in] Pointer to semaphore structure

  • timeout[in] Timeout to wait in milliseconds. When 0 is applied, wait forever

Returns

Number of milliseconds waited for semaphore to become available or LWESP_SYS_TIMEOUT if not available within given time

uint8_t lwesp_sys_sem_release(lwesp_sys_sem_t *p)

Release semaphore.

Parameters

p[in] Pointer to semaphore structure

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_sem_isvalid(lwesp_sys_sem_t *p)

Check if semaphore is valid.

Parameters

p[in] Pointer to semaphore structure

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_sem_invalid(lwesp_sys_sem_t *p)

Invalid semaphore.

Parameters

p[in] Pointer to semaphore structure

Returns

1 on success, 0 otherwise

Message queues

uint8_t lwesp_sys_mbox_create(lwesp_sys_mbox_t *b, size_t size)

Create a new message queue with entry type of void *

Parameters
  • b[out] Pointer to message queue structure

  • size[in] Number of entries for message queue to hold

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_mbox_delete(lwesp_sys_mbox_t *b)

Delete message queue.

Parameters

b[in] Pointer to message queue structure

Returns

1 on success, 0 otherwise

uint32_t lwesp_sys_mbox_put(lwesp_sys_mbox_t *b, void *m)

Put a new entry to message queue and wait until memory available.

Parameters
  • b[in] Pointer to message queue structure

  • m[in] Pointer to entry to insert to message queue

Returns

Time in units of milliseconds needed to put a message to queue

uint32_t lwesp_sys_mbox_get(lwesp_sys_mbox_t *b, void **m, uint32_t timeout)

Get a new entry from message queue with timeout.

Parameters
  • b[in] Pointer to message queue structure

  • m[in] Pointer to pointer to result to save value from message queue to

  • timeout[in] Maximal timeout to wait for new message. When 0 is applied, wait for unlimited time

Returns

Time in units of milliseconds needed to put a message to queue or LWESP_SYS_TIMEOUT if it was not successful

uint8_t lwesp_sys_mbox_putnow(lwesp_sys_mbox_t *b, void *m)

Put a new entry to message queue without timeout (now or fail)

Parameters
  • b[in] Pointer to message queue structure

  • m[in] Pointer to message to save to queue

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_mbox_getnow(lwesp_sys_mbox_t *b, void **m)

Get an entry from message queue immediately.

Parameters
  • b[in] Pointer to message queue structure

  • m[in] Pointer to pointer to result to save value from message queue to

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_mbox_isvalid(lwesp_sys_mbox_t *b)

Check if message queue is valid.

Parameters

b[in] Pointer to message queue structure

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_mbox_invalid(lwesp_sys_mbox_t *b)

Invalid message queue.

Parameters

b[in] Pointer to message queue structure

Returns

1 on success, 0 otherwise

Threads

uint8_t lwesp_sys_thread_create(lwesp_sys_thread_t *t, const char *name, lwesp_sys_thread_fn thread_func, void *const arg, size_t stack_size, lwesp_sys_thread_prio_t prio)

Create a new thread.

Parameters
  • t[out] Pointer to thread identifier if create was successful. It may be set to NULL

  • name[in] Name of a new thread

  • thread_func[in] Thread function to use as thread body

  • arg[in] Thread function argument

  • stack_size[in] Size of thread stack in uints of bytes. If set to 0, reserve default stack size

  • prio[in] Thread priority

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_thread_terminate(lwesp_sys_thread_t *t)

Terminate thread (shut it down and remove)

Parameters

t[in] Pointer to thread handle to terminate. If set to NULL, terminate current thread (thread from where function is called)

Returns

1 on success, 0 otherwise

uint8_t lwesp_sys_thread_yield(void)

Yield current thread.

Returns

1 on success, 0 otherwise

Defines

LWESP_SYS_MUTEX_NULL

Mutex invalid value.

Value assigned to lwesp_sys_mutex_t type when it is not valid.

LWESP_SYS_SEM_NULL

Semaphore invalid value.

Value assigned to lwesp_sys_sem_t type when it is not valid.

LWESP_SYS_MBOX_NULL

Message box invalid value.

Value assigned to lwesp_sys_mbox_t type when it is not valid.

LWESP_SYS_TIMEOUT

OS timeout value.

Value returned by operating system functions (mutex wait, sem wait, mbox wait) when it returns timeout and does not give valid value to application

LWESP_SYS_THREAD_PRIO

Default thread priority value used by middleware to start built-in threads.

Threads can well operate with normal (default) priority and do not require any special feature in terms of priority for proper operation.

LWESP_SYS_THREAD_SS

Stack size in units of bytes for system threads.

It is used as default stack size for all built-in threads.

Typedefs

typedef void (*lwesp_sys_thread_fn)(void*)

Thread function prototype.

typedef void *lwesp_sys_mutex_t

System mutex type.

It is used by middleware as base type of mutex.

typedef void *lwesp_sys_sem_t

System semaphore type.

It is used by middleware as base type of mutex.

typedef void *lwesp_sys_mbox_t

System message queue type.

It is used by middleware as base type of mutex.

typedef void *lwesp_sys_thread_t

System thread ID type.

typedef int lwesp_sys_thread_prio_t

System thread priority type.

It is used as priority type for system function, to start new threads by middleware.

Applications

Cayenne MQTT API
group LWESP_APP_CAYENNE_API

MQTT client API for Cayenne.

Defines

LWESP_CAYENNE_API_VERSION

Cayenne API version in string.

LWESP_CAYENNE_HOST

Cayenne host server.

LWESP_CAYENNE_PORT

Cayenne port number.

LWESP_CAYENNE_NO_CHANNEL

No channel macro

LWESP_CAYENNE_ALL_CHANNELS

All channels macro

Typedefs

typedef lwespr_t (*lwesp_cayenne_evt_fn)(struct lwesp_cayenne *c, lwesp_cayenne_evt_t *evt)

Cayenne event callback function.

Param c

[in] Cayenne handle

Param evt

[in] Event handle

Return

lwespOK on success, member of lwespr_t otherwise

Enums

enum lwesp_cayenne_topic_t

List of possible cayenne topics.

Values:

enumerator LWESP_CAYENNE_TOPIC_DATA

Data topic

enumerator LWESP_CAYENNE_TOPIC_COMMAND

Command topic

enumerator LWESP_CAYENNE_TOPIC_CONFIG
enumerator LWESP_CAYENNE_TOPIC_RESPONSE
enumerator LWESP_CAYENNE_TOPIC_SYS_MODEL
enumerator LWESP_CAYENNE_TOPIC_SYS_VERSION
enumerator LWESP_CAYENNE_TOPIC_SYS_CPU_MODEL
enumerator LWESP_CAYENNE_TOPIC_SYS_CPU_SPEED
enumerator LWESP_CAYENNE_TOPIC_DIGITAL
enumerator LWESP_CAYENNE_TOPIC_DIGITAL_COMMAND
enumerator LWESP_CAYENNE_TOPIC_DIGITAL_CONFIG
enumerator LWESP_CAYENNE_TOPIC_ANALOG
enumerator LWESP_CAYENNE_TOPIC_ANALOG_COMMAND
enumerator LWESP_CAYENNE_TOPIC_ANALOG_CONFIG
enumerator LWESP_CAYENNE_TOPIC_END

Last entry

enum lwesp_cayenne_rlwesp_t

Cayenne response types.

Values:

enumerator LWESP_CAYENNE_RESP_OK

Response OK

enumerator LWESP_CAYENNE_RESP_ERROR

Response error

enum lwesp_cayenne_evt_type_t

Cayenne events.

Values:

enumerator LWESP_CAYENNE_EVT_CONNECT

Connect to Cayenne event

enumerator LWESP_CAYENNE_EVT_DISCONNECT

Disconnect from Cayenne event

enumerator LWESP_CAYENNE_EVT_DATA

Data received event

Functions

lwespr_t lwesp_cayenne_create(lwesp_cayenne_t *c, const lwesp_mqtt_client_info_t *client_info, lwesp_cayenne_evt_fn evt_fn)

Create new instance of cayenne MQTT connection.

Note

Each call to this functions starts new thread for async receive processing. Function will block until thread is created and successfully started

Parameters
  • c[in] Cayenne empty handle

  • client_info[in] MQTT client info with username, password and id

  • evt_fn[in] Event function

Returns

lwespOK on success, member of lwespr_t otherwise

lwespr_t lwesp_cayenne_subscribe(lwesp_cayenne_t *c, lwesp_cayenne_topic_t topic, uint16_t channel)

Subscribe to cayenne based topics and channels.

Parameters
  • c[in] Cayenne handle

  • topic[in] Cayenne topic

  • channel[in] Optional channel number. Use LWESP_CAYENNE_NO_CHANNEL when channel is not needed or LWESP_CAYENNE_ALL_CHANNELS to subscribe to all channels

Returns

lwespOK on success, member of lwespr_t otherwise

lwespr_t lwesp_cayenne_publish_data(lwesp_cayenne_t *c, lwesp_cayenne_topic_t topic, uint16_t channel, const char *type, const char *unit, const char *data)

Publish data to cayenne cloud.

Parameters
  • c[in] Cayenne handle

  • topic[in] Cayenne specific topic to publish on

  • channel[in] Device channel to publish on

  • type[in] Data type, string format, for example temp for temperature. Set to NULL if not used

  • unit[in] Data unit, string format, for example c for celcius. Set to NULL if not used

  • data[in] Actual data, for example 127 for 127 degrees

Returns

lwespOK on success, member of lwespr_t otherwise

lwespr_t lwesp_cayenne_publish_float(lwesp_cayenne_t *c, lwesp_cayenne_topic_t topic, uint16_t channel, const char *type, const char *unit, float f)
lwespr_t lwesp_cayenne_publish_response(lwesp_cayenne_t *c, lwesp_cayenne_msg_t *msg, lwesp_cayenne_rlwesp_t resp, const char *message)

Publish response message to command.

Parameters
  • c[in] Cayenne handle

  • msg[in] Received message with command topic

  • resp[in] Response type, either OK or ERROR

  • message[in] Message text in case of error to be displayed to Cayenne dashboard

Returns

lwespOK on success, member of lwespr_t otherwise

struct lwesp_cayenne_key_value_t
#include <lwesp_cayenne.h>

Key/Value pair structure.

Public Members

const char *key

Key string

const char *value

Value string

struct lwesp_cayenne_msg_t
#include <lwesp_cayenne.h>

Cayenne message.

Public Members

lwesp_cayenne_topic_t topic

Message topic

uint16_t channel

Message channel, optional, based on topic type

const char *seq

Sequence string on command

lwesp_cayenne_key_value_t values[2]

Key/Value pair of values

size_t values_count

Count of valid pairs in values member

struct lwesp_cayenne_evt_t
#include <lwesp_cayenne.h>

Cayenne event.

Public Members

lwesp_cayenne_evt_type_t type

Event type

lwesp_cayenne_msg_t *msg

Pointer to data message

struct lwesp_cayenne_evt_t::[anonymous]::[anonymous] data

Data event, used with LWESP_CAYENNE_EVT_DATA event

union lwesp_cayenne_evt_t::[anonymous] evt

Event union

struct lwesp_cayenne_t
#include <lwesp_cayenne.h>

Cayenne handle.

Public Members

lwesp_mqtt_client_api_p api_c

MQTT API client

const lwesp_mqtt_client_info_t *info_c

MQTT Client info structure

lwesp_cayenne_msg_t msg

Received data message

lwesp_cayenne_evt_t evt

Event handle

lwesp_cayenne_evt_fn evt_fn

Event callback function

lwesp_sys_thread_t thread

Cayenne thread handle

lwesp_sys_sem_t sem

Sync semaphore handle

HTTP Server
group LWESP_APP_HTTP_SERVER

HTTP server based on callback API.

Defines

HTTP_MAX_HEADERS

Maximal number of headers we can control.

lwesp_http_server_write_string(hs, str)

Write string to HTTP server output.

See

lwesp_http_server_write

Note

May only be called from SSI callback function

Parameters
  • hs[in] HTTP handle

  • str[in] String to write

Returns

Number of bytes written to output

Typedefs

typedef char *(*http_cgi_fn)(http_param_t *params, size_t params_len)

CGI callback function.

Param params

[in] Pointer to list of parameteres and their values

Param params_len

[in] Number of parameters

Return

Function must return a new URI which is used later as response string, such as “/index.html” or similar

typedef lwespr_t (*http_post_start_fn)(struct http_state *hs, const char *uri, uint32_t content_length)

Post request started with non-zero content length function prototype.

Param hs

[in] HTTP state

Param uri

[in] POST request URI

Param content_length

[in] Total content length (Content-Length HTTP parameter) in units of bytes

Return

lwespOK on success, member of lwespr_t otherwise

typedef lwespr_t (*http_post_data_fn)(struct http_state *hs, lwesp_pbuf_p pbuf)

Post data received on request function prototype.

Note

This function may be called multiple time until content_length from http_post_start_fn callback is not reached

Param hs

[in] HTTP state

Param pbuf

[in] Packet buffer wit reciveed data

Return

lwespOK on success, member of lwespr_t otherwise

typedef lwespr_t (*http_post_end_fn)(struct http_state *hs)

End of POST data request function prototype.

Param hs

[in] HTTP state

Return

lwespOK on success, member of lwespr_t otherwise

typedef size_t (*http_ssi_fn)(struct http_state *hs, const char *tag_name, size_t tag_len)

SSI (Server Side Includes) callback function prototype.

Note

User can use server write functions to directly write to connection output

Param hs

[in] HTTP state

Param tag_name

[in] Name of TAG to replace with user content

Param tag_len

[in] Length of TAG

Returns
  • 1 – Everything was written on this tag

  • 0 – There are still data to write to output which means callback will be called again for user to process all the data

typedef uint8_t (*http_fs_open_fn)(struct http_fs_file *file, const char *path)

File system open file function Function is called when user file system (FAT or similar) should be invoked to open a file from specific path.

Param file

[in] Pointer to file where user has to set length of file if opening was successful

Param path

[in] Path of file to open

Return

1 if file is opened, 0 otherwise

typedef uint32_t (*http_fs_read_fn)(struct http_fs_file *file, void *buff, size_t btr)

File system read file function Function may be called for 2 purposes. First is to read data and second to get remaining length of file to read.

Param file

[in] File pointer to read content

Param buff

[in] Buffer to read data to. When parameter is set to NULL, number of remaining bytes available to read should be returned

Param btr

[in] Number of bytes to read from file. This parameter has no meaning when buff is NULL

Return

Number of bytes read or number of bytes available to read

typedef uint8_t (*http_fs_close_fn)(struct http_fs_file *file)

Close file callback function.

Param file

[in] File to close

Return

1 on success, 0 otherwise

Enums

enum http_req_method_t

Request method type.

Values:

enumerator HTTP_METHOD_NOTALLOWED

HTTP method is not allowed

enumerator HTTP_METHOD_GET

HTTP request method GET

enumerator HTTP_METHOD_POST

HTTP request method POST

enum http_ssi_state_t

List of SSI TAG parsing states.

Values:

enumerator HTTP_SSI_STATE_WAIT_BEGIN

Waiting beginning of tag

enumerator HTTP_SSI_STATE_BEGIN

Beginning detected, parsing it

enumerator HTTP_SSI_STATE_TAG

Parsing TAG value

enumerator HTTP_SSI_STATE_END

Parsing end of TAG

Functions

lwespr_t lwesp_http_server_init(const http_init_t *init, lwesp_port_t port)

Initialize HTTP server at specific port.

Parameters
  • init[in] Initialization structure for server

  • port[in] Port for HTTP server, usually 80

Returns

lwespOK on success, member of lwespr_t otherwise

size_t lwesp_http_server_write(http_state_t *hs, const void *data, size_t len)

Write data directly to connection from callback.

Note

This function may only be called from SSI callback function for HTTP server

Parameters
  • hs[in] HTTP state

  • data[in] Data to write

  • len[in] Length of bytes to write

Returns

Number of bytes written

struct http_param_t
#include <lwesp_http_server.h>

HTTP parameters on http URI in format ?param1=value1&param2=value2&...

Public Members

const char *name

Name of parameter

const char *value

Parameter value

struct http_cgi_t
#include <lwesp_http_server.h>

CGI structure to register handlers on URI paths.

Public Members

const char *uri

URI path for CGI handler

http_cgi_fn fn

Callback function to call when we have a CGI match

struct http_init_t
#include <lwesp_http_server.h>

HTTP server initialization structure.

Public Members

http_post_start_fn post_start_fn

Callback function for post start

http_post_data_fn post_data_fn

Callback functon for post data

http_post_end_fn post_end_fn

Callback functon for post end

const http_cgi_t *cgi

Pointer to array of CGI entries. Set to NULL if not used

size_t cgi_count

Length of CGI array. Set to 0 if not used

http_ssi_fn ssi_fn

SSI callback function

http_fs_open_fn fs_open

Open file function callback

http_fs_read_fn fs_read

Read file function callback

http_fs_close_fn fs_close

Close file function callback

struct http_fs_file_table_t
#include <lwesp_http_server.h>

HTTP file system table structure of static files in device memory.

Public Members

const char *path

File path, ex. “/index.html”

const void *data

Pointer to file data

uint32_t size

Size of file in units of bytes

struct http_fs_file_t
#include <lwesp_http_server.h>

HTTP response file structure.

Public Members

const uint8_t *data

Pointer to data array in case file is static

uint8_t is_static

Flag indicating file is static and no dynamic read is required

uint32_t size

Total length of file

uint32_t fptr

File pointer to indicate next read position

const uint16_t *rem_open_files

Pointer to number of remaining open files. User can use value on this pointer to get number of other opened files

void *arg

User custom argument, may be used for user specific file system object

struct http_state_t
#include <lwesp_http_server.h>

HTTP state structure.

Public Members

lwesp_conn_p conn

Connection handle

lwesp_pbuf_p p

Header received pbuf chain

size_t conn_mem_available

Available memory in connection send queue

uint32_t written_total

Total number of bytes written into send buffer

uint32_t sent_total

Number of bytes we already sent

http_req_method_t req_method

Used request method

uint8_t headers_received

Did we fully received a headers?

uint8_t process_resp

Process with response flag

uint32_t content_length

Total expected content length for request (on POST) (without headers)

uint32_t content_received

Content length received so far (POST request, without headers)

http_fs_file_t rlwesp_file

Response file structure

uint8_t rlwesp_file_opened

Status if response file is opened and ready

const uint8_t *buff

Buffer pointer with data

uint32_t buff_len

Total length of buffer

uint32_t buff_ptr

Current buffer pointer

void *arg

User optional argument

const char *dyn_hdr_strs[4]

Pointer to constant strings for dynamic header outputs

size_t dyn_hdr_idx

Current header for processing on output

size_t dyn_hdr_pos

Current position in current index for output

char dyn_hdr_cnt_len[30]

Content length header response: “Content-Length: 0123456789\r\n”

uint8_t is_ssi

Flag if current request is SSI enabled

http_ssi_state_t ssi_state

Current SSI state when parsing SSI tags

char ssi_tag_buff[5 + 3 + 10 + 1]

Temporary buffer for SSI tag storing

size_t ssi_tag_buff_ptr

Current write pointer

size_t ssi_tag_buff_written

Number of bytes written so far to output buffer in case tag is not valid

size_t ssi_tag_len

Length of SSI tag

size_t ssi_tag_process_more

Set to 1 when we have to process tag multiple times

group LWESP_APP_HTTP_SERVER_FS_FAT

FATFS file system implementation for dynamic files.

Functions

uint8_t http_fs_open(http_fs_file_t *file, const char *path)

Open a file of specific path.

Parameters
  • file[in] File structure to fill if file is successfully open

  • path[in] File path to open in format “/js/scripts.js” or “/index.html”

Returns

1 on success, 0 otherwise

uint32_t http_fs_read(http_fs_file_t *file, void *buff, size_t btr)

Read a file content.

Parameters
  • file[in] File handle to read

  • buff[out] Buffer to read data to. When set to NULL, function should return remaining available data to read

  • btr[in] Number of bytes to read. Has no meaning when buff = NULL

Returns

Number of bytes read or number of bytes available to read

uint8_t http_fs_close(http_fs_file_t *file)

Close a file handle.

Parameters

file[in] File handle

Returns

1 on success, 0 otherwise

MQTT Client

MQTT client v3.1.1 implementation, based on callback (non-netconn) connection API.

MQTT application example code
  1/*
  2 * MQTT client example with ESP device.
  3 *
  4 * Once device is connected to network,
  5 * it will try to connect to mosquitto test server and start the MQTT.
  6 *
  7 * If successfully connected, it will publish data to "esp8266_mqtt_topic" topic every x seconds.
  8 *
  9 * To check if data are sent, you can use mqtt-spy PC software to inspect
 10 * test.mosquitto.org server and subscribe to publishing topic
 11 */
 12
 13#include "lwesp/apps/lwesp_mqtt_client.h"
 14#include "lwesp/lwesp.h"
 15#include "lwesp/lwesp_timeout.h"
 16#include "mqtt_client.h"
 17
 18/**
 19 * \brief           MQTT client structure
 20 */
 21static lwesp_mqtt_client_p
 22mqtt_client;
 23
 24/**
 25 * \brief           Client ID is structured from ESP station MAC address
 26 */
 27static char
 28mqtt_client_id[13];
 29
 30/**
 31 * \brief           Connection information for MQTT CONNECT packet
 32 */
 33static const lwesp_mqtt_client_info_t
 34mqtt_client_info = {
 35    .id = mqtt_client_id,                       /* The only required field for connection! */
 36
 37    .keep_alive = 10,
 38    // .user = "test_username",
 39    // .pass = "test_password",
 40};
 41
 42static void mqtt_cb(lwesp_mqtt_client_p client, lwesp_mqtt_evt_t* evt);
 43static void example_do_connect(lwesp_mqtt_client_p client);
 44static uint32_t retries = 0;
 45
 46/**
 47 * \brief           Custom callback function for ESP events
 48 */
 49static lwespr_t
 50mqtt_lwesp_cb(lwesp_evt_t* evt) {
 51    switch (lwesp_evt_get_type(evt)) {
 52#if LWESP_CFG_MODE_STATION
 53        case LWESP_EVT_WIFI_GOT_IP: {
 54            example_do_connect(mqtt_client);    /* Start connection after we have a connection to network client */
 55            break;
 56        }
 57#endif /* LWESP_CFG_MODE_STATION */
 58        default:
 59            break;
 60    }
 61    return lwespOK;
 62}
 63
 64/**
 65 * \brief           MQTT client thread
 66 * \param[in]       arg: User argument
 67 */
 68void
 69mqtt_client_thread(void const* arg) {
 70    lwesp_mac_t mac;
 71
 72    lwesp_evt_register(mqtt_lwesp_cb);              /* Register new callback for general events from ESP stack */
 73
 74    /* Get station MAC to format client ID */
 75    if (lwesp_sta_getmac(&mac, NULL, NULL, 1) == lwespOK) {
 76        snprintf(mqtt_client_id, sizeof(mqtt_client_id), "%02X%02X%02X%02X%02X%02X",
 77                 (unsigned)mac.mac[0], (unsigned)mac.mac[1], (unsigned)mac.mac[2],
 78                 (unsigned)mac.mac[3], (unsigned)mac.mac[4], (unsigned)mac.mac[5]
 79                );
 80    } else {
 81        strcpy(mqtt_client_id, "unknown");
 82    }
 83    printf("MQTT Client ID: %s\r\n", mqtt_client_id);
 84
 85    /*
 86     * Create a new client with 256 bytes of RAW TX data
 87     * and 128 bytes of RAW incoming data
 88     */
 89    mqtt_client = lwesp_mqtt_client_new(256, 128);/* Create new MQTT client */
 90    if (lwesp_sta_is_joined()) {                  /* If ESP is already joined to network */
 91        example_do_connect(mqtt_client);        /* Start connection to MQTT server */
 92    }
 93
 94    /* Make dummy delay of thread */
 95    while (1) {
 96        lwesp_delay(1000);
 97    }
 98}
 99
100/**
101 * \brief           Timeout callback for MQTT events
102 * \param[in]       arg: User argument
103 */
104void
105mqtt_timeout_cb(void* arg) {
106    static uint32_t num = 10;
107    lwesp_mqtt_client_p client = arg;
108    lwespr_t res;
109
110    static char tx_data[20];
111
112    if (lwesp_mqtt_client_is_connected(client)) {
113        sprintf(tx_data, "R: %u, N: %u", (unsigned)retries, (unsigned)num);
114        if ((res = lwesp_mqtt_client_publish(client, "esp8266_mqtt_topic", tx_data, LWESP_U16(strlen(tx_data)), LWESP_MQTT_QOS_EXACTLY_ONCE, 0, (void*)((uintptr_t)num))) == lwespOK) {
115            printf("Publishing %d...\r\n", (int)num);
116            num++;
117        } else {
118            printf("Cannot publish...: %d\r\n", (int)res);
119        }
120    }
121    lwesp_timeout_add(10000, mqtt_timeout_cb, client);
122}
123
124/**
125 * \brief           MQTT event callback function
126 * \param[in]       client: MQTT client where event occurred
127 * \param[in]       evt: Event type and data
128 */
129static void
130mqtt_cb(lwesp_mqtt_client_p client, lwesp_mqtt_evt_t* evt) {
131    switch (lwesp_mqtt_client_evt_get_type(client, evt)) {
132        /*
133         * Connect event
134         * Called if user successfully connected to MQTT server
135         * or even if connection failed for some reason
136         */
137        case LWESP_MQTT_EVT_CONNECT: {            /* MQTT connect event occurred */
138            lwesp_mqtt_conn_status_t status = lwesp_mqtt_client_evt_connect_get_status(client, evt);
139
140            if (status == LWESP_MQTT_CONN_STATUS_ACCEPTED) {
141                printf("MQTT accepted!\r\n");
142                /*
143                 * Once we are accepted by server,
144                 * it is time to subscribe to different topics
145                 * We will subscrive to "mqtt_lwesp_example_topic" topic,
146                 * and will also set the same name as subscribe argument for callback later
147                 */
148                lwesp_mqtt_client_subscribe(client, "esp8266_mqtt_topic", LWESP_MQTT_QOS_EXACTLY_ONCE, "esp8266_mqtt_topic");
149
150                /* Start timeout timer after 5000ms and call mqtt_timeout_cb function */
151                lwesp_timeout_add(5000, mqtt_timeout_cb, client);
152            } else {
153                printf("MQTT server connection was not successful: %d\r\n", (int)status);
154
155                /* Try to connect all over again */
156                example_do_connect(client);
157            }
158            break;
159        }
160
161        /*
162         * Subscribe event just happened.
163         * Here it is time to check if it was successful or failed attempt
164         */
165        case LWESP_MQTT_EVT_SUBSCRIBE: {
166            const char* arg = lwesp_mqtt_client_evt_subscribe_get_argument(client, evt);  /* Get user argument */
167            lwespr_t res = lwesp_mqtt_client_evt_subscribe_get_result(client, evt); /* Get result of subscribe event */
168
169            if (res == lwespOK) {
170                printf("Successfully subscribed to %s topic\r\n", arg);
171                if (!strcmp(arg, "esp8266_mqtt_topic")) {   /* Check topic name we were subscribed */
172                    /* Subscribed to "esp8266_mqtt_topic" topic */
173
174                    /*
175                     * Now publish an even on example topic
176                     * and set QoS to minimal value which does not guarantee message delivery to received
177                     */
178                    lwesp_mqtt_client_publish(client, "esp8266_mqtt_topic", "test_data", 9, LWESP_MQTT_QOS_AT_MOST_ONCE, 0, (void*)1);
179                }
180            }
181            break;
182        }
183
184        /* Message published event occurred */
185        case LWESP_MQTT_EVT_PUBLISH: {
186            uint32_t val = (uint32_t)(uintptr_t)lwesp_mqtt_client_evt_publish_get_argument(client, evt);/* Get user argument, which is in fact our custom number */
187
188            printf("Publish event, user argument on message was: %d\r\n", (int)val);
189            break;
190        }
191
192        /*
193         * A new message was published to us
194         * and now it is time to read the data
195         */
196        case LWESP_MQTT_EVT_PUBLISH_RECV: {
197            const char* topic = lwesp_mqtt_client_evt_publish_recv_get_topic(client, evt);
198            size_t topic_len = lwesp_mqtt_client_evt_publish_recv_get_topic_len(client, evt);
199            const uint8_t* payload = lwesp_mqtt_client_evt_publish_recv_get_payload(client, evt);
200            size_t payload_len = lwesp_mqtt_client_evt_publish_recv_get_payload_len(client, evt);
201
202            LWESP_UNUSED(payload);
203            LWESP_UNUSED(payload_len);
204            LWESP_UNUSED(topic);
205            LWESP_UNUSED(topic_len);
206            break;
207        }
208
209        /* Client is fully disconnected from MQTT server */
210        case LWESP_MQTT_EVT_DISCONNECT: {
211            printf("MQTT client disconnected!\r\n");
212            example_do_connect(client);         /* Connect to server all over again */
213            break;
214        }
215
216        default:
217            break;
218    }
219}
220
221/** Make a connection to MQTT server in non-blocking mode */
222static void
223example_do_connect(lwesp_mqtt_client_p client) {
224    if (client == NULL) {
225        return;
226    }
227
228    /*
229     * Start a simple connection to open source
230     * MQTT server on mosquitto.org
231     */
232    retries++;
233    lwesp_timeout_remove(mqtt_timeout_cb);
234    lwesp_mqtt_client_connect(mqtt_client, "test.mosquitto.org", 1883, mqtt_cb, &mqtt_client_info);
235}
group LWESP_APP_MQTT_CLIENT

MQTT client.

Typedefs

typedef struct lwesp_mqtt_client *lwesp_mqtt_client_p

Pointer to lwesp_mqtt_client_t structure.

typedef void (*lwesp_mqtt_evt_fn)(lwesp_mqtt_client_p client, lwesp_mqtt_evt_t *evt)

MQTT event callback function.

Param client

[in] MQTT client

Param evt

[in] MQTT event with type and related data

Enums

enum lwesp_mqtt_qos_t

Quality of service enumeration.

Values:

enumerator LWESP_MQTT_QOS_AT_MOST_ONCE

Delivery is not guaranteed to arrive, but can arrive up to 1 time = non-critical packets where losses are allowed

enumerator LWESP_MQTT_QOS_AT_LEAST_ONCE

Delivery is quaranteed at least once, but it may be delivered multiple times with the same content

enumerator LWESP_MQTT_QOS_EXACTLY_ONCE

Delivery is quaranteed exactly once = very critical packets such as billing informations or similar

enum lwesp_mqtt_state_t

State of MQTT client.

Values:

enumerator LWESP_MQTT_CONN_DISCONNECTED

Connection with server is not established

enumerator LWESP_MQTT_CONN_CONNECTING

Client is connecting to server

enumerator LWESP_MQTT_CONN_DISCONNECTING

Client connection is disconnecting from server

enumerator LWESP_MQTT_CONNECTING

MQTT client is connecting… CONNECT command has been sent to server

enumerator LWESP_MQTT_CONNECTED

MQTT is fully connected and ready to send data on topics

enum lwesp_mqtt_evt_type_t

MQTT event types.

Values:

enumerator LWESP_MQTT_EVT_CONNECT

MQTT client connect event

enumerator LWESP_MQTT_EVT_SUBSCRIBE

MQTT client subscribed to specific topic

enumerator LWESP_MQTT_EVT_UNSUBSCRIBE

MQTT client unsubscribed from specific topic

enumerator LWESP_MQTT_EVT_PUBLISH

MQTT client publish message to server event.

Note

When publishing packet with quality of service LWESP_MQTT_QOS_AT_MOST_ONCE, you may not receive event, even if packet was successfully sent, thus do not rely on this event for packet with qos = LWESP_MQTT_QOS_AT_MOST_ONCE

enumerator LWESP_MQTT_EVT_PUBLISH_RECV

MQTT client received a publish message from server

enumerator LWESP_MQTT_EVT_DISCONNECT

MQTT client disconnected from MQTT server

enumerator LWESP_MQTT_EVT_KEEP_ALIVE

MQTT keep-alive sent to server and reply received

enum lwesp_mqtt_conn_status_t

List of possible results from MQTT server when executing connect command.

Values:

enumerator LWESP_MQTT_CONN_STATUS_ACCEPTED

Connection accepted and ready to use

enumerator LWESP_MQTT_CONN_STATUS_REFUSED_PROTOCOL_VERSION

Connection Refused, unacceptable protocol version

enumerator LWESP_MQTT_CONN_STATUS_REFUSED_ID

Connection refused, identifier rejected

enumerator LWESP_MQTT_CONN_STATUS_REFUSED_SERVER

Connection refused, server unavailable

enumerator LWESP_MQTT_CONN_STATUS_REFUSED_USER_PASS

Connection refused, bad user name or password

enumerator LWESP_MQTT_CONN_STATUS_REFUSED_NOT_AUTHORIZED

Connection refused, not authorized

enumerator LWESP_MQTT_CONN_STATUS_TCP_FAILED

TCP connection to server was not successful

Functions

lwesp_mqtt_client_p lwesp_mqtt_client_new(size_t tx_buff_len, size_t rx_buff_len)

Allocate a new MQTT client structure.

Parameters
  • tx_buff_len[in] Length of raw data output buffer

  • rx_buff_len[in] Length of raw data input buffer

Returns

Pointer to new allocated MQTT client structure or NULL on failure

void lwesp_mqtt_client_delete(lwesp_mqtt_client_p client)

Delete MQTT client structure.

Note

MQTT client must be disconnected first

Parameters

client[in] MQTT client

lwespr_t lwesp_mqtt_client_connect(lwesp_mqtt_client_p client, const char *host, lwesp_port_t port, lwesp_mqtt_evt_fn evt_fn, const lwesp_mqtt_client_info_t *info)

Connect to MQTT server.

Note

After TCP connection is established, CONNECT packet is automatically sent to server

Parameters
  • client[in] MQTT client

  • host[in] Host address for server

  • port[in] Host port number

  • evt_fn[in] Callback function for all events on this MQTT client

  • info[in] Information structure for connection

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_mqtt_client_disconnect(lwesp_mqtt_client_p client)

Disconnect from MQTT server.

Parameters

client[in] MQTT client

Returns

lwespOK if request sent to queue or member of lwespr_t otherwise

uint8_t lwesp_mqtt_client_is_connected(lwesp_mqtt_client_p client)

Test if client is connected to server and accepted to MQTT protocol.

Note

Function will return error if TCP is connected but MQTT not accepted

Parameters

client[in] MQTT client

Returns

1 on success, 0 otherwise

lwespr_t lwesp_mqtt_client_subscribe(lwesp_mqtt_client_p client, const char *topic, lwesp_mqtt_qos_t qos, void *arg)

Subscribe to MQTT topic.

Parameters
  • client[in] MQTT client

  • topic[in] Topic name to subscribe to

  • qos[in] Quality of service. This parameter can be a value of lwesp_mqtt_qos_t

  • arg[in] User custom argument used in callback

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_mqtt_client_unsubscribe(lwesp_mqtt_client_p client, const char *topic, void *arg)

Unsubscribe from MQTT topic.

Parameters
  • client[in] MQTT client

  • topic[in] Topic name to unsubscribe from

  • arg[in] User custom argument used in callback

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_mqtt_client_publish(lwesp_mqtt_client_p client, const char *topic, const void *payload, uint16_t len, lwesp_mqtt_qos_t qos, uint8_t retain, void *arg)

Publish a new message on specific topic.

Parameters
  • client[in] MQTT client

  • topic[in] Topic to send message to

  • payload[in] Message data

  • payload_len[in] Length of payload data

  • qos[in] Quality of service. This parameter can be a value of lwesp_mqtt_qos_t enumeration

  • retain[in] Retian parameter value

  • arg[in] User custom argument used in callback

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

void *lwesp_mqtt_client_get_arg(lwesp_mqtt_client_p client)

Get user argument on client.

Parameters

client[in] MQTT client handle

Returns

User argument

void lwesp_mqtt_client_set_arg(lwesp_mqtt_client_p client, void *arg)

Set user argument on client.

Parameters
  • client[in] MQTT client handle

  • arg[in] User argument

struct lwesp_mqtt_client_info_t
#include <lwesp_mqtt_client.h>

MQTT client information structure.

Public Members

const char *id

Client unique identifier. It is required and must be set by user

const char *user

Authentication username. Set to NULL if not required

const char *pass

Authentication password, set to NULL if not required

uint16_t keep_alive

Keep-alive parameter in units of seconds. When set to 0, functionality is disabled (not recommended)

const char *will_topic

Will topic

const char *will_message

Will message

lwesp_mqtt_qos_t will_qos

Will topic quality of service

struct lwesp_mqtt_request_t
#include <lwesp_mqtt_client.h>

MQTT request object.

Public Members

uint8_t status

Entry status flag for in use or pending bit

uint16_t packet_id

Packet ID generated by client on publish

void *arg

User defined argument

uint32_t expected_sent_len

Number of total bytes which must be sent on connection before we can say “packet was sent”.

uint32_t timeout_start_time

Timeout start time in units of milliseconds

struct lwesp_mqtt_evt_t
#include <lwesp_mqtt_client.h>

MQTT event structure for callback function.

Public Members

lwesp_mqtt_evt_type_t type

Event type

lwesp_mqtt_conn_status_t status

Connection status with MQTT

struct lwesp_mqtt_evt_t::[anonymous]::[anonymous] connect

Event for connecting to server

uint8_t is_accepted

Status if client was accepted to MQTT prior disconnect event

struct lwesp_mqtt_evt_t::[anonymous]::[anonymous] disconnect

Event for disconnecting from server

void *arg

User argument for callback function

lwespr_t res

Response status

struct lwesp_mqtt_evt_t::[anonymous]::[anonymous] sub_unsub_scribed

Event for (un)subscribe to/from topics

struct lwesp_mqtt_evt_t::[anonymous]::[anonymous] publish

Published event

const uint8_t *topic

Pointer to topic identifier

size_t topic_len

Length of topic

const void *payload

Topic payload

size_t payload_len

Length of topic payload

uint8_t dup

Duplicate flag if message was sent again

lwesp_mqtt_qos_t qos

Received packet quality of service

struct lwesp_mqtt_evt_t::[anonymous]::[anonymous] publish_recv

Publish received event

union lwesp_mqtt_evt_t::[anonymous] evt

Event data parameters

group LWESP_APP_MQTT_CLIENT_EVT

Event helper functions.

Connect event

Note

Use these functions on LWESP_MQTT_EVT_CONNECT event

lwesp_mqtt_client_evt_connect_get_status(client, evt)

Get connection status.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

Connection status. Member of lwesp_mqtt_conn_status_t

Disconnect event

Note

Use these functions on LWESP_MQTT_EVT_DISCONNECT event

lwesp_mqtt_client_evt_disconnect_is_accepted(client, evt)

Check if MQTT client was accepted by server when disconnect event occurred.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

1 on success, 0 otherwise

Subscribe/unsubscribe event

Note

Use these functions on LWESP_MQTT_EVT_SUBSCRIBE or LWESP_MQTT_EVT_UNSUBSCRIBE events

lwesp_mqtt_client_evt_subscribe_get_argument(client, evt)

Get user argument used on lwesp_mqtt_client_subscribe.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

User argument

lwesp_mqtt_client_evt_subscribe_get_result(client, evt)

Get result of subscribe event.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

lwespOK on success, member of lwespr_t otherwise

lwesp_mqtt_client_evt_unsubscribe_get_argument(client, evt)

Get user argument used on lwesp_mqtt_client_unsubscribe.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

User argument

lwesp_mqtt_client_evt_unsubscribe_get_result(client, evt)

Get result of unsubscribe event.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

lwespOK on success, member of lwespr_t otherwise

Publish receive event

Note

Use these functions on LWESP_MQTT_EVT_PUBLISH_RECV event

lwesp_mqtt_client_evt_publish_recv_get_topic(client, evt)

Get topic from received publish packet.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

Topic name

lwesp_mqtt_client_evt_publish_recv_get_topic_len(client, evt)

Get topic length from received publish packet.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

Topic length

lwesp_mqtt_client_evt_publish_recv_get_payload(client, evt)

Get payload from received publish packet.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

Packet payload

lwesp_mqtt_client_evt_publish_recv_get_payload_len(client, evt)

Get payload length from received publish packet.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

Payload length

lwesp_mqtt_client_evt_publish_recv_is_duplicate(client, evt)

Check if packet is duplicated.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

1 if duplicated, 0 otherwise

lwesp_mqtt_client_evt_publish_recv_get_qos(client, evt)

Get received quality of service.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

Member of lwesp_mqtt_qos_t enumeration

Publish event

Note

Use these functions on LWESP_MQTT_EVT_PUBLISH event

lwesp_mqtt_client_evt_publish_get_argument(client, evt)

Get user argument used on lwesp_mqtt_client_publish.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

User argument

lwesp_mqtt_client_evt_publish_get_result(client, evt)

Get result of publish event.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

lwespOK on success, member of lwespr_t otherwise

Defines

lwesp_mqtt_client_evt_get_type(client, evt)

Get MQTT event type.

Parameters
  • client[in] MQTT client

  • evt[in] Event handle

Returns

MQTT Event type, value of lwesp_mqtt_evt_type_t enumeration

MQTT Client API

MQTT Client API provides sequential API built on top of MQTT Client.

MQTT API application example code
  1/*
  2 * MQTT client API example with ESP device.
  3 *
  4 * Once device is connected to network,
  5 * it will try to connect to mosquitto test server and start the MQTT.
  6 *
  7 * If successfully connected, it will publish data to "lwesp_mqtt_topic" topic every x seconds.
  8 *
  9 * To check if data are sent, you can use mqtt-spy PC software to inspect
 10 * test.mosquitto.org server and subscribe to publishing topic
 11 */
 12
 13#include "lwesp/apps/lwesp_mqtt_client_api.h"
 14#include "mqtt_client_api.h"
 15#include "lwesp/lwesp_mem.h"
 16
 17/**
 18 * \brief           Connection information for MQTT CONNECT packet
 19 */
 20static const lwesp_mqtt_client_info_t
 21mqtt_client_info = {
 22    .keep_alive = 10,
 23
 24    /* Server login data */
 25    .user = "8a215f70-a644-11e8-ac49-e932ed599553",
 26    .pass = "26aa943f702e5e780f015cd048a91e8fb54cca28",
 27
 28    /* Device identifier address */
 29    .id = "869f5a20-af9c-11e9-b01f-db5cf74e7fb7",
 30};
 31
 32/**
 33 * \brief           Memory for topic
 34 */
 35static char
 36mqtt_topic_str[256];
 37
 38/**
 39 * \brief           Memory for data
 40 */
 41static char
 42mqtt_topic_data[256];
 43
 44/**
 45 * \brief           Generate random number and write it to string
 46 * \param[out]      str: Output string with new number
 47 */
 48void
 49generate_random(char* str) {
 50    static uint32_t random_beg = 0x8916;
 51    random_beg = random_beg * 0x00123455 + 0x85654321;
 52    sprintf(str, "%u", (unsigned)((random_beg >> 8) & 0xFFFF));
 53}
 54
 55/**
 56 * \brief           MQTT client API thread
 57 */
 58void
 59mqtt_client_api_thread(void const* arg) {
 60    lwesp_mqtt_client_api_p client;
 61    lwesp_mqtt_conn_status_t conn_status;
 62    lwesp_mqtt_client_api_buf_p buf;
 63    lwespr_t res;
 64    char random_str[10];
 65
 66    /* Create new MQTT API */
 67    client = lwesp_mqtt_client_api_new(256, 128);
 68    if (client == NULL) {
 69        goto terminate;
 70    }
 71
 72    while (1) {
 73        /* Make a connection */
 74        printf("Joining MQTT server\r\n");
 75
 76        /* Try to join */
 77        conn_status = lwesp_mqtt_client_api_connect(client, "mqtt.mydevices.com", 1883, &mqtt_client_info);
 78        if (conn_status == LWESP_MQTT_CONN_STATUS_ACCEPTED) {
 79            printf("Connected and accepted!\r\n");
 80            printf("Client is ready to subscribe and publish to new messages\r\n");
 81        } else {
 82            printf("Connect API response: %d\r\n", (int)conn_status);
 83            lwesp_delay(5000);
 84            continue;
 85        }
 86
 87        /* Subscribe to topics */
 88        sprintf(mqtt_topic_str, "v1/%s/things/%s/cmd/#", mqtt_client_info.user, mqtt_client_info.id);
 89        if (lwesp_mqtt_client_api_subscribe(client, mqtt_topic_str, LWESP_MQTT_QOS_AT_LEAST_ONCE) == lwespOK) {
 90            printf("Subscribed to topic\r\n");
 91        } else {
 92            printf("Problem subscribing to topic!\r\n");
 93        }
 94
 95        while (1) {
 96            /* Receive MQTT packet with 1000ms timeout */
 97            res = lwesp_mqtt_client_api_receive(client, &buf, 5000);
 98            if (res == lwespOK) {
 99                if (buf != NULL) {
100                    printf("Publish received!\r\n");
101                    printf("Topic: %s, payload: %s\r\n", buf->topic, buf->payload);
102                    lwesp_mqtt_client_api_buf_free(buf);
103                    buf = NULL;
104                }
105            } else if (res == lwespCLOSED) {
106                printf("MQTT connection closed!\r\n");
107                break;
108            } else if (res == lwespTIMEOUT) {
109                printf("Timeout on MQTT receive function. Manually publishing.\r\n");
110
111                /* Publish data on channel 1 */
112                generate_random(random_str);
113                sprintf(mqtt_topic_str, "v1/%s/things/%s/data/1", mqtt_client_info.user, mqtt_client_info.id);
114                sprintf(mqtt_topic_data, "temp,c=%s", random_str);
115                lwesp_mqtt_client_api_publish(client, mqtt_topic_str, mqtt_topic_data, strlen(mqtt_topic_data), LWESP_MQTT_QOS_AT_LEAST_ONCE, 0);
116            }
117        }
118        //goto terminate;
119    }
120
121terminate:
122    lwesp_mqtt_client_api_delete(client);
123    printf("MQTT client thread terminate\r\n");
124    lwesp_sys_thread_terminate(NULL);
125}
group LWESP_APP_MQTT_CLIENT_API

Sequential, single thread MQTT client API.

Typedefs

typedef struct lwesp_mqtt_client_api_buf *lwesp_mqtt_client_api_buf_p

Pointer to lwesp_mqtt_client_api_buf_t structure.

Functions

lwesp_mqtt_client_api_p lwesp_mqtt_client_api_new(size_t tx_buff_len, size_t rx_buff_len)

Create new MQTT client API.

Parameters
  • tx_buff_len[in] Maximal TX buffer for maximal packet length

  • rx_buff_len[in] Maximal RX buffer

Returns

Client handle on success, NULL otherwise

void lwesp_mqtt_client_api_delete(lwesp_mqtt_client_api_p client)

Delete client from memory.

Parameters

client[in] MQTT API client handle

lwesp_mqtt_conn_status_t lwesp_mqtt_client_api_connect(lwesp_mqtt_client_api_p client, const char *host, lwesp_port_t port, const lwesp_mqtt_client_info_t *info)

Connect to MQTT broker.

Parameters
  • client[in] MQTT API client handle

  • host[in] TCP host

  • port[in] TCP port

  • info[in] MQTT client info

Returns

LWESP_MQTT_CONN_STATUS_ACCEPTED on success, member of lwesp_mqtt_conn_status_t otherwise

lwespr_t lwesp_mqtt_client_api_close(lwesp_mqtt_client_api_p client)

Close MQTT connection.

Parameters

client[in] MQTT API client handle

Returns

lwespOK on success, member of lwespr_t otherwise

lwespr_t lwesp_mqtt_client_api_subscribe(lwesp_mqtt_client_api_p client, const char *topic, lwesp_mqtt_qos_t qos)

Subscribe to topic.

Parameters
  • client[in] MQTT API client handle

  • topic[in] Topic to subscribe on

  • qos[in] Quality of service. This parameter can be a value of lwesp_mqtt_qos_t

Returns

lwespOK on success, member of lwespr_t otherwise

lwespr_t lwesp_mqtt_client_api_unsubscribe(lwesp_mqtt_client_api_p client, const char *topic)

Unsubscribe from topic.

Parameters
  • client[in] MQTT API client handle

  • topic[in] Topic to unsubscribe from

Returns

lwespOK on success, member of lwespr_t otherwise

lwespr_t lwesp_mqtt_client_api_publish(lwesp_mqtt_client_api_p client, const char *topic, const void *data, size_t btw, lwesp_mqtt_qos_t qos, uint8_t retain)

Publish new packet to MQTT network.

Parameters
  • client[in] MQTT API client handle

  • topic[in] Topic to publish on

  • data[in] Data to send

  • btw[in] Number of bytes to send for data parameter

  • qos[in] Quality of service. This parameter can be a value of lwesp_mqtt_qos_t

  • retain[in] Set to 1 for retain flag, 0 otherwise

Returns

lwespOK on success, member of lwespr_t otherwise

uint8_t lwesp_mqtt_client_api_is_connected(lwesp_mqtt_client_api_p client)

Check if client MQTT connection is active.

Parameters

client[in] MQTT API client handle

Returns

1 on success, 0 otherwise

lwespr_t lwesp_mqtt_client_api_receive(lwesp_mqtt_client_api_p client, lwesp_mqtt_client_api_buf_p *p, uint32_t timeout)

Receive next packet in specific timeout time.

Note

This function can be called from separate thread than the rest of API function, which allows you to handle receive data separated with custom timeout

Parameters
  • client[in] MQTT API client handle

  • p[in] Pointer to output buffer

  • timeout[in] Maximal time to wait before function returns timeout

Returns

lwespOK on success, lwespCLOSED if MQTT is closed, lwespTIMEOUT on timeout

void lwesp_mqtt_client_api_buf_free(lwesp_mqtt_client_api_buf_p p)

Free buffer memory after usage.

Parameters

p[in] Buffer to free

struct lwesp_mqtt_client_api_buf_t
#include <lwesp_mqtt_client_api.h>

MQTT API RX buffer.

Public Members

char *topic

Topic data

size_t topic_len

Topic length

uint8_t *payload

Payload data

size_t payload_len

Payload length

lwesp_mqtt_qos_t qos

Quality of service

Netconn API

Netconn API is addon on top of existing connection module and allows sending and receiving data with sequential API calls, similar to POSIX socket API.

It can operate in client or server mode and uses operating system features, such as message queues and semaphore to link non-blocking callback API for connections with sequential API for application thread.

Note

Connection API does not directly allow receiving data with sequential and linear code execution. All is based on connection event system. Netconn adds this functionality as it is implemented on top of regular connection API.

Warning

Netconn API are designed to be called from application threads ONLY. It is not allowed to call any of netconn API functions from within interrupt or callback event functions.

Netconn client
Netconn API client block diagram

Netconn API client block diagram

Above block diagram shows basic architecture of netconn client application. There is always one application thread (in green) which calls netconn API functions to interact with connection API in synchronous mode.

Every netconn connection uses dedicated structure to handle message queue for data received packet buffers. Each time new packet is received (red block, data received event), reference to it is written to message queue of netconn structure, while application thread reads new entries from the same queue to get packets.

Netconn client example
  1#include "netconn_client.h"
  2#include "lwesp/lwesp.h"
  3
  4/**
  5 * \brief           Host and port settings
  6 */
  7#define NETCONN_HOST        "example.com"
  8#define NETCONN_PORT        80
  9
 10/**
 11 * \brief           Request header to send on successful connection
 12 */
 13static const char
 14request_header[] = ""
 15                   "GET / HTTP/1.1\r\n"
 16                   "Host: " NETCONN_HOST "\r\n"
 17                   "Connection: close\r\n"
 18                   "\r\n";
 19
 20/**
 21 * \brief           Netconn client thread implementation
 22 * \param[in]       arg: User argument
 23 */
 24void
 25netconn_client_thread(void const* arg) {
 26    lwespr_t res;
 27    lwesp_pbuf_p pbuf;
 28    lwesp_netconn_p client;
 29    lwesp_sys_sem_t* sem = (void*)arg;
 30
 31    /*
 32     * First create a new instance of netconn
 33     * connection and initialize system message boxes
 34     * to accept received packet buffers
 35     */
 36    client = lwesp_netconn_new(LWESP_NETCONN_TYPE_TCP);
 37    if (client != NULL) {
 38        /*
 39         * Connect to external server as client
 40         * with custom NETCONN_CONN_HOST and CONN_PORT values
 41         *
 42         * Function will block thread until we are successfully connected (or not) to server
 43         */
 44        res = lwesp_netconn_connect(client, NETCONN_HOST, NETCONN_PORT);
 45        if (res == lwespOK) {                     /* Are we successfully connected? */
 46            printf("Connected to " NETCONN_HOST "\r\n");
 47            res = lwesp_netconn_write(client, request_header, sizeof(request_header) - 1);    /* Send data to server */
 48            if (res == lwespOK) {
 49                res = lwesp_netconn_flush(client);    /* Flush data to output */
 50            }
 51            if (res == lwespOK) {                 /* Were data sent? */
 52                printf("Data were successfully sent to server\r\n");
 53
 54                /*
 55                 * Since we sent HTTP request,
 56                 * we are expecting some data from server
 57                 * or at least forced connection close from remote side
 58                 */
 59                do {
 60                    /*
 61                     * Receive single packet of data
 62                     *
 63                     * Function will block thread until new packet
 64                     * is ready to be read from remote side
 65                     *
 66                     * After function returns, don't forgot the check value.
 67                     * Returned status will give you info in case connection
 68                     * was closed too early from remote side
 69                     */
 70                    res = lwesp_netconn_receive(client, &pbuf);
 71                    if (res == lwespCLOSED) {     /* Was the connection closed? This can be checked by return status of receive function */
 72                        printf("Connection closed by remote side...\r\n");
 73                        break;
 74                    } else if (res == lwespTIMEOUT) {
 75                        printf("Netconn timeout while receiving data. You may try multiple readings before deciding to close manually\r\n");
 76                    }
 77
 78                    if (res == lwespOK && pbuf != NULL) { /* Make sure we have valid packet buffer */
 79                        /*
 80                         * At this point read and manipulate
 81                         * with received buffer and check if you expect more data
 82                         *
 83                         * After you are done using it, it is important
 84                         * you free the memory otherwise memory leaks will appear
 85                         */
 86                        printf("Received new data packet of %d bytes\r\n", (int)lwesp_pbuf_length(pbuf, 1));
 87                        lwesp_pbuf_free(pbuf);    /* Free the memory after usage */
 88                        pbuf = NULL;
 89                    }
 90                } while (1);
 91            } else {
 92                printf("Error writing data to remote host!\r\n");
 93            }
 94
 95            /*
 96             * Check if connection was closed by remote server
 97             * and in case it wasn't, close it manually
 98             */
 99            if (res != lwespCLOSED) {
100                lwesp_netconn_close(client);
101            }
102        } else {
103            printf("Cannot connect to remote host %s:%d!\r\n", NETCONN_HOST, NETCONN_PORT);
104        }
105        lwesp_netconn_delete(client);             /* Delete netconn structure */
106    }
107
108    printf("Terminating thread\r\n");
109    if (lwesp_sys_sem_isvalid(sem)) {
110        lwesp_sys_sem_release(sem);
111    }
112    lwesp_sys_thread_terminate(NULL);             /* Terminate current thread */
113}
Netconn server
Netconn API server block diagram

Netconn API server block diagram

When netconn is configured in server mode, it is possible to accept new clients from remote side. Application creates netconn server connection, which can only accept clients and cannot send/receive any data. It configures server on dedicated port (selected by application) and listens on it.

When new client connects, server callback function is called with new active connection event. Newly accepted connection is then written to server structure netconn which is later read by application thread. At the same time, netconn connection structure (blue) is created to allow standard send/receive operation on active connection.

Note

Each connected client has its own netconn connection structure. When multiple clients connect to server at the same time, multiple entries are written to connection accept message queue and are ready to be processed by application thread.

From this point, program flow is the same as in case of netconn client.

This is basic example for netconn thread. It waits for client and processes it in blocking mode.

Warning

When multiple clients connect at the same time to netconn server, they are processed one-by-one, sequentially. This may introduce delay in response for other clients. Check netconn concurrency option to process multiple clients at the same time

Netconn server with single processing thread
 1/*
 2 * Netconn server example is based on single thread
 3 * and it listens for single client only on port 23
 4 */
 5#include "netconn_server_1thread.h"
 6#include "lwesp/lwesp.h"
 7
 8/**
 9 * \brief           Basic thread for netconn server to test connections
10 * \param[in]       arg: User argument
11 */
12void
13netconn_server_1thread_thread(void* arg) {
14    lwespr_t res;
15    lwesp_netconn_p server, client;
16    lwesp_pbuf_p p;
17
18    /* Create netconn for server */
19    server = lwesp_netconn_new(LWESP_NETCONN_TYPE_TCP);
20    if (server == NULL) {
21        printf("Cannot create server netconn!\r\n");
22    }
23
24    /* Bind it to port 23 */
25    res = lwesp_netconn_bind(server, 23);
26    if (res != lwespOK) {
27        printf("Cannot bind server\r\n");
28        goto out;
29    }
30
31    /* Start listening for incoming connections with maximal 1 client */
32    res = lwesp_netconn_listen_with_max_conn(server, 1);
33    if (res != lwespOK) {
34        goto out;
35    }
36
37    /* Unlimited loop */
38    while (1) {
39        /* Accept new client */
40        res = lwesp_netconn_accept(server, &client);
41        if (res != lwespOK) {
42            break;
43        }
44        printf("New client accepted!\r\n");
45        while (1) {
46            /* Receive data */
47            res = lwesp_netconn_receive(client, &p);
48            if (res == lwespOK) {
49                printf("Data received!\r\n");
50                lwesp_pbuf_free(p);
51            } else {
52                printf("Netconn receive returned: %d\r\n", (int)res);
53                if (res == lwespCLOSED) {
54                    printf("Connection closed by client\r\n");
55                    break;
56                }
57            }
58        }
59        /* Delete client */
60        if (client != NULL) {
61            lwesp_netconn_delete(client);
62            client = NULL;
63        }
64    }
65    /* Delete client */
66    if (client != NULL) {
67        lwesp_netconn_delete(client);
68        client = NULL;
69    }
70
71out:
72    printf("Terminating netconn thread!\r\n");
73    if (server != NULL) {
74        lwesp_netconn_delete(server);
75    }
76    lwesp_sys_thread_terminate(NULL);
77}
Netconn server concurrency
Netconn API server concurrency block diagram

Netconn API server concurrency block diagram

When compared to classic netconn server, concurrent netconn server mode allows multiple clients to be processed at the same time. This can drastically improve performance and response time on clients side, especially when many clients are connected to server at the same time.

Every time server application thread (green block) gets new client to process, it starts a new processing thread instead of doing it in accept thread.

  • Server thread is only dedicated to accept clients and start threads

  • Multiple processing thread can run in parallel to send/receive data from multiple clients

  • No delay when multi clients are active at the same time

  • Higher memory footprint is necessary as there are multiple threads active

Netconn server with multiple processing threads
  1/*
  2 * Netconn server example is based on single "user" thread
  3 * which listens for new connections and accepts them.
  4 *
  5 * When a new client is accepted by server,
  6 * separate thread for client is created where
  7 * data is read, processed and send back to user
  8 */
  9#include "netconn_server.h"
 10#include "lwesp/lwesp.h"
 11
 12static void netconn_server_processing_thread(void* const arg);
 13
 14/**
 15 * \brief           Main page response file
 16 */
 17static const uint8_t
 18rlwesp_data_mainpage_top[] = ""
 19                           "HTTP/1.1 200 OK\r\n"
 20                           "Content-Type: text/html\r\n"
 21                           "\r\n"
 22                           "<html>"
 23                           "   <head>"
 24                           "       <link rel=\"stylesheet\" href=\"style.css\" type=\"text/css\" />"
 25                           "       <meta http-equiv=\"refresh\" content=\"1\" />"
 26                           "   </head>"
 27                           "   <body>"
 28                           "       <p>Netconn driven website!</p>"
 29                           "       <p>Total system up time: <b>";
 30
 31/**
 32 * \brief           Bottom part of main page
 33 */
 34static const uint8_t
 35rlwesp_data_mainpage_bottom[] = ""
 36                              "       </b></p>"
 37                              "   </body>"
 38                              "</html>";
 39
 40/**
 41 * \brief           Style file response
 42 */
 43static const uint8_t
 44rlwesp_data_style[] = ""
 45                    "HTTP/1.1 200 OK\r\n"
 46                    "Content-Type: text/css\r\n"
 47                    "\r\n"
 48                    "body { color: red; font-family: Tahoma, Arial; };";
 49
 50/**
 51 * \brief           404 error response
 52 */
 53static const uint8_t
 54rlwesp_error_404[] = ""
 55                   "HTTP/1.1 404 Not Found\r\n"
 56                   "\r\n"
 57                   "Error 404";
 58
 59/**
 60 * \brief           Netconn server thread implementation
 61 * \param[in]       arg: User argument
 62 */
 63void
 64netconn_server_thread(void const* arg) {
 65    lwespr_t res;
 66    lwesp_netconn_p server, client;
 67
 68    /*
 69     * First create a new instance of netconn
 70     * connection and initialize system message boxes
 71     * to accept clients and packet buffers
 72     */
 73    server = lwesp_netconn_new(LWESP_NETCONN_TYPE_TCP);
 74    if (server != NULL) {
 75        printf("Server netconn created\r\n");
 76
 77        /* Bind network connection to port 80 */
 78        res = lwesp_netconn_bind(server, 80);
 79        if (res == lwespOK) {
 80            printf("Server netconn listens on port 80\r\n");
 81            /*
 82             * Start listening for incoming connections
 83             * on previously binded port
 84             */
 85            res = lwesp_netconn_listen(server);
 86
 87            while (1) {
 88                /*
 89                 * Wait and accept new client connection
 90                 *
 91                 * Function will block thread until
 92                 * new client is connected to server
 93                 */
 94                res = lwesp_netconn_accept(server, &client);
 95                if (res == lwespOK) {
 96                    printf("Netconn new client connected. Starting new thread...\r\n");
 97                    /*
 98                     * Start new thread for this request.
 99                     *
100                     * Read and write back data to user in separated thread
101                     * to allow processing of multiple requests at the same time
102                     */
103                    if (lwesp_sys_thread_create(NULL, "client", (lwesp_sys_thread_fn)netconn_server_processing_thread, client, 512, LWESP_SYS_THREAD_PRIO)) {
104                        printf("Netconn client thread created\r\n");
105                    } else {
106                        printf("Netconn client thread creation failed!\r\n");
107
108                        /* Force close & delete */
109                        lwesp_netconn_close(client);
110                        lwesp_netconn_delete(client);
111                    }
112                } else {
113                    printf("Netconn connection accept error!\r\n");
114                    break;
115                }
116            }
117        } else {
118            printf("Netconn server cannot bind to port\r\n");
119        }
120    } else {
121        printf("Cannot create server netconn\r\n");
122    }
123
124    printf("Terminating thread\r\n");
125    lwesp_netconn_delete(server);                 /* Delete netconn structure */
126    lwesp_sys_thread_terminate(NULL);             /* Terminate current thread */
127}
128
129/**
130 * \brief           Thread to process single active connection
131 * \param[in]       arg: Thread argument
132 */
133static void
134netconn_server_processing_thread(void* const arg) {
135    lwesp_netconn_p client;
136    lwesp_pbuf_p pbuf, p = NULL;
137    lwespr_t res;
138    char strt[20];
139
140    client = arg;                               /* Client handle is passed to argument */
141
142    printf("A new connection accepted!\r\n");   /* Print simple message */
143
144    do {
145        /*
146         * Client was accepted, we are now
147         * expecting client will send to us some data
148         *
149         * Wait for data and block thread for that time
150         */
151        res = lwesp_netconn_receive(client, &pbuf);
152
153        if (res == lwespOK) {
154            printf("Netconn data received, %d bytes\r\n", (int)lwesp_pbuf_length(pbuf, 1));
155            /* Check reception of all header bytes */
156            if (p == NULL) {
157                p = pbuf;                       /* Set as first buffer */
158            } else {
159                lwesp_pbuf_cat(p, pbuf);          /* Concatenate buffers together */
160            }
161            if (lwesp_pbuf_strfind(pbuf, "\r\n\r\n", 0) != LWESP_SIZET_MAX) {
162                if (lwesp_pbuf_strfind(pbuf, "GET / ", 0) != LWESP_SIZET_MAX) {
163                    uint32_t now;
164                    printf("Main page request\r\n");
165                    now = lwesp_sys_now();        /* Get current time */
166                    sprintf(strt, "%u ms; %d s", (unsigned)now, (unsigned)(now / 1000));
167                    lwesp_netconn_write(client, rlwesp_data_mainpage_top, sizeof(rlwesp_data_mainpage_top) - 1);
168                    lwesp_netconn_write(client, strt, strlen(strt));
169                    lwesp_netconn_write(client, rlwesp_data_mainpage_bottom, sizeof(rlwesp_data_mainpage_bottom) - 1);
170                } else if (lwesp_pbuf_strfind(pbuf, "GET /style.css ", 0) != LWESP_SIZET_MAX) {
171                    printf("Style page request\r\n");
172                    lwesp_netconn_write(client, rlwesp_data_style, sizeof(rlwesp_data_style) - 1);
173                } else {
174                    printf("404 error not found\r\n");
175                    lwesp_netconn_write(client, rlwesp_error_404, sizeof(rlwesp_error_404) - 1);
176                }
177                lwesp_netconn_close(client);      /* Close netconn connection */
178                lwesp_pbuf_free(p);               /* Do not forget to free memory after usage! */
179                p = NULL;
180                break;
181            }
182        }
183    } while (res == lwespOK);
184
185    if (p != NULL) {                            /* Free received data */
186        lwesp_pbuf_free(p);
187        p = NULL;
188    }
189    lwesp_netconn_delete(client);                 /* Destroy client memory */
190    lwesp_sys_thread_terminate(NULL);             /* Terminate this thread */
191}
Non-blocking receive

By default, netconn API is written to only work in separate application thread, dedicated for network connection processing. Because of that, by default every function is fully blocking. It will wait until result is ready to be used by application.

It is, however, possible to enable timeout feature for receiving data only. When this feature is enabled, lwesp_netconn_receive() will block for maximal timeout set with lwesp_netconn_set_receive_timeout() function.

When enabled, if there is no received data for timeout amount of time, function will return with timeout status and application needs to process it accordingly.

Tip

LWESP_CFG_NETCONN_RECEIVE_TIMEOUT must be set to 1 to use this feature.

group LWESP_NETCONN

Network connection.

Defines

LWESP_NETCONN_RECEIVE_NO_WAIT

Receive data with no timeout.

Note

Used with lwesp_netconn_set_receive_timeout function

Typedefs

typedef struct lwesp_netconn *lwesp_netconn_p

Netconn object structure.

Enums

enum lwesp_netconn_type_t

Netconn connection type.

Values:

enumerator LWESP_NETCONN_TYPE_TCP

TCP connection

enumerator LWESP_NETCONN_TYPE_SSL

SSL connection

enumerator LWESP_NETCONN_TYPE_UDP

UDP connection

enumerator LWESP_NETCONN_TYPE_TCPV6

TCP connection over IPv6

enumerator LWESP_NETCONN_TYPE_SSLV6

SSL connection over IPv6

Functions

lwesp_netconn_p lwesp_netconn_new(lwesp_netconn_type_t type)

Create new netconn connection.

Parameters

type[in] Netconn connection type

Returns

New netconn connection on success, NULL otherwise

lwespr_t lwesp_netconn_delete(lwesp_netconn_p nc)

Delete netconn connection.

Parameters

nc[in] Netconn handle

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_netconn_bind(lwesp_netconn_p nc, lwesp_port_t port)

Bind a connection to specific port, can be only used for server connections.

Parameters
  • nc[in] Netconn handle

  • port[in] Port used to bind a connection to

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_netconn_connect(lwesp_netconn_p nc, const char *host, lwesp_port_t port)

Connect to server as client.

Parameters
  • nc[in] Netconn handle

  • host[in] Pointer to host, such as domain name or IP address in string format

  • port[in] Target port to use

Returns

lwespOK if successfully connected, member of lwespr_t otherwise

lwespr_t lwesp_netconn_receive(lwesp_netconn_p nc, lwesp_pbuf_p *pbuf)

Receive data from connection.

Parameters
  • nc[in] Netconn handle used to receive from

  • pbuf[in] Pointer to pointer to save new receive buffer to. When function returns, user must check for valid pbuf value pbuf != NULL

Returns

lwespOK when new data ready

Returns

lwespCLOSED when connection closed by remote side

Returns

lwespTIMEOUT when receive timeout occurs

Returns

Any other member of lwespr_t otherwise

lwespr_t lwesp_netconn_close(lwesp_netconn_p nc)

Close a netconn connection.

Parameters

nc[in] Netconn handle to close

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

int8_t lwesp_netconn_get_connnum(lwesp_netconn_p nc)

Get connection number used for netconn.

Parameters

nc[in] Netconn handle

Returns

-1 on failure, connection number between 0 and LWESP_CFG_MAX_CONNS otherwise

lwesp_conn_p lwesp_netconn_get_conn(lwesp_netconn_p nc)

Get netconn connection handle.

Parameters

nc[in] Netconn handle

Returns

ESP connection handle

lwesp_netconn_type_t lwesp_netconn_get_type(lwesp_netconn_p nc)

Get netconn connection type.

Parameters

nc[in] Netconn handle

Returns

ESP connection type

void lwesp_netconn_set_receive_timeout(lwesp_netconn_p nc, uint32_t timeout)

Set timeout value for receiving data.

When enabled, lwesp_netconn_receive will only block for up to timeout value and will return if no new data within this time

Parameters
  • nc[in] Netconn handle

  • timeout[in] Timeout in units of milliseconds. Set to 0 to disable timeout feature Set to > 0 to set maximum milliseconds to wait before timeout Set to LWESP_NETCONN_RECEIVE_NO_WAIT to enable non-blocking receive

uint32_t lwesp_netconn_get_receive_timeout(lwesp_netconn_p nc)

Get netconn receive timeout value.

Parameters

nc[in] Netconn handle

Returns

Timeout in units of milliseconds. If value is 0, timeout is disabled (wait forever)

lwespr_t lwesp_netconn_connect_ex(lwesp_netconn_p nc, const char *host, lwesp_port_t port, uint16_t keep_alive, const char *local_ip, lwesp_port_t local_port, uint8_t mode)

Connect to server as client, allow keep-alive option.

Parameters
  • nc[in] Netconn handle

  • host[in] Pointer to host, such as domain name or IP address in string format

  • port[in] Target port to use

  • keep_alive[in] Keep alive period seconds

  • local_ip[in] Local ip in connected command

  • local_port[in] Local port address

  • mode[in] UDP mode

Returns

lwespOK if successfully connected, member of lwespr_t otherwise

lwespr_t lwesp_netconn_listen(lwesp_netconn_p nc)

Listen on previously binded connection.

Parameters

nc[in] Netconn handle used to listen for new connections

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_netconn_listen_with_max_conn(lwesp_netconn_p nc, uint16_t max_connections)

Listen on previously binded connection with max allowed connections at a time.

Parameters
  • nc[in] Netconn handle used to listen for new connections

  • max_connections[in] Maximal number of connections server can accept at a time This parameter may not be larger than LWESP_CFG_MAX_CONNS

Returns

lwespOK on success, member of lwespr_t otherwise

lwespr_t lwesp_netconn_set_listen_conn_timeout(lwesp_netconn_p nc, uint16_t timeout)

Set timeout value in units of seconds when connection is in listening mode If new connection is accepted, it will be automatically closed after seconds elapsed without any data exchange.

Note

Call this function before you put connection to listen mode with lwesp_netconn_listen

Parameters
  • nc[in] Netconn handle used for listen mode

  • timeout[in] Time in units of seconds. Set to 0 to disable timeout feature

Returns

lwespOK on success, member of lwespr_t otherwise

lwespr_t lwesp_netconn_accept(lwesp_netconn_p nc, lwesp_netconn_p *client)

Accept a new connection.

Parameters
  • nc[in] Netconn handle used as base connection to accept new clients

  • client[out] Pointer to netconn handle to save new connection to

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_netconn_write(lwesp_netconn_p nc, const void *data, size_t btw)

Write data to connection output buffers.

Note

This function may only be used on TCP or SSL connections

Parameters
  • nc[in] Netconn handle used to write data to

  • data[in] Pointer to data to write

  • btw[in] Number of bytes to write

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_netconn_flush(lwesp_netconn_p nc)

Flush buffered data on netconn TCP/SSL connection.

Note

This function may only be used on TCP/SSL connection

Parameters

nc[in] Netconn handle to flush data

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_netconn_send(lwesp_netconn_p nc, const void *data, size_t btw)

Send data on UDP connection to default IP and port.

Parameters
  • nc[in] Netconn handle used to send

  • data[in] Pointer to data to write

  • btw[in] Number of bytes to write

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

lwespr_t lwesp_netconn_sendto(lwesp_netconn_p nc, const lwesp_ip_t *ip, lwesp_port_t port, const void *data, size_t btw)

Send data on UDP connection to specific IP and port.

Note

Use this function in case of UDP type netconn

Parameters
  • nc[in] Netconn handle used to send

  • ip[in] Pointer to IP address

  • port[in] Port number used to send data

  • data[in] Pointer to data to write

  • btw[in] Number of bytes to write

Returns

lwespOK on success, member of lwespr_t enumeration otherwise

Command line interface

CLI Input module
group CLI_INPUT

Command line interface helper funcions for paring input data.

Functions to parse incoming data for command line interface (CLI).

Functions

void cli_in_data(cli_printf cliprintf, char ch)

parse new characters to the CLI

Parameters
  • cliprintf[in] Pointer to CLI printf function

  • ch[in] new character to CLI

CLI Configuration
group CLI_CONFIG

Default CLI configuration.

Configuration for command line interface (CLI).

Defines

CLI_PROMPT

CLI promet, printed on every NL.

CLI_NL

CLI NL, default is NL and CR.

CLI_MAX_CMD_LENGTH

Max CLI command length.

CLI_CMD_HISTORY

Max sotred CLI commands to history.

CLI_MAX_NUM_OF_ARGS

Max CLI arguments in a single command.

CLI_MAX_MODULES

Max modules for CLI.

group CLI

Command line interface.

Functions to initialize everything needed for command line interface (CLI).

Typedefs

typedef void cli_printf(const char *format, ...)

Printf handle for CLI.

Param format

[in] string format

typedef void cli_function(cli_printf cliprintf, int argc, char **argv)

CLI entriy function.

Param cliprintf

[in] Printf handle callback

Param argc

[in] Number of arguments

Param argv

[in] Pointer to pointer to arguments

Functions

const cli_command_t *cli_lookup_command(char *command)

Find the CLI command that matches the input string.

Parameters

command[in] pointer to command string for which we are searching

Returns

pointer of the command if we found a match, else NULL

void cli_tab_auto_complete(cli_printf cliprintf, char *cmd_buffer, uint32_t *cmd_pos, bool print_options)

CLI auto completion function.

Parameters
  • cliprintf[in] Pointer to CLI printf function

  • cmd_buffer[in] CLI command buffer

  • cmd_pos[in] pointer to current courser postion in command buffer

  • print_options[in] additional prints in case of double tab

bool cli_register_commands(const cli_command_t *commands, size_t num_of_commands)

Register new CLI commands.

Parameters
  • commands[in] Pointer to commands table

  • num_of_commands[in] Number of new commands

Returns

true when new commands where succesfully added, else false

void cli_init(void)

CLI Init function for adding basic CLI commands.

struct cli_command_t
#include <cli.h>

CLI command structure.

Public Members

const char *name

Command name

const char *help

Command help

cli_function *func

Command function

struct cli_commands_t
#include <cli.h>

List of commands.

Public Members

const cli_command_t *commands

Pointer to commands

size_t num_of_commands

Total number of commands

Examples and demos

Various examples are provided for fast library evaluation on embedded systems. These are prepared and maintained for 2 platforms, but could be easily extended to more platforms:

Warning

Library is platform independent and can be used on any platform.

Example architectures

There are many platforms available today on a market, however supporting them all would be tough task for single person. Therefore it has been decided to support (for purpose of examples) 2 platforms only, WIN32 and STM32.

WIN32

Examples for WIN32 are prepared as Visual Studio Community projects. You can directly open project in the IDE, compile & debug.

Application opens COM port, set in the low-level driver. External USB to UART converter (FTDI-like device) is necessary in order to connect to ESP device.

Note

ESP device is connected with USB to UART converter only by RX and TX pins.

Device driver is located in /lwesp/src/system/lwesp_ll_win32.c

STM32

Embedded market is supported by many vendors and STMicroelectronics is, with their STM32 series of microcontrollers, one of the most important players. There are numerous amount of examples and topics related to this architecture.

Examples for STM32 are natively supported with STM32CubeIDE, an official development IDE from STMicroelectronics.

You can run examples on one of official development boards, available in repository examples.

Supported development boards

Board name

ESP settings

Debug settings

UART

MTX

MRX

RST

GP0

GP2

CHPD

UART

MDTX

MDRX

STM32F769I-Discovery

UART5

PC12

PD2

PJ14

USART1

PA9

PA10

STM32F723E-Discovery

UART5

PC12

PD2

PG14

PD6

PD3

USART6

PC6

PC7

STM32L496G-Discovery

USART1

PB6

PG10

PB2

PH2

PA0

PA4

USART2

PA2

PD6

STM32L432KC-Nucleo

USART1

PA9

PA10

PA12

PA7

PA6

PB0

USART2

PA2

PA3

STM32F429ZI-Nucleo

USART2

PD5

PD6

PD1

PD4

PD7

PD3

USART3

PD8

PD9

Pins to connect with ESP device:

  • MTX: MCU TX pin, connected to ESP RX pin

  • MRX: MCU RX pin, connected to ESP TX pin

  • RST: MCU output pin to control reset state of ESP device

  • GP0: GPIO0 pin of ESP8266, connected to MCU, configured as output at MCU side

  • GP2: GPIO2 pin of ESP8266, connected to MCU, configured as output at MCU side

  • CHPD: CH_PD pin of ESP8266, connected to MCU, configured as output at MCU side

Note

GP0, GP2, CH_PD pins are not always necessary for ESP device to work properly. When not used, these pins must be tied to fixed values as explained in ESP datasheet.

Other pins are for your information and are used for debugging purposes on board.

  • MDTX: MCU Debug TX pin, connected via on-board ST-Link to PC

  • MDRX: MCU Debug RX pin, connected via on-board ST-Link to PC

  • Baudrate is always set to 921600 bauds

Examples list

Here is a list of all examples coming with this library.

Tip

Examples are located in /examples/ folder in downloaded package. Check Download library section to get your package.

Warning

Several examples need to connect to access point first, then they may start client connection or pinging server. Application needs to modify file /snippets/station_manager.c and update ap_list variable with preferred access points, in order to allow ESP to connect to home/local network

Ex. Access point

ESP device is configured as software access point, allowing stations to connect to it. When station connects to access point, it will output its MAC and IP addresses.

Ex. Client

Application tries to connect to custom server with classic, event-based API. It starts concurrent connections and processes data in its event callback function.

Ex. Server

It starts server on port 80 in event based connection mode. Every client is processed in callback function.

When ESP is successfully connected to access point, it is possible to connect to it using its assigned IP address.

Ex. Domain name server

ESP tries to get domain name from specific domain name, example.com as an example. It needs to be connected to access point to have access to global internet.

Ex. MQTT Client

This example demonstrates raw MQTT connection to mosquitto test server. A new application thread is started after ESP successfully connects to access point. MQTT application starts by initiating a new TCP connection.

This is event-based example as there is no linear code.

Ex. MQTT Client API

Similar to MQTT Client examples, but it uses separate thread to process events in blocking mode. Application does not use events to process data, rather it uses blocking API to receive packets

Ex. Netconn client

Netconn client is based on sequential API. It starts connection to server, sends initial request and then waits to receive data.

Processing is in separate thread and fully sequential, no callbacks or events.

Ex. Netconn server

Netconn server is based on sequential API. It starts server on specific port (see example details) and it waits for new client in separate threads. Once new client has been accepted, it waits for client request and processes data accordingly by sending reply message back.

Tip

Server may accept multiple clients at the same time