Skip to content

Commit

Permalink
Cellular feature addition: allow AT command delay to be overridden. (…
Browse files Browse the repository at this point in the history
…#1039)

For each cellular module, a minimum time from the OK or ERROR being received for one AT command to the start of the next AT command is set, range usually between 20 and 100 milliseconds. It is now possible to read and override this value with uCellAtCommandDelayGet(), uCellAtCommandDelaySet(), should you wish to optimize the speed of execution of AT commands in your product.

VERY IMPORTANT: THIS SHOULD BE DONE WITH GREAT CARE; a delay that is too short may lead to AT interface failures, commands being confused with one another, etc., and these issues may occur in random places, at random times, dependent upon the AT command that was just executed and, potentially, external factors (network searching, GNSS chip interaction, etc.). You should only reduce the value from the default if you have a good set of regression tests for your product solution that you can run to verify that a shortened delay does not introduce problems for the AT commands that you end up using, in the situations that you use them.
  • Loading branch information
RobMeades authored Nov 8, 2023
1 parent d54638d commit a12674d
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 4 deletions.
35 changes: 35 additions & 0 deletions cell/api/u_cell.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,41 @@ void uCellRemove(uDeviceHandle_t cellHandle);
int32_t uCellAtClientHandleGet(uDeviceHandle_t cellHandle,
uAtClientHandle_t *pAtHandle);

/** Get the delay between the end of one AT command and the
* start of the next AT command.
*
* @param cellHandle the handle of the cellular instance.
* @return on success the delay in milliseconds,
* else negative error code.
*/
int32_t uCellAtCommandDelayGet(uDeviceHandle_t cellHandle);

/** Set the delay between the end of one AT command and the
* start of the next AT command. A safe default value is
* set on a per-module basis but you may wish to optimise the
* speed of exchange of AT command in your product, your use-case.
* THIS SHOULD BE DONE WITH GREAT CARE; a delay that is too
* short may lead to AT interface failures, commands being
* confused with one another, etc., and these issues may occur
* in random places, at random times, dependent upon the AT
* command that was just executed and, potentially, external
* factors (network searching, GNSS chip interaction, etc.).
* You should only reduce the value from the default if you
* have a good set of regression tests for your product solution
* that you can run to verify that a shortened delay does not
* introduce problems for the AT commands that you end up using
* in the situations that you use them.
*
* @param cellHandle the handle of the cellular instance.
* @param delayMs the minimum time from "OK" or "ERROR"
* being received for one AT command to
* the next AT command being issued.
* @return zero on success, else negative error
* code.
*/
int32_t uCellAtCommandDelaySet(uDeviceHandle_t cellHandle,
int32_t delayMs);

#ifdef __cplusplus
}
#endif
Expand Down
47 changes: 46 additions & 1 deletion cell/src/u_cell.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ int32_t uCellAdd(uCellModuleType_t moduleType,
uAtClientTimeoutSet(atHandle,
pInstance->pModule->atTimeoutSeconds * 1000);
uAtClientDelaySet(atHandle,
pInstance->pModule->commandDelayMs);
pInstance->pModule->commandDelayDefaultMs);
#ifndef U_CFG_CELL_DISABLE_UART_POWER_SAVING
// Here we set the power-saving wake-up handler but note
// that this might be _removed_ during the power-on
Expand Down Expand Up @@ -485,4 +485,49 @@ int32_t uCellAtClientHandleGet(uDeviceHandle_t cellHandle,
return errorCode;
}

// Get the inter-AT command delay.
int32_t uCellAtCommandDelayGet(uDeviceHandle_t cellHandle)
{
int32_t errorCodeOrDelayMs = (int32_t) U_ERROR_COMMON_NOT_INITIALISED;
uCellPrivateInstance_t *pInstance;

if (gUCellPrivateMutex != NULL) {

U_PORT_MUTEX_LOCK(gUCellPrivateMutex);

errorCodeOrDelayMs = (int32_t) U_ERROR_COMMON_INVALID_PARAMETER;
pInstance = pUCellPrivateGetInstance(cellHandle);
if (pInstance != NULL) {
errorCodeOrDelayMs = uAtClientDelayGet(pInstance->atHandle);
}

U_PORT_MUTEX_UNLOCK(gUCellPrivateMutex);
}

return errorCodeOrDelayMs;
}

// Set the inter-AT command delay.
int32_t uCellAtCommandDelaySet(uDeviceHandle_t cellHandle, int32_t delayMs)
{
int32_t errorCode = (int32_t) U_ERROR_COMMON_NOT_INITIALISED;
uCellPrivateInstance_t *pInstance;

if (gUCellPrivateMutex != NULL) {

U_PORT_MUTEX_LOCK(gUCellPrivateMutex);

errorCode = (int32_t) U_ERROR_COMMON_INVALID_PARAMETER;
pInstance = pUCellPrivateGetInstance(cellHandle);
if ((pInstance != NULL) && (delayMs >= 0)) {
uAtClientDelaySet(pInstance->atHandle, delayMs);
errorCode = (int32_t) U_ERROR_COMMON_SUCCESS;
}

U_PORT_MUTEX_UNLOCK(gUCellPrivateMutex);
}

return errorCode;
}

// End of file
6 changes: 3 additions & 3 deletions cell/src/u_cell_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,9 @@ typedef struct {
int32_t atTimeoutSeconds; /**< The time to wait for completion of an
AT command, i.e. from sending ATblah to
receiving OK or ERROR back. */
int32_t commandDelayMs; /**< How long to wait between the end of
one AT command and the start of the
next. */
int32_t commandDelayDefaultMs; /**< How long to wait between the end of
one AT command and the start of the
next, default value. */
int32_t responseMaxWaitMs; /**< The maximum response time one can
expect from the cellular module.
This is usually quite large since,
Expand Down
34 changes: 34 additions & 0 deletions cell/test/u_cell_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,13 @@ U_PORT_TEST_FUNCTION("[cell]", "cellAdd")
# if (U_CFG_TEST_UART_B >= 0)
uAtClientHandle_t atClientHandleB;
uDeviceHandle_t devHandleB;
int32_t y;
# endif
uDeviceHandle_t dummyHandle;
uAtClientHandle_t atClientHandle = NULL;
int32_t resourceCount;
int32_t errorCode;
int32_t x;

// Whatever called us likely initialised the
// port so deinitialise it here to obtain the
Expand Down Expand Up @@ -167,6 +169,20 @@ U_PORT_TEST_FUNCTION("[cell]", "cellAdd")
&atClientHandle) == 0);
U_PORT_TEST_ASSERT(atClientHandle == atClientHandleA);

// Check that we can get and set the inter-AT command delay
// of this cellular instance
x = uCellAtCommandDelayGet(devHandleA);
U_TEST_PRINT_LINE("inter AT-command delay is %d ms.", x);
U_PORT_TEST_ASSERT(x >= 0);
x++;
errorCode = uCellAtCommandDelaySet(devHandleA, x);
U_PORT_TEST_ASSERT(errorCode == (int32_t) U_ERROR_COMMON_SUCCESS);
errorCode = uCellAtCommandDelayGet(devHandleA);
U_TEST_PRINT_LINE("inter AT-command delay is now %d ms.", errorCode);
U_PORT_TEST_ASSERT(errorCode == x);
x--;
U_PORT_TEST_ASSERT(uCellAtCommandDelaySet(devHandleA, x) == 0);

U_TEST_PRINT_LINE("adding another instance on the same AT client, should fail...");
U_PORT_TEST_ASSERT(uCellAdd(U_CELL_MODULE_TYPE_SARA_U201, atClientHandleA,
-1, -1, -1, false, &dummyHandle) < 0);
Expand Down Expand Up @@ -203,6 +219,24 @@ U_PORT_TEST_FUNCTION("[cell]", "cellAdd")
U_PORT_TEST_ASSERT(uCellAdd(U_CELL_MODULE_TYPE_SARA_R5, atClientHandleB,
-1, -1, -1, false, &dummyHandle) < 0);

// Check that we can get and set the inter-AT command delay
// of this cellular instance without affecting the other
y = uCellAtCommandDelayGet(devHandleA);
U_PORT_TEST_ASSERT(y >= 0);
x = uCellAtCommandDelayGet(devHandleB);
U_TEST_PRINT_LINE("inter AT-command delay is %d ms.", x);
U_PORT_TEST_ASSERT(x >= 0);
x++;
errorCode = uCellAtCommandDelaySet(devHandleB, x);
U_PORT_TEST_ASSERT(errorCode == (int32_t) U_ERROR_COMMON_SUCCESS);
errorCode = uCellAtCommandDelayGet(devHandleB);
U_TEST_PRINT_LINE("inter AT-command delay is now %d ms.", errorCode);
U_PORT_TEST_ASSERT(errorCode == x);
errorCode = uCellAtCommandDelayGet(devHandleA);
U_PORT_TEST_ASSERT(errorCode == y);
x--;
U_PORT_TEST_ASSERT(uCellAtCommandDelaySet(devHandleB, x) == 0);

// Don't remove this one, let uCellDeinit() do it
# endif

Expand Down

0 comments on commit a12674d

Please sign in to comment.