LwGSM 0.1.0 documentation

Welcome to the documentation for version 0.1.0.

LwGSM is generic, platform independent, library to control SIM800/SIM900 or SIM7000/SIM7020 (NB-Iot LTE) devices from SIMCom. Its objective is to run on master system, while SIMCom device runs official AT commands firmware developed and maintained by SIMCom.

Features

  • Supports SIM800/SIM900 (2G) and SIM7000/SIM7020 (NB-Iot LTE) modules

  • Platform independent and very easy to port

    • Development of library under Win32 platform

    • Provided examples for ARM Cortex-M or Win32 platforms

  • Written in C language (C99)

  • Allows different configurations to optimize user requirements

  • Supports implementation with operating systems with advanced inter-thread communications

    • Currently only OS mode is supported

    • 2 different threads handling user data and received data

      • First (producer) thread (collects user commands from user threads and starts the command processing)

      • Second (process) thread reads the data from GSM device and does the job accordingly

  • Allows sequential API for connections in client and server mode

  • Includes several applications built on top of library

    • MQTT client for MQTT connection

  • User friendly MIT license

Requirements

  • C compiler

  • Supported GSM Physical device

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

Download library

Library is primarly hosted on Github.

  • Download latest release from releases area on Github

  • Clone develop branch for latest development

Download from releases

All releases are available on Github releases area.

Clone from Github
First-time clone
  • Download and install git if not already

  • 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/lwgsm command to clone entire repository, including submodules

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

    • Run git clone --recurse-submodules --branch master https://github.com/MaJerle/lwgsm 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 resources repository is. Use command cd your_path

  • Run git pull origin master --recurse-submodules command to pull latest changes and to fetch latest changes from submodules

  • Run git submodule foreach git pull origin master to update & merge all submodules

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.

  • Copy lwgsm folder to your project

  • Add lwgsm/src/include folder to include path of your toolchain

  • Add port architecture lwgsm/src/include/system/port/_arch_ folder to include path of your toolchain

  • Add source files from lwgsm/src/ folder to toolchain build

  • Add source files from lwgsm/src/system/ folder to toolchain build for arch port

  • Copy lwgsm/src/include/lwgsm/lwgsm_opts_template.h to project folder and rename it to lwgsm_opts.h

  • Build the project

Configuration file

Library comes with template config file, which can be modified according to needs. This file shall be named lwgsm_opts.h and its default template looks like the one below.

Note

Default configuration template file location: lwgsm/src/include/lwgsm/lwgsm_opts_template.h. File must be renamed to lwgsm_opts.h first and then copied to the project directory (or simply renamed in-place) where compiler include paths have access to it by using #include "lwgsm_opts.h".

Tip

Check Configuration section for possible configuration settings

Template options file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
 * \file            lwgsm_opts_template.h
 * \brief           Template config file
 */

/*
 * 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.
 *
 * This file is part of LwGSM - Lightweight GSM-AT library.
 *
 * Author:          Tilen MAJERLE <tilen@majerle.eu>
 * Version:         v0.1.0
 */
#ifndef LWGSM_HDR_OPTS_H
#define LWGSM_HDR_OPTS_H

/* Rename this file to "lwgsm_opts.h" for your application */

/*
 * Open "include/lwgsm/lwgsm_opt.h" and
 * copy & replace here settings you want to change values
 */

#endif /* LWGSM_HDR_OPTS_H */

User manual

Overview

IoT activity is embedded in today’s application. Almost every device uses some type of communication, from WiFi, BLE, Sub-GHz or NB-IoT/LTE/2G/3G.

LwGSM has been developed to allow customers to:

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

  • Shorten time to market

Customers using LwGSM do not need to take care about proper command for specific task, they can call API functions to execute the task. 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.

To summarize:

  • GSM device runs official AT firmware, provided by device vendor

  • Host MCU runs custom application, together with LwGSM library

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

Architecture

Architecture of the library consists of 4 layers.

LwGSM layer architecture overview

LwGSM 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 GSM 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 LwGSM 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 LWGSM_LL, is part, dedicated for communication between LwGSM middleware and GSM physical device. Application needs to implement output function to send necessary AT command instruction aswell as implement input module to send received data from GSM device to LwGSM 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.

GSM physical device

Inter thread communication

LwGSM 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 lwgsm_threads.c file.

Processing thread

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

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

  • RING indicating new call to be processed by GSM

  • 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 0, CONNECT OK 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 GSM 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:

  • GSM station successfully connected to access point

  • GSM 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 lwgsm_evt_register() function to register a new, custom, event function.

Tip

Implementation of Netconn API leverages lwgsm_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
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
/**
 * \file            lwgsm_netconn.c
 * \brief           API functions for sequential calls
 */

/*
 * 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.
 *
 * This file is part of LwGSM - Lightweight GSM-AT library.
 *
 * Author:          Tilen MAJERLE <tilen@majerle.eu>
 * Version:         v0.1.0
 */
#include "lwgsm/lwgsm_netconn.h"
#include "lwgsm/lwgsm_private.h"
#include "lwgsm/lwgsm_conn.h"
#include "lwgsm/lwgsm_mem.h"

#if LWGSM_CFG_NETCONN || __DOXYGEN__

/* Check conditions */
#if !LWGSM_CFG_CONN
#error "LWGSM_CFG_CONN must be enabled for NETCONN API!"
#endif /* !LWGSM_CFG_CONN */

#if LWGSM_CFG_NETCONN_RECEIVE_QUEUE_LEN < 2
#error "LWGSM_CFG_NETCONN_RECEIVE_QUEUE_LEN must be greater or equal to 2"
#endif /* LWGSM_CFG_NETCONN_RECEIVE_QUEUE_LEN < 2 */

/**
 * \brief           Sequential API structure
 */
typedef struct lwgsm_netconn {
    struct lwgsm_netconn* next;                 /*!< Linked list entry */

    lwgsm_netconn_type_t type;                  /*!< Netconn type */

    size_t rcv_packets;                         /*!< Number of received packets so far on this connection */
    lwgsm_conn_p conn;                          /*!< Pointer to actual connection */

    lwgsm_sys_mbox_t mbox_receive;              /*!< Message queue for receive mbox */

    lwgsm_linbuff_t buff;                       /*!< Linear buffer structure */

    uint16_t conn_timeout;                      /*!< Connection timeout in units of seconds when
                                                    netconn is in server (listen) mode.
                                                    Connection will be automatically closed if there is no
                                                    data exchange in time. Set to `0` when timeout feature is disabled. */

#if LWGSM_CFG_NETCONN_RECEIVE_TIMEOUT || __DOXYGEN__
    uint32_t rcv_timeout;                       /*!< Receive timeout in unit of milliseconds */
#endif
} lwgsm_netconn_t;

static uint8_t recv_closed = 0xFF;
static lwgsm_netconn_t* netconn_list;           /*!< Linked list of netconn entries */

/**
 * \brief           Flush all mboxes and clear possible used memories
 * \param[in]       nc: Pointer to netconn to flush
 * \param[in]       protect: Set to 1 to protect against multi-thread access
 */
static void
flush_mboxes(lwgsm_netconn_t* nc, uint8_t protect) {
    lwgsm_pbuf_p pbuf;
    if (protect) {
        lwgsm_core_lock();
    }
    if (lwgsm_sys_mbox_isvalid(&nc->mbox_receive)) {
        while (lwgsm_sys_mbox_getnow(&nc->mbox_receive, (void**)&pbuf)) {
            if (pbuf != NULL && (uint8_t*)pbuf != (uint8_t*)&recv_closed) {
                lwgsm_pbuf_free(pbuf);          /* Free received data buffers */
            }
        }
        lwgsm_sys_mbox_delete(&nc->mbox_receive);   /* Delete message queue */
        lwgsm_sys_mbox_invalid(&nc->mbox_receive);  /* Invalid handle */
    }
    if (protect) {
        lwgsm_core_unlock();
    }
}

/**
 * \brief           Callback function for every server connection
 * \param[in]       evt: Pointer to callback structure
 * \return          Member of \ref lwgsmr_t enumeration
 */
static lwgsmr_t
netconn_evt(lwgsm_evt_t* evt) {
    lwgsm_conn_p conn;
    lwgsm_netconn_t* nc = NULL;
    uint8_t close = 0;

    conn = lwgsm_conn_get_from_evt(evt);        /* Get connection from event */
    switch (lwgsm_evt_get_type(evt)) {
        /*
         * A new connection has been active
         * and should be handled by netconn API
         */
        case LWGSM_EVT_CONN_ACTIVE: {           /* A new connection active is active */
            if (lwgsm_conn_is_client(conn)) {   /* Was connection started by us? */
                nc = lwgsm_conn_get_arg(conn);  /* Argument should be already set */
                if (nc != NULL) {
                    nc->conn = conn;            /* Save actual connection */
                } else {
                    close = 1;                  /* Close this connection, invalid netconn */
                }
            } else {
                LWGSM_DEBUGF(LWGSM_CFG_DBG_NETCONN | LWGSM_DBG_TYPE_TRACE | LWGSM_DBG_LVL_WARNING,
                           "[NETCONN] Closing connection, it is not in client mode!\r\n");
                close = 1;                      /* Close the connection at this point */
            }

            /* Decide if some events want to close the connection */
            if (close) {
                if (nc != NULL) {
                    lwgsm_conn_set_arg(conn, NULL); /* Reset argument */
                    lwgsm_netconn_delete(nc);   /* Free memory for API */
                }
                lwgsm_conn_close(conn, 0);      /* Close the connection */
                close = 0;
            }
            break;
        }

        /*
         * We have a new data received which
         * should have netconn structure as argument
         */
        case LWGSM_EVT_CONN_RECV: {
            lwgsm_pbuf_p pbuf;

            nc = lwgsm_conn_get_arg(conn);      /* Get API from connection */
            pbuf = lwgsm_evt_conn_recv_get_buff(evt);   /* Get received buff */

            lwgsm_conn_recved(conn, pbuf);      /* Notify stack about received data */

            lwgsm_pbuf_ref(pbuf);               /* Increase reference counter */
            if (nc == NULL || !lwgsm_sys_mbox_isvalid(&nc->mbox_receive)
                || !lwgsm_sys_mbox_putnow(&nc->mbox_receive, pbuf)) {
                LWGSM_DEBUGF(LWGSM_CFG_DBG_NETCONN,
                           "[NETCONN] Ignoring more data for receive!\r\n");
                lwgsm_pbuf_free(pbuf);          /* Free pbuf */
                return lwgsmOKIGNOREMORE;       /* Return OK to free the memory and ignore further data */
            }
            ++nc->rcv_packets;                  /* Increase number of received packets */
            LWGSM_DEBUGF(LWGSM_CFG_DBG_NETCONN | LWGSM_DBG_TYPE_TRACE,
                       "[NETCONN] Received pbuf contains %d bytes. Handle written to receive mbox\r\n",
                       (int)lwgsm_pbuf_length(pbuf, 0));
            break;
        }

        /* Connection was just closed */
        case LWGSM_EVT_CONN_CLOSE: {
            nc = lwgsm_conn_get_arg(conn);      /* Get API from connection */

            /*
             * In case we have a netconn available,
             * simply write pointer to received variable to indicate closed state
             */
            if (nc != NULL && lwgsm_sys_mbox_isvalid(&nc->mbox_receive)) {
                lwgsm_sys_mbox_putnow(&nc->mbox_receive, (void*)&recv_closed);
            }

            break;
        }
        default:
            return lwgsmERR;
    }
    return lwgsmOK;
}

/**
 * \brief           Global event callback function
 * \param[in]       evt: Callback information and data
 * \return          \ref lwgsmOK on success, member of \ref lwgsmr_t otherwise
 */
static lwgsmr_t
lwgsm_evt(lwgsm_evt_t* evt) {
    switch (lwgsm_evt_get_type(evt)) {
        default:
            break;
    }
    return lwgsmOK;
}

/**
 * \brief           Create new netconn connection
 * \param[in]       type: Netconn connection type
 * \return          New netconn connection on success, `NULL` otherwise
 */
lwgsm_netconn_p
lwgsm_netconn_new(lwgsm_netconn_type_t type) {
    lwgsm_netconn_t* a;
    static uint8_t first = 1;

    /* Register only once! */
    lwgsm_core_lock();
    if (first) {
        first = 0;
        lwgsm_evt_register(lwgsm_evt);          /* Register global event function */
    }
    lwgsm_core_unlock();
    a = lwgsm_mem_calloc(1, sizeof(*a));        /* Allocate memory for core object */
    if (a != NULL) {
        a->type = type;                         /* Save netconn type */
        a->conn_timeout = 0;                    /* Default connection timeout */
        if (!lwgsm_sys_mbox_create(&a->mbox_receive, LWGSM_CFG_NETCONN_RECEIVE_QUEUE_LEN)) {/* Allocate memory for receiving message box */
            LWGSM_DEBUGF(LWGSM_CFG_DBG_NETCONN | LWGSM_DBG_TYPE_TRACE | LWGSM_DBG_LVL_DANGER,
                       "[NETCONN] Cannot create receive MBOX\r\n");
            goto free_ret;
        }
        lwgsm_core_lock();
        if (netconn_list == NULL) {             /* Add new netconn to the existing list */
            netconn_list = a;
        } else {
            a->next = netconn_list;             /* Add it to beginning of the list */
            netconn_list = a;
        }
        lwgsm_core_unlock();
    }
    return a;
free_ret:
    if (lwgsm_sys_mbox_isvalid(&a->mbox_receive)) {
        lwgsm_sys_mbox_delete(&a->mbox_receive);
        lwgsm_sys_mbox_invalid(&a->mbox_receive);
    }
    if (a != NULL) {
        lwgsm_mem_free_s((void**)&a);
    }
    return NULL;
}

/**
 * \brief           Delete netconn connection
 * \param[in]       nc: Netconn handle
 * \return          \ref lwgsmOK on success, member of \ref lwgsmr_t enumeration otherwise
 */
lwgsmr_t
lwgsm_netconn_delete(lwgsm_netconn_p nc) {
    LWGSM_ASSERT("netconn != NULL", nc != NULL);

    lwgsm_core_lock();
    flush_mboxes(nc, 0);                        /* Clear mboxes */

    /* Remove netconn from linkedlist */
    if (netconn_list == nc) {
        netconn_list = netconn_list->next;      /* Remove first from linked list */
    } else if (netconn_list != NULL) {
        lwgsm_netconn_p tmp, prev;
        /* Find element on the list */
        for (prev = netconn_list, tmp = netconn_list->next;
             tmp != NULL; prev = tmp, tmp = tmp->next) {
            if (nc == tmp) {
                prev->next = tmp->next;         /* Remove tmp from linked list */
                break;
            }
        }
    }
    lwgsm_core_unlock();

    lwgsm_mem_free_s((void**)&nc);
    return lwgsmOK;
}

/**
 * \brief           Connect to server as client
 * \param[in]       nc: Netconn handle
 * \param[in]       host: Pointer to host, such as domain name or IP address in string format
 * \param[in]       port: Target port to use
 * \return          \ref lwgsmOK if successfully connected, member of \ref lwgsmr_t otherwise
 */
lwgsmr_t
lwgsm_netconn_connect(lwgsm_netconn_p nc, const char* host, lwgsm_port_t port) {
    lwgsmr_t res;

    LWGSM_ASSERT("nc != NULL", nc != NULL);
    LWGSM_ASSERT("host != NULL", host != NULL);
    LWGSM_ASSERT("port > 0", port > 0);

    /*
     * Start a new connection as client and:
     *
     *  - Set current netconn structure as argument
     *  - Set netconn callback function for connection management
     *  - Start connection in blocking mode
     */
    res = lwgsm_conn_start(NULL, (lwgsm_conn_type_t)nc->type, host, port, nc, netconn_evt, 1);
    return res;
}

/**
 * \brief           Write data to connection output buffers
 * \note            This function may only be used on TCP or SSL connections
 * \param[in]       nc: Netconn handle used to write data to
 * \param[in]       data: Pointer to data to write
 * \param[in]       btw: Number of bytes to write
 * \return          \ref lwgsmOK on success, member of \ref lwgsmr_t enumeration otherwise
 */
lwgsmr_t
lwgsm_netconn_write(lwgsm_netconn_p nc, const void* data, size_t btw) {
    size_t len, sent;
    const uint8_t* d = data;
    lwgsmr_t res;

    LWGSM_ASSERT("nc != NULL", nc != NULL);
    LWGSM_ASSERT("nc->type must be TCP or SSL", nc->type == LWGSM_NETCONN_TYPE_TCP || nc->type == LWGSM_NETCONN_TYPE_SSL);
    LWGSM_ASSERT("nc->conn must be active", lwgsm_conn_is_active(nc->conn));

    /*
     * Several steps are done in write process
     *
     * 1. Check if buffer is set and check if there is something to write to it.
     *    1. In case buffer will be full after copy, send it and free memory.
     * 2. Check how many bytes we can write directly without need to copy
     * 3. Try to allocate a new buffer and copy remaining input data to it
     * 4. In case buffer allocation fails, send data directly (may affect on speed and effectivenes)
     */

    /* Step 1 */
    if (nc->buff.buff != NULL) {                /* Is there a write buffer ready to accept more data? */
        len = LWGSM_MIN(nc->buff.len - nc->buff.ptr, btw);  /* Get number of bytes we can write to buffer */
        if (len > 0) {
            LWGSM_MEMCPY(&nc->buff.buff[nc->buff.ptr], data, len);  /* Copy memory to temporary write buffer */
            d += len;
            nc->buff.ptr += len;
            btw -= len;
        }

        /* Step 1.1 */
        if (nc->buff.ptr == nc->buff.len) {
            res = lwgsm_conn_send(nc->conn, nc->buff.buff, nc->buff.len, &sent, 1);

            lwgsm_mem_free_s((void**)&nc->buff.buff);
            if (res != lwgsmOK) {
                return res;
            }
        } else {
            return lwgsmOK;                     /* Buffer is not yet full yet */
        }
    }

    /* Step 2 */
    if (btw >= LWGSM_CFG_CONN_MAX_DATA_LEN) {
        size_t rem;
        rem = btw % LWGSM_CFG_CONN_MAX_DATA_LEN;/* Get remaining bytes for max data length */
        res = lwgsm_conn_send(nc->conn, d, btw - rem, &sent, 1);/* Write data directly */
        if (res != lwgsmOK) {
            return res;
        }
        d += sent;                              /* Advance in data pointer */
        btw -= sent;                            /* Decrease remaining data to send */
    }

    if (btw == 0) {                             /* Sent everything? */
        return lwgsmOK;
    }

    /* Step 3 */
    if (nc->buff.buff == NULL) {                /* Check if we should allocate a new buffer */
        nc->buff.buff = lwgsm_mem_malloc(sizeof(*nc->buff.buff) * LWGSM_CFG_CONN_MAX_DATA_LEN);
        nc->buff.len = LWGSM_CFG_CONN_MAX_DATA_LEN; /* Save buffer length */
        nc->buff.ptr = 0;                       /* Save buffer pointer */
    }

    /* Step 4 */
    if (nc->buff.buff != NULL) {                /* Memory available? */
        LWGSM_MEMCPY(&nc->buff.buff[nc->buff.ptr], d, btw); /* Copy data to buffer */
        nc->buff.ptr += btw;
    } else {                                    /* Still no memory available? */
        return lwgsm_conn_send(nc->conn, data, btw, NULL, 1);   /* Simply send directly blocking */
    }
    return lwgsmOK;
}

/**
 * \brief           Flush buffered data on netconn \e TCP/SSL connection
 * \note            This function may only be used on \e TCP/SSL connection
 * \param[in]       nc: Netconn handle to flush data
 * \return          \ref lwgsmOK on success, member of \ref lwgsmr_t enumeration otherwise
 */
lwgsmr_t
lwgsm_netconn_flush(lwgsm_netconn_p nc) {
    LWGSM_ASSERT("nc != NULL", nc != NULL);
    LWGSM_ASSERT("nc->type must be TCP or SSL", nc->type == LWGSM_NETCONN_TYPE_TCP || nc->type == LWGSM_NETCONN_TYPE_SSL);
    LWGSM_ASSERT("nc->conn must be active", lwgsm_conn_is_active(nc->conn));

    /*
     * In case we have data in write buffer,
     * flush them out to network
     */
    if (nc->buff.buff != NULL) {                /* Check remaining data */
        if (nc->buff.ptr > 0) {                 /* Do we have data in current buffer? */
            lwgsm_conn_send(nc->conn, nc->buff.buff, nc->buff.ptr, NULL, 1);/* Send data */
        }
        lwgsm_mem_free_s((void**)&nc->buff.buff);
    }
    return lwgsmOK;
}

/**
 * \brief           Send data on \e UDP connection to default IP and port
 * \param[in]       nc: Netconn handle used to send
 * \param[in]       data: Pointer to data to write
 * \param[in]       btw: Number of bytes to write
 * \return          \ref lwgsmOK on success, member of \ref lwgsmr_t enumeration otherwise
 */
lwgsmr_t
lwgsm_netconn_send(lwgsm_netconn_p nc, const void* data, size_t btw) {
    LWGSM_ASSERT("nc != NULL", nc != NULL);
    LWGSM_ASSERT("nc->type must be UDP", nc->type == LWGSM_NETCONN_TYPE_UDP);
    LWGSM_ASSERT("nc->conn must be active", lwgsm_conn_is_active(nc->conn));

    return lwgsm_conn_send(nc->conn, data, btw, NULL, 1);
}

/**
 * \brief           Send data on \e UDP connection to specific IP and port
 * \note            Use this function in case of UDP type netconn
 * \param[in]       nc: Netconn handle used to send
 * \param[in]       ip: Pointer to IP address
 * \param[in]       port: Port number used to send data
 * \param[in]       data: Pointer to data to write
 * \param[in]       btw: Number of bytes to write
 * \return          \ref lwgsmOK on success, member of \ref lwgsmr_t enumeration otherwise
 */
lwgsmr_t
lwgsm_netconn_sendto(lwgsm_netconn_p nc, const lwgsm_ip_t* ip, lwgsm_port_t port, const void* data, size_t btw) {
    LWGSM_ASSERT("nc != NULL", nc != NULL);
    LWGSM_ASSERT("nc->type must be UDP", nc->type == LWGSM_NETCONN_TYPE_UDP);
    LWGSM_ASSERT("nc->conn must be active", lwgsm_conn_is_active(nc->conn));

    return lwgsm_conn_sendto(nc->conn, ip, port, data, btw, NULL, 1);
}

/**
 * \brief           Receive data from connection
 * \param[in]       nc: Netconn handle used to receive from
 * \param[in]       pbuf: Pointer to pointer to save new receive buffer to.
 *                     When function returns, user must check for valid pbuf value `pbuf != NULL`
 * \return          \ref lwgsmOK when new data ready,
 * \return          \ref lwgsmCLOSED when connection closed by remote side,
 * \return          \ref lwgsmTIMEOUT when receive timeout occurs
 * \return          Any other member of \ref lwgsmr_t otherwise
 */
lwgsmr_t
lwgsm_netconn_receive(lwgsm_netconn_p nc, lwgsm_pbuf_p* pbuf) {
    LWGSM_ASSERT("nc != NULL", nc != NULL);
    LWGSM_ASSERT("pbuf != NULL", pbuf != NULL);

    *pbuf = NULL;
#if LWGSM_CFG_NETCONN_RECEIVE_TIMEOUT
    /*
     * Wait for new received data for up to specific timeout
     * or throw error for timeout notification
     */
    if (lwgsm_sys_mbox_get(&nc->mbox_receive, (void**)pbuf, nc->rcv_timeout) == LWGSM_SYS_TIMEOUT) {
        return lwgsmTIMEOUT;
    }
#else /* LWGSM_CFG_NETCONN_RECEIVE_TIMEOUT */
    /* Forever wait for new receive packet */
    lwgsm_sys_mbox_get(&nc->mbox_receive, (void**)pbuf, 0);
#endif /* !LWGSM_CFG_NETCONN_RECEIVE_TIMEOUT */

    /* Check if connection closed */
    if ((uint8_t*)(*pbuf) == (uint8_t*)&recv_closed) {
        *pbuf = NULL;                           /* Reset pbuf */
        return lwgsmCLOSED;
    }
    return lwgsmOK;                             /* We have data available */
}

/**
 * \brief           Close a netconn connection
 * \param[in]       nc: Netconn handle to close
 * \return          \ref lwgsmOK on success, member of \ref lwgsmr_t enumeration otherwise
 */
lwgsmr_t
lwgsm_netconn_close(lwgsm_netconn_p nc) {
    lwgsm_conn_p conn;

    LWGSM_ASSERT("nc != NULL", nc != NULL);
    LWGSM_ASSERT("nc->conn != NULL", nc->conn != NULL);
    LWGSM_ASSERT("nc->conn must be active", lwgsm_conn_is_active(nc->conn));

    lwgsm_netconn_flush(nc);                    /* Flush data and ignore result */
    conn = nc->conn;
    nc->conn = NULL;

    lwgsm_conn_set_arg(conn, NULL);             /* Reset argument */
    lwgsm_conn_close(conn, 1);                  /* Close the connection */
    flush_mboxes(nc, 1);                        /* Flush message queues */
    return lwgsmOK;
}

/**
 * \brief           Get connection number used for netconn
 * \param[in]       nc: Netconn handle
 * \return          `-1` on failure, connection number between `0` and \ref LWGSM_CFG_MAX_CONNS otherwise
 */
int8_t
lwgsm_netconn_getconnnum(lwgsm_netconn_p nc) {
    if (nc != NULL && nc->conn != NULL) {
        return lwgsm_conn_getnum(nc->conn);
    }
    return -1;
}

#if LWGSM_CFG_NETCONN_RECEIVE_TIMEOUT || __DOXYGEN__

/**
 * \brief           Set timeout value for receiving data.
 *
 * When enabled, \ref lwgsm_netconn_receive will only block for up to
 * \e timeout value and will return if no new data within this time
 *
 * \param[in]       nc: Netconn handle
 * \param[in]       timeout: Timeout in units of milliseconds.
 *                  Set to `0` to disable timeout for \ref lwgsm_netconn_receive function
 */
void
lwgsm_netconn_set_receive_timeout(lwgsm_netconn_p nc, uint32_t timeout) {
    nc->rcv_timeout = timeout;
}

/**
 * \brief           Get netconn receive timeout value
 * \param[in]       nc: Netconn handle
 * \return          Timeout in units of milliseconds.
 *                  If value is `0`, timeout is disabled (wait forever)
 */
uint32_t
lwgsm_netconn_get_receive_timeout(lwgsm_netconn_p nc) {
    return nc->rcv_timeout;                     /* Return receive timeout */
}

#endif /* LWGSM_CFG_NETCONN_RECEIVE_TIMEOUT || __DOXYGEN__ */

#endif /* LWGSM_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 LWGSM_EVT_CONN_*, such as LWGSM_EVT_CONN_RECV. Check Event management for list of all connection events.

Connection events callback function is set when client (application starts connection) starts a new connection with lwgsm_conn_start() function

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

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

static lwgsmr_t   conn_callback_func(lwgsm_evt_t* evt);

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

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

    /* Attach to GSM network */
    lwgsm_network_request_attach();

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

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

    conn = lwgsm_conn_get_from_evt(evt);          /* Get connection handle from event */
    if (conn == NULL) {
        return lwgsmERR;
    }
    conn_num = lwgsm_conn_getnum(conn);           /* Get connection number for identification */
    switch (lwgsm_evt_get_type(evt)) {
        case LWGSM_EVT_CONN_ACTIVE: {             /* Connection just active */
            printf("Connection %d active!\r\n", (int)conn_num);
            res = lwgsm_conn_send(conn, req_data, sizeof(req_data) - 1, NULL, 0); /* Start sending data in non-blocking mode */
            if (res == lwgsmOK) {
                printf("Sending request data to server...\r\n");
            } else {
                printf("Cannot send request data to server. Closing connection manually...\r\n");
                lwgsm_conn_close(conn, 0);        /* Close the connection */
            }
            break;
        }
        case LWGSM_EVT_CONN_CLOSE: {              /* Connection closed */
            if (lwgsm_evt_conn_close_is_forced(evt)) {
                printf("Connection %d closed by client!\r\n", (int)conn_num);
            } else {
                printf("Connection %d closed by remote side!\r\n", (int)conn_num);
            }
            break;
        }
        case LWGSM_EVT_CONN_SEND: {               /* Data send event */
            lwgsmr_t res = lwgsm_evt_conn_send_get_result(evt);
            if (res == lwgsmOK) {
                printf("Data sent successfully on connection %d...waiting to receive data from remote side...\r\n", (int)conn_num);
            } else {
                printf("Error while sending data on connection %d!\r\n", (int)conn_num);
            }
            break;
        }
        case LWGSM_EVT_CONN_RECV: {               /* Data received from remote side */
            lwgsm_pbuf_p pbuf = lwgsm_evt_conn_recv_get_buff(evt);
            lwgsm_conn_recved(conn, pbuf);        /* Notify stack about received pbuf */
            printf("Received %d bytes on connection %d..\r\n", (int)lwgsm_pbuf_length(pbuf, 1), (int)conn_num);
            break;
        }
        case LWGSM_EVT_CONN_ERROR: {              /* Error connecting to server */
            const char* host = lwgsm_evt_conn_error_get_host(evt);
            lwgsm_port_t port = lwgsm_evt_conn_error_get_port(evt);
            printf("Error connecting to %s:%d\r\n", host, (int)port);
            break;
        }
        default:
            break;
    }
    return lwgsmOK;
}
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 SMS send. It uses custom API callback function to notify application when command has been executed successfully

Simple example for API call event, using DNS module
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/* Somewhere in thread function */

/* Get device hostname in blocking mode */
/* Function returns actual result */
if (lwgsm_sms_send("+0123456789", "text", NULL, NULL, 1 /* 1 means blocking call */) == lwgsmOK) {
    /* At this point we have valid result from device */
    printf("SMS sent successfully\r\n");
} else {
    printf("Error trying to send SMS..\r\n");
}

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 GSM 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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/* Somewhere in thread function */

/* Get device hostname in blocking mode */
/* Function returns actual result */
if (lwgsm_sms_send("+0123456789", "text", NULL, NULL, 1 /* 1 means blocking call */) == lwgsmOK) {
    /* At this point we have valid result from device */
    printf("SMS sent successfully\r\n");
} else {
    printf("Error trying to send SMS..\r\n");
}
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 to do so will result in function returning error.

Example code:

Non-blocking command example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* Hostname event function, called when lwgsm_sms_send() function finishes */
void
sms_send_fn(lwgsmr_t res, void* arg) {
    /* Check actual result from device */
    if (res == lwgsmOK) {
        printf("SMS sent successfully\r\n");
    } else {
        printf("Error trying to send SMS\r\n");
    }
}

/* Somewhere in thread and/or other GSM event function */

/* Send SMS in non-blocking mode */
/* Function now returns if command has been sent to internal message queue */
if (lwgsm_sms_send("number", "text message", sms_send_fn, NULL, 0 /* 0 means non-blocking call */) == lwgsmOK) {
    /* At this point we only know that command has been sent to queue */
    printf("SMS send message command sent to queue.\r\n");
} else {
    /* Error writing message to queue */
    printf("Cannot send SMS send message command to queue. Maybe out of memory? Check result from function\r\n");
}

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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* Hostname event function, called when lwgsm_sms_send() function finishes */
void
sms_send_fn(lwgsmr_t res, void* arg) {
    /* Check actual result from device */
    if (res == lwgsmOK) {
        printf("SMS sent successfully\r\n");
    } else {
        printf("Error trying to send SMS\r\n");
    }
}

/* Check hostname */
void
check_hostname(void) {
    char message[] = "text message";

    /* Send SMS in non-blocking mode */
    /* Function now returns if command has been sent to internal message queue */
    /* It uses pointer to local data but w/o blocking command */
    if (lwgsm_sms_send("number", message, sms_send_fn, NULL, 0 /* 0 means non-blocking call */) == lwgsmOK) {
        /* At this point we only know that command has been sent to queue */
        printf("SMS send message command sent to queue.\r\n");
    } else {
        /* Error writing message to queue */
        printf("Cannot send SMS send message command to queue. Maybe out of memory? Check result from function\r\n");
    }
}

Porting guide

High level of LwGSM library is platform independent, written in ANSI C99, however there is an important part where middleware needs to communicate with target GSM 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 GSM 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 lwgsm_ll_init() and lwgsm_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 GSM middleware. GSM 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 functions, 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 lwgsm_sys_. It must also prepare header file for standard types in order to support OS types within GSM middleware.

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

Note

Check System functions for function prototypes.

Steps to follow
  • Copy lwgsm/src/system/lwgsm_sys_template.c to the same folder and rename it to application port, eg. lwgsm_sys_win32.c

  • Open newly created file and implement all system functions

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

  • Open lwgsm_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 lwgsm_input_process() or lwgsm_input() functions, based on application configuration of LWGSM_CFG_INPUT_USE_PROCESS parameter.

    • When LWGSM_CFG_INPUT_USE_PROCESS is disabled, dedicated receive buffer is created by LwGSM library and lwgsm_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 LWGSM_CFG_INPUT_USE_PROCESS is enabled, lwgsm_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 LWGSM_MEM_SIZE size

  • It sets send and reset callback functions for LwGSM library

Actual implementation of low-level driver for WIN32
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
/**
 * \file            lwgsm_ll_win32.c
 * \brief           Low-level communication with GSM device for WIN32
 */

/*
 * 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.
 *
 * This file is part of LwGSM - Lightweight GSM-AT library.
 *
 * Author:          Tilen MAJERLE <tilen@majerle.eu>
 * Version:         v0.1.0
 */
#include "system/lwgsm_ll.h"
#include "lwgsm/lwgsm.h"
#include "lwgsm/lwgsm_mem.h"
#include "lwgsm/lwgsm_input.h"

#if !__DOXYGEN__

static uint8_t initialized = 0;
static HANDLE thread_handle;
static volatile HANDLE com_port;                /*!< COM port handle */
static uint8_t data_buffer[0x1000];             /*!< Received data array */

static void uart_thread(void* param);

/**
 * \brief           Send data to GSM device, function called from GSM stack when we have data to send
 * \param[in]       data: Pointer to data to send
 * \param[in]       len: Number of bytes to send
 * \return          Number of bytes sent
 */
static size_t
send_data(const void* data, size_t len) {
    DWORD written;
    if (com_port != NULL) {
#if !LWGSM_CFG_AT_ECHO
        const uint8_t* d = data;
        HANDLE hConsole;

        hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
        SetConsoleTextAttribute(hConsole, FOREGROUND_RED);
        for (DWORD i = 0; i < len; ++i) {
            printf("%c", d[i]);
        }
        SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
#endif /* !LWGSM_CFG_AT_ECHO */

        /* Write data to AT port */
        WriteFile(com_port, data, len, &written, NULL);
        FlushFileBuffers(com_port);
        return written;
    }
    return 0;
}

/**
 * \brief           Configure UART (USB to UART)
 */
static void
configure_uart(uint32_t baudrate) {
    DCB dcb = { 0 };
    dcb.DCBlength = sizeof(dcb);

    /*
     * On first call,
     * create virtual file on selected COM port and open it
     * as generic read and write
     */
    if (!initialized) {
        static const LPCWSTR com_ports[] = {
            L"\\\\.\\COM23",
            L"\\\\.\\COM12",
            L"\\\\.\\COM9",
            L"\\\\.\\COM8",
            L"\\\\.\\COM4"
        };
        for (size_t i = 0; i < sizeof(com_ports) / sizeof(com_ports[0]); ++i) {
            com_port = CreateFile(com_ports[i],
                                  GENERIC_READ | GENERIC_WRITE,
                                  0,
                                  0,
                                  OPEN_EXISTING,
                                  0,
                                  NULL
                                 );
            if (GetCommState(com_port, &dcb)) {
                printf("COM PORT %s opened!\r\n", (const char*)com_ports[i]);
                break;
            }
        }
    }

    /* Configure COM port parameters */
    if (GetCommState(com_port, &dcb)) {
        COMMTIMEOUTS timeouts;

        dcb.BaudRate = baudrate;
        dcb.ByteSize = 8;
        dcb.Parity = NOPARITY;
        dcb.StopBits = ONESTOPBIT;

        if (!SetCommState(com_port, &dcb)) {
            printf("Cannot set COM PORT info\r\n");
        }
        if (GetCommTimeouts(com_port, &timeouts)) {
            /* Set timeout to return immediately from ReadFile function */
            timeouts.ReadIntervalTimeout = MAXDWORD;
            timeouts.ReadTotalTimeoutConstant = 0;
            timeouts.ReadTotalTimeoutMultiplier = 0;
            if (!SetCommTimeouts(com_port, &timeouts)) {
                printf("Cannot set COM PORT timeouts\r\n");
            }
            GetCommTimeouts(com_port, &timeouts);
        } else {
            printf("Cannot get COM PORT timeouts\r\n");
        }
    } else {
        printf("Cannot get COM PORT info\r\n");
    }

    /* On first function call, create a thread to read data from COM port */
    if (!initialized) {
        thread_handle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)uart_thread, NULL, 0, 0);
    }
}

/**
 * \brief            UART thread
 */
static void
uart_thread(void* param) {
    DWORD bytes_read;
    lwgsm_sys_sem_t sem;
    FILE* file = NULL;

    lwgsm_sys_sem_create(&sem, 0);              /* Create semaphore for delay functions */

    while (com_port == NULL) {
        lwgsm_sys_sem_wait(&sem, 1);            /* Add some delay with yield */
    }

    fopen_s(&file, "log_file.txt", "w+");       /* Open debug file in write mode */
    while (1) {
        /*
         * Try to read data from COM port
         * and send it to upper layer for processing
         */
        do {
            ReadFile(com_port, data_buffer, sizeof(data_buffer), &bytes_read, NULL);
            if (bytes_read > 0) {
                HANDLE hConsole;
                hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
                SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN);
                for (DWORD i = 0; i < bytes_read; ++i) {
                    printf("%c", data_buffer[i]);
                }
                SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);

                /* Send received data to input processing module */
#if LWGSM_CFG_INPUT_USE_PROCESS
                lwgsm_input_process(data_buffer, (size_t)bytes_read);
#else /* LWGSM_CFG_INPUT_USE_PROCESS */
                lwgsm_input(data_buffer, (size_t)bytes_read);
#endif /* !LWGSM_CFG_INPUT_USE_PROCESS */

                /* Write received data to output debug file */
                if (file != NULL) {
                    fwrite(data_buffer, 1, bytes_read, file);
                    fflush(file);
                }
            }
        } while (bytes_read == (DWORD)sizeof(data_buffer));

        /* Implement delay to allow other tasks processing */
        lwgsm_sys_sem_wait(&sem, 1);
    }
}

/**
 * \brief           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 GSM stack when using OS.
 *                  When \ref LWGSM_CFG_INPUT_USE_PROCESS is set to 1, this function may be called from user UART thread.
 *
 * \param[in,out]   ll: Pointer to \ref lwgsm_ll_t structure to fill data for communication functions
 * \return          \ref lwgsmOK on success, member of \ref lwgsmr_t enumeration otherwise
 */
lwgsmr_t
lwgsm_ll_init(lwgsm_ll_t* ll) {
#if !LWGSM_CFG_MEM_CUSTOM
    /* Step 1: Configure memory for dynamic allocations */
    static uint8_t memory[0x10000];             /* Create memory for dynamic allocations with specific size */

    /*
     * Create memory region(s) of memory.
     * If device has internal/external memory available,
     * multiple memories may be used
     */
    lwgsm_mem_region_t mem_regions[] = {
        { memory, sizeof(memory) }
    };
    if (!initialized) {
        lwgsm_mem_assignmemory(mem_regions, LWGSM_ARRAYSIZE(mem_regions));  /* Assign memory for allocations to GSM library */
    }
#endif /* !LWGSM_CFG_MEM_CUSTOM */

    /* Step 2: Set AT port send function to use when we have data to transmit */
    if (!initialized) {
        ll->send_fn = send_data;                /* Set callback function to send data */
    }

    /* Step 3: Configure AT port to be able to send/receive data to/from GSM device */
    configure_uart(ll->uart.baudrate);          /* Initialize UART for communication */
    initialized = 1;
    return lwgsmOK;
}

#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 lwgsm_input_process() function to directly process received data without using intermediate receive buffer

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

  • It sets send and reset callback functions for LwGSM library

Actual implementation of low-level driver for STM32
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
/**
 * \file            lwgsm_ll_stm32.c
 * \brief           Generic STM32 driver, included in various STM32 driver variants
 */

/*
 * 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.
 *
 * This file is part of LwGSM - Lightweight GSM-AT library.
 *
 * Author:          Tilen MAJERLE <tilen@majerle.eu>
 * Version:         v0.1.0
 */

/*
 * How it works
 *
 * On first call to \ref lwgsm_ll_init, new thread is created and processed in usart_ll_thread function.
 * USART is configured in RX DMA mode and any incoming bytes are processed inside thread function.
 * DMA and USART implement interrupt handlers to notify main thread about new data ready to send to upper layer.
 *
 * More about UART + RX DMA: https://github.com/MaJerle/stm32-usart-dma-rx-tx
 *
 * \ref LWGSM_CFG_INPUT_USE_PROCESS must be enabled in `lwgsm_config.h` to use this driver.
 */
#include "lwgsm/lwgsm.h"
#include "lwgsm/lwgsm_mem.h"
#include "lwgsm/lwgsm_input.h"
#include "system/lwgsm_ll.h"

#if !__DOXYGEN__

#if !LWGSM_CFG_INPUT_USE_PROCESS
#error "LWGSM_CFG_INPUT_USE_PROCESS must be enabled in `lwgsm_config.h` to use this driver."
#endif /* LWGSM_CFG_INPUT_USE_PROCESS */

#if !defined(LWGSM_USART_DMA_RX_BUFF_SIZE)
#define LWGSM_USART_DMA_RX_BUFF_SIZE      0x1000
#endif /* !defined(LWGSM_USART_DMA_RX_BUFF_SIZE) */

#if !defined(LWGSM_MEM_SIZE)
#define LWGSM_MEM_SIZE                    0x1000
#endif /* !defined(LWGSM_MEM_SIZE) */

#if !defined(LWGSM_USART_RDR_NAME)
#define LWGSM_USART_RDR_NAME              RDR
#endif /* !defined(LWGSM_USART_RDR_NAME) */

/* USART memory */
static uint8_t      usart_mem[LWGSM_USART_DMA_RX_BUFF_SIZE];
static uint8_t      is_running, initialized;
static size_t       old_pos;

/* USART thread */
static void usart_ll_thread(void* arg);
static osThreadId_t usart_ll_thread_id;

/* Message queue */
static osMessageQueueId_t usart_ll_mbox_id;

/**
 * \brief           USART data processing
 */
static void
usart_ll_thread(void* arg) {
    size_t pos;

    LWGSM_UNUSED(arg);

    while (1) {
        void* d;
        /* Wait for the event message from DMA or USART */
        osMessageQueueGet(usart_ll_mbox_id, &d, NULL, osWaitForever);

        /* Read data */
#if defined(LWGSM_USART_DMA_RX_STREAM)
        pos = sizeof(usart_mem) - LL_DMA_GetDataLength(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_STREAM);
#else
        pos = sizeof(usart_mem) - LL_DMA_GetDataLength(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_CH);
#endif /* defined(LWGSM_USART_DMA_RX_STREAM) */
        if (pos != old_pos && is_running) {
            if (pos > old_pos) {
                lwgsm_input_process(&usart_mem[old_pos], pos - old_pos);
            } else {
                lwgsm_input_process(&usart_mem[old_pos], sizeof(usart_mem) - old_pos);
                if (pos > 0) {
                    lwgsm_input_process(&usart_mem[0], pos);
                }
            }
            old_pos = pos;
            if (old_pos == sizeof(usart_mem)) {
                old_pos = 0;
            }
        }
    }
}

/**
 * \brief           Configure UART using DMA for receive in double buffer mode and IDLE line detection
 */
static void
configure_uart(uint32_t baudrate) {
    static LL_USART_InitTypeDef usart_init;
    static LL_DMA_InitTypeDef dma_init;
    LL_GPIO_InitTypeDef gpio_init;

    if (!initialized) {
        /* Enable peripheral clocks */
        LWGSM_USART_CLK;
        LWGSM_USART_DMA_CLK;
        LWGSM_USART_TX_PORT_CLK;
        LWGSM_USART_RX_PORT_CLK;

#if defined(LWGSM_RESET_PIN)
        LWGSM_RESET_PORT_CLK;
#endif /* defined(LWGSM_RESET_PIN) */

        /* Global pin configuration */
        LL_GPIO_StructInit(&gpio_init);
        gpio_init.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
        gpio_init.Pull = LL_GPIO_PULL_UP;
        gpio_init.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
        gpio_init.Mode = LL_GPIO_MODE_OUTPUT;

#if defined(LWGSM_RESET_PIN)
        /* Configure RESET pin */
        gpio_init.Pin = LWGSM_RESET_PIN;
        LL_GPIO_Init(LWGSM_RESET_PORT, &gpio_init);
#endif /* defined(LWGSM_RESET_PIN) */

        /* Configure USART pins */
        gpio_init.Mode = LL_GPIO_MODE_ALTERNATE;

        /* TX PIN */
        gpio_init.Alternate = LWGSM_USART_TX_PIN_AF;
        gpio_init.Pin = LWGSM_USART_TX_PIN;
        LL_GPIO_Init(LWGSM_USART_TX_PORT, &gpio_init);

        /* RX PIN */
        gpio_init.Alternate = LWGSM_USART_RX_PIN_AF;
        gpio_init.Pin = LWGSM_USART_RX_PIN;
        LL_GPIO_Init(LWGSM_USART_RX_PORT, &gpio_init);

        /* Configure UART */
        LL_USART_DeInit(LWGSM_USART);
        LL_USART_StructInit(&usart_init);
        usart_init.BaudRate = baudrate;
        usart_init.DataWidth = LL_USART_DATAWIDTH_8B;
        usart_init.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
        usart_init.OverSampling = LL_USART_OVERSAMPLING_16;
        usart_init.Parity = LL_USART_PARITY_NONE;
        usart_init.StopBits = LL_USART_STOPBITS_1;
        usart_init.TransferDirection = LL_USART_DIRECTION_TX_RX;
        LL_USART_Init(LWGSM_USART, &usart_init);

        /* Enable USART interrupts and DMA request */
        LL_USART_EnableIT_IDLE(LWGSM_USART);
        LL_USART_EnableIT_PE(LWGSM_USART);
        LL_USART_EnableIT_ERROR(LWGSM_USART);
        LL_USART_EnableDMAReq_RX(LWGSM_USART);

        /* Enable USART interrupts */
        NVIC_SetPriority(LWGSM_USART_IRQ, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0x07, 0x00));
        NVIC_EnableIRQ(LWGSM_USART_IRQ);

        /* Configure DMA */
        is_running = 0;
#if defined(LWGSM_USART_DMA_RX_STREAM)
        LL_DMA_DeInit(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_STREAM);
        dma_init.Channel = LWGSM_USART_DMA_RX_CH;
#else
        LL_DMA_DeInit(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_CH);
        dma_init.PeriphRequest = LWGSM_USART_DMA_RX_REQ_NUM;
#endif /* defined(LWGSM_USART_DMA_RX_STREAM) */
        dma_init.PeriphOrM2MSrcAddress = (uint32_t)&LWGSM_USART->LWGSM_USART_RDR_NAME;
        dma_init.MemoryOrM2MDstAddress = (uint32_t)usart_mem;
        dma_init.Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
        dma_init.Mode = LL_DMA_MODE_CIRCULAR;
        dma_init.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
        dma_init.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
        dma_init.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_BYTE;
        dma_init.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE;
        dma_init.NbData = sizeof(usart_mem);
        dma_init.Priority = LL_DMA_PRIORITY_MEDIUM;
#if defined(LWGSM_USART_DMA_RX_STREAM)
        LL_DMA_Init(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_STREAM, &dma_init);
#else
        LL_DMA_Init(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_CH, &dma_init);
#endif /* defined(LWGSM_USART_DMA_RX_STREAM) */

        /* Enable DMA interrupts */
#if defined(LWGSM_USART_DMA_RX_STREAM)
        LL_DMA_EnableIT_HT(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_STREAM);
        LL_DMA_EnableIT_TC(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_STREAM);
        LL_DMA_EnableIT_TE(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_STREAM);
        LL_DMA_EnableIT_FE(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_STREAM);
        LL_DMA_EnableIT_DME(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_STREAM);
#else
        LL_DMA_EnableIT_HT(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_CH);
        LL_DMA_EnableIT_TC(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_CH);
        LL_DMA_EnableIT_TE(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_CH);
#endif /* defined(LWGSM_USART_DMA_RX_STREAM) */

        /* Enable DMA interrupts */
        NVIC_SetPriority(LWGSM_USART_DMA_RX_IRQ, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0x07, 0x00));
        NVIC_EnableIRQ(LWGSM_USART_DMA_RX_IRQ);

        old_pos = 0;
        is_running = 1;

        /* Start DMA and USART */
#if defined(LWGSM_USART_DMA_RX_STREAM)
        LL_DMA_EnableStream(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_STREAM);
#else
        LL_DMA_EnableChannel(LWGSM_USART_DMA, LWGSM_USART_DMA_RX_CH);
#endif /* defined(LWGSM_USART_DMA_RX_STREAM) */
        LL_USART_Enable(LWGSM_USART);
    } else {
        osDelay(10);
        LL_USART_Disable(LWGSM_USART);
        usart_init.BaudRate = baudrate;
        LL_USART_Init(LWGSM_USART, &usart_init);
        LL_USART_Enable(LWGSM_USART);
    }

    /* Create mbox and start thread */
    if (usart_ll_mbox_id == NULL) {
        usart_ll_mbox_id = osMessageQueueNew(10, sizeof(void*), NULL);
    }
    if (usart_ll_thread_id == NULL) {
        const osThreadAttr_t attr = {
            .stack_size = 1024
        };
        usart_ll_thread_id = osThreadNew(usart_ll_thread, usart_ll_mbox_id, &attr);
    }
}

#if defined(LWGSM_RESET_PIN)
/**
 * \brief           Hardware reset callback
 */
static uint8_t
reset_device(uint8_t state) {
    if (state) {                                /* Activate reset line */
        LL_GPIO_ResetOutputPin(LWGSM_RESET_PORT, LWGSM_RESET_PIN);
    } else {
        LL_GPIO_SetOutputPin(LWGSM_RESET_PORT, LWGSM_RESET_PIN);
    }
    return 1;
}
#endif /* defined(LWGSM_RESET_PIN) */

/**
 * \brief           Send data to GSM device
 * \param[in]       data: Pointer to data to send
 * \param[in]       len: Number of bytes to send
 * \return          Number of bytes sent
 */
static size_t
send_data(const void* data, size_t len) {
    const uint8_t* d = data;

    for (size_t i = 0; i < len; ++i, ++d) {
        LL_USART_TransmitData8(LWGSM_USART, *d);
        while (!LL_USART_IsActiveFlag_TXE(LWGSM_USART)) {}
    }
    return len;
}

/**
 * \brief           Callback function called from initialization process
 * \note            This function may be called multiple times if AT baudrate is changed from application
 * \param[in,out]   ll: Pointer to \ref lwgsm_ll_t structure to fill data for communication functions
 * \param[in]       baudrate: Baudrate to use on AT port
 * \return          Member of \ref lwgsmr_t enumeration
 */
lwgsmr_t
lwgsm_ll_init(lwgsm_ll_t* ll) {
#if !LWGSM_CFG_MEM_CUSTOM
    static uint8_t memory[LWGSM_MEM_SIZE];
    lwgsm_mem_region_t mem_regions[] = {
        { memory, sizeof(memory) }
    };

    if (!initialized) {
        lwgsm_mem_assignmemory(mem_regions, LWGSM_ARRAYSIZE(mem_regions));  /* Assign memory for allocations */
    }
#endif /* !LWGSM_CFG_MEM_CUSTOM */

    if (!initialized) {
        ll->send_fn = send_data;                /* Set callback function to send data */
#if defined(LWGSM_RESET_PIN)
        ll->reset_fn = reset_device;            /* Set callback for hardware reset */
#endif /* defined(LWGSM_RESET_PIN) */
    }

    configure_uart(ll->uart.baudrate);          /* Initialize UART for communication */
    initialized = 1;
    return lwgsmOK;
}

/**
 * \brief           Callback function to de-init low-level communication part
 * \param[in,out]   ll: Pointer to \ref lwgsm_ll_t structure to fill data for communication functions
 * \return          \ref lwgsmOK on success, member of \ref lwgsmr_t enumeration otherwise
 */
lwgsmr_t
lwgsm_ll_deinit(lwgsm_ll_t* ll) {
    if (usart_ll_mbox_id != NULL) {
        osMessageQueueId_t tmp = usart_ll_mbox_id;
        usart_ll_mbox_id = NULL;
        osMessageQueueDelete(tmp);
    }
    if (usart_ll_thread_id != NULL) {
        osThreadId_t tmp = usart_ll_thread_id;
        usart_ll_thread_id = NULL;
        osThreadTerminate(tmp);
    }
    initialized = 0;
    LWGSM_UNUSED(ll);
    return lwgsmOK;
}

/**
 * \brief           UART global interrupt handler
 */
void
LWGSM_USART_IRQHANDLER(void) {
    LL_USART_ClearFlag_IDLE(LWGSM_USART);
    LL_USART_ClearFlag_PE(LWGSM_USART);
    LL_USART_ClearFlag_FE(LWGSM_USART);
    LL_USART_ClearFlag_ORE(LWGSM_USART);
    LL_USART_ClearFlag_NE(LWGSM_USART);

    if (usart_ll_mbox_id != NULL) {
        void* d = (void*)1;
        osMessageQueuePut(usart_ll_mbox_id, &d, 0, 0);
    }
}

/**
 * \brief           UART DMA stream/channel handler
 */
void
LWGSM_USART_DMA_RX_IRQHANDLER(void) {
    LWGSM_USART_DMA_RX_CLEAR_TC;
    LWGSM_USART_DMA_RX_CLEAR_HT;

    if (usart_ll_mbox_id != NULL) {
        void* d = (void*)1;
        osMessageQueuePut(usart_ll_mbox_id, &d, 0, 0);
    }
}

#endif /* !__DOXYGEN__ */
Example: System functions for WIN32
Actual header implementation of system functions for WIN32
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/**
 * \file            lwgsm_sys_port.h
 * \brief           WIN32 based system file implementation
 */

/*
 * 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.
 *
 * This file is part of LwGSM - Lightweight GSM-AT library.
 *
 * Author:          Tilen MAJERLE <tilen@majerle.eu>
 * Version:         v0.1.0
 */
#ifndef LWGSM_HDR_SYSTEM_PORT_H
#define LWGSM_HDR_SYSTEM_PORT_H

#include <stdint.h>
#include <stdlib.h>
#include "lwgsm/lwgsm_opt.h"
#include "windows.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#if LWGSM_CFG_OS && !__DOXYGEN__

typedef HANDLE                      lwgsm_sys_mutex_t;
typedef HANDLE                      lwgsm_sys_sem_t;
typedef HANDLE                      lwgsm_sys_mbox_t;
typedef HANDLE                      lwgsm_sys_thread_t;
typedef int                         lwgsm_sys_thread_prio_t;

#define LWGSM_SYS_MUTEX_NULL          ((HANDLE)0)
#define LWGSM_SYS_SEM_NULL            ((HANDLE)0)
#define LWGSM_SYS_MBOX_NULL           ((HANDLE)0)
#define LWGSM_SYS_TIMEOUT             (INFINITE)
#define LWGSM_SYS_THREAD_PRIO         (0)
#define LWGSM_SYS_THREAD_SS           (4096)

#endif /* LWGSM_CFG_OS && !__DOXYGEN__ */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* LWGSM_HDR_SYSTEM_PORT_H */
Actual implementation of system functions for WIN32
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
/**
 * \file            lwgsm_sys_win32.c
 * \brief           System dependant functions for WIN32
 */

/*
 * 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.
 *
 * This file is part of LwGSM - Lightweight GSM-AT library.
 *
 * Author:          Tilen MAJERLE <tilen@majerle.eu>
 * Version:         v0.1.0
 */
#include <string.h>
#include <stdlib.h>
#include "system/lwgsm_sys.h"

#if !__DOXYGEN__

/**
 * \brief           Custom message queue implementation for WIN32
 */
typedef struct {
    lwgsm_sys_sem_t sem_not_empty;              /*!< Semaphore indicates not empty */
    lwgsm_sys_sem_t sem_not_full;               /*!< Semaphore indicates not full */
    lwgsm_sys_sem_t sem;                        /*!< Semaphore to lock access */
    size_t in, out, size;
    void* entries[1];
} win32_mbox_t;

static LARGE_INTEGER freq, sys_start_time;
static lwgsm_sys_mutex_t sys_mutex;             /* Mutex ID for main protection */

static uint8_t
mbox_is_full(win32_mbox_t* m) {
    size_t size = 0;
    if (m->in > m->out) {
        size = (m->in - m->out);
    } else if (m->out > m->in) {
        size = m->size - m->out + m->in;
    }
    return size == m->size - 1;
}

static uint8_t
mbox_is_empty(win32_mbox_t* m) {
    return m->in == m->out;
}

static uint32_t
osKernelSysTick(void) {
    LONGLONG ret;
    LARGE_INTEGER now;

    QueryPerformanceFrequency(&freq);           /* Get frequency */
    QueryPerformanceCounter(&now);              /* Get current time */
    ret = now.QuadPart - sys_start_time.QuadPart;
    return (uint32_t)(((ret) * 1000) / freq.QuadPart);
}

uint8_t
lwgsm_sys_init(void) {
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&sys_start_time);

    lwgsm_sys_mutex_create(&sys_mutex);
    return 1;
}

uint32_t
lwgsm_sys_now(void) {
    return osKernelSysTick();
}

uint8_t
lwgsm_sys_protect(void) {
    lwgsm_sys_mutex_lock(&sys_mutex);
    return 1;
}

uint8_t
lwgsm_sys_unprotect(void) {
    lwgsm_sys_mutex_unlock(&sys_mutex);
    return 1;
}

uint8_t
lwgsm_sys_mutex_create(lwgsm_sys_mutex_t* p) {
    *p = CreateMutex(NULL, FALSE, NULL);
    return *p != NULL;
}

uint8_t
lwgsm_sys_mutex_delete(lwgsm_sys_mutex_t* p) {
    return CloseHandle(*p);
}

uint8_t
lwgsm_sys_mutex_lock(lwgsm_sys_mutex_t* p) {
    DWORD ret;
    ret = WaitForSingleObject(*p, INFINITE);
    if (ret != WAIT_OBJECT_0) {
        return 0;
    }
    return 1;
}

uint8_t
lwgsm_sys_mutex_unlock(lwgsm_sys_mutex_t* p) {
    return (uint8_t)ReleaseMutex(*p);
}

uint8_t
lwgsm_sys_mutex_isvalid(lwgsm_sys_mutex_t* p) {
    return p != NULL && *p != NULL;
}

uint8_t
lwgsm_sys_mutex_invalid(lwgsm_sys_mutex_t* p) {
    *p = LWGSM_SYS_MUTEX_NULL;
    return 1;
}

uint8_t
lwgsm_sys_sem_create(lwgsm_sys_sem_t* p, uint8_t cnt) {
    HANDLE h;
    h = CreateSemaphore(NULL, !!cnt, 1, NULL);
    *p = h;
    return *p != NULL;
}

uint8_t
lwgsm_sys_sem_delete(lwgsm_sys_sem_t* p) {
    return CloseHandle(*p);
}

uint32_t
lwgsm_sys_sem_wait(lwgsm_sys_sem_t* p, uint32_t timeout) {
    DWORD ret;
    uint32_t tick = osKernelSysTick();

    if (timeout == 0) {
        ret = WaitForSingleObject(*p, INFINITE);
        return 1;
    } else {
        ret = WaitForSingleObject(*p, timeout);
        if (ret == WAIT_OBJECT_0) {
            return 1;
        } else {
            return LWGSM_SYS_TIMEOUT;
        }
    }
}

uint8_t
lwgsm_sys_sem_release(lwgsm_sys_sem_t* p) {
    return ReleaseSemaphore(*p, 1, NULL);
}

uint8_t
lwgsm_sys_sem_isvalid(lwgsm_sys_sem_t* p) {
    return p != NULL && *p != NULL;
}

uint8_t
lwgsm_sys_sem_invalid(lwgsm_sys_sem_t* p) {
    *p = LWGSM_SYS_SEM_NULL;
    return 1;
}

uint8_t
lwgsm_sys_mbox_create(lwgsm_sys_mbox_t* b, size_t size) {
    win32_mbox_t* mbox;

    *b = NULL;

    mbox = malloc(sizeof(*mbox) + size * sizeof(void*));
    if (mbox != NULL) {
        memset(mbox, 0x00, sizeof(*mbox));
        mbox->size = size + 1;                  /* Set it to 1 more as cyclic buffer has only one less than size */
        lwgsm_sys_sem_create(&mbox->sem, 1);
        lwgsm_sys_sem_create(&mbox->sem_not_empty, 0);
        lwgsm_sys_sem_create(&mbox->sem_not_full, 0);
        *b = mbox;
    }
    return *b != NULL;
}

uint8_t
lwgsm_sys_mbox_delete(lwgsm_sys_mbox_t* b) {
    win32_mbox_t* mbox = *b;
    lwgsm_sys_sem_delete(&mbox->sem);
    lwgsm_sys_sem_delete(&mbox->sem_not_full);
    lwgsm_sys_sem_delete(&mbox->sem_not_empty);
    free(mbox);
    return 1;
}

uint32_t
lwgsm_sys_mbox_put(lwgsm_sys_mbox_t* b, void* m) {
    win32_mbox_t* mbox = *b;
    uint32_t time = osKernelSysTick();          /* Get start time */

    lwgsm_sys_sem_wait(&mbox->sem, 0);          /* Wait for access */

    /*
     * Since function is blocking until ready to write something to queue,
     * wait and release the semaphores to allow other threads
     * to process the queue before we can write new value.
     */
    while (mbox_is_full(mbox)) {
        lwgsm_sys_sem_release(&mbox->sem);      /* Release semaphore */
        lwgsm_sys_sem_wait(&mbox->sem_not_full, 0); /* Wait for semaphore indicating not full */
        lwgsm_sys_sem_wait(&mbox->sem, 0);      /* Wait availability again */
    }
    mbox->entries[mbox->in] = m;
    if (++mbox->in >= mbox->size) {
        mbox->in = 0;
    }
    lwgsm_sys_sem_release(&mbox->sem_not_empty);/* Signal non-empty state */
    lwgsm_sys_sem_release(&mbox->sem);          /* Release access for other threads */
    return osKernelSysTick() - time;
}

uint32_t
lwgsm_sys_mbox_get(lwgsm_sys_mbox_t* b, void** m, uint32_t timeout) {
    win32_mbox_t* mbox = *b;
    uint32_t time;

    time = osKernelSysTick();

    /* Get exclusive access to message queue */
    if (lwgsm_sys_sem_wait(&mbox->sem, timeout) == LWGSM_SYS_TIMEOUT) {
        return LWGSM_SYS_TIMEOUT;
    }
    while (mbox_is_empty(mbox)) {
        lwgsm_sys_sem_release(&mbox->sem);
        if (lwgsm_sys_sem_wait(&mbox->sem_not_empty, timeout) == LWGSM_SYS_TIMEOUT) {
            return LWGSM_SYS_TIMEOUT;
        }
        lwgsm_sys_sem_wait(&mbox->sem, timeout);
    }
    *m = mbox->entries[mbox->out];
    if (++mbox->out >= mbox->size) {
        mbox->out = 0;
    }
    lwgsm_sys_sem_release(&mbox->sem_not_full);
    lwgsm_sys_sem_release(&mbox->sem);

    return osKernelSysTick() - time;
}

uint8_t
lwgsm_sys_mbox_putnow(lwgsm_sys_mbox_t* b, void* m) {
    win32_mbox_t* mbox = *b;

    lwgsm_sys_sem_wait(&mbox->sem, 0);
    if (mbox_is_full(mbox)) {
        lwgsm_sys_sem_release(&mbox->sem);
        return 0;
    }
    mbox->entries[mbox->in] = m;
    if (mbox->in == mbox->out) {
        lwgsm_sys_sem_release(&mbox->sem_not_empty);
    }
    if (++mbox->in >= mbox->size) {
        mbox->in = 0;
    }
    lwgsm_sys_sem_release(&mbox->sem);
    return 1;
}

uint8_t
lwgsm_sys_mbox_getnow(lwgsm_sys_mbox_t* b, void** m) {
    win32_mbox_t* mbox = *b;

    lwgsm_sys_sem_wait(&mbox->sem, 0);          /* Wait exclusive access */
    if (mbox->in == mbox->out) {
        lwgsm_sys_sem_release(&mbox->sem);      /* Release access */
        return 0;
    }

    *m = mbox->entries[mbox->out];
    if (++mbox->out >= mbox->size) {
        mbox->out = 0;
    }
    lwgsm_sys_sem_release(&mbox->sem_not_full); /* Queue not full anymore */
    lwgsm_sys_sem_release(&mbox->sem);          /* Release semaphore */
    return 1;
}

uint8_t
lwgsm_sys_mbox_isvalid(lwgsm_sys_mbox_t* b) {
    return b != NULL && *b != NULL;             /* Return status if message box is valid */
}

uint8_t
lwgsm_sys_mbox_invalid(lwgsm_sys_mbox_t* b) {
    *b = LWGSM_SYS_MBOX_NULL;                   /* Invalidate message box */
    return 1;
}

uint8_t
lwgsm_sys_thread_create(lwgsm_sys_thread_t* t, const char* name, lwgsm_sys_thread_fn thread_func, void* const arg, size_t stack_size, lwgsm_sys_thread_prio_t prio) {
    HANDLE h;
    DWORD id;
    h = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)thread_func, arg, 0, &id);
    if (t != NULL) {
        *t = h;
    }
    return h != NULL;
}

uint8_t
lwgsm_sys_thread_terminate(lwgsm_sys_thread_t* t) {
    HANDLE h = NULL;

    if (t == NULL) {                            /* Shall we terminate ourself? */
        h = GetCurrentThread();                 /* Get current thread handle */
    } else {                                    /* We have known thread, find handle by looking at ID */
        h = *t;
    }
    TerminateThread(h, 0);
    return 1;
}

uint8_t
lwgsm_sys_thread_yield(void) {
    /* Not implemented */
    return 1;
}

#endif /* !__DOXYGEN__ */
Example: System functions for CMSIS-OS
Actual header implementation of system functions for CMSIS-OS based operating systems
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/**
 * \file            lwgsm_sys_port.h
 * \brief           System dependent functions for CMSIS-OS based operating system
 */

/*
 * 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.
 *
 * This file is part of LwGSM - Lightweight GSM-AT library.
 *
 * Author:          Tilen MAJERLE <tilen@majerle.eu>
 * Version:         v0.1.0
 */
#ifndef LWGSM_HDR_SYSTEM_PORT_H
#define LWGSM_HDR_SYSTEM_PORT_H

#include <stdint.h>
#include <stdlib.h>
#include "lwgsm/lwgsm_opt.h"
#include "cmsis_os.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#if LWGSM_CFG_OS && !__DOXYGEN__

typedef osMutexId_t                 lwgsm_sys_mutex_t;
typedef osSemaphoreId_t             lwgsm_sys_sem_t;
typedef osMessageQueueId_t          lwgsm_sys_mbox_t;
typedef osThreadId_t                lwgsm_sys_thread_t;
typedef osPriority_t                lwgsm_sys_thread_prio_t;

#define LWGSM_SYS_MUTEX_NULL          ((lwgsm_sys_mutex_t)0)
#define LWGSM_SYS_SEM_NULL            ((lwgsm_sys_sem_t)0)
#define LWGSM_SYS_MBOX_NULL           ((lwgsm_sys_mbox_t)0)
#define LWGSM_SYS_TIMEOUT             ((uint32_t)osWaitForever)
#define LWGSM_SYS_THREAD_PRIO         (osPriorityNormal)
#define LWGSM_SYS_THREAD_SS           (512)

#endif /* LWGSM_CFG_OS && !__DOXYGEN__ */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* LWGSM_HDR_SYSTEM_PORT_H */
Actual implementation of system functions for CMSIS-OS based operating systems
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/**
 * \file            lwgsm_sys_cmsis_os.c
 * \brief           System dependent functions for CMSIS-OS based operating system
 */

/*
 * 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.
 *
 * This file is part of LwGSM - Lightweight GSM-AT library.
 *
 * Author:          Tilen MAJERLE <tilen@majerle.eu>
 * Version:         v0.1.0
 */
#include "system/lwgsm_sys.h"
#include "cmsis_os.h"

#if !__DOXYGEN__

static osMutexId_t sys_mutex;

uint8_t
lwgsm_sys_init(void) {
    lwgsm_sys_mutex_create(&sys_mutex);
    return 1;
}

uint32_t
lwgsm_sys_now(void) {
    return osKernelSysTick();
}

uint8_t
lwgsm_sys_protect(void) {
    lwgsm_sys_mutex_lock(&sys_mutex);
    return 1;
}

uint8_t
lwgsm_sys_unprotect(void) {
    lwgsm_sys_mutex_unlock(&sys_mutex);
    return 1;
}

uint8_t
lwgsm_sys_mutex_create(lwgsm_sys_mutex_t* p) {
    const osMutexAttr_t attr = {
        .attr_bits = osMutexRecursive
    };
    *p = osMutexNew(&attr);
    return *p != NULL;
}

uint8_t
lwgsm_sys_mutex_delete(lwgsm_sys_mutex_t* p) {
    return osMutexDelete(*p) == osOK;
}

uint8_t
lwgsm_sys_mutex_lock(lwgsm_sys_mutex_t* p) {
    return osMutexAcquire(*p, osWaitForever) == osOK;
}

uint8_t
lwgsm_sys_mutex_unlock(lwgsm_sys_mutex_t* p) {
    return osMutexRelease(*p) == osOK;
}

uint8_t
lwgsm_sys_mutex_isvalid(lwgsm_sys_mutex_t* p) {
    return p != NULL && *p != NULL;
}

uint8_t
lwgsm_sys_mutex_invalid(lwgsm_sys_mutex_t* p) {
    *p = LWGSM_SYS_MUTEX_NULL;
    return 1;
}

uint8_t
lwgsm_sys_sem_create(lwgsm_sys_sem_t* p, uint8_t cnt) {
    return (*p = osSemaphoreNew(1, cnt > 0 ? 1 : 0, NULL)) != NULL;
}

uint8_t
lwgsm_sys_sem_delete(lwgsm_sys_sem_t* p) {
    return osSemaphoreDelete(*p) == osOK;
}

uint32_t
lwgsm_sys_sem_wait(lwgsm_sys_sem_t* p, uint32_t timeout) {
    uint32_t tick = osKernelSysTick();
    return (osSemaphoreAcquire(*p, timeout == 0 ? osWaitForever : timeout) == osOK) ? (osKernelSysTick() - tick) : LWGSM_SYS_TIMEOUT;
}

uint8_t
lwgsm_sys_sem_release(lwgsm_sys_sem_t* p) {
    return osSemaphoreRelease(*p) == osOK;
}

uint8_t
lwgsm_sys_sem_isvalid(lwgsm_sys_sem_t* p) {
    return p != NULL && *p != NULL;
}

uint8_t
lwgsm_sys_sem_invalid(lwgsm_sys_sem_t* p) {
    *p = LWGSM_SYS_SEM_NULL;
    return 1;
}

uint8_t
lwgsm_sys_mbox_create(lwgsm_sys_mbox_t* b, size_t size) {
    return (*b = osMessageQueueNew(size, sizeof(void*), NULL)) != NULL;
}

uint8_t
lwgsm_sys_mbox_delete(lwgsm_sys_mbox_t* b) {
    if (osMessageQueueGetCount(*b) > 0) {
        return 0;
    }
    return osMessageQueueDelete(*b) == osOK;
}

uint32_t
lwgsm_sys_mbox_put(lwgsm_sys_mbox_t* b, void* m) {
    uint32_t tick = osKernelSysTick();
    return osMessageQueuePut(*b, &m, 0, osWaitForever) == osOK ? (osKernelSysTick() - tick) : LWGSM_SYS_TIMEOUT;
}

uint32_t
lwgsm_sys_mbox_get(lwgsm_sys_mbox_t* b, void** m, uint32_t timeout) {
    uint32_t tick = osKernelSysTick();
    return osMessageQueueGet(*b, m, NULL, timeout == 0 ? osWaitForever : timeout) == osOK ? (osKernelSysTick() - tick) : LWGSM_SYS_TIMEOUT;
}

uint8_t
lwgsm_sys_mbox_putnow(lwgsm_sys_mbox_t* b, void* m) {
    return osMessageQueuePut(*b, &m, 0, 0) == osOK;
}

uint8_t
lwgsm_sys_mbox_getnow(lwgsm_sys_mbox_t* b, void** m) {
    return osMessageQueueGet(*b, m, NULL, 0) == osOK;
}

uint8_t
lwgsm_sys_mbox_isvalid(lwgsm_sys_mbox_t* b) {
    return b != NULL && *b != NULL;
}

uint8_t
lwgsm_sys_mbox_invalid(lwgsm_sys_mbox_t* b) {
    *b = LWGSM_SYS_MBOX_NULL;
    return 1;
}

uint8_t
lwgsm_sys_thread_create(lwgsm_sys_thread_t* t, const char* name, lwgsm_sys_thread_fn thread_func, void* const arg, size_t stack_size, lwgsm_sys_thread_prio_t prio) {
    lwgsm_sys_thread_t id;
    const osThreadAttr_t thread_attr = {
        .name = (char*)name,
        .priority = (osPriority)prio,
        .stack_size = stack_size > 0 ? stack_size : LWGSM_SYS_THREAD_SS
    };

    id = osThreadNew(thread_func, arg, &thread_attr);
    if (t != NULL) {
        *t = id;
    }
    return id != NULL;
}

uint8_t
lwgsm_sys_thread_terminate(lwgsm_sys_thread_t* t) {
    if (t != NULL) {
        osThreadTerminate(*t);
    } else {
        osThreadExit();
    }
    return 1;
}

uint8_t
lwgsm_sys_thread_yield(void) {
    osThreadYield();
    return 1;
}

#endif /* !__DOXYGEN__ */

API reference

List of all the modules:

LwGSM

Ring buffer
group LWGSM_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 lwgsm_buff_init(lwgsm_buff_t *buff, size_t size)

Initialize buffer.

Return

1 on success, 0 otherwise

Parameters
  • [in] buff: Pointer to buffer structure

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

void lwgsm_buff_free(lwgsm_buff_t *buff)

Free dynamic allocation if used on memory.

Parameters
  • [in] buff: Pointer to buffer structure

void lwgsm_buff_reset(lwgsm_buff_t *buff)

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

Parameters
  • [in] buff: Buffer handle

size_t lwgsm_buff_write(lwgsm_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.

Return

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

Parameters
  • [in] buff: Buffer handle

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

  • [in] btw: Number of bytes to write

size_t lwgsm_buff_read(lwgsm_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.

Return

Number of bytes read and copied to data array

Parameters
  • [in] buff: Buffer handle

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

  • [in] btr: Number of bytes to read

size_t lwgsm_buff_peek(lwgsm_buff_t *buff, size_t skip_count, void *data, size_t btp)

Read from buffer without changing read pointer (peek only)

Return

Number of bytes peeked and written to output array

Parameters
  • [in] buff: Buffer handle

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

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

  • [in] btp: Number of bytes to peek

size_t lwgsm_buff_get_free(lwgsm_buff_t *buff)

Get number of bytes in buffer available to write.

Return

Number of free bytes in memory

Parameters
  • [in] buff: Buffer handle

size_t lwgsm_buff_get_full(lwgsm_buff_t *buff)

Get number of bytes in buffer available to read.

Return

Number of bytes ready to be read

Parameters
  • [in] buff: Buffer handle

void *lwgsm_buff_get_linear_block_read_address(lwgsm_buff_t *buff)

Get linear address for buffer for fast read.

Return

Linear buffer start address

Parameters
  • [in] buff: Buffer handle

size_t lwgsm_buff_get_linear_block_read_length(lwgsm_buff_t *buff)

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

Return

Linear buffer size in units of bytes for read operation

Parameters
  • [in] buff: Buffer handle

size_t lwgsm_buff_skip(lwgsm_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

Return

Number of bytes skipped

Parameters
  • [in] buff: Buffer handle

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

void *lwgsm_buff_get_linear_block_write_address(lwgsm_buff_t *buff)

Get linear address for buffer for fast read.

Return

Linear buffer start address

Parameters
  • [in] buff: Buffer handle

size_t lwgsm_buff_get_linear_block_write_length(lwgsm_buff_t *buff)

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

Return

Linear buffer size in units of bytes for write operation

Parameters
  • [in] buff: Buffer handle

size_t lwgsm_buff_advance(lwgsm_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

Return

Number of bytes advanced for write operation

Parameters
  • [in] buff: Buffer handle

  • [in] len: Number of bytes to advance

struct lwgsm_buff_t
#include <lwgsm_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.

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

  • Up to 5 TCP connections active at the same time

  • Up to 5 UDP connections active at the same time

  • Up to 1 SSL connection active at a time

Note

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

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

Example below shows bare minimum implementation to:

  • Start a new connection to remote host

  • Send HTTP GET request to remote host

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

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

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

static lwgsmr_t   conn_callback_func(lwgsm_evt_t* evt);

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

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

    /* Attach to GSM network */
    lwgsm_network_request_attach();

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

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

    conn = lwgsm_conn_get_from_evt(evt);          /* Get connection handle from event */
    if (conn == NULL) {
        return lwgsmERR;
    }
    conn_num = lwgsm_conn_getnum(conn);           /* Get connection number for identification */
    switch (lwgsm_evt_get_type(evt)) {
        case LWGSM_EVT_CONN_ACTIVE: {             /* Connection just active */
            printf("Connection %d active!\r\n", (int)conn_num);
            res = lwgsm_conn_send(conn, req_data, sizeof(req_data) - 1, NULL, 0); /* Start sending data in non-blocking mode */
            if (res == lwgsmOK) {
                printf("Sending request data to server...\r\n");
            } else {
                printf("Cannot send request data to server. Closing connection manually...\r\n");
                lwgsm_conn_close(conn, 0);        /* Close the connection */
            }
            break;
        }
        case LWGSM_EVT_CONN_CLOSE: {              /* Connection closed */
            if (lwgsm_evt_conn_close_is_forced(evt)) {
                printf("Connection %d closed by client!\r\n", (int)conn_num);
            } else {
                printf("Connection %d closed by remote side!\r\n", (int)conn_num);
            }
            break;
        }
        case LWGSM_EVT_CONN_SEND: {               /* Data send event */
            lwgsmr_t res = lwgsm_evt_conn_send_get_result(evt);
            if (res == lwgsmOK) {
                printf("Data sent successfully on connection %d...waiting to receive data from remote side...\r\n", (int)conn_num);
            } else {
                printf("Error while sending data on connection %d!\r\n", (int)conn_num);
            }
            break;
        }
        case LWGSM_EVT_CONN_RECV: {               /* Data received from remote side */
            lwgsm_pbuf_p pbuf = lwgsm_evt_conn_recv_get_buff(evt);
            lwgsm_conn_recved(conn, pbuf);        /* Notify stack about received pbuf */
            printf("Received %d bytes on connection %d..\r\n", (int)lwgsm_pbuf_length(pbuf, 1), (int)conn_num);
            break;
        }
        case LWGSM_EVT_CONN_ERROR: {              /* Error connecting to server */
            const char* host = lwgsm_evt_conn_error_get_host(evt);
            lwgsm_port_t port = lwgsm_evt_conn_error_get_port(evt);
            printf("Error connecting to %s:%d\r\n", host, (int)port);
            break;
        }
        default:
            break;
    }
    return lwgsmOK;
}
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 lwgsm_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.

GSM 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.

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 lwgsm_conn_send() or lwgsm_conn_sendto() functions.

group LWGSM_CONN

Connection API functions.

Typedefs

typedef struct lwgsm_conn *lwgsm_conn_p

Pointer to lwgsm_conn_t structure.

Enums

enum lwgsm_conn_type_t

List of possible connection types.

Values:

enumerator LWGSM_CONN_TYPE_TCP

Connection type is TCP

enumerator LWGSM_CONN_TYPE_UDP

Connection type is UDP

enumerator LWGSM_CONN_TYPE_SSL

Connection type is TCP over SSL

Functions

lwgsmr_t lwgsm_conn_start(lwgsm_conn_p *conn, lwgsm_conn_type_t type, const char *const host, lwgsm_port_t port, void *const arg, lwgsm_evt_fn conn_evt_fn, const uint32_t blocking)

Start a new connection of specific type.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

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

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

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

  • [in] port: Connection port

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

  • [in] conn_evt_fn: Callback function for this connection

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

lwgsmr_t lwgsm_conn_close(lwgsm_conn_p conn, const uint32_t blocking)

Close specific or all connections.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

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

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

lwgsmr_t lwgsm_conn_send(lwgsm_conn_p conn, const void *data, size_t btw, size_t *const bw, const uint32_t blocking)

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

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

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

  • [in] data: Data to send

  • [in] btw: Number of bytes to send

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

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

lwgsmr_t lwgsm_conn_sendto(lwgsm_conn_p conn, const lwgsm_ip_t *const ip, lwgsm_port_t port, const void *data, size_t btw, size_t *bw, const uint32_t blocking)

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

Note

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

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

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

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

  • [in] port: Remote port connection

  • [in] data: Pointer to data to send

  • [in] btw: Number of bytes to send

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

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

lwgsmr_t lwgsm_conn_set_arg(lwgsm_conn_p conn, void *const arg)

Set argument variable for connection.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

See

lwgsm_conn_get_arg

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

  • [in] arg: Pointer to argument

void *lwgsm_conn_get_arg(lwgsm_conn_p conn)

Get user defined connection argument.

Return

User argument

See

lwgsm_conn_set_arg

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

uint8_t lwgsm_conn_is_client(lwgsm_conn_p conn)

Check if connection type is client.

Return

1 on success, 0 otherwise

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

uint8_t lwgsm_conn_is_active(lwgsm_conn_p conn)

Check if connection is active.

Return

1 on success, 0 otherwise

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

uint8_t lwgsm_conn_is_closed(lwgsm_conn_p conn)

Check if connection is closed.

Return

1 on success, 0 otherwise

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

int8_t lwgsm_conn_getnum(lwgsm_conn_p conn)

Get the number from connection.

Return

Connection number in case of success or -1 on failure

Parameters
  • [in] conn: Connection pointer

lwgsmr_t lwgsm_get_conns_status(const uint32_t blocking)

Gets connections status.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

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

lwgsm_conn_p lwgsm_conn_get_from_evt(lwgsm_evt_t *evt)

Get connection from connection based event.

Return

Connection pointer on success, NULL otherwise

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

lwgsmr_t lwgsm_conn_write(lwgsm_conn_p conn, const void *data, size_t btw, uint8_t flush, size_t *const mem_available)

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

Note

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

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] conn: Connection to write

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

  • [in] btw: Number of bytes to write

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

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

lwgsmr_t lwgsm_conn_recved(lwgsm_conn_p conn, lwgsm_pbuf_p pbuf)

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

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

Note

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

Note

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

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] conn: Connection handle

  • [in] pbuf: Packet buffer received on connection

size_t lwgsm_conn_get_total_recved_count(lwgsm_conn_p conn)

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

Return

Count of received bytes on connection

Parameters
  • [in] conn: Connection handle

uint8_t lwgsm_conn_get_remote_ip(lwgsm_conn_p conn, lwgsm_ip_t *ip)

Get connection remote IP address.

Return

1 on success, 0 otherwise

Parameters
  • [in] conn: Connection handle

  • [out] ip: Pointer to IP output handle

lwgsm_port_t lwgsm_conn_get_remote_port(lwgsm_conn_p conn)

Get connection remote port number.

Return

Port number on success, 0 otherwise

Parameters
  • [in] conn: Connection handle

lwgsm_port_t lwgsm_conn_get_local_port(lwgsm_conn_p conn)

Get connection local port number.

Return

Port number on success, 0 otherwise

Parameters
  • [in] conn: Connection handle

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 LWGSM_CFG_DBG_OUT configuration.

For successful debugging, application must:

  • Enable global debugging by setting LWGSM_CFG_DBG to LWGSM_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 LWGSM_DBG_ON

Tip

Check Configuration for all modules with debug implementation.

An example code with config and latter usage:

Debug configuration setup
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
/* Modifications of lwgsm_opts.h file for configuration */

/* Enable global debug */
#define LWGSM_CFG_DBG               LWGSM_DBG_ON

/*
 * Enable debug types.
 * Application may use bitwise OR | to use multiple types:
 *    LWGSM_DBG_TYPE_TRACE | LWGSM_DBG_TYPE_STATE
 */
#define LWGSM_CFG_DBG_TYPES_ON      LWGSM_DBG_TYPE_TRACE

/* Enable debug on custom module */
#define MY_DBG_MODULE               LWGSM_DBG_ON
Debug usage within middleware
1
2
3
4
5
6
7
8
9
#include "lwgsm/lwgsm_debug.h"

/*
 * Print debug message to the screen
 * Trace message will be printed as it is enabled in types 
 * while state message will not be printed.
 */
LWGSM_DEBUGF(MY_DBG_MODULE | LWGSM_DBG_TYPE_TRACE, "This is trace message on my program\r\n");
LWGSM_DEBUGF(MY_DBG_MODULE | LWGSM_DBG_TYPE_STATE, "This is state message on my program\r\n");
group LWGSM_DEBUG

Debugging support module to track stack.

Debug levels

List of debug levels

LWGSM_DBG_LVL_ALL

Print all messages of all types

LWGSM_DBG_LVL_WARNING

Print warning and upper messages

LWGSM_DBG_LVL_DANGER

Print danger errors

LWGSM_DBG_LVL_SEVERE

Print severe problems affecting program flow

LWGSM_DBG_LVL_MASK

Mask for getting debug level

Debug types

List of possible debugging types

LWGSM_DBG_TYPE_TRACE

Debug trace messages for program flow

LWGSM_DBG_TYPE_STATE

Debug state messages (such as state machines)

LWGSM_DBG_TYPE_ALL

All debug types

Defines

LWGSM_DBG_ON

Indicates debug is enabled

LWGSM_DBG_OFF

Indicates debug is disabled

LWGSM_DEBUGF(c, fmt, ...)

Print message to the debug “window” if enabled.

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

  • [in] fmt: Formatted string for debug

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

LWGSM_DEBUGW(c, cond, fmt, ...)

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

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

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

  • [in] fmt: Formatted string for debug

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

Device info
group LWGSM_DEVICE_INFO

Basic device information.

Functions

lwgsmr_t lwgsm_device_get_manufacturer(char *manuf, size_t len, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get device manufacturer.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] manuf: Pointer to output string array to save manufacturer info

  • [in] len: Length of string array including NULL termination

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

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

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

lwgsmr_t lwgsm_device_get_model(char *model, size_t len, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get device model name.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] model: Pointer to output string array to save model info

  • [in] len: Length of string array including NULL termination

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

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

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

lwgsmr_t lwgsm_device_get_revision(char *rev, size_t len, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get device revision.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] rev: Pointer to output string array to save revision info

  • [in] len: Length of string array including NULL termination

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

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

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

lwgsmr_t lwgsm_device_get_serial_number(char *serial, size_t len, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get device serial number.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] serial: Pointer to output string array to save serial number info

  • [in] len: Length of string array including NULL termination

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

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

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

Event management
group LWGSM_EVT

Event helper functions.

Reset event

Event helper functions for LWGSM_EVT_RESET event

lwgsmr_t lwgsm_evt_reset_get_result(lwgsm_evt_t *cc)

Get reset sequence operation status.

Return

Member of lwgsmr_t enumeration

Parameters
  • [in] cc: Event data

Restore event

Event helper functions for LWGSM_EVT_RESTORE event

lwgsmr_t lwgsm_evt_restore_get_result(lwgsm_evt_t *cc)

Get restore sequence operation status.

Return

Member of lwgsmr_t enumeration

Parameters
  • [in] cc: Event data

Current network operator

Event helper functions for LWGSM_EVT_NETWORK_OPERATOR_CURRENT event

const lwgsm_operator_curr_t *lwgsm_evt_network_operator_get_current(lwgsm_evt_t *cc)

Get current operator data from event.

Return

Current operator handle

Parameters
  • [in] cc: Event data

Connection data received

Event helper functions for LWGSM_EVT_CONN_RECV event

lwgsm_pbuf_p lwgsm_evt_conn_recv_get_buff(lwgsm_evt_t *cc)

Get buffer from received data.

Return

Buffer handle

Parameters
  • [in] cc: Event handle

lwgsm_conn_p lwgsm_evt_conn_recv_get_conn(lwgsm_evt_t *cc)

Get connection handle for receive.

Return

Connection handle

Parameters
  • [in] cc: Event handle

Connection data send

Event helper functions for LWGSM_EVT_CONN_SEND event

lwgsm_conn_p lwgsm_evt_conn_send_get_conn(lwgsm_evt_t *cc)

Get connection handle for data sent event.

Return

Connection handle

Parameters
  • [in] cc: Event handle

size_t lwgsm_evt_conn_send_get_length(lwgsm_evt_t *cc)

Get number of bytes sent on connection.

Return

Number of bytes sent

Parameters
  • [in] cc: Event handle

lwgsmr_t lwgsm_evt_conn_send_get_result(lwgsm_evt_t *cc)

Check if connection send was successful.

Return

Member of lwgsmr_t enumeration

Parameters
  • [in] cc: Event handle

Connection active

Event helper functions for LWGSM_EVT_CONN_ACTIVE event

lwgsm_conn_p lwgsm_evt_conn_active_get_conn(lwgsm_evt_t *cc)

Get connection handle.

Return

Connection handle

Parameters
  • [in] cc: Event handle

uint8_t lwgsm_evt_conn_active_is_client(lwgsm_evt_t *cc)

Check if new connection is client.

Return

1 if client, 0 otherwise

Parameters
  • [in] cc: Event handle

Connection close event

Event helper functions for LWGSM_EVT_CONN_CLOSE event

lwgsm_conn_p lwgsm_evt_conn_close_get_conn(lwgsm_evt_t *cc)

Get connection handle.

Return

Connection handle

Parameters
  • [in] cc: Event handle

uint8_t lwgsm_evt_conn_close_is_client(lwgsm_evt_t *cc)

Check if close connection was client.

Return

1 if client, 0 otherwise

Parameters
  • [in] cc: Event handle

uint8_t lwgsm_evt_conn_close_is_forced(lwgsm_evt_t *cc)

Check if connection close even was forced by user.

Return

1 if forced, 0 otherwise

Parameters
  • [in] cc: Event handle

lwgsmr_t lwgsm_evt_conn_close_get_result(lwgsm_evt_t *cc)

Get connection close event result.

Return

Member of lwgsmr_t enumeration

Parameters
  • [in] cc: Event handle

Connection poll

Event helper functions for LWGSM_EVT_CONN_POLL event

lwgsm_conn_p lwgsm_evt_conn_poll_get_conn(lwgsm_evt_t *cc)

Get connection handle.

Return

Connection handle

Parameters
  • [in] cc: Event handle

Connection error

Event helper functions for LWGSM_EVT_CONN_ERROR event

lwgsmr_t lwgsm_evt_conn_error_get_error(lwgsm_evt_t *cc)

Get connection error type.

Return

Member of lwgsmr_t enumeration

Parameters
  • [in] cc: Event handle

lwgsm_conn_type_t lwgsm_evt_conn_error_get_type(lwgsm_evt_t *cc)

Get connection type.

Return

Member of lwgsmr_t enumeration

Parameters
  • [in] cc: Event handle

const char *lwgsm_evt_conn_error_get_host(lwgsm_evt_t *cc)

Get connection host.

Return

Host name for connection

Parameters
  • [in] cc: Event handle

lwgsm_port_t lwgsm_evt_conn_error_get_port(lwgsm_evt_t *cc)

Get connection port.

Return

Host port number

Parameters
  • [in] cc: Event handle

void *lwgsm_evt_conn_error_get_arg(lwgsm_evt_t *cc)

Get user argument.

Return

User argument

Parameters
  • [in] cc: Event handle

Signal strength

Event helper functions for LWGSM_EVT_CONN_RECV event

int16_t lwgsm_evt_signal_strength_get_rssi(lwgsm_evt_t *cc)

Get RSSi from CSQ command.

Return

RSSI value in units of dBm

Parameters
  • [in] cc: Event data

SMS received

Event helper functions for LWGSM_EVT_SMS_RECV event

size_t lwgsm_evt_sms_recv_get_pos(lwgsm_evt_t *cc)

Get SMS position in memory which has been saved on receive.

Return

SMS position in memory

Parameters
  • [in] cc: Event handle

lwgsm_mem_t lwgsm_evt_sms_recv_get_mem(lwgsm_evt_t *cc)

Get SMS memory used to save SMS on receive.

Return

SMS memory location

Parameters
  • [in] cc: Event handle

SMS content read

Event helper functions for LWGSM_EVT_SMS_READ event

lwgsm_sms_entry_t *lwgsm_evt_sms_read_get_entry(lwgsm_evt_t *cc)

Get SMS entry after successful read.

Return

SMS entry

Parameters
  • [in] cc: Event handle

lwgsmr_t lwgsm_evt_sms_read_get_result(lwgsm_evt_t *cc)

Get SMS read operation result.

Return

SMS entry

Parameters
  • [in] cc: Event handle

SMS send

Event helper functions for LWGSM_EVT_SMS_SEND event

lwgsmr_t lwgsm_evt_sms_send_get_result(lwgsm_evt_t *cc)

Get SMS send result status.

Return

Member of lwgsmr_t enumeration

Parameters
  • [in] cc: Event handle

size_t lwgsm_evt_sms_send_get_pos(lwgsm_evt_t *cc)

Get SMS send position in memory.

Note

Use only if SMS sent successfully

Return

Position in memory

Parameters
  • [in] cc: Event handle

SMS delete

Event helper functions for LWGSM_EVT_SMS_DELETE event

lwgsmr_t lwgsm_evt_sms_delete_get_result(lwgsm_evt_t *cc)

Get SMS delete result status.

Return

Member of lwgsmr_t enumeration

Parameters
  • [in] cc: Event handle

size_t lwgsm_evt_sms_delete_get_pos(lwgsm_evt_t *cc)

Get SMS delete memory position.

Return

Deleted position in memory

Parameters
  • [in] cc: Event handle

lwgsm_mem_t lwgsm_evt_sms_delete_get_mem(lwgsm_evt_t *cc)

Get SMS delete memory.

Return

SMS memory for delete operation

Parameters
  • [in] cc: Event handle

Call status changed

Event helper functions for LWGSM_EVT_CALL_CHANGED event

const lwgsm_call_t *lwgsm_evt_call_changed_get_call(lwgsm_evt_t *cc)

Get call information from changed event.

Return

Position in memory

Parameters
  • [in] cc: Event handle

Operator scan

Event helper functions for LWGSM_EVT_OPERATOR_SCAN event

lwgsmr_t lwgsm_evt_operator_scan_get_result(lwgsm_evt_t *cc)

Get operator scan operation status.

Return

Member of lwgsmr_t enumeration

Parameters
  • [in] cc: Event data

lwgsm_operator_t *lwgsm_evt_operator_scan_get_entries(lwgsm_evt_t *cc)

Get operator entries from scan.

Return

Pointer to array of operator entries

Parameters
  • [in] cc: Event data

size_t lwgsm_evt_operator_scan_get_length(lwgsm_evt_t *cc)

Get length of operators scanned.

Return

Number of operators scanned

Parameters
  • [in] cc: Event data

Typedefs

typedef lwgsmr_t (*lwgsm_evt_fn)(struct lwgsm_evt *evt)

Event function prototype.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] evt: Callback event data

Enums

enum lwgsm_evt_type_t

List of possible callback types received to user.

Values:

enumerator LWGSM_EVT_INIT_FINISH

Initialization has been finished at this point

enumerator LWGSM_EVT_RESET

Device reset operation finished

enumerator LWGSM_EVT_RESTORE

Device restore operation finished

enumerator LWGSM_EVT_CMD_TIMEOUT

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

enumerator LWGSM_EVT_DEVICE_PRESENT

Notification when device present status changes

enumerator LWGSM_EVT_DEVICE_IDENTIFIED

Device identified event

enumerator LWGSM_EVT_SIGNAL_STRENGTH

Signal strength event

enumerator LWGSM_EVT_SIM_STATE_CHANGED

SIM card state changed

enumerator LWGSM_EVT_OPERATOR_SCAN

Operator scan finished event

enumerator LWGSM_EVT_NETWORK_OPERATOR_CURRENT

Current operator event

enumerator LWGSM_EVT_NETWORK_REG_CHANGED

Network registration changed. Available even when LWGSM_CFG_NETWORK is disabled

enumerator LWGSM_EVT_NETWORK_ATTACHED

Attached to network, PDP context active and ready for TCP/IP application

enumerator LWGSM_EVT_NETWORK_DETACHED

Detached from network, PDP context not active anymore

enumerator LWGSM_EVT_CONN_RECV

Connection data received

enumerator LWGSM_EVT_CONN_SEND

Connection data send

enumerator LWGSM_EVT_CONN_ACTIVE

Connection just became active

enumerator LWGSM_EVT_CONN_ERROR

Client connection start was not successful

enumerator LWGSM_EVT_CONN_CLOSE

Connection close event. Check status if successful

enumerator LWGSM_EVT_CONN_POLL

Poll for connection if there are any changes

enumerator LWGSM_EVT_SMS_ENABLE

SMS enable event

enumerator LWGSM_EVT_SMS_READY

SMS ready event

enumerator LWGSM_EVT_SMS_SEND

SMS send event

enumerator LWGSM_EVT_SMS_RECV

SMS received

enumerator LWGSM_EVT_SMS_READ

SMS read

enumerator LWGSM_EVT_SMS_DELETE

SMS delete

enumerator LWGSM_EVT_SMS_LIST

SMS list

enumerator LWGSM_EVT_CALL_ENABLE

Call enable event

enumerator LWGSM_EVT_CALL_READY

Call ready event

enumerator LWGSM_EVT_CALL_CHANGED

Call info changed, +CLCK statement received

enumerator LWGSM_EVT_CALL_RING

Call is ringing event

enumerator LWGSM_EVT_CALL_BUSY

Call is busy

enumerator LWGSM_EVT_CALL_NO_CARRIER

No carrier to make a call

enumerator LWGSM_EVT_PB_ENABLE

Phonebook enable event

enumerator LWGSM_EVT_PB_LIST

Phonebook list event

enumerator LWGSM_EVT_PB_SEARCH

Phonebook search event

Functions

lwgsmr_t lwgsm_evt_register(lwgsm_evt_fn fn)

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

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] fn: Callback function to call on specific event

lwgsmr_t lwgsm_evt_unregister(lwgsm_evt_fn fn)

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

Note

Function must be first registered using lwgsm_evt_register

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] fn: Callback function to remove from event list

lwgsm_evt_type_t lwgsm_evt_get_type(lwgsm_evt_t *cc)

Get event type.

Return

Event type. Member of lwgsm_evt_type_t enumeration

Parameters
  • [in] cc: Event handle

struct lwgsm_evt_t
#include <lwgsm_typedefs.h>

Global callback structure to pass as parameter to callback function.

Public Members

lwgsm_evt_type_t type

Callback type

lwgsmr_t res

Reset operation result

Restore operation result

Scan operation result

Send data result

Result of close event. Set to lwgsmOK on success.

SMS send result information

SMS read result information

Operation success

Result on command

Enable status

struct lwgsm_evt_t::[anonymous]::[anonymous] reset

Reset sequence finish. Use with LWGSM_EVT_RESET event

struct lwgsm_evt_t::[anonymous]::[anonymous] restore

Restore sequence finish. Use with LWGSM_EVT_RESTORE event

lwgsm_sim_state_t state

SIM state

struct lwgsm_evt_t::[anonymous]::[anonymous] cpin

CPIN event

const lwgsm_operator_curr_t *operator_current

Current operator info

struct lwgsm_evt_t::[anonymous]::[anonymous] operator_current

Current operator event. Use with LWGSM_EVT_NETWORK_OPERATOR_CURRENT event

lwgsm_operator_t *ops

Pointer to operators

size_t opf

Number of operators found

struct lwgsm_evt_t::[anonymous]::[anonymous] operator_scan

Operator scan event. Use with LWGSM_EVT_OPERATOR_SCAN event

int16_t rssi

Strength in units of dBm

struct lwgsm_evt_t::[anonymous]::[anonymous] rssi

Signal strength event. Use with LWGSM_EVT_SIGNAL_STRENGTH event

lwgsm_conn_p conn

Connection where data were received

Connection where data were sent

Pointer to connection

Set connection pointer

lwgsm_pbuf_p buff

Pointer to received data

struct lwgsm_evt_t::[anonymous]::[anonymous] conn_data_recv

Network data received. Use with LWGSM_EVT_CONN_RECV event

size_t sent

Number of bytes sent on connection

struct lwgsm_evt_t::[anonymous]::[anonymous] conn_data_send

Data successfully sent. Use with LWGSM_EVT_CONN_SEND event

const char *host

Host to use for connection

lwgsm_port_t port

Remote port used for connection

lwgsm_conn_type_t type

Connection type

void *arg

Connection argument used on connection

lwgsmr_t err

Error value

struct lwgsm_evt_t::[anonymous]::[anonymous] conn_error

Client connection start error. Use with LWGSM_EVT_CONN_ERROR event

uint8_t client

Set to 1 if connection is/was client mode

uint8_t forced

Set to 1 if connection action was forced

struct lwgsm_evt_t::[anonymous]::[anonymous] conn_active_close

Process active and closed statuses at the same time. Use with LWGSM_EVT_CONN_ACTIVE or LWGSM_EVT_CONN_CLOSE events

struct lwgsm_evt_t::[anonymous]::[anonymous] conn_poll

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

lwgsmr_t status

Enable status

struct lwgsm_evt_t::[anonymous]::[anonymous] sms_enable

SMS enable event. Use with LWGSM_EVT_SMS_ENABLE event

size_t pos

Position in memory

Received position in memory for sent SMS

Deleted position in memory for sent SMS

struct lwgsm_evt_t::[anonymous]::[anonymous] sms_send

SMS sent info. Use with LWGSM_EVT_SMS_SEND event

lwgsm_mem_t mem

Memory of received message

Memory of deleted message

Memory used for scan

struct lwgsm_evt_t::[anonymous]::[anonymous] sms_recv

SMS received info. Use with LWGSM_EVT_SMS_RECV event

lwgsm_sms_entry_t *entry

SMS entry

struct lwgsm_evt_t::[anonymous]::[anonymous] sms_read

SMS read. Use with LWGSM_EVT_SMS_READ event

struct lwgsm_evt_t::[anonymous]::[anonymous] sms_delete

SMS delete. Use with LWGSM_EVT_SMS_DELETE event

lwgsm_sms_entry_t *entries

Pointer to entries

size_t size

Number of valid entries

struct lwgsm_evt_t::[anonymous]::[anonymous] sms_list

SMS list. Use with LWGSM_EVT_SMS_LIST event

struct lwgsm_evt_t::[anonymous]::[anonymous] call_enable

Call enable event. Use with LWGSM_EVT_CALL_ENABLE event

const lwgsm_call_t *call

Call information

struct lwgsm_evt_t::[anonymous]::[anonymous] call_changed

Call changed info. Use with LWGSM_EVT_CALL_CHANGED event

struct lwgsm_evt_t::[anonymous]::[anonymous] pb_enable

Phonebook enable event. Use with LWGSM_EVT_PB_ENABLE event

lwgsm_pb_entry_t *entries

Pointer to entries

struct lwgsm_evt_t::[anonymous]::[anonymous] pb_list

Phonebok list. Use with LWGSM_EVT_PB_LIST event

const char *search

Search string

struct lwgsm_evt_t::[anonymous]::[anonymous] pb_search

Phonebok search list. Use with LWGSM_EVT_PB_SEARCH event

union lwgsm_evt_t::[anonymous] evt

Callback event union

File Transfer Protocol
group LWGSM_FTP

File Transfer Protocol (FTP) manager.

Currently it is under development

HTTP
group LWGSM_HTTP

Hyper Text Transfer Protocol (HTTP) manager.

Currently it is under development

Input module

Input module is used to input received data from GSM device to LwGSM-Lib middleware part. 2 processing options are possible:

Tip

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

Indirect processing

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

Function lwgsm_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 lwgsm_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 LWGSM_INPUT

Input function for received data.

Functions

lwgsmr_t lwgsm_input(const void *data, size_t len)

Write data to input buffer.

Note

LWGSM_CFG_INPUT_USE_PROCESS must be disabled to use this function

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] data: Pointer to data to write

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

lwgsmr_t lwgsm_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

LWGSM_CFG_INPUT_USE_PROCESS must be enabled to use this function

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

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

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

Memory manager
group LWGSM_MEM

Dynamic memory manager.

Functions

uint8_t lwgsm_mem_assignmemory(const lwgsm_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

Return

1 on success, 0 otherwise

Note

Function is not available when LWGSM_CFG_MEM_CUSTOM is 1

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

  • [in] len: Number of regions to use

void *lwgsm_mem_malloc(size_t size)

Allocate memory of specific size.

Return

Memory address on success, NULL otherwise

Note

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

Parameters
  • [in] size: Number of bytes to allocate

void *lwgsm_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

Return

Memory address on success, NULL otherwise

Note

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

Parameters

void *lwgsm_mem_calloc(size_t num, size_t size)

Allocate memory of specific size and set memory to zero.

Return

Memory address on success, NULL otherwise

Note

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

Parameters
  • [in] num: Number of elements to allocate

  • [in] size: Size of each element

void lwgsm_mem_free(void *ptr)

Free memory.

Note

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

Parameters

uint8_t lwgsm_mem_free_s(void **ptr)

Free memory in safe way by invalidating pointer after freeing.

Return

1 on success, 0 otherwise

Parameters
  • [in] ptr: Pointer to pointer to allocated memory to free

struct lwgsm_mem_region_t
#include <lwgsm_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

Network
group LWGSM_NETWORK

Network manager.

Enums

enum lwgsm_network_reg_status_t

Network Registration status.

Values:

enumerator LWGSM_NETWORK_REG_STATUS_SIM_ERR

SIM card error

enumerator LWGSM_NETWORK_REG_STATUS_CONNECTED

Device is connected to network

enumerator LWGSM_NETWORK_REG_STATUS_SEARCHING

Network search is in progress

enumerator LWGSM_NETWORK_REG_STATUS_DENIED

Registration denied

enumerator LWGSM_NETWORK_REG_STATUS_CONNECTED_ROAMING

Device is connected and is roaming

enumerator LWGSM_NETWORK_REG_STATUS_CONNECTED_SMS_ONLY

Device is connected to home network in SMS-only mode

enumerator LWGSM_NETWORK_REG_STATUS_CONNECTED_ROAMING_SMS_ONLY

Device is roaming in SMS-only mode

Functions

lwgsmr_t lwgsm_network_rssi(int16_t *rssi, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Read RSSI signal from network operator.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [out] rssi: RSSI output variable. When set to 0, RSSI is not valid

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

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

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

lwgsm_network_reg_status_t lwgsm_network_get_reg_status(void)

Get network registration status.

Return

Member of lwgsm_network_reg_status_t enumeration

lwgsmr_t lwgsm_network_attach(const char *apn, const char *user, const char *pass, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Attach to network and active PDP context.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] apn: APN name

  • [in] user: User name to attach. Set to NULL if not used

  • [in] pass: User password to attach. Set to NULL if not used

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

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

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

lwgsmr_t lwgsm_network_detach(const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Detach from network.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

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

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

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

uint8_t lwgsm_network_is_attached(void)

Check if device is attached to network and PDP context is active.

Return

1 on success, 0 otherwise

lwgsmr_t lwgsm_network_copy_ip(lwgsm_ip_t *ip)

Copy IP address from internal value to user variable.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [out] ip: Pointer to output IP variable

lwgsmr_t lwgsm_network_check_status(const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Check network PDP status.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

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

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

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

Network API

Network API provides functions for multi-thread application network management. It allows multiple threads to request to join to network (internet access).

Network API module controls when network connection shall be active or can be closed.

group LWGSM_NETWORK_API

Network API functions for multi-thread operations.

Functions

lwgsmr_t lwgsm_network_set_credentials(const char *apn, const char *user, const char *pass)

Set system network credentials before asking for attach.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] apn: APN domain. Set to NULL if not used

  • [in] user: APN username. Set to NULL if not used

  • [in] pass: APN password. Set to NULL if not used

lwgsmr_t lwgsm_network_request_attach(void)

Request manager to attach to network.

Note

This function is blocking and cannot be called from event functions

Return

lwgsmOK on success (when attached), member of lwgsmr_t otherwise

lwgsmr_t lwgsm_network_request_detach(void)

Request manager to detach from network.

If other threads use network, manager will not disconnect from network otherwise it will disable network access

Note

This function is blocking and cannot be called from event functions

Return

lwgsmOK on success (when attached), member of lwgsmr_t otherwise

Network operator
group LWGSM_OPERATOR

network operator API

Enums

enum lwgsm_operator_status_t

Operator status value.

Values:

enumerator LWGSM_OPERATOR_STATUS_UNKNOWN

Unknown operator

enumerator LWGSM_OPERATOR_STATUS_AVAILABLE

Operator is available

enumerator LWGSM_OPERATOR_STATUS_CURRENT

Operator is currently active

enumerator LWGSM_OPERATOR_STATUS_FORBIDDEN

Operator is forbidden

enum lwgsm_operator_mode_t

Operator selection mode.

Values:

enumerator LWGSM_OPERATOR_MODE_AUTO

Operator automatic mode

enumerator LWGSM_OPERATOR_MODE_MANUAL

Operator manual mode

enumerator LWGSM_OPERATOR_MODE_DEREGISTER

Operator deregistered from network

enumerator LWGSM_OPERATOR_MODE_MANUAL_AUTO

Operator manual mode first. If fails, auto mode enabled

enum lwgsm_operator_format_t

Operator data format.

Values:

enumerator LWGSM_OPERATOR_FORMAT_LONG_NAME

COPS command returned long name

enumerator LWGSM_OPERATOR_FORMAT_SHORT_NAME

COPS command returned short name

enumerator LWGSM_OPERATOR_FORMAT_NUMBER

COPS command returned number

enumerator LWGSM_OPERATOR_FORMAT_INVALID

Unknown format

Functions

lwgsmr_t lwgsm_operator_get(lwgsm_operator_curr_t *curr, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Get current operator.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [out] curr: Pointer to output variable to save info about current operator

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

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

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

lwgsmr_t lwgsm_operator_set(lwgsm_operator_mode_t mode, lwgsm_operator_format_t format, const char *name, uint32_t num, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Set current operator.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] mode: Operator mode. This parameter can be a value of lwgsm_operator_mode_t enumeration

  • [in] format: Operator data format. This parameter can be a value of lwgsm_operator_format_t enumeration

  • [in] name: Operator name. This parameter must be valid according to format parameter

  • [in] num: Operator number. This parameter must be valid according to format parameter

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

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

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

lwgsmr_t lwgsm_operator_scan(lwgsm_operator_t *ops, size_t opsl, size_t *opf, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Scan for available operators.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] ops: Pointer to array to write found operators

  • [in] opsl: Length of input array in units of elements

  • [out] opf: Pointer to ouput variable to save number of operators found

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

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

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

struct lwgsm_operator_t
#include <lwgsm_typedefs.h>

Operator details for scan.

Public Members

lwgsm_operator_status_t stat

Operator status

char long_name[20]

Operator long name

char short_name[20]

Operator short name

uint32_t num

Operator numeric value

struct lwgsm_operator_curr_t
#include <lwgsm_typedefs.h>

Current operator info.

Public Members

lwgsm_operator_mode_t mode

Operator mode

lwgsm_operator_format_t format

Data format

char long_name[20]

Long name format

char short_name[20]

Short name format

uint32_t num

Number format

union lwgsm_operator_curr_t::[anonymous] data

Operator data union

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 lwgsm_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 lwgsm_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 lwgsm_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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
lwgsm_pbuf_p a, b;

/* Create 2 pbufs of different sizes */
a = lwgsm_pbuf_new(10);
b = lwgsm_pbuf_new(20);

/* Link them together with concat operation */
/* Reference on b will stay as is, won't be increased */
lwgsm_pbuf_cat(a, b);

/*
 * Operating with b variable has from now on undefined behavior,
 * application shall stop using variable b to access pbuf.
 *
 * The best way would be to set b reference to NULL
 */
b = NULL;

/*
 * When application doesn't need pbufs anymore,
 * free a and it will also free b
 */
lwgsm_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 lwgsm_pbuf_chain(), it also has to manually free its reference using lwgsm_pbuf_free() function. Forgetting to free pbuf invokes memory leak

An example code showing proper usage of chain operation:

Packet buffer chain example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
lwgsm_pbuf_p a, b;

/* Create 2 pbufs of different sizes */
a = lwgsm_pbuf_new(10);
b = lwgsm_pbuf_new(20);

/* Chain both pbufs together */
/* This will increase reference on b as 2 variables now point to it */
lwgsm_pbuf_chain(a, b);

/*
 * When application does not need a anymore, it may free it

 * This will free only pbuf a, as pbuf b has now 2 references:
 *  - one from pbuf a
 *  - one from variable b
 */

/* If application calls this, it will free only first pbuf */
/* As there is link to b pbuf somewhere */
lwgsm_pbuf_free(a);                               

/* Reset a variable, not used anymore */
a = NULL;

/*
 * At this point, b is still valid memory block,
 * but when application doesn't need it anymore,
 * it should free it, otherwise memory leak appears
 */
lwgsm_pbuf_free(b);

/* Reset b variable */
b = 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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const void* data;
size_t pos, len;
lwgsm_pbuf_p a, b, c;

const char str_a[] = "This is one long";
const char str_a[] = "string. We want to save";
const char str_a[] = "chain of pbufs to file";

/* Create pbufs to hold these strings */
a = lwgsm_pbuf_new(strlen(str_a));
b = lwgsm_pbuf_new(strlen(str_b));
c = lwgsm_pbuf_new(strlen(str_c));

/* Write data to pbufs */
lwgsm_pbuf_take(a, str_a, strlen(str_a), 0);
lwgsm_pbuf_take(b, str_b, strlen(str_b), 0);
lwgsm_pbuf_take(c, str_c, strlen(str_c), 0);

/* Connect pbufs together */
lwgsm_pbuf_chain(a, b);
lwgsm_pbuf_chain(a, c);

/*
 * pbuf a now contains chain of b and c together
 * and at this point application wants to print (or save) data from chained pbuf
 *
 * Process pbuf by pbuf with code below
 */

/*
 * Get linear address of current pbuf at specific offset
 * Function will return pointer to memory address at specific position
 * and `len` will hold length of data block
 */
pos = 0;
while ((data = lwgsm_pbuf_get_linear_addr(a, pos, &len)) != NULL) {
    /* Custom process function... */
    /* Process data with data pointer and block length */
    process_data(data, len);
    printf("Str: %.*s", len, data);

    /* Increase offset position for next block */
    pos += len;
}

/* Call free only on a pbuf. Since it is chained, b and c will be freed too */
lwgsm_pbuf_free(a);
group LWGSM_PBUF

Packet buffer manager.

Typedefs

typedef struct lwgsm_pbuf *lwgsm_pbuf_p

Pointer to lwgsm_pbuf_t structure.

Functions

lwgsm_pbuf_p lwgsm_pbuf_new(size_t len)

Allocate packet buffer for network data of specific size.

Return

Pointer to allocated memory, NULL otherwise

Parameters
  • [in] len: Length of payload memory to allocate

size_t lwgsm_pbuf_free(lwgsm_pbuf_p pbuf)

Free previously allocated packet buffer.

Return

Number of freed pbufs from head

Parameters
  • [in] pbuf: Packet buffer to free

void *lwgsm_pbuf_data(const lwgsm_pbuf_p pbuf)

Get data pointer from packet buffer.

Return

Pointer to data buffer on success, NULL otherwise

Parameters
  • [in] pbuf: Packet buffer

size_t lwgsm_pbuf_length(const lwgsm_pbuf_p pbuf, uint8_t tot)

Get length of packet buffer.

Return

Length of data in units of bytes

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

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

lwgsmr_t lwgsm_pbuf_take(lwgsm_pbuf_p pbuf, const void *data, size_t len, size_t offset)

Copy user data to chain of pbufs.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

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

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

  • [in] len: Length of input data to copy

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

size_t lwgsm_pbuf_copy(lwgsm_pbuf_p pbuf, void *data, size_t len, size_t offset)

Copy memory from pbuf to user linear memory.

Return

Number of bytes copied

Parameters
  • [in] pbuf: Pbuf to copy from

  • [out] data: User linear memory to copy to

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

  • [in] offset: Possible start offset in pbuf

lwgsmr_t lwgsm_pbuf_cat(lwgsm_pbuf_p head, const lwgsm_pbuf_p tail)

Concatenate 2 packet buffers together to one big packet.

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 lwgsm_pbuf_free function anymore, as it might make memory undefined for head pbuf.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

See

lwgsm_pbuf_chain

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

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

lwgsmr_t lwgsm_pbuf_chain(lwgsm_pbuf_p head, lwgsm_pbuf_p tail)

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

Note

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

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

See

lwgsm_pbuf_cat

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

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

lwgsmr_t lwgsm_pbuf_ref(lwgsm_pbuf_p pbuf)

Increment reference count on pbuf.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] pbuf: pbuf to increase reference

uint8_t lwgsm_pbuf_get_at(const lwgsm_pbuf_p pbuf, size_t pos, uint8_t *el)

Get value from pbuf at specific position.

Return

1 on success, 0 otherwise

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

  • [in] pos: Position at which to get element

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

size_t lwgsm_pbuf_memcmp(const lwgsm_pbuf_p pbuf, const void *data, size_t len, size_t offset)

Compare pbuf memory with memory from data.

Note

Compare is done on entire pbuf chain

Return

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

See

lwgsm_pbuf_strcmp

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

  • [in] data: Actual data to compare with

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

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

size_t lwgsm_pbuf_strcmp(const lwgsm_pbuf_p pbuf, const char *str, size_t offset)

Compare pbuf memory with input string.

Note

Compare is done on entire pbuf chain

Return

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

See

lwgsm_pbuf_memcmp

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

  • [in] str: String to be compared with pbuf

  • [in] offset: Start memory offset in pbuf

size_t lwgsm_pbuf_memfind(const lwgsm_pbuf_p pbuf, const void *data, size_t len, size_t off)

Find desired needle in a haystack.

Return

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

See

lwgsm_pbuf_strfind

Parameters
  • [in] pbuf: Pbuf used as haystack

  • [in] needle: Data memory used as needle

  • [in] len: Length of needle memory

  • [in] off: Starting offset in pbuf memory

size_t lwgsm_pbuf_strfind(const lwgsm_pbuf_p pbuf, const char *str, size_t off)

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

Return

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

See

lwgsm_pbuf_memfind

Parameters
  • [in] pbuf: Pbuf used as haystack

  • [in] str: String to search for in pbuf

  • [in] off: Starting offset in pbuf memory

uint8_t lwgsm_pbuf_advance(lwgsm_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

Return

1 on success, 0 otherwise

Parameters
  • [in] pbuf: Pbuf to advance

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

lwgsm_pbuf_p lwgsm_pbuf_skip(lwgsm_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

Return

New pbuf on success, NULL otherwise

Parameters
  • [in] pbuf: Start of pbuf chain

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

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

void *lwgsm_pbuf_get_linear_addr(const lwgsm_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

Return

Pointer to memory on success, NULL otherwise

Parameters
  • [in] pbuf: Pbuf to get linear address

  • [in] offset: Start offset from where to start

  • [out] new_len: Length of memory returned by function

void lwgsm_pbuf_set_ip(lwgsm_pbuf_p pbuf, const lwgsm_ip_t *ip, lwgsm_port_t port)

Set IP address and port number for received data.

Parameters
  • [in] pbuf: Packet buffer

  • [in] ip: IP to assing to packet buffer

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

struct lwgsm_pbuf_t
#include <lwgsm_private.h>

Packet buffer structure.

Public Members

struct lwgsm_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

lwgsm_ip_t ip

Remote address for received IPD data

lwgsm_port_t port

Remote port for received IPD data

Phonebook
group LWGSM_PHONEBOOK

Phonebook manager.

Functions

lwgsmr_t lwgsm_pb_enable(const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Enable phonebook functionality.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

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

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

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

lwgsmr_t lwgsm_pb_disable(const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Disable phonebook functionality.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

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

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

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

lwgsmr_t lwgsm_pb_add(lwgsm_mem_t mem, const char *name, const char *num, lwgsm_number_type_t type, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Add new phonebook entry to desired memory.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] mem: Memory to use to save entry. Use LWGSM_MEM_CURRENT to use current memory

  • [in] name: Entry name

  • [in] num: Entry phone number

  • [in] type: Entry phone number type

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

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

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

lwgsmr_t lwgsm_pb_edit(lwgsm_mem_t mem, size_t pos, const char *name, const char *num, lwgsm_number_type_t type, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Edit or overwrite phonebook entry at desired memory and position.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] mem: Memory to use to save entry. Use LWGSM_MEM_CURRENT to use current memory

  • [in] pos: Entry position in memory to edit

  • [in] name: New entry name

  • [in] num: New entry phone number

  • [in] type: New entry phone number type

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

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

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

lwgsmr_t lwgsm_pb_delete(lwgsm_mem_t mem, size_t pos, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Delete phonebook entry at desired memory and position.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] mem: Memory to use to save entry. Use LWGSM_MEM_CURRENT to use current memory

  • [in] pos: Entry position in memory to delete

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

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

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

lwgsmr_t lwgsm_pb_read(lwgsm_mem_t mem, size_t pos, lwgsm_pb_entry_t *entry, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Read single phonebook entry.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] mem: Memory to use to save entry. Use LWGSM_MEM_CURRENT to use current memory

  • [in] pos: Entry position in memory to read

  • [out] entry: Pointer to entry variable to save data

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

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

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

lwgsmr_t lwgsm_pb_list(lwgsm_mem_t mem, size_t start_index, lwgsm_pb_entry_t *entries, size_t etr, size_t *er, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

List entires from specific memory.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] mem: Memory to use to save entry. Use LWGSM_MEM_CURRENT to use current memory

  • [in] start_index: Start position in memory to list

  • [out] entries: Pointer to array to save entries

  • [in] etr: Number of entries to read

  • [out] er: Pointer to output variable to save entries listed

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

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

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

lwgsmr_t lwgsm_pb_search(lwgsm_mem_t mem, const char *search, lwgsm_pb_entry_t *entries, size_t etr, size_t *er, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Search for entires with specific name from specific memory.

Note

Search works by entry name only. Phone number search is not available

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] mem: Memory to use to save entry. Use LWGSM_MEM_CURRENT to use current memory

  • [in] search: String to search for

  • [out] entries: Pointer to array to save entries

  • [in] etr: Number of entries to read

  • [out] er: Pointer to output variable to save entries found

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

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

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

Ping support
group LWGSM_PING

PING manager.

SIM card
group LWGSM_SIM

SIM card manager.

Enums

enum lwgsm_sim_state_t

SIM state.

Values:

enumerator LWGSM_SIM_STATE_NOT_INSERTED

SIM is not inserted in socket

enumerator LWGSM_SIM_STATE_READY

SIM is ready for operations

enumerator LWGSM_SIM_STATE_NOT_READY

SIM is not ready for any operation

enumerator LWGSM_SIM_STATE_PIN

SIM is waiting for SIM to be given

enumerator LWGSM_SIM_STATE_PUK

SIM is waiting for PUT to be given

enumerator LWGSM_SIM_STATE_PH_PIN
enumerator LWGSM_SIM_STATE_PH_PUK

Functions

lwgsm_sim_state_t lwgsm_sim_get_current_state(void)

Get current cached SIM state from stack.

Note

Information is always valid, starting after successful device reset using lwgsm_reset function call

Return

Member of lwgsm_sim_state_t enumeration

lwgsmr_t lwgsm_sim_pin_enter(const char *pin, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Enter pin code to unlock SIM.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] pin: Pin code in string format

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

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

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

lwgsmr_t lwgsm_sim_pin_add(const char *pin, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Add pin number to open SIM card.

Note

Use this function only if your SIM card doesn’t have PIN code. If you wish to change current pin, use lwgsm_sim_pin_change instead

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] pin: Current SIM pin code

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

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

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

lwgsmr_t lwgsm_sim_pin_remove(const char *pin, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Remove pin code from SIM.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] pin: Current pin code

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

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

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

lwgsmr_t lwgsm_sim_pin_change(const char *pin, const char *new_pin, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Change current pin code.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] pin: Current pin code

  • [in] new_pin: New pin code

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

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

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

lwgsmr_t lwgsm_sim_puk_enter(const char *puk, const char *new_pin, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Enter PUK code and new PIN to unlock SIM card.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] puk: PUK code associated with SIM card

  • [in] new_pin: New PIN code to use

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

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

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

SMS
group LWGSM_SMS

SMS manager.

Enums

enum lwgsm_sms_status_t

SMS status in current memory.

Values:

enumerator LWGSM_SMS_STATUS_ALL

Process all SMS, used for mass delete or SMS list

enumerator LWGSM_SMS_STATUS_READ

SMS status is read

enumerator LWGSM_SMS_STATUS_UNREAD

SMS status is unread

enumerator LWGSM_SMS_STATUS_SENT

SMS status is sent

enumerator LWGSM_SMS_STATUS_UNSENT

SMS status is unsent

enumerator LWGSM_SMS_STATUS_INBOX

SMS status, used only for mass delete operation

Functions

lwgsmr_t lwgsm_sms_enable(const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Enable SMS functionality.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

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

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

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

lwgsmr_t lwgsm_sms_disable(const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Disable SMS functionality.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

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

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

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

lwgsmr_t lwgsm_sms_send(const char *num, const char *text, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Send SMS text to phone number.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] num: String number

  • [in] text: Text to send. Maximal 160 characters

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

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

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

lwgsmr_t lwgsm_sms_read(lwgsm_mem_t mem, size_t pos, lwgsm_sms_entry_t *entry, uint8_t update, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Read SMS entry at specific memory and position.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] mem: Memory used to read message from

  • [in] pos: Position number in memory to read

  • [out] entry: Pointer to SMS entry structure to fill data to

  • [in] update: Flag indicates update. Set to 1 to change UNREAD messages to READ or 0 to leave as is

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

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

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

lwgsmr_t lwgsm_sms_delete(lwgsm_mem_t mem, size_t pos, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Delete SMS entry at specific memory and position.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] mem: Memory used to read message from

  • [in] pos: Position number in memory to read

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

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

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

lwgsmr_t lwgsm_sms_delete_all(lwgsm_sms_status_t status, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Delete all SMS entries with specific status.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] status: SMS status. This parameter can be one of all possible types in lwgsm_sms_status_t enumeration

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

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

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

lwgsmr_t lwgsm_sms_list(lwgsm_mem_t mem, lwgsm_sms_status_t stat, lwgsm_sms_entry_t *entries, size_t etr, size_t *er, uint8_t update, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

List SMS from SMS memory.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] mem: Memory to read entries from. Use LWGSM_MEM_CURRENT to read from current memory

  • [in] stat: SMS status to read, either read, unread, sent, unsent or all

  • [out] entries: Pointer to array to save SMS entries

  • [in] etr: Number of entries to read

  • [out] er: Pointer to output variable to save number of entries in array

  • [in] update: Flag indicates update. Set to 1 to change UNREAD messages to READ or 0 to leave as is

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

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

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

lwgsmr_t lwgsm_sms_set_preferred_storage(lwgsm_mem_t mem1, lwgsm_mem_t mem2, lwgsm_mem_t mem3, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Set preferred storage for SMS.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] mem1: Preferred memory for read/delete SMS operations. Use LWGSM_MEM_CURRENT to keep it as is

  • [in] mem2: Preferred memory for sent/write SMS operations. Use LWGSM_MEM_CURRENT to keep it as is

  • [in] mem3: Preferred memory for received SMS entries. Use LWGSM_MEM_CURRENT to keep it as is

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

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

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

struct lwgsm_sms_mem_t
#include <lwgsm_private.h>

SMS memory information.

Public Members

uint32_t mem_available

Bit field of available memories

lwgsm_mem_t current

Current memory choice

size_t total

Size of memory in units of entries

size_t used

Number of used entries

struct lwgsm_sms_t
#include <lwgsm_private.h>

SMS structure.

Public Members

uint8_t ready

Flag indicating feature ready by device

uint8_t enabled

Flag indicating feature enabled

lwgsm_sms_mem_t mem[3]

3 memory info for operation,receive,sent storage

struct lwgsm_pb_mem_t
#include <lwgsm_private.h>

SMS memory information.

Public Members

uint32_t mem_available

Bit field of available memories

lwgsm_mem_t current

Current memory choice

size_t total

Size of memory in units of entries

size_t used

Number of used entries

struct lwgsm_sms_entry_t
#include <lwgsm_typedefs.h>

SMS entry structure.

Public Members

lwgsm_mem_t mem

Memory storage

size_t pos

Memory position

lwgsm_datetime_t datetime

Date and time

lwgsm_sms_status_t status

Message status

char number[26]

Phone number

char name[20]

Name in phonebook if exists

char data[161]

Data memory

size_t length

Length of SMS data

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, GSM middleware will call timeout callback.

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

group LWGSM_TIMEOUT

Timeout manager.

Typedefs

typedef void (*lwgsm_timeout_fn)(void *arg)

Timeout callback function prototype.

Parameters
  • [in] arg: Custom user argument

Functions

lwgsmr_t lwgsm_timeout_add(uint32_t time, lwgsm_timeout_fn fn, void *arg)

Add new timeout to processing list.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

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

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

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

lwgsmr_t lwgsm_timeout_remove(lwgsm_timeout_fn fn)

Remove callback from timeout list.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] fn: Callback function to identify timeout to remove

struct lwgsm_timeout_t
#include <lwgsm_typedefs.h>

Timeout structure.

Public Members

struct lwgsm_timeout *next

Pointer to next timeout entry

uint32_t time

Time difference from previous entry

void *arg

Argument to pass to callback function

lwgsm_timeout_fn fn

Callback function for timeout

Structures and enumerations
group LWGSM_TYPEDEFS

List of core structures and enumerations.

Typedefs

typedef uint16_t lwgsm_port_t

Port variable.

typedef void (*lwgsm_api_cmd_evt_fn)(lwgsmr_t res, void *arg)

Function declaration for API function command event callback function.

Parameters
  • [in] res: Operation result, member of lwgsmr_t enumeration

  • [in] arg: Custom user argument

Enums

enum lwgsm_cmd_t

List of possible messages.

Values:

enumerator LWGSM_CMD_IDLE

IDLE mode

enumerator LWGSM_CMD_RESET

Reset device

enumerator LWGSM_CMD_RESET_DEVICE_FIRST_CMD

Reset device first driver specific command

enumerator LWGSM_CMD_ATE0

Disable ECHO mode on AT commands

enumerator LWGSM_CMD_ATE1

Enable ECHO mode on AT commands

enumerator LWGSM_CMD_GSLP

Set GSM to sleep mode

enumerator LWGSM_CMD_RESTORE

Restore GSM internal settings to default values

enumerator LWGSM_CMD_UART
enumerator LWGSM_CMD_CGACT_SET_0
enumerator LWGSM_CMD_CGACT_SET_1
enumerator LWGSM_CMD_CGATT_SET_0
enumerator LWGSM_CMD_CGATT_SET_1
enumerator LWGSM_CMD_NETWORK_ATTACH

Attach to a network

enumerator LWGSM_CMD_NETWORK_DETACH

Detach from network

enumerator LWGSM_CMD_CIPMUX_SET
enumerator LWGSM_CMD_CIPRXGET_SET
enumerator LWGSM_CMD_CSTT_SET
enumerator LWGSM_CMD_CALL_ENABLE
enumerator LWGSM_CMD_A

Re-issues the Last Command Given

enumerator LWGSM_CMD_ATA

Answer an Incoming Call

enumerator LWGSM_CMD_ATD

Mobile Originated Call to Dial A Number

enumerator LWGSM_CMD_ATD_N

Originate Call to Phone Number in Current Memory: ATD<n>

enumerator LWGSM_CMD_ATD_STR

Originate Call to Phone Number in Memory Which Corresponds to Field “str”: ATD>str

enumerator LWGSM_CMD_ATDL

Redial Last Telephone Number Used

enumerator LWGSM_CMD_ATE

Set Command Echo Mode

enumerator LWGSM_CMD_ATH

Disconnect Existing

enumerator LWGSM_CMD_ATI

Display Product Identification Information

enumerator LWGSM_CMD_ATL

Set Monitor speaker

enumerator LWGSM_CMD_ATM

Set Monitor Speaker Mode

enumerator LWGSM_CMD_PPP

Switch from Data Mode or PPP Online Mode to Command Mode, “+++” originally

enumerator LWGSM_CMD_ATO

Switch from Command Mode to Data Mode

enumerator LWGSM_CMD_ATP

Select Pulse Dialing

enumerator LWGSM_CMD_ATQ

Set Result Code Presentation Mode

enumerator LWGSM_CMD_ATS0

Set Number of Rings before Automatically Answering the Call

enumerator LWGSM_CMD_ATS3

Set Command Line Termination Character

enumerator LWGSM_CMD_ATS4

Set Response Formatting Character

enumerator LWGSM_CMD_ATS5

Set Command Line Editing Character

enumerator LWGSM_CMD_ATS6

Pause Before Blind

enumerator LWGSM_CMD_ATS7

Set Number of Seconds to Wait for Connection Completion

enumerator LWGSM_CMD_ATS8

Set Number of Seconds to Wait for Comma Dial Modifier Encountered in Dial String of D Command

enumerator LWGSM_CMD_ATS10

Set Disconnect Delay after Indicating the Absence of Data Carrier

enumerator LWGSM_CMD_ATT

Select Tone Dialing

enumerator LWGSM_CMD_ATV

TA Response Format

enumerator LWGSM_CMD_ATX

Set CONNECT Result Code Format and Monitor Call Progress

enumerator LWGSM_CMD_ATZ

Reset Default Configuration

enumerator LWGSM_CMD_AT_C

Set DCD Function Mode, AT&C

enumerator LWGSM_CMD_AT_D

Set DTR Function, AT&D

enumerator LWGSM_CMD_AT_F

Factory Defined Configuration, AT&F

enumerator LWGSM_CMD_AT_V

Display Current Configuration, AT&V

enumerator LWGSM_CMD_AT_W

Store Active Profile, AT&W

enumerator LWGSM_CMD_GCAP

Request Complete TA Capabilities List

enumerator LWGSM_CMD_GMI

Request Manufacturer Identification

enumerator LWGSM_CMD_GMM

Request TA Model Identification

enumerator LWGSM_CMD_GMR

Request TA Revision Identification of Software Release

enumerator LWGSM_CMD_GOI

Request Global Object Identification

enumerator LWGSM_CMD_GSN

Request TA Serial Number Identification (IMEI)

enumerator LWGSM_CMD_ICF

Set TE-TA Control Character Framing

enumerator LWGSM_CMD_IFC

Set TE-TA Local Data Flow Control

enumerator LWGSM_CMD_IPR

Set TE-TA Fixed Local Rate

enumerator LWGSM_CMD_HVOIC

Disconnect Voice Call Only

enumerator LWGSM_CMD_COPS_SET

Set operator

enumerator LWGSM_CMD_COPS_GET

Get current operator

enumerator LWGSM_CMD_COPS_GET_OPT

Get a list of available operators

enumerator LWGSM_CMD_CPAS

Phone Activity Status

enumerator LWGSM_CMD_CGMI_GET

Request Manufacturer Identification

enumerator LWGSM_CMD_CGMM_GET

Request Model Identification

enumerator LWGSM_CMD_CGMR_GET

Request TA Revision Identification of Software Release

enumerator LWGSM_CMD_CGSN_GET

Request Product Serial Number Identification (Identical with +GSN)

enumerator LWGSM_CMD_CLCC_SET

List Current Calls of ME

enumerator LWGSM_CMD_CLCK

Facility Lock

enumerator LWGSM_CMD_CACM

Accumulated Call Meter (ACM) Reset or Query

enumerator LWGSM_CMD_CAMM

Accumulated Call Meter Maximum (ACM max) Set or Query

enumerator LWGSM_CMD_CAOC

Advice of Charge

enumerator LWGSM_CMD_CBST

Select Bearer Service Type

enumerator LWGSM_CMD_CCFC

Call Forwarding Number and Conditions Control

enumerator LWGSM_CMD_CCWA

Call Waiting Control

enumerator LWGSM_CMD_CEER

Extended Error Report

enumerator LWGSM_CMD_CSCS

Select TE Character Set

enumerator LWGSM_CMD_CSTA

Select Type of Address

enumerator LWGSM_CMD_CHLD

Call Hold and Multiparty

enumerator LWGSM_CMD_CIMI

Request International Mobile Subscriber Identity

enumerator LWGSM_CMD_CLIP

Calling Line Identification Presentation

enumerator LWGSM_CMD_CLIR

Calling Line Identification Restriction

enumerator LWGSM_CMD_CMEE_SET

Report Mobile Equipment Error

enumerator LWGSM_CMD_COLP

Connected Line Identification Presentation

enumerator LWGSM_CMD_PHONEBOOK_ENABLE
enumerator LWGSM_CMD_CPBF

Find Phonebook Entries

enumerator LWGSM_CMD_CPBR

Read Current Phonebook Entries

enumerator LWGSM_CMD_CPBS_SET

Select Phonebook Memory Storage

enumerator LWGSM_CMD_CPBS_GET

Get current Phonebook Memory Storage

enumerator LWGSM_CMD_CPBS_GET_OPT

Get available Phonebook Memory Storages

enumerator LWGSM_CMD_CPBW_SET

Write Phonebook Entry

enumerator LWGSM_CMD_CPBW_GET_OPT

Get options for write Phonebook Entry

enumerator LWGSM_CMD_SIM_PROCESS_BASIC_CMDS

Command setup, executed when SIM is in READY state

enumerator LWGSM_CMD_CPIN_SET

Enter PIN

enumerator LWGSM_CMD_CPIN_GET

Read current SIM status

enumerator LWGSM_CMD_CPIN_ADD

Add new PIN to SIM if pin is not set

enumerator LWGSM_CMD_CPIN_CHANGE

Change already active SIM

enumerator LWGSM_CMD_CPIN_REMOVE

Remove current PIN

enumerator LWGSM_CMD_CPUK_SET

Enter PUK and set new PIN

enumerator LWGSM_CMD_CSQ_GET

Signal Quality Report

enumerator LWGSM_CMD_CFUN_SET

Set Phone Functionality

enumerator LWGSM_CMD_CFUN_GET

Get Phone Functionality

enumerator LWGSM_CMD_CREG_SET

Network Registration set output

enumerator LWGSM_CMD_CREG_GET

Get current network registration status

enumerator LWGSM_CMD_CBC

Battery Charge

enumerator LWGSM_CMD_CNUM

Subscriber Number

enumerator LWGSM_CMD_CPWD

Change Password

enumerator LWGSM_CMD_CR

Service Reporting Control

enumerator LWGSM_CMD_CRC

Set Cellular Result Codes for Incoming Call Indication

enumerator LWGSM_CMD_CRLP

Select Radio Link Protocol Parameters

enumerator LWGSM_CMD_CRSM

Restricted SIM Access

enumerator LWGSM_CMD_VTD

Tone Duration

enumerator LWGSM_CMD_VTS

DTMF and Tone Generation

enumerator LWGSM_CMD_CMUX

Multiplexer Control

enumerator LWGSM_CMD_CPOL

Preferred Operator List

enumerator LWGSM_CMD_COPN

Read Operator Names

enumerator LWGSM_CMD_CCLK

Clock

enumerator LWGSM_CMD_CSIM

Generic SIM Access

enumerator LWGSM_CMD_CALM

Alert Sound Mode

enumerator LWGSM_CMD_CALS

Alert Sound Select

enumerator LWGSM_CMD_CRSL

Ringer Sound Level

enumerator LWGSM_CMD_CLVL

Loud Speaker Volume Level

enumerator LWGSM_CMD_CMUT

Mute Control

enumerator LWGSM_CMD_CPUC

Price Per Unit and Currency Table

enumerator LWGSM_CMD_CCWE

Call Meter Maximum Event

enumerator LWGSM_CMD_CUSD_SET

Unstructured Supplementary Service Data, Set command

enumerator LWGSM_CMD_CUSD_GET

Unstructured Supplementary Service Data, Get command

enumerator LWGSM_CMD_CUSD

Unstructured Supplementary Service Data, Execute command

enumerator LWGSM_CMD_CSSN

Supplementary Services Notification

enumerator LWGSM_CMD_CIPMUX

Start Up Multi-IP Connection

enumerator LWGSM_CMD_CIPSTART

Start Up TCP or UDP Connection

enumerator LWGSM_CMD_CIPSEND

Send Data Through TCP or UDP Connection

enumerator LWGSM_CMD_CIPQSEND

Select Data Transmitting Mode

enumerator LWGSM_CMD_CIPACK

Query Previous Connection Data Transmitting State

enumerator LWGSM_CMD_CIPCLOSE

Close TCP or UDP Connection

enumerator LWGSM_CMD_CIPSHUT

Deactivate GPRS PDP Context

enumerator LWGSM_CMD_CLPORT

Set Local Port

enumerator LWGSM_CMD_CSTT

Start Task and Set APN, username, password

enumerator LWGSM_CMD_CIICR

Bring Up Wireless Connection with GPRS or CSD

enumerator LWGSM_CMD_CIFSR

Get Local IP Address

enumerator LWGSM_CMD_CIPSTATUS

Query Current Connection Status

enumerator LWGSM_CMD_CDNSCFG

Configure Domain Name Server

enumerator LWGSM_CMD_CDNSGIP

Query the IP Address of Given Domain Name

enumerator LWGSM_CMD_CIPHEAD

Add an IP Head at the Beginning of a Package Received

enumerator LWGSM_CMD_CIPATS

Set Auto Sending Timer

enumerator LWGSM_CMD_CIPSPRT

Set Prompt of greater than sign When Module Sends Data

enumerator LWGSM_CMD_CIPSERVER

Configure Module as Server

enumerator LWGSM_CMD_CIPCSGP

Set CSD or GPRS for Connection Mode

enumerator LWGSM_CMD_CIPSRIP

Show Remote IP Address and Port When Received Data

enumerator LWGSM_CMD_CIPDPDP

Set Whether to Check State of GPRS Network Timing

enumerator LWGSM_CMD_CIPMODE

Select TCPIP Application Mode

enumerator LWGSM_CMD_CIPCCFG

Configure Transparent Transfer Mode

enumerator LWGSM_CMD_CIPSHOWTP

Display Transfer Protocol in IP Head When Received Data

enumerator LWGSM_CMD_CIPUDPMODE

UDP Extended Mode

enumerator LWGSM_CMD_CIPRXGET

Get Data from Network Manually

enumerator LWGSM_CMD_CIPSCONT

Save TCPIP Application Context

enumerator LWGSM_CMD_CIPRDTIMER

Set Remote Delay Timer

enumerator LWGSM_CMD_CIPSGTXT

Select GPRS PDP context

enumerator LWGSM_CMD_CIPTKA

Set TCP Keepalive Parameters

enumerator LWGSM_CMD_CIPSSL

Connection SSL function

enumerator LWGSM_CMD_SMS_ENABLE
enumerator LWGSM_CMD_CMGD

Delete SMS Message

enumerator LWGSM_CMD_CMGF

Select SMS Message Format

enumerator LWGSM_CMD_CMGL

List SMS Messages from Preferred Store

enumerator LWGSM_CMD_CMGR

Read SMS Message

enumerator LWGSM_CMD_CMGS

Send SMS Message

enumerator LWGSM_CMD_CMGW

Write SMS Message to Memory

enumerator LWGSM_CMD_CMSS

Send SMS Message from Storage

enumerator LWGSM_CMD_CMGDA

MASS SMS delete

enumerator LWGSM_CMD_CNMI

New SMS Message Indications

enumerator LWGSM_CMD_CPMS_SET

Set preferred SMS Message Storage

enumerator LWGSM_CMD_CPMS_GET

Get preferred SMS Message Storage

enumerator LWGSM_CMD_CPMS_GET_OPT

Get optional SMS message storages

enumerator LWGSM_CMD_CRES

Restore SMS Settings

enumerator LWGSM_CMD_CSAS

Save SMS Settings

enumerator LWGSM_CMD_CSCA

SMS Service Center Address

enumerator LWGSM_CMD_CSCB

Select Cell Broadcast SMS Messages

enumerator LWGSM_CMD_CSDH

Show SMS Text Mode Parameters

enumerator LWGSM_CMD_CSMP

Set SMS Text Mode Parameters

enumerator LWGSM_CMD_CSMS

Select Message Service

enumerator LWGSM_CMD_END

Last CMD entry

enum lwgsm_conn_connect_res_t

Connection result on connect command.

Values:

enumerator LWGSM_CONN_CONNECT_UNKNOWN

No valid result

enumerator LWGSM_CONN_CONNECT_OK

Connected OK

enumerator LWGSM_CONN_CONNECT_ERROR

Error on connection

enumerator LWGSM_CONN_CONNECT_ALREADY

Already connected

enum lwgsmr_t

Result enumeration used across application functions.

Values:

enumerator lwgsmOK

Function returned OK

enumerator lwgsmOKIGNOREMORE

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

enumerator lwgsmERR

Generic error

enumerator lwgsmPARERR

Wrong parameters on function call

enumerator lwgsmERRMEM

Memory error occurred

enumerator lwgsmTIMEOUT

Timeout occurred on command

enumerator lwgsmCONT

There is still some command to be processed in current command

enumerator lwgsmCLOSED

Connection just closed

enumerator lwgsmINPROG

Operation is in progress

enumerator lwgsmERRNOTENABLED

Feature not enabled error

enumerator lwgsmERRNOIP

Station does not have IP address

enumerator lwgsmERRNOFREECONN

There is no free connection available to start

enumerator lwgsmERRCONNTIMEOUT

Timeout received when connection to access point

enumerator lwgsmERRPASS

Invalid password for access point

enumerator lwgsmERRNOAP

No access point found with specific SSID and MAC address

enumerator lwgsmERRCONNFAIL

Connection failed to access point

enumerator lwgsmERRWIFINOTCONNECTED

Wifi not connected to access point

enumerator lwgsmERRNODEVICE

Device is not present

enumerator lwgsmERRBLOCKING

Blocking mode command is not allowed

enum lwgsm_device_model_t

GSM device model type.

Values:

enumerator LWGSM_DEVICE_MODEL_END

End of device model

enumerator LWGSM_DEVICE_MODEL_UNKNOWN

Unknown device model

enum lwgsm_mem_t

Available device memories.

Values:

enumerator LWGSM_MEM_END

End of memory list

enumerator LWGSM_MEM_CURRENT

Use current memory for read/delete operation

enumerator LWGSM_MEM_UNKNOWN

Unknown memory

enum lwgsm_number_type_t

GSM number type.

Values:

enumerator LWGSM_NUMBER_TYPE_NATIONAL

Number is national

enumerator LWGSM_NUMBER_TYPE_INTERNATIONAL

Number is international

struct lwgsm_conn_t
#include <lwgsm_private.h>

Connection structure.

Public Members

lwgsm_conn_type_t type

Connection type

uint8_t num

Connection number

lwgsm_ip_t remote_ip

Remote IP address

lwgsm_port_t remote_port

Remote port number

lwgsm_port_t local_port

Local IP address

lwgsm_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.

lwgsm_linbuff_t buff

Linear buffer structure

size_t total_recved

Total number of bytes received

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 bearer

Bearer used. Can be 1 or 0

struct lwgsm_conn_t::[anonymous]::[anonymous] f

Connection flags

union lwgsm_conn_t::[anonymous] status

Connection status union with flag bits

struct lwgsm_pbuf_t
#include <lwgsm_private.h>

Packet buffer structure.

Public Members

struct lwgsm_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

lwgsm_ip_t ip

Remote address for received IPD data

lwgsm_port_t port

Remote port for received IPD data

struct lwgsm_ipd_t
#include <lwgsm_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

lwgsm_conn_p conn

Pointer to connection for network data

size_t buff_ptr

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

lwgsm_pbuf_p buff

Pointer to data buffer used for receiving data

struct lwgsm_msg_t
#include <lwgsm_private.h>

Message queue structure to share between threads.

Public Members

lwgsm_cmd_t cmd_def

Default message type received from queue

lwgsm_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

lwgsm_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

lwgsmr_t res

Result of message operation

lwgsmr_t (*fn)(struct lwgsm_msg*)

Processing callback function to process packet

uint32_t delay

Delay to use before sending first reset AT command

struct lwgsm_msg_t::[anonymous]::[anonymous] reset

Reset device

uint32_t baudrate

Baudrate for AT port

struct lwgsm_msg_t::[anonymous]::[anonymous] uart

UART configuration

uint8_t mode

Functionality mode

struct lwgsm_msg_t::[anonymous]::[anonymous] cfun

Set phone functionality

const char *pin

Pin code to write

New pin code

Current pin code

New PIN code

struct lwgsm_msg_t::[anonymous]::[anonymous] cpin_enter

Enter pin code

struct lwgsm_msg_t::[anonymous]::[anonymous] cpin_add

Add pin code if previously wasn’t set

const char *current_pin

Current pin code

const char *new_pin

New pin code

struct lwgsm_msg_t::[anonymous]::[anonymous] cpin_change

Change current pin code

struct lwgsm_msg_t::[anonymous]::[anonymous] cpin_remove

Remove PIN code

const char *puk

PUK code

struct lwgsm_msg_t::[anonymous]::[anonymous] cpuk_enter

Enter PUK and new PIN

size_t cnum_tries

Number of tries

struct lwgsm_msg_t::[anonymous]::[anonymous] sim_info

Get information for SIM card

char *str

Pointer to output string array

size_t len

Length of output string array including trailing zero memory

struct lwgsm_msg_t::[anonymous]::[anonymous] device_info

All kind of device info, serial number, model, manufacturer, revision

int16_t *rssi

Pointer to RSSI variable

struct lwgsm_msg_t::[anonymous]::[anonymous] csq

Signal strength

uint8_t read

Flag indicating we can read the COPS actual data

Read the data flag

lwgsm_operator_t *ops

Pointer to operators array

size_t opsl

Length of operators array

size_t opsi

Current operator index array

size_t *opf

Pointer to number of operators found

struct lwgsm_msg_t::[anonymous]::[anonymous] cops_scan

Scan operators

lwgsm_operator_curr_t *curr

Pointer to output current operator

struct lwgsm_msg_t::[anonymous]::[anonymous] cops_get

Get current operator info

lwgsm_operator_mode_t mode

COPS mode

lwgsm_operator_format_t format

Operator format to print

const char *name

Short or long name, according to format

Entry name

uint32_t num

Number in case format is number

struct lwgsm_msg_t::[anonymous]::[anonymous] cops_set

Set operator settings

lwgsm_conn_t **conn

Pointer to pointer to save connection used

const char *host

Host to use for connection

lwgsm_port_t port

Remote port used for connection

lwgsm_conn_type_t type

Connection type

void *arg

Connection custom argument

lwgsm_evt_fn evt_func

Callback function to use on connection

uint8_t num

Connection number used for start

lwgsm_conn_connect_res_t conn_res

Connection result status

struct lwgsm_msg_t::[anonymous]::[anonymous] conn_start

Structure for starting new connection

lwgsm_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 lwgsm_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 lwgsm_ip_t *remote_ip

Remote IP address for UDP connection

lwgsm_port_t remote_port

Remote port 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 lwgsm_msg_t::[anonymous]::[anonymous] conn_send

Structure to send data on connection

const char *num

Phone number

Entry number

const char *text

SMS content to send

uint8_t format

SMS format, 0 = PDU, 1 = text

size_t pos

Set on +CMGS response if command is OK

SMS position in memory

Memory position. Set to 0 to use new one or SIZE_T MAX to delete entry

struct lwgsm_msg_t::[anonymous]::[anonymous] sms_send

Send SMS

lwgsm_mem_t mem

Memory to read from

Memory to delete from

Memory to use for read

Array of memories

Memory to use

lwgsm_sms_entry_t *entry

Pointer to entry to write info

uint8_t update

Update SMS status after read operation

struct lwgsm_msg_t::[anonymous]::[anonymous] sms_read

Read single SMS

struct lwgsm_msg_t::[anonymous]::[anonymous] sms_delete

Delete SMS message

lwgsm_sms_status_t status

SMS status to delete

SMS entries status

struct lwgsm_msg_t::[anonymous]::[anonymous] sms_delete_all

Mass delete SMS messages

lwgsm_sms_entry_t *entries

Pointer to entries

size_t etr

Entries to read (array length)

NUmber of entries to read

size_t ei

Current entry index in array

Current entry index

size_t *er

Final entries read pointer for user

struct lwgsm_msg_t::[anonymous]::[anonymous] sms_list

List SMS messages

struct lwgsm_msg_t::[anonymous]::[anonymous] sms_memory

Set preferred memories

const char *number

Phone number to dial

struct lwgsm_msg_t::[anonymous]::[anonymous] call_start

Start a new call

lwgsm_number_type_t type

Entry phone number type

uint8_t del

Flag indicates delete

struct lwgsm_msg_t::[anonymous]::[anonymous] pb_write

Write/Edit/Delete entry

size_t start_index

Start index in phonebook to read

lwgsm_pb_entry_t *entries

Pointer to entries array

struct lwgsm_msg_t::[anonymous]::[anonymous] pb_list

List phonebook entries

const char *search

Search string

struct lwgsm_msg_t::[anonymous]::[anonymous] pb_search

Search phonebook entries

const char *code

Code to send

char *resp

Response array

size_t resp_len

Length of response array

size_t resp_write_ptr

Write pointer for response

uint8_t quote_det

Information if quote has been detected

struct lwgsm_msg_t::[anonymous]::[anonymous] ussd

Execute USSD command

const char *apn

APN address

const char *user

APN username

const char *pass

APN password

struct lwgsm_msg_t::[anonymous]::[anonymous] network_attach

Settings for network attach

union lwgsm_msg_t::[anonymous] msg

Group of different possible message contents

struct lwgsm_ip_mac_t
#include <lwgsm_private.h>

IP and MAC structure with netmask and gateway addresses.

Public Members

lwgsm_ip_t ip

IP address

lwgsm_ip_t gw

Gateway address

lwgsm_ip_t nm

Netmask address

lwgsm_mac_t mac

MAC address

#include <lwgsm_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 lwgsm_evt_func_t
#include <lwgsm_private.h>

Callback function linked list prototype.

Public Members

struct lwgsm_evt_func *next

Next function in the list

lwgsm_evt_fn fn

Function pointer itself

struct lwgsm_sms_mem_t
#include <lwgsm_private.h>

SMS memory information.

Public Members

uint32_t mem_available

Bit field of available memories

lwgsm_mem_t current

Current memory choice

size_t total

Size of memory in units of entries

size_t used

Number of used entries

struct lwgsm_sms_t
#include <lwgsm_private.h>

SMS structure.

Public Members

uint8_t ready

Flag indicating feature ready by device

uint8_t enabled

Flag indicating feature enabled

lwgsm_sms_mem_t mem[3]

3 memory info for operation,receive,sent storage

struct lwgsm_pb_mem_t
#include <lwgsm_private.h>

SMS memory information.

Public Members

uint32_t mem_available

Bit field of available memories

lwgsm_mem_t current

Current memory choice

size_t total

Size of memory in units of entries

size_t used

Number of used entries

struct lwgsm_pb_t
#include <lwgsm_private.h>

Phonebook structure.

Public Members

uint8_t ready

Flag indicating feature ready by device

uint8_t enabled

Flag indicating feature enabled

lwgsm_pb_mem_t mem

Memory information

struct lwgsm_sim_t
#include <lwgsm_private.h>

SIM structure.

Public Members

lwgsm_sim_state_t state

Current SIM status

struct lwgsm_network_t
#include <lwgsm_private.h>

Network info.

Public Members

lwgsm_network_reg_status_t status

Network registration status

lwgsm_operator_curr_t curr_operator

Current operator information

uint8_t is_attached

Flag indicating device is attached and PDP context is active

lwgsm_ip_t ip_addr

Device IP address when network PDP context is enabled

struct lwgsm_modules_t
#include <lwgsm_private.h>

GSM modules structure.

Public Members

char model_manufacturer[20]

Device manufacturer

char model_number[20]

Device model number

char model_serial_number[20]

Device serial number

char model_revision[20]

Device revision

lwgsm_device_model_t model

Device model

lwgsm_sim_t sim

SIM data

lwgsm_network_t network

Network status

int16_t rssi

RSSI signal strength. 0 = invalid, -53 % -113 = valid

uint8_t active_conns_cur_parse_num

Current connection number used for parsing

lwgsm_conn_t conns[LWGSM_CFG_MAX_CONNS]

Array of all connection structures

lwgsm_ipd_t ipd

Connection incoming data structure

uint8_t conn_val_id

Validation ID increased each time device connects to network

lwgsm_sms_t sms

SMS information

lwgsm_pb_t pb

Phonebook information

lwgsm_call_t call

Call information

struct lwgsm_t
#include <lwgsm_private.h>

GSM global structure.

Public Members

size_t locked_cnt

Counter how many times (recursive) stack is currently locked

lwgsm_sys_sem_t sem_sync

Synchronization semaphore between threads

lwgsm_sys_mbox_t mbox_producer

Producer message queue handle

lwgsm_sys_mbox_t mbox_process

Consumer message queue handle

lwgsm_sys_thread_t thread_produce

Producer thread handle

lwgsm_sys_thread_t thread_process

Processing thread handle

lwgsm_buff_t buff

Input processing buffer

lwgsm_ll_t ll

Low level functions

lwgsm_msg_t *msg

Pointer to current user message being executed

lwgsm_evt_t evt

Callback processing structure

lwgsm_evt_func_t *evt_func

Callback function linked list

lwgsm_modules_t m

All modules. When resetting, reset structure

uint8_t initialized

Flag indicating GSM library is initialized

uint8_t dev_present

Flag indicating GSM device is present

struct lwgsm_t::[anonymous]::[anonymous] f

Flags structure

union lwgsm_t::[anonymous] status

Status structure

struct lwgsm_dev_mem_map_t
#include <lwgsm_private.h>

Memory mapping structure between string and value in app.

Public Members

lwgsm_mem_t mem

Mem indication

const char *mem_str

Memory string

struct lwgsm_dev_model_map_t
#include <lwgsm_private.h>

Device models map between model and other information.

Public Members

lwgsm_device_model_t model

Device model

const char *id_str

Model string identification

uint8_t is_2g

Status if modem is 2G

uint8_t is_lte

Status if modem is LTE

struct lwgsm_unicode_t
#include <lwgsm_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

lwgsmr_t res

Current result of processing

struct lwgsm_ip_t
#include <lwgsm_typedefs.h>

IP structure.

Public Members

uint8_t ip[4]

IPv4 address

struct lwgsm_mac_t
#include <lwgsm_typedefs.h>

MAC address.

Public Members

uint8_t mac[6]

MAC address

struct lwgsm_datetime_t
#include <lwgsm_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, 0 = invalid

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 lwgsm_linbuff_t
#include <lwgsm_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 LWGSM_UNICODE

Unicode support manager.

Functions

lwgsmr_t lwgsmi_unicode_decode(lwgsm_unicode_t *uni, uint8_t ch)

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

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

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

Return Value
  • lwgsmOK: Function succedded, there is a valid UTF-8 sequence

  • lwgsmINPROG: Function continues well but expects some more data to finish sequence

  • lwgsmERR: Error in UTF-8 sequence

struct lwgsm_unicode_t
#include <lwgsm_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

lwgsmr_t res

Current result of processing

Unstructured Supplementary Service Data
group LWGSM_USSD

Unstructured Supplementary Service Data.

Functions

lwgsmr_t lwgsm_ussd_run(const char *code, char *resp, size_t resp_len, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Run USSD command, such as *123# to get balance on SIM card.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] code: Code to run, such as *123#

  • [out] resp: Pointer to array to save response

  • [in] resp_len: Length of array, including string NULL termination

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

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

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

Utilities

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

group LWGSM_UTILS

Utilities.

Defines

LWGSM_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 lwgsmr_t enumeration

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

  • [in] c: Condition to test

LWGSM_MEM_ALIGN(x)

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

Return

Input value aligned to specific number of bytes

Parameters
  • [in] x: Input value to align

LWGSM_MIN(x, y)

Get minimal value between x and y inputs.

Return

Minimal value between x and y parameters

Parameters
  • [in] x: First input to test

  • [in] y: Second input to test

LWGSM_MAX(x, y)

Get maximal value between x and y inputs.

Return

Maximal value between x and y parameters

Parameters
  • [in] x: First input to test

  • [in] y: Second input to test

LWGSM_ARRAYSIZE(x)

Get size of statically declared array.

Return

Number of array elements

Parameters
  • [in] x: Input array

LWGSM_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
  • [in] x: Variable which is not used

LWGSM_U32(x)

Get input value casted to unsigned 32-bit value.

Parameters
  • [in] x: Input value

LWGSM_U16(x)

Get input value casted to unsigned 16-bit value.

Parameters
  • [in] x: Input value

LWGSM_U8(x)

Get input value casted to unsigned 8-bit value.

Parameters
  • [in] x: Input value

LWGSM_I32(x)

Get input value casted to signed 32-bit value.

Parameters
  • [in] x: Input value

LWGSM_I16(x)

Get input value casted to signed 16-bit value.

Parameters
  • [in] x: Input value

LWGSM_I8(x)

Get input value casted to signed 8-bit value.

Parameters
  • [in] x: Input value

LWGSM_SZ(x)

Get input value casted to size_t value.

Parameters
  • [in] x: Input value

lwgsm_u32_to_str(num, out)

Convert unsigned 32-bit number to string.

Return

Pointer to output variable

Parameters
  • [in] num: Number to convert

  • [out] out: Output variable to save string

lwgsm_u32_to_hex_str(num, out, w)

Convert unsigned 32-bit number to HEX string.

Return

Pointer to output variable

Parameters
  • [in] num: Number to convert

  • [out] out: Output variable to save string

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

lwgsm_i32_to_str(num, out)

Convert signed 32-bit number to string.

Return

Pointer to output variable

Parameters
  • [in] num: Number to convert

  • [out] out: Output variable to save string

lwgsm_u16_to_str(num, out)

Convert unsigned 16-bit number to string.

Return

Pointer to output variable

Parameters
  • [in] num: Number to convert

  • [out] out: Output variable to save string

lwgsm_u16_to_hex_str(num, out, w)

Convert unsigned 16-bit number to HEX string.

Return

Pointer to output variable

Parameters
  • [in] num: Number to convert

  • [out] out: Output variable to save string

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

lwgsm_i16_to_str(num, out)

Convert signed 16-bit number to string.

Return

Pointer to output variable

Parameters
  • [in] num: Number to convert

  • [out] out: Output variable to save string

lwgsm_u8_to_str(num, out)

Convert unsigned 8-bit number to string.

Return

Pointer to output variable

Parameters
  • [in] num: Number to convert

  • [out] out: Output variable to save string

lwgsm_u8_to_hex_str(num, out, w)

Convert unsigned 16-bit number to HEX string.

Return

Pointer to output variable

Parameters
  • [in] num: Number to convert

  • [out] out: Output variable to save string

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

lwgsm_i8_to_str(num, out)

Convert signed 8-bit number to string.

Return

Pointer to output variable

Parameters
  • [in] num: Number to convert

  • [out] out: Output variable to save string

Functions

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

Convert unsigned 32-bit number to string.

Return

Pointer to output variable

Parameters
  • [in] num: Number to convert

  • [out] out: Output variable to save string

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

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

char *lwgsm_i32_to_gen_str(int32_t num, char *out)

Convert signed 32-bit number to string.

Return

Pointer to output variable

Parameters
  • [in] num: Number to convert

  • [out] out: Output variable to save string

group LWGSM

Lightweight GSM-AT parser library.

Functions

lwgsmr_t lwgsm_init(lwgsm_evt_fn evt_func, const uint32_t blocking)

Init and prepare GSM 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.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] evt_func: Global event callback function for all major events

  • [in] blocking: Status whether command should be blocking or not. Used when LWGSM_CFG_RESET_ON_INIT is enabled.

lwgsmr_t lwgsm_reset(const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Execute reset and send default commands.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

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

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

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

lwgsmr_t lwgsm_reset_with_delay(uint32_t delay, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Execute reset and send default commands with delay.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

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

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

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

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

lwgsmr_t lwgsm_set_func_mode(uint8_t mode, const lwgsm_api_cmd_evt_fn evt_fn, void *const evt_arg, const uint32_t blocking)

Set modem function mode.

Note

Use this function to set modem to normal or low-power mode

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] mode: Mode status. Set to 1 for full functionality or 0 for low-power mode (no functionality)

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

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

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

lwgsmr_t lwgsm_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 lwgsm_core_unlock the same amount of time to make sure lock gets back to 0

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

lwgsmr_t lwgsm_core_unlock(void)

Unlock stack for multi-thread access.

Used in conjunction with lwgsm_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

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

lwgsmr_t lwgsm_device_set_present(uint8_t present, const lwgsm_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

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] present: Flag indicating device is present

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

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

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

uint8_t lwgsm_device_is_present(void)

Check if device is present.

Return

1 on success, 0 otherwise

uint8_t lwgsm_delay(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

Return

1 on success, 0 otherwise

Parameters
  • [in] ms: Milliseconds to delay

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 lwgsm_opts.h file.

Note

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

group LWGSM_OPT

GSM-AT options.

Defines

LWGSM_CFG_OS

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

Note

Value must be set to 1 in the current revision

Note

Check OS configuration group for more configuration related to operating system

LWGSM_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 lwgsm_mem_malloc, lwgsm_mem_calloc, lwgsm_mem_realloc and lwgsm_mem_free

Note

Function declaration follows standard C functions malloc, calloc, realloc, free. Declaration is available in lwgsm/lwgsm_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

LWGSM_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 don’t support unaligned memory access. This CPUs must have set correct memory alignment value.

Note

This value must be power of 2

LWGSM_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.

LWGSM_CFG_MAX_CONNS

Maximal number of connections AT software can support on GSM device.

LWGSM_CFG_CONN_MAX_DATA_LEN

Maximal number of bytes we can send at single command to GSM.

Note

Value can not exceed 1460 bytes or no data will be ever send

Note

This is limitation of GSM AT commands and on systems where RAM is not an issue, it should be set to maximal value (1460) to optimize data transfer speed performance

LWGSM_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 we are successful.

LWGSM_CFG_IPD_MAX_BUFF_SIZE

Maximum single buffer size for network receive data (TCP/UDP connections)

Note

When GSM sends buffer buffer than maximal, multiple buffers are created

LWGSM_CFG_AT_PORT_BAUDRATE

Default baudrate used for AT port.

Note

Later, user may call API function to change to desired baudrate if necessary

LWGSM_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 LWGSM_CFG_INPUT_USE_PROCESS is enabled

LWGSM_CFG_RESET_ON_INIT

Enables 1 or disables 0 reset sequence after lwgsm_init call.

Note

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

LWGSM_CFG_RESET_ON_DEVICE_PRESENT

Enables 1 or disables 0 reset sequence after lwgsm_device_set_present call.

Note

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

LWGSM_CFG_RESET_DELAY_DEFAULT

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

LWGSM_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

group LWGSM_OPT_DBG

Debugging configurations.

Defines

LWGSM_CFG_DBG

Set global debug support.

Possible values are LWGSM_DBG_ON or LWGSM_DBG_OFF

Note

Set to LWGSM_DBG_OFF to globally disable all debugs

LWGSM_CFG_DBG_OUT(fmt, ...)

Debugging output function.

Called with format and optional parameters for printf style debug

LWGSM_CFG_DBG_LVL_MIN

Minimal debug level.

Check LWGSM_DBG_LVL for possible values

LWGSM_CFG_DBG_TYPES_ON

Enabled debug types.

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

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

LWGSM_CFG_DBG_INIT

Set debug level for init function.

Possible values are LWGSM_DBG_ON or LWGSM_DBG_OFF

LWGSM_CFG_DBG_MEM

Set debug level for memory manager.

Possible values are LWGSM_DBG_ON or LWGSM_DBG_OFF

LWGSM_CFG_DBG_INPUT

Set debug level for input module.

Possible values are LWGSM_DBG_ON or LWGSM_DBG_OFF

LWGSM_CFG_DBG_THREAD

Set debug level for GSM threads.

Possible values are LWGSM_DBG_ON or LWGSM_DBG_OFF

LWGSM_CFG_DBG_ASSERT

Set debug level for asserting of input variables.

Possible values are LWGSM_DBG_ON or LWGSM_DBG_OFF

LWGSM_CFG_DBG_IPD

Set debug level for incoming data received from device.

Possible values are LWGSM_DBG_ON or LWGSM_DBG_OFF

LWGSM_CFG_DBG_PBUF

Set debug level for packet buffer manager.

Possible values are LWGSM_DBG_ON or LWGSM_DBG_OFF

LWGSM_CFG_DBG_CONN

Set debug level for connections.

Possible values are LWGSM_DBG_ON or LWGSM_DBG_OFF

LWGSM_CFG_DBG_VAR

Set debug level for dynamic variable allocations.

Possible values are LWGSM_DBG_ON or LWGSM_DBG_OFF

LWGSM_CFG_DBG_NETCONN

Set debug level for netconn sequential API.

Possible values are LWGSM_DBG_ON or LWGSM_DBG_OFF

LWGSM_CFG_AT_ECHO

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

Note

This mode is useful when debugging GSM communication

group LWGSM_OPT_OS

Operating system dependant configuration.

Defines

LWGSM_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

LWGSM_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

LWGSM_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.

Note

This mode can only be used when LWGSM_CFG_OS is enabled

Note

When using this mode, separate thread must be dedicated only for reading data on AT port

Note

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

LWGSM_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.

LWGSM_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 LWGSM_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

LWGSM_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);

Return

Destination memory start address

Parameters
  • [in] dst: Destination memory start address

  • [in] src: Source memory start address

  • [in] len: Number of bytes to copy

LWGSM_MEMSET(dst, b, len)

Memory set function declaration.

Function prototype must be similar to:

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

Return

Destination memory start address

Parameters
  • [in] dst: Destination memory start address

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

  • [in] len: Number of bytes to set

group LWGSM_OPT_MODULES

Configuration of specific modules.

Defines

LWGSM_CFG_NETWORK

Enables 1 or disables 0 network functionality used for TCP/IP communication.

Network must be enabled to use all GPRS/LTE functions such as connection API, FTP, HTTP, etc.

LWGSM_CFG_NETWORK_IGNORE_CGACT_RESULT

Ignores 1 or not 0 result from AT+CGACT command.

Note

This may be used for data-only SIM cards where command might fail when trying to attach to network for data transfer

LWGSM_CFG_CONN

Enables 1 or disables 0 connection API.

Note

LWGSM_CFG_NETWORK must be enabled to use connection feature

LWGSM_CFG_SMS

Enables 1 or disables 0 SMS API.

LWGSM_CFG_CALL

Enables 1 or disables 0 call API.

LWGSM_CFG_PHONEBOOK

Enables 1 or disables 0 phonebook API.

LWGSM_CFG_HTTP

Enables 1 or disables 0 HTTP API.

Note

LWGSM_CFG_NETWORK must be enabled to use connection feature

LWGSM_CFG_FTP

Enables 1 or disables 0 FTP API.

Note

LWGSM_CFG_NETWORK must be enabled to use connection feature

LWGSM_CFG_PING

Enables 1 or disables 0 PING API.

Note

LWGSM_CFG_NETWORK must be enabled to use connection feature

LWGSM_CFG_USSD

Enables 1 or disables 0 USSD API.

group LWGSM_OPT_MODULES_NETCONN

Configuration of netconn API module.

Defines

LWGSM_CFG_NETCONN

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

Note

To use this feature, OS support is mandatory.

See

LWGSM_CFG_OS

LWGSM_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.

LWGSM_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

LWGSM_CFG_NETCONN_RECEIVE_QUEUE_LEN

Receive queue length for pbuf entries.

Defines maximal number of pbuf data packet references for receive

group LWGSM_OPT_MODULES_MQTT

Configuration of MQTT and MQTT API client modules.

Defines

LWGSM_CFG_MQTT_MAX_REQUESTS

Maximal number of open MQTT requests at a time.

LWGSM_CFG_DBG_MQTT

Set debug level for MQTT client module.

Possible values are LWGSM_DBG_ON or LWGSM_DBG_OFF

LWGSM_CFG_DBG_MQTT_API

Set debug level for MQTT API client module.

Possible values are LWGSM_DBG_ON or LWGSM_DBG_OFF

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 LWGSM_LL

Low-level communication functions.

Typedefs

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

Function prototype for AT output data.

Return

Number of bytes sent

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

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

typedef uint8_t (*lwgsm_ll_reset_fn)(uint8_t state)

Function prototype for hardware reset of GSM device.

Return

1 on successful action, 0 otherwise

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

Functions

lwgsmr_t lwgsm_ll_init(lwgsm_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 GSM stack when using OS. When LWGSM_CFG_INPUT_USE_PROCESS is set to 1, this function may be called from user UART thread.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [inout] ll: Pointer to lwgsm_ll_t structure to fill data for communication functions

lwgsmr_t lwgsm_ll_deinit(lwgsm_ll_t *ll)

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

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [inout] ll: Pointer to lwgsm_ll_t structure to fill data for communication functions

struct lwgsm_ll_t
#include <lwgsm_typedefs.h>

Low level user specific functions.

Public Members

lwgsm_ll_send_fn send_fn

Callback function to transmit data

lwgsm_ll_reset_fn reset_fn

Reset callback function

uint32_t baudrate

UART baudrate value

struct lwgsm_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 LWGSM_SYS

System based function for OS management, timings, etc.

Main

uint8_t lwgsm_sys_init(void)

Init system dependant parameters.

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

Return

1 on success, 0 otherwise

uint32_t lwgsm_sys_now(void)

Get current time in units of milliseconds.

Return

Current time in units of milliseconds

uint8_t lwgsm_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.

Return

1 on success, 0 otherwise

uint8_t lwgsm_sys_unprotect(void)

Unprotect middleware core.

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

Note

Most operating systems support recursive mutexes.

Return

1 on success, 0 otherwise

Mutex

uint8_t lwgsm_sys_mutex_create(lwgsm_sys_mutex_t *p)

Create new recursive mutex.

Note

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

Return

1 on success, 0 otherwise

Parameters
  • [out] p: Pointer to mutex structure to allocate

uint8_t lwgsm_sys_mutex_delete(lwgsm_sys_mutex_t *p)

Delete recursive mutex from system.

Return

1 on success, 0 otherwise

Parameters
  • [in] p: Pointer to mutex structure

uint8_t lwgsm_sys_mutex_lock(lwgsm_sys_mutex_t *p)

Lock recursive mutex, wait forever to lock.

Return

1 on success, 0 otherwise

Parameters
  • [in] p: Pointer to mutex structure

uint8_t lwgsm_sys_mutex_unlock(lwgsm_sys_mutex_t *p)

Unlock recursive mutex.

Return

1 on success, 0 otherwise

Parameters
  • [in] p: Pointer to mutex structure

uint8_t lwgsm_sys_mutex_isvalid(lwgsm_sys_mutex_t *p)

Check if mutex structure is valid system.

Return

1 on success, 0 otherwise

Parameters
  • [in] p: Pointer to mutex structure

uint8_t lwgsm_sys_mutex_invalid(lwgsm_sys_mutex_t *p)

Set recursive mutex structure as invalid.

Return

1 on success, 0 otherwise

Parameters
  • [in] p: Pointer to mutex structure

Semaphores

uint8_t lwgsm_sys_sem_create(lwgsm_sys_sem_t *p, uint8_t cnt)

Create a new binary semaphore and set initial state.

Note

Semaphore may only have 1 token available

Return

1 on success, 0 otherwise

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

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

uint8_t lwgsm_sys_sem_delete(lwgsm_sys_sem_t *p)

Delete binary semaphore.

Return

1 on success, 0 otherwise

Parameters
  • [in] p: Pointer to semaphore structure

uint32_t lwgsm_sys_sem_wait(lwgsm_sys_sem_t *p, uint32_t timeout)

Wait for semaphore to be available.

Return

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

Parameters
  • [in] p: Pointer to semaphore structure

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

uint8_t lwgsm_sys_sem_release(lwgsm_sys_sem_t *p)

Release semaphore.

Return

1 on success, 0 otherwise

Parameters
  • [in] p: Pointer to semaphore structure

uint8_t lwgsm_sys_sem_isvalid(lwgsm_sys_sem_t *p)

Check if semaphore is valid.

Return

1 on success, 0 otherwise

Parameters
  • [in] p: Pointer to semaphore structure

uint8_t lwgsm_sys_sem_invalid(lwgsm_sys_sem_t *p)

Invalid semaphore.

Return

1 on success, 0 otherwise

Parameters
  • [in] p: Pointer to semaphore structure

Message queues

uint8_t lwgsm_sys_mbox_create(lwgsm_sys_mbox_t *b, size_t size)

Create a new message queue with entry type of void *

Return

1 on success, 0 otherwise

Parameters
  • [out] b: Pointer to message queue structure

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

uint8_t lwgsm_sys_mbox_delete(lwgsm_sys_mbox_t *b)

Delete message queue.

Return

1 on success, 0 otherwise

Parameters
  • [in] b: Pointer to message queue structure

uint32_t lwgsm_sys_mbox_put(lwgsm_sys_mbox_t *b, void *m)

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

Return

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

Parameters
  • [in] b: Pointer to message queue structure

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

uint32_t lwgsm_sys_mbox_get(lwgsm_sys_mbox_t *b, void **m, uint32_t timeout)

Get a new entry from message queue with timeout.

Return

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

Parameters
  • [in] b: Pointer to message queue structure

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

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

uint8_t lwgsm_sys_mbox_putnow(lwgsm_sys_mbox_t *b, void *m)

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

Return

1 on success, 0 otherwise

Parameters
  • [in] b: Pointer to message queue structure

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

uint8_t lwgsm_sys_mbox_getnow(lwgsm_sys_mbox_t *b, void **m)

Get an entry from message queue immediately.

Return

1 on success, 0 otherwise

Parameters
  • [in] b: Pointer to message queue structure

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

uint8_t lwgsm_sys_mbox_isvalid(lwgsm_sys_mbox_t *b)

Check if message queue is valid.

Return

1 on success, 0 otherwise

Parameters
  • [in] b: Pointer to message queue structure

uint8_t lwgsm_sys_mbox_invalid(lwgsm_sys_mbox_t *b)

Invalid message queue.

Return

1 on success, 0 otherwise

Parameters
  • [in] b: Pointer to message queue structure

Threads

uint8_t lwgsm_sys_thread_create(lwgsm_sys_thread_t *t, const char *name, lwgsm_sys_thread_fn thread_func, void *const arg, size_t stack_size, lwgsm_sys_thread_prio_t prio)

Create a new thread.

Return

1 on success, 0 otherwise

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

  • [in] name: Name of a new thread

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

  • [in] arg: Thread function argument

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

  • [in] prio: Thread priority

uint8_t lwgsm_sys_thread_terminate(lwgsm_sys_thread_t *t)

Terminate thread (shut it down and remove)

Return

1 on success, 0 otherwise

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

uint8_t lwgsm_sys_thread_yield(void)

Yield current thread.

Return

1 on success, 0 otherwise

Defines

LWGSM_SYS_MUTEX_NULL

Mutex invalid value.

Value assigned to lwgsm_sys_mutex_t type when it is not valid.

LWGSM_SYS_SEM_NULL

Semaphore invalid value.

Value assigned to lwgsm_sys_sem_t type when it is not valid.

LWGSM_SYS_MBOX_NULL

Message box invalid value.

Value assigned to lwgsm_sys_mbox_t type when it is not valid.

LWGSM_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

LWGSM_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 prioer operation.

LWGSM_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 (*lwgsm_sys_thread_fn)(void*)

Thread function prototype.

typedef osMutexId_t lwgsm_sys_mutex_t

System mutex type.

It is used by middleware as base type of mutex.

typedef osSemaphoreId_t lwgsm_sys_sem_t

System semaphore type.

It is used by middleware as base type of mutex.

typedef osMessageQueueId_t lwgsm_sys_mbox_t

System message queue type.

It is used by middleware as base type of mutex.

typedef osThreadId_t lwgsm_sys_thread_t

System thread ID type.

typedef osPriority lwgsm_sys_thread_prio_t

System thread priority type.

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

Applications

MQTT Client

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

group LWGSM_APP_MQTT_CLIENT

MQTT client.

Typedefs

typedef struct lwgsm_mqtt_client *lwgsm_mqtt_client_p

Pointer to lwgsm_mqtt_client_t structure.

typedef void (*lwgsm_mqtt_evt_fn)(lwgsm_mqtt_client_p client, lwgsm_mqtt_evt_t *evt)

MQTT event callback function.

Parameters
  • [in] client: MQTT client

  • [in] evt: MQTT event with type and related data

Enums

enum lwgsm_mqtt_qos_t

Quality of service enumeration.

Values:

enumerator LWGSM_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 LWGSM_MQTT_QOS_AT_LEAST_ONCE

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

enumerator LWGSM_MQTT_QOS_EXACTLY_ONCE

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

enum lwgsm_mqtt_state_t

State of MQTT client.

Values:

enumerator LWGSM_MQTT_CONN_DISCONNECTED

Connection with server is not established

enumerator LWGSM_MQTT_CONN_CONNECTING

Client is connecting to server

enumerator LWGSM_MQTT_CONN_DISCONNECTING

Client connection is disconnecting from server

enumerator LWGSM_MQTT_CONNECTING

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

enumerator LWGSM_MQTT_CONNECTED

MQTT is fully connected and ready to send data on topics

enum lwgsm_mqtt_evt_type_t

MQTT event types.

Values:

enumerator LWGSM_MQTT_EVT_CONNECT

MQTT client connect event

enumerator LWGSM_MQTT_EVT_SUBSCRIBE

MQTT client subscribed to specific topic

enumerator LWGSM_MQTT_EVT_UNSUBSCRIBE

MQTT client unsubscribed from specific topic

enumerator LWGSM_MQTT_EVT_PUBLISH

MQTT client publish message to server event.

Note

When publishing packet with quality of service LWGSM_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 = LWGSM_MQTT_QOS_AT_MOST_ONCE

enumerator LWGSM_MQTT_EVT_PUBLISH_RECV

MQTT client received a publish message from server

enumerator LWGSM_MQTT_EVT_DISCONNECT

MQTT client disconnected from MQTT server

enumerator LWGSM_MQTT_EVT_KEEP_ALIVE

MQTT keep-alive sent to server and reply received

enum lwgsm_mqtt_conn_status_t

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

Values:

enumerator LWGSM_MQTT_CONN_STATUS_ACCEPTED

Connection accepted and ready to use

enumerator LWGSM_MQTT_CONN_STATUS_REFUSED_PROTOCOL_VERSION

Connection Refused, unacceptable protocol version

enumerator LWGSM_MQTT_CONN_STATUS_REFUSED_ID

Connection refused, identifier rejected

enumerator LWGSM_MQTT_CONN_STATUS_REFUSED_SERVER

Connection refused, server unavailable

enumerator LWGSM_MQTT_CONN_STATUS_REFUSED_USER_PASS

Connection refused, bad user name or password

enumerator LWGSM_MQTT_CONN_STATUS_REFUSED_NOT_AUTHORIZED

Connection refused, not authorized

enumerator LWGSM_MQTT_CONN_STATUS_TCP_FAILED

TCP connection to server was not successful

Functions

lwgsm_mqtt_client_p lwgsm_mqtt_client_new(size_t tx_buff_len, size_t rx_buff_len)

Allocate a new MQTT client structure.

Return

Pointer to new allocated MQTT client structure or NULL on failure

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

  • [in] rx_buff_len: Length of raw data input buffer

void lwgsm_mqtt_client_delete(lwgsm_mqtt_client_p client)

Delete MQTT client structure.

Note

MQTT client must be disconnected first

Parameters
  • [in] client: MQTT client

lwgsmr_t lwgsm_mqtt_client_connect(lwgsm_mqtt_client_p client, const char *host, lwgsm_port_t port, lwgsm_mqtt_evt_fn evt_fn, const lwgsm_mqtt_client_info_t *info)

Connect to MQTT server.

Note

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

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] client: MQTT client

  • [in] host: Host address for server

  • [in] port: Host port number

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

  • [in] info: Information structure for connection

lwgsmr_t lwgsm_mqtt_client_disconnect(lwgsm_mqtt_client_p client)

Disconnect from MQTT server.

Return

lwgsmOK if request sent to queue or member of lwgsmr_t otherwise

Parameters
  • [in] client: MQTT client

uint8_t lwgsm_mqtt_client_is_connected(lwgsm_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

Return

1 on success, 0 otherwise

Parameters
  • [in] client: MQTT client

lwgsmr_t lwgsm_mqtt_client_subscribe(lwgsm_mqtt_client_p client, const char *topic, lwgsm_mqtt_qos_t qos, void *arg)

Subscribe to MQTT topic.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] client: MQTT client

  • [in] topic: Topic name to subscribe to

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

  • [in] arg: User custom argument used in callback

lwgsmr_t lwgsm_mqtt_client_unsubscribe(lwgsm_mqtt_client_p client, const char *topic, void *arg)

Unsubscribe from MQTT topic.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] client: MQTT client

  • [in] topic: Topic name to unsubscribe from

  • [in] arg: User custom argument used in callback

lwgsmr_t lwgsm_mqtt_client_publish(lwgsm_mqtt_client_p client, const char *topic, const void *payload, uint16_t len, lwgsm_mqtt_qos_t qos, uint8_t retain, void *arg)

Publish a new message on specific topic.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] client: MQTT client

  • [in] topic: Topic to send message to

  • [in] payload: Message data

  • [in] payload_len: Length of payload data

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

  • [in] retain: Retian parameter value

  • [in] arg: User custom argument used in callback

void *lwgsm_mqtt_client_get_arg(lwgsm_mqtt_client_p client)

Get user argument on client.

Return

User argument

Parameters
  • [in] client: MQTT client handle

void lwgsm_mqtt_client_set_arg(lwgsm_mqtt_client_p client, void *arg)

Set user argument on client.

Parameters
  • [in] client: MQTT client handle

  • [in] arg: User argument

struct lwgsm_mqtt_client_info_t
#include <lwgsm_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

lwgsm_mqtt_qos_t will_qos

Will topic quality of service

struct lwgsm_mqtt_request_t
#include <lwgsm_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 lwgsm_mqtt_evt_t
#include <lwgsm_mqtt_client.h>

MQTT event structure for callback function.

Public Members

lwgsm_mqtt_evt_type_t type

Event type

lwgsm_mqtt_conn_status_t status

Connection status with MQTT

struct lwgsm_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 lwgsm_mqtt_evt_t::[anonymous]::[anonymous] disconnect

Event for disconnecting from server

void *arg

User argument for callback function

lwgsmr_t res

Response status

struct lwgsm_mqtt_evt_t::[anonymous]::[anonymous] sub_unsub_scribed

Event for (un)subscribe to/from topics

struct lwgsm_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

lwgsm_mqtt_qos_t qos

Received packet quality of service

struct lwgsm_mqtt_evt_t::[anonymous]::[anonymous] publish_recv

Publish received event

union lwgsm_mqtt_evt_t::[anonymous] evt

Event data parameters

group LWGSM_APP_MQTT_CLIENT_EVT

Event helper functions.

Connect event

Note

Use these functions on LWGSM_MQTT_EVT_CONNECT event

lwgsm_mqtt_client_evt_connect_get_status(client, evt)

Get connection status.

Return

Connection status. Member of lwgsm_mqtt_conn_status_t

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

Disconnect event

Note

Use these functions on LWGSM_MQTT_EVT_DISCONNECT event

lwgsm_mqtt_client_evt_disconnect_is_accepted(client, evt)

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

Return

1 on success, 0 otherwise

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

Subscribe/unsubscribe event

Note

Use these functions on LWGSM_MQTT_EVT_SUBSCRIBE or LWGSM_MQTT_EVT_UNSUBSCRIBE events

lwgsm_mqtt_client_evt_subscribe_get_argument(client, evt)

Get user argument used on lwgsm_mqtt_client_subscribe.

Return

User argument

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

lwgsm_mqtt_client_evt_subscribe_get_result(client, evt)

Get result of subscribe event.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

lwgsm_mqtt_client_evt_unsubscribe_get_argument(client, evt)

Get user argument used on lwgsm_mqtt_client_unsubscribe.

Return

User argument

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

lwgsm_mqtt_client_evt_unsubscribe_get_result(client, evt)

Get result of unsubscribe event.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

Publish receive event

Note

Use these functions on LWGSM_MQTT_EVT_PUBLISH_RECV event

lwgsm_mqtt_client_evt_publish_recv_get_topic(client, evt)

Get topic from received publish packet.

Return

Topic name

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

lwgsm_mqtt_client_evt_publish_recv_get_topic_len(client, evt)

Get topic length from received publish packet.

Return

Topic length

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

lwgsm_mqtt_client_evt_publish_recv_get_payload(client, evt)

Get payload from received publish packet.

Return

Packet payload

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

lwgsm_mqtt_client_evt_publish_recv_get_payload_len(client, evt)

Get payload length from received publish packet.

Return

Payload length

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

lwgsm_mqtt_client_evt_publish_recv_is_duplicate(client, evt)

Check if packet is duplicated.

Return

1 if duplicated, 0 otherwise

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

lwgsm_mqtt_client_evt_publish_recv_get_qos(client, evt)

Get received quality of service.

Return

Member of lwgsm_mqtt_qos_t enumeration

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

Publish event

Note

Use these functions on LWGSM_MQTT_EVT_PUBLISH event

lwgsm_mqtt_client_evt_publish_get_argument(client, evt)

Get user argument used on lwgsm_mqtt_client_publish.

Return

User argument

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

lwgsm_mqtt_client_evt_publish_get_result(client, evt)

Get result of publish event.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

Defines

lwgsm_mqtt_client_evt_get_type(client, evt)

Get MQTT event type.

Return

MQTT Event type, value of lwgsm_mqtt_evt_type_t enumeration

Parameters
  • [in] client: MQTT client

  • [in] evt: Event handle

MQTT Client API

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

MQTT API application example code
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
 * MQTT client API example with GSM device.
 *
 * Once device is connected to network,
 * it will try to connect to mosquitto test server and start the MQTT.
 *
 * If successfully connected, it will publish data to "lwgsm_mqtt_topic" topic every x seconds.
 *
 * To check if data are sent, you can use mqtt-spy PC software to inspect
 * test.mosquitto.org server and subscribe to publishing topic
 */

#include "lwgsm/apps/lwgsm_mqtt_client_api.h"
#include "mqtt_client_api.h"
#include "lwgsm/lwgsm_mem.h"
#include "lwgsm/lwgsm_network_api.h"

/**
 * \brief           Connection information for MQTT CONNECT packet
 */
static const lwgsm_mqtt_client_info_t
mqtt_client_info = {
    .keep_alive = 10,

    /* Server login data */
    .user = "8a215f70-a644-11e8-ac49-e932ed599553",
    .pass = "26aa943f702e5e780f015cd048a91e8fb54cca28",

    /* Device identifier address */
    .id = "2c3573a0-0176-11e9-a056-c5cffe7f75f9",
};

/**
 * \brief           Memory for temporary topic
 */
static char
mqtt_topic_str[256];

/**
 * \brief           Generate random number and write it to string
 * \param[out]      str: Output string with new number
 */
void
generate_random(char* str) {
    static uint32_t random_beg = 0x8916;
    random_beg = random_beg * 0x00123455 + 0x85654321;
    sprintf(str, "%u", (unsigned)((random_beg >> 8) & 0xFFFF));
}

/**
 * \brief           MQTT client API thread
 */
void
mqtt_client_api_thread(void const* arg) {
    lwgsm_mqtt_client_api_p client;
    lwgsm_mqtt_conn_status_t conn_status;
    lwgsm_mqtt_client_api_buf_p buf;
    lwgsmr_t res;
    char random_str[10];

    /* Request network attach */
    while (lwgsm_network_request_attach() != lwgsmOK) {
        lwgsm_delay(1000);
    }

    /* Create new MQTT API */
    client = lwgsm_mqtt_client_api_new(256, 128);
    if (client == NULL) {
        goto terminate;
    }

    while (1) {
        /* Make a connection */
        printf("Joining MQTT server\r\n");

        /* Try to join */
        conn_status = lwgsm_mqtt_client_api_connect(client, "mqtt.mydevices.com", 1883, &mqtt_client_info);
        if (conn_status == LWGSM_MQTT_CONN_STATUS_ACCEPTED) {
            printf("Connected and accepted!\r\n");
            printf("Client is ready to subscribe and publish to new messages\r\n");
        } else {
            printf("Connect API response: %d\r\n", (int)conn_status);
            lwgsm_delay(5000);
            continue;
        }

        /* Subscribe to topics */
        sprintf(mqtt_topic_str, "v1/%s/things/%s/cmd/#", mqtt_client_info.user, mqtt_client_info.id);
        if (lwgsm_mqtt_client_api_subscribe(client, mqtt_topic_str, LWGSM_MQTT_QOS_AT_LEAST_ONCE) == lwgsmOK) {
            printf("Subscribed to topic\r\n");
        } else {
            printf("Problem subscribing to topic!\r\n");
        }

        while (1) {
            /* Receive MQTT packet with 1000ms timeout */
            res = lwgsm_mqtt_client_api_receive(client, &buf, 5000);
            if (res == lwgsmOK) {
                if (buf != NULL) {
                    printf("Publish received!\r\n");
                    printf("Topic: %s, payload: %s\r\n", buf->topic, buf->payload);
                    lwgsm_mqtt_client_api_buf_free(buf);
                    buf = NULL;
                }
            } else if (res == lwgsmCLOSED) {
                printf("MQTT connection closed!\r\n");
                break;
            } else if (res == lwgsmTIMEOUT) {
                printf("Timeout on MQTT receive function. Manually publishing.\r\n");

                /* Publish data on channel 1 */
                generate_random(random_str);
                sprintf(mqtt_topic_str, "v1/%s/things/%s/data/1", mqtt_client_info.user, mqtt_client_info.id);
                lwgsm_mqtt_client_api_publish(client, mqtt_topic_str, random_str, strlen(random_str), LWGSM_MQTT_QOS_AT_LEAST_ONCE, 0);
            }
        }
        goto terminate;
    }

terminate:
    lwgsm_mqtt_client_api_delete(client);
    lwgsm_network_request_detach();
    printf("MQTT client thread terminate\r\n");
    lwgsm_sys_thread_terminate(NULL);
}
group LWGSM_APP_MQTT_CLIENT_API

Sequential, single thread MQTT client API.

Typedefs

typedef struct lwgsm_mqtt_client_api_buf *lwgsm_mqtt_client_api_buf_p

Pointer to lwgsm_mqtt_client_api_buf_t structure.

Functions

lwgsm_mqtt_client_api_p lwgsm_mqtt_client_api_new(size_t tx_buff_len, size_t rx_buff_len)

Create new MQTT client API.

Return

Client handle on success, NULL otherwise

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

  • [in] rx_buff_len: Maximal RX buffer

void lwgsm_mqtt_client_api_delete(lwgsm_mqtt_client_api_p client)

Delete client from memory.

Parameters
  • [in] client: MQTT API client handle

lwgsm_mqtt_conn_status_t lwgsm_mqtt_client_api_connect(lwgsm_mqtt_client_api_p client, const char *host, lwgsm_port_t port, const lwgsm_mqtt_client_info_t *info)

Connect to MQTT broker.

Return

LWGSM_MQTT_CONN_STATUS_ACCEPTED on success, member of lwgsm_mqtt_conn_status_t otherwise

Parameters
  • [in] client: MQTT API client handle

  • [in] host: TCP host

  • [in] port: TCP port

  • [in] info: MQTT client info

lwgsmr_t lwgsm_mqtt_client_api_close(lwgsm_mqtt_client_api_p client)

Close MQTT connection.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] client: MQTT API client handle

lwgsmr_t lwgsm_mqtt_client_api_subscribe(lwgsm_mqtt_client_api_p client, const char *topic, lwgsm_mqtt_qos_t qos)

Subscribe to topic.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] client: MQTT API client handle

  • [in] topic: Topic to subscribe on

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

lwgsmr_t lwgsm_mqtt_client_api_unsubscribe(lwgsm_mqtt_client_api_p client, const char *topic)

Unsubscribe from topic.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] client: MQTT API client handle

  • [in] topic: Topic to unsubscribe from

lwgsmr_t lwgsm_mqtt_client_api_publish(lwgsm_mqtt_client_api_p client, const char *topic, const void *data, size_t btw, lwgsm_mqtt_qos_t qos, uint8_t retain)

Publish new packet to MQTT network.

Return

lwgsmOK on success, member of lwgsmr_t otherwise

Parameters
  • [in] client: MQTT API client handle

  • [in] topic: Topic to publish on

  • [in] data: Data to send

  • [in] btw: Number of bytes to send for data parameter

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

  • [in] retain: Set to 1 for retain flag, 0 otherwise

uint8_t lwgsm_mqtt_client_api_is_connected(lwgsm_mqtt_client_api_p client)

Check if client MQTT connection is active.

Return

1 on success, 0 otherwise

Parameters
  • [in] client: MQTT API client handle

lwgsmr_t lwgsm_mqtt_client_api_receive(lwgsm_mqtt_client_api_p client, lwgsm_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

Return

lwgsmOK on success, lwgsmCLOSED if MQTT is closed, lwgsmTIMEOUT on timeout

Parameters
  • [in] client: MQTT API client handle

  • [in] p: Pointer to output buffer

  • [in] timeout: Maximal time to wait before function returns timeout

void lwgsm_mqtt_client_api_buf_free(lwgsm_mqtt_client_api_buf_p p)

Free buffer memory after usage.

Parameters
  • [in] p: Buffer to free

struct lwgsm_mqtt_client_api_buf_t
#include <lwgsm_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

lwgsm_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 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
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "netconn_client.h"
#include "lwgsm/lwgsm.h"
#include "lwgsm/lwgsm_network_api.h"

#if LWGSM_CFG_NETCONN

/**
 * \brief           Host and port settings
 */
#define NETCONN_HOST        "example.com"
#define NETCONN_PORT        80

/**
 * \brief           Request header to send on successful connection
 */
static const char
request_header[] = ""
                   "GET / HTTP/1.1\r\n"
                   "Host: " NETCONN_HOST "\r\n"
                   "Connection: close\r\n"
                   "\r\n";

/**
 * \brief           Netconn client thread implementation
 * \param[in]       arg: User argument
 */
void
netconn_client_thread(void const* arg) {
    lwgsmr_t res;
    lwgsm_pbuf_p pbuf;
    lwgsm_netconn_p client;
    lwgsm_sys_sem_t* sem = (void*)arg;

    /* Request attach to network */
    while (lwgsm_network_request_attach() != lwgsmOK) {
        lwgsm_delay(1000);
    }

    /*
     * First create a new instance of netconn
     * connection and initialize system message boxes
     * to accept received packet buffers
     */
    client = lwgsm_netconn_new(LWGSM_NETCONN_TYPE_TCP);
    if (client != NULL) {
        /*
         * Connect to external server as client
         * with custom NETCONN_CONN_HOST and CONN_PORT values
         *
         * Function will block thread until we are successfully connected (or not) to server
         */
        res = lwgsm_netconn_connect(client, NETCONN_HOST, NETCONN_PORT);
        if (res == lwgsmOK) {                     /* Are we successfully connected? */
            printf("Connected to " NETCONN_HOST "\r\n");
            res = lwgsm_netconn_write(client, request_header, sizeof(request_header) - 1);    /* Send data to server */
            if (res == lwgsmOK) {
                res = lwgsm_netconn_flush(client);/* Flush data to output */
            }
            if (res == lwgsmOK) {                 /* Were data sent? */
                printf("Data were successfully sent to server\r\n");

                /*
                 * Since we sent HTTP request,
                 * we are expecting some data from server
                 * or at least forced connection close from remote side
                 */
                do {
                    /*
                     * Receive single packet of data
                     *
                     * Function will block thread until new packet
                     * is ready to be read from remote side
                     *
                     * After function returns, don't forgot the check value.
                     * Returned status will give you info in case connection
                     * was closed too early from remote side
                     */
                    res = lwgsm_netconn_receive(client, &pbuf);
                    if (res == lwgsmCLOSED) {     /* Was the connection closed? This can be checked by return status of receive function */
                        printf("Connection closed by remote side...\r\n");
                        break;
                    } else if (res == lwgsmTIMEOUT) {
                        printf("Netconn timeout while receiving data. You may try multiple readings before deciding to close manually\r\n");
                    }

                    if (res == lwgsmOK && pbuf != NULL) { /* Make sure we have valid packet buffer */
                        /*
                         * At this point read and manipulate
                         * with received buffer and check if you expect more data
                         *
                         * After you are done using it, it is important
                         * you free the memory otherwise memory leaks will appear
                         */
                        printf("Received new data packet of %d bytes\r\n", (int)lwgsm_pbuf_length(pbuf, 1));
                        lwgsm_pbuf_free(pbuf);    /* Free the memory after usage */
                        pbuf = NULL;
                    }
                } while (1);
            } else {
                printf("Error writing data to remote host!\r\n");
            }

            /*
             * Check if connection was closed by remote server
             * and in case it wasn't, close it manually
             */
            if (res != lwgsmCLOSED) {
                lwgsm_netconn_close(client);
            }
        } else {
            printf("Cannot connect to remote host %s:%d!\r\n", NETCONN_HOST, NETCONN_PORT);
        }
        lwgsm_netconn_delete(client);             /* Delete netconn structure */
    }
    lwgsm_network_request_detach();               /* Detach from network */

    if (lwgsm_sys_sem_isvalid(sem)) {
        lwgsm_sys_sem_release(sem);
    }
    lwgsm_sys_thread_terminate(NULL);             /* Terminate current thread */
}

#endif /* LWGSM_CFG_NETCONN */
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, lwgsm_netconn_receive() will block for maximal timeout set with lwgsm_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

LWGSM_CFG_NETCONN_RECEIVE_TIMEOUT must be set to 1 to use this feature.

group LWGSM_NETCONN

Network connection.

Typedefs

typedef struct lwgsm_netconn *lwgsm_netconn_p

Netconn object structure.

Enums

enum lwgsm_netconn_type_t

Netconn connection type.

Values:

enumerator LWGSM_NETCONN_TYPE_TCP

TCP connection

enumerator LWGSM_NETCONN_TYPE_UDP

UDP connection

enumerator LWGSM_NETCONN_TYPE_SSL

TCP connection over SSL

Functions

lwgsm_netconn_p lwgsm_netconn_new(lwgsm_netconn_type_t type)

Create new netconn connection.

Return

New netconn connection on success, NULL otherwise

Parameters
  • [in] type: Netconn connection type

lwgsmr_t lwgsm_netconn_delete(lwgsm_netconn_p nc)

Delete netconn connection.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] nc: Netconn handle

lwgsmr_t lwgsm_netconn_connect(lwgsm_netconn_p nc, const char *host, lwgsm_port_t port)

Connect to server as client.

Return

lwgsmOK if successfully connected, member of lwgsmr_t otherwise

Parameters
  • [in] nc: Netconn handle

  • [in] host: Pointer to host, such as domain name or IP address in string format

  • [in] port: Target port to use

lwgsmr_t lwgsm_netconn_receive(lwgsm_netconn_p nc, lwgsm_pbuf_p *pbuf)

Receive data from connection.

Return

lwgsmOK when new data ready,

Return

lwgsmCLOSED when connection closed by remote side,

Return

lwgsmTIMEOUT when receive timeout occurs

Return

Any other member of lwgsmr_t otherwise

Parameters
  • [in] nc: Netconn handle used to receive from

  • [in] pbuf: Pointer to pointer to save new receive buffer to. When function returns, user must check for valid pbuf value pbuf != NULL

lwgsmr_t lwgsm_netconn_close(lwgsm_netconn_p nc)

Close a netconn connection.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] nc: Netconn handle to close

int8_t lwgsm_netconn_getconnnum(lwgsm_netconn_p nc)

Get connection number used for netconn.

Return

-1 on failure, connection number between 0 and LWGSM_CFG_MAX_CONNS otherwise

Parameters
  • [in] nc: Netconn handle

void lwgsm_netconn_set_receive_timeout(lwgsm_netconn_p nc, uint32_t timeout)

Set timeout value for receiving data.

When enabled, lwgsm_netconn_receive will only block for up to timeout value and will return if no new data within this time

Parameters
  • [in] nc: Netconn handle

  • [in] timeout: Timeout in units of milliseconds. Set to 0 to disable timeout for lwgsm_netconn_receive function

uint32_t lwgsm_netconn_get_receive_timeout(lwgsm_netconn_p nc)

Get netconn receive timeout value.

Return

Timeout in units of milliseconds. If value is 0, timeout is disabled (wait forever)

Parameters
  • [in] nc: Netconn handle

lwgsmr_t lwgsm_netconn_write(lwgsm_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

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] nc: Netconn handle used to write data to

  • [in] data: Pointer to data to write

  • [in] btw: Number of bytes to write

lwgsmr_t lwgsm_netconn_flush(lwgsm_netconn_p nc)

Flush buffered data on netconn TCP/SSL connection.

Note

This function may only be used on TCP/SSL connection

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] nc: Netconn handle to flush data

lwgsmr_t lwgsm_netconn_send(lwgsm_netconn_p nc, const void *data, size_t btw)

Send data on UDP connection to default IP and port.

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] nc: Netconn handle used to send

  • [in] data: Pointer to data to write

  • [in] btw: Number of bytes to write

lwgsmr_t lwgsm_netconn_sendto(lwgsm_netconn_p nc, const lwgsm_ip_t *ip, lwgsm_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

Return

lwgsmOK on success, member of lwgsmr_t enumeration otherwise

Parameters
  • [in] nc: Netconn handle used to send

  • [in] ip: Pointer to IP address

  • [in] port: Port number used to send data

  • [in] data: Pointer to data to write

  • [in] btw: Number of bytes to write

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 GSM device.

Note

GSM device is connected with USB to UART converter only by RX and TX pins.

Device driver is located in /lwgsm/src/system/lwgsm_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

GSM settings

Debug settings

UART

MTX

MRX

RST

UART

MDTX

MDRX

STM32F429ZI-Nucleo

USART6

PC6

PC7

PC5

USART3

PD8

PD9

Pins to connect with GSM device:

  • MTX: MCU TX pin, connected to GSM RX pin

  • MRX: MCU RX pin, connected to GSM TX pin

  • RST: MCU output pin to control reset state of GSM device

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.

Tip

Do not forget to set PIN & PUK codes of your SIM card before running any of examples. Open /snippets/sim_manager.c and update pin_code and puk_code variables.

Device info

Simple example which prints basic device information:

  • Device Manufacturer

  • Device Model

  • Device serial number

  • Device revision number

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

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.

Call

Call example answers received call. If GSM device supports calls and has microphone/speaker connected to module itself, it can simply communicate over voice.

Call & SMS

This example shows how to receive a call and send reply with SMS. When application receives call, it hangs-up immediately and sends back SMS asking caller to send SMS instead.

When application receives SMS, it will send same SMS content back to the sender’s number.

SMS Send receive

It demonstrates sending and receiving SMS either in events or using thread processing.