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
5TCP connections active at the same timeUp to
5UDP connections active at the same timeUp to
1SSL 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
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
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.
-
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.
-
void *
lwgsm_conn_get_arg(lwgsm_conn_p conn)¶ Get user defined connection argument.
- Return
User argument
- See
- 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
1on success,0otherwise- 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
1on success,0otherwise- 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
1on success,0otherwise- 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
-
lwgsm_conn_p
lwgsm_conn_get_from_evt(lwgsm_evt_t *evt)¶ Get connection from connection based event.
- Return
Connection pointer on success,
NULLotherwise- 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 to1if 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
1on success,0otherwise- 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,
0otherwise- 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,
0otherwise- Parameters
[in] conn: Connection handle
-
typedef struct lwgsm_conn *