Description
These are notes based on v1.0.3 of the library, summarizing its known limitations and setting out possible future improvements:
Internet Protocol Sockets: Write Socket Data
The SARA-R5 has two "write socket data" commands: +USOWR and +USOST.
+USOWR will work for both TCP and UDP connections, but +USOST is preferred for UDP.
+USOWR (socketWrite)
+USOWR supports three syntaxes: Base, Base HEX; and Binary Extended.
With Base syntax, some characters (like carriage return and line feed) are forbidden.
With Base HEX, the data is provided in hexadecimal format. The module converts it to binary before sending to the socket.
Base HEX needs to be enabled (configured) through +UDCONF=1. HEX mode is disabled by default. The library currently supports UDCONF=5/6/7/8 for Direct Link connections. It would be easy to add a setHEXModeConfiguration(bool enable)
function.
Base HEX doesn't seem to offer any significant advantage over Binary Extended - except there is no need to wait for the "@" before transferring the data.
I don't propose to add support for Base HEX.
socketWrite
is overloaded, you can provide the data as const char *
or String
:
SARA_R5_error_t socketWrite(int socket, const char *str);
SARA_R5_error_t socketWrite(int socket, String str);
The const char *
function cannot be used for binary data - especially because it uses strlen
to get the length of the data (any 0x0 bytes would cause that to fail). The String
function could be used for binary data, but the code currently converts the data to const char *
using .c_str()
(ref) and then passes it to the const char *
function which uses strlen
to determine the length...
In summary: socketWrite
does not currently support binary data.
Action: correct this! Add a len
parameter to socketWrite
so it can handle Binary Extended data correctly. Update the String
function so the length is passed correctly.
socketWrite(int socket, const char *data, int len = -1)
+USOST (socketWriteUDP)
For UDP sockets, there is no need to open the socket before writing to it.
The library provides support for writing data to UDP sockets with:
SARA_R5_error_t socketWriteUDP(int socket, const char *address, int port, const char *str, int len = -1);
SARA_R5_error_t socketWriteUDP(int socket, String address, int port, String str, int len = -1);
The String
function converts the data to const char *
using .c_str()
(ref) and then passes it to the const char *
function. This is OK for binary data as the length ( len
) is preserved. (The function does use strlen
to determine the length - but only if len
is -1. If the user provides len
, all is well.)
Internet Protocol Sockets: Read Socket Data
The SARA-R5 has two "write socket data" commands: +USORD and +USORF.
+USORF is for UDP connections only.
The library provides two ways to read the data: read functions and a (single) callback.
Socket Read Functions
The read functions are:
SARA_R5_error_t socketRead(int socket, int length, char *readDest);
SARA_R5_error_t socketReadUDP(int socket, int length, char *readDest);
socketRead
can be used to read data from UDP sockets, but socketReadUDP
is preferred.
socketRead
handles binary data correctly.
socketReadUDP
has some major limitations: the UDP remote IP address and port are lost.
I think we can solve the socketReadUDP
limitations - and maintain backward-compatibility - by changing it to:
SARA_R5_error_t socketReadUDP(int socket, int length, char *readDest, IPAddress *remoteIPAddress = NULL, int *remotePort = NULL);
Action: change the function and implement it nicely.
If the read length is set to zero, both +USORD and +USORF will return the total amount of data in the SARA's network buffer. The library does not currently support this. If len
is set to zero, Both socketRead
and socketReadUDP
will (I think) return SARA_R5_ERROR_UNEXPECTED_RESPONSE
as no quote will be found. This needs to be improved.
Action: Add additional functions / features to support requesting the buffer length.
Socket Read Callback
The callback is configured with setSocketReadCallback
:
void setSocketReadCallback(void (*socketReadCallback)(int, String));
int
is the socket. String
contains the data.
There are some major limitations here:
The same callback is used for TCP and UDP data. This is a major limitation as the UDP remote IP address and port are lost.
Going forward, I propose we provide a separate callback for UDP data.
For TCP:
The data is returned in a String. This is OK for binary data. The length can be determined correctly using the .length()
command. But it is not an elegant solution for binary data.
We could provide an extra set
function and an extra callback:
void setSocketReadCallback(void (*socketReadCallback)(int, const char *, int)); // socket, data, dataLength
where: int
is the socket, const char *
contains the data, int
is the length.
We would need to change processURCEvent
(specifically parseSocketReadIndication
) so it would know which of the two callbacks to call. But that would be easy to do. We'd just need to make sure that calling one set
function sets the callback pointer for the other to NULL. parseSocketReadIndication
would call the callback that isn't NULL.
Action: think more about this - then almost certainly implement it.
For UDP:
UDP needs its own callback. Action: add one!
void setSocketReadUDPCallback(void (*socketReadUDPCallback)(int, const char *, int, IPAddress, int)); // socket, data, dataLength, remoteIPAddress, remotePort
Note: this would break backward-compatibility for anyone currently using setSocketReadCallback
for UDP sockets. They won't get their data any more...
Or, even better - maintaining backward-compatibility - change the new extra set
function to:
void setSocketReadCallback(void (*socketReadCallback)(int, const char *, int, IPAddress, int)); // socket, data, dataLength, remoteIPAddress, remotePort
where: int
is the socket, const char *
contains the data, int
is the length. remoteIPAddress
and remotePort
would be set to zero for TCP. Users using the original setSocketReadCallback
for UDP sockets could still get their data (minus the remote address and port).
Action: think more about this - then almost certainly implement it.
+UUOST
processURCEvent
does not currently support the +UUOST URC - the UDP write result. It would be nice to add support for this, including a callback.
Action: think more about this - then almost certainly implement it.
Direct Link Mode
With:
SARA_R5_error_t socketDirectLinkMode(int socket);
SARA_R5_error_t socketDirectLinkTimeTrigger(int socket, unsigned long timerTrigger);
SARA_R5_error_t socketDirectLinkDataLengthTrigger(int socket, int dataLengthTrigger);
SARA_R5_error_t socketDirectLinkCharacterTrigger(int socket, int characterTrigger);
SARA_R5_error_t socketDirectLinkCongestionTimer(int socket, unsigned long congestionTimer);
I believe the library includes everything needed for direct link mode? Except, it might be nice to add a endSocketDirectLink()
function:
- Wait two seconds (in a thread-friendly way)
- Send +++
Action: think more about this.
+USOER
Socket errors are reported through +USOER. The library provides the socketGetLastError
function. No improvements necessary?
+USOCLCFG
Dormant sockets can be closed automatically through +USOCLCFG. The library does not currently support this command, but closing dormant sockets is enabled by default. It would be easy to add a setDormantSocketCloseBehaviour(bool enable)
function.
Action: think more about this - then almost certainly implement it.
+USOCTL
The library does not currently support for +USOCTL. It would be nice to add support so that the total amount of bytes transferred, socket type, remote IP address, socket status, etc. could be queried. To make it easy for the user, it would be best to provide multiple functions:
SARA_R5_error_t querySocketType(int socket, SARA_R5_socket_protocol_t *protocol)
SARA_R5_error_t querySocketLastError(int socket, int *error)
SARA_R5_error_t querySocketTotalBytesSent(int socket, uint32_t *total)
SARA_R5_error_t querySocketTotalBytesReceived(int socket, uint32_t *total)
SARA_R5_error_t querySocketRemoteIPAddress(int socket, IPAddress address, int *port)
SARA_R5_error_t querySocketRemoteIPAddress(int socket, String address, int *port)
SARA_R5_error_t querySocketRemoteIPAddress(int socket, char *address, int *port)
SARA_R5_error_t querySocketStatusTCP(int socket, int *status)
SARA_R5_error_t querySocketOutUnackData(int socket, uint32_t *total)
Action: think more about this - then almost certainly implement it.
Other improvements:
I'd like to try and standardize on using IPAddress for all IP address parameters. Action: Add IPAddress-based functions/overloads:
SARA_R5_error_t socketConnect(int socket, IPAddress address, int port);
SARA_R5_error_t socketWriteUDP(int socket, IPAddress address, int port, const char *str, int len = -1);
Action: think more about this - then almost certainly implement it.