diff --git a/DEVELOPMENT_PRINCIPLES.md b/DEVELOPMENT_PRINCIPLES.md index 6d7a6c07..a4c8179f 100644 --- a/DEVELOPMENT_PRINCIPLES.md +++ b/DEVELOPMENT_PRINCIPLES.md @@ -72,9 +72,9 @@ The only exception to the above is when there has been active work on the `ubxli As an aside, if `master` moves on underneath a branch **THAT YOU ALONE** are working on, please do a `rebase` of that development branch onto `master`, rather then merging the changes from `master` onto your branch, (i.e. checkout `master` locally, pull the latest `master` and then `rebase` your branch onto `master`); the reason for this is that, otherwise, the merge process can be confused and end up thinking that you intend to remove things that have just been added in the `master` branch. If you share the branch with someone else, i.e. you are not working on it alone, then take care because rebasing obviously changes history; it may still be the right thing to do, 'cos the ground has indeed moved underneath you, history _has_ changed, but make sure that anyone else who is working on the branch with you is aware of what you have done when you push the branch back to the repo. # Beware The Wrap -Embedded systems usually have no better than a 32 bit millisecond tick count, i.e. a signed 32 bit counter that will wrap at `INT32_MAX`, so modulo 2^31, or 2,147,483,648, or about 25 days; the return value of the port layer `uPortGetTickTimeMs()` is an `int32_t` for this reason. +Embedded systems usually have no better than a 32 bit millisecond tick count, i.e. a 32 bit counter that will wrap at 2^32 - 1, or 4,294,967,295, or about 50 days (25 days if treated as signed); the return value of the port layer `uPortGetTickTimeMs()` is a 32-bit integer for this reason. -The systems that `ubxlib` is built into will need to be up for longer than 25 days, so the `ubxlib` code must behave well around such a wrap and, specifically, not unintentionally become stuck for 25 days if the tick counter happens to wrap while the code is waiting on it. Always use the `uPortTickTimeExpiredMs()` or `uPortTickTimeBeyondStopMs()` functions (see [u_port.h](/port/api/u_port.h)) while waiting for a number of ticks to pass; these are designed to ensure that nothing will get stuck. +The systems that `ubxlib` is built into will need to be up for longer than 50 days, so the `ubxlib` code must behave well around such a wrap and, specifically, not unintentionally become stuck for 50 days if the tick counter happens to wrap while the code is waiting on it. For any timeouts or delays, **always** use the [uTimeout](/common/timeout/api/u_timeout.h) API, which defines an "anonymous" `uTimeoutStart_t` structure that can be populated with a call to `uTimeoutStart()` and then checked with the `uTimeoutExpiredMs()` or the `uTimeoutExpiredSeconds()` functions; these are designed to ensure that nothing will get stuck. # Be Explicit About Units Where a number represents a quantity it will have a unit: seconds, milliseconds, nanoseconds, Volts, milliVolts, decibels, decibels relative to one milliWatt (dBm), words (as opposed to bytes), sheep, etc. You may recall the tale of the [Mars Climate Orbiter](https://en.wikipedia.org/wiki/Mars_Climate_Orbiter), a $327 million spacecraft that was lost because the NASA navigation software expected measurements in newton-seconds while their contractor was providing measurements in pound-force seconds, a factor of 4.5 different; where a number represents a quantity, **be explicit** about the unit by including it in the variable/parameter name. For instance, presented with a variable/parameter named `timeout`, you could get things wrong by three orders of magnitude or more when applying that parameter, without realising it; naming it something like `timeoutMs` or `timeoutSeconds` will make the intended usage clear. \ No newline at end of file diff --git a/ble/api/u_ble_gap.h b/ble/api/u_ble_gap.h index 93933a79..3467a25f 100644 --- a/ble/api/u_ble_gap.h +++ b/ble/api/u_ble_gap.h @@ -79,6 +79,39 @@ extern "C" { #define U_BT_LE_AD_GENERAL 0x02 /**< General Discoverable */ #define U_BT_LE_AD_NO_BREDR 0x04 /**< BR/EDR not supported */ +/** BLE radio modes (PHY) */ +#define U_BT_LE_PHY_DONT_CARE 0 /**< Let other side decide */ +#define U_BT_LE_PHY_1_MPBS 1 /**< 1 Mbps */ +#define U_BT_LE_PHY_2_MBPS 2 /**< 2 Mbps */ +#define U_BT_LE_PHY_CODED 4 /**< Coded PHY (when supported by the module) */ + +/** BLE device I/O capabilities for bonding */ +#define U_BT_LE_IO_NONE 0 /**< No input and no output */ +#define U_BT_LE_IO_DISP_ONLY 1 /**< Display only */ +#define U_BT_LE_IO_DISP_YES_NO 2 /**< Display yes/no */ +#define U_BT_LE_IO_KEYB_ONLY 3 /**< Keyboard only */ +#define U_BT_LE_IO_KEYB_DISP 4 /**< Keyboard and display */ + +/** BLE bonding security modes */ +#define U_BT_LE_BOND_NO_SEC 0 /**< Security disabled */ +#define U_BT_LE_BOND_UNAUTH 1 /**< Allow unauthenticated bonding (Just Works) */ +#define U_BT_LE_BOND_AUTH 2 /**< Only allow authenticated bonding */ +#define U_BT_LE_BOND_AUTH_ENCR 3 /**< Only allow authenticated bonding with + encrypted Bluetooth link. Fallback to + simple bonding if the remote side does not + support secure connections */ +#define U_BT_LE_BOND_STRICT 4 /**< Only allow authenticated bonding with encrypted + Bluetooth link. Strictly uses secure connections */ + +/** BLE bonding error codes */ +#define U_BT_LE_BOND_ERR_SUCCESS 0 /**< Bonding procedure succeeded */ +#define U_BT_LE_BOND_ERR_TIMEOUT 1 /**< Bonding procedure failed due to timeout */ +#define U_BT_LE_BOND_ERR_FAILED 2 /**< Bonding failed because of authentication or + pairing failed. */ +#define U_BT_LE_BOND_ERR_WEAK 3 /**< Bonding failed because the protection against + Man-In-The-Middle attack could not be guaranteed, + the generated link key was too weak */ + #define U_SHORT_RANGE_BT_ADDRESS_SIZE 14 /* ---------------------------------------------------------------- @@ -112,7 +145,7 @@ typedef struct { typedef bool (*uBleGapScanCallback_t)(uBleScanResult_t *pScanResult); /** Connect/disconnect callback for central and peripheral. - * @param[in] connHandle connection handle identifying the peer. + * @param connHandle connection handle identifying the peer. * Must later be used for uBleGapDisconnect and * in subsequent call to related gatt functions. * @param[in] pAddress peer address. @@ -123,33 +156,155 @@ typedef void (*uBleGapConnectCallback_t)(int32_t connHandle, char *pAddress, boo /** BLE advertisement configuration parameters. */ typedef struct { - uint32_t minIntervalMs; /**< Advertising interval minimum in ms */ - uint32_t maxIntervalMs; /**< Advertising interval maximum in ms */ - bool connectable; /**< Peripheral connectable */ - uint8_t maxClients; /**< Maximum number of connected clients */ - uint8_t *pAdvData; /**< Advertisement data */ - uint8_t advDataLength; /**< Advertisement data size */ - uint8_t *pRespData; /**< Advertisement response data */ - uint8_t respDataLength; /**< Advertisement response data size */ + uint32_t minIntervalMs; /**< Advertising interval minimum in ms. */ + uint32_t maxIntervalMs; /**< Advertising interval maximum in ms. */ + bool connectable; /**< Peripheral connectable. */ + uint8_t maxClients; /**< Maximum number of connected clients. */ + uint8_t *pAdvData; /**< Advertisement data. */ + uint8_t advDataLength; /**< Advertisement data size. */ + uint8_t *pRespData; /**< Advertisement response data. */ + uint8_t respDataLength; /**< Advertisement response data size. */ } uBleGapAdvConfig_t; +/** BLE connection configuration settings. +*/ +typedef struct { + uint16_t scanIntervalMs; /**< Scan interval in ms. */ + uint16_t scanWindowMs; /**< Scan window in ms. */ + uint32_t connCreateTimeoutMs; /**< Timeout for connection in ms. */ + uint16_t connIntervalMinMs; /**< Connection interval minimum in ms. */ + uint16_t connIntervalMaxMs; /**< Connection interval maximum in ms. */ + uint16_t connLatency; /**< Connection peripheral latency. */ + uint32_t linkLossTimeoutMs; /**< Connection link loss timeout in ms. */ + uint16_t preferredTxPhy; /**< Preferred transmitter PHY. */ + uint16_t preferredRxPhy; /**< Preferred receiver PHY. */ +} uBleGapConnectConfig_t; + +/** PHY update callback, the result of a call to uBleGapRequestPhyChange(). + * @param connHandle connection handle identifying the peer. + * @param status Bluetooth status code. + * @param txPhy transmitter PHY. + * @param rxPhy receiver PHY. + */ +typedef void (*uBleGapPhyUpdateCallback_t)(int32_t connHandle, int32_t status, + int32_t txPhy, int32_t rxPhy); + +/** Bonding callback when I/O capability set to #U_BT_LE_IO_DISP_YES_NO. + * Confirm or deny by calling uBleGapBondConfirm(). + * @param[in] pAddress mac address of the bonding remote. + * @param numericValue numeric value to confirm. + */ +typedef void (*uBleGapBondConfirmCallback_t)(const char *pAddress, int32_t numericValue); + +/** Bonding callback when I/O capability set to #U_BT_LE_IO_KEYB_ONLY. + * The passkey show on the remote device must be returned by calling uBleGapBondEnterPasskey(). + * @param[in] pAddress mac address of the bonding remote. + */ +typedef void (*uBleGapBondPasskeyRequestCallback_t)(const char *pAddress); + +/** Bonding callback when I/O capability set to #U_BT_LE_IO_DISP_ONLY. + * The passkey provided must be entered on the remote device. + * @param[in] pAddress mac address of the bonding remote. + * @param passkey passkey to be shown. + */ +typedef void (*uBleGapBondPasskeyEntryCallback_t)(const char *pAddress, int32_t passkey); + +/** Callback indicating the completion result of a bonding started by uBleGapBond(). + * @param[in] pAddress mac address of the bonding remote. + * @param status value from one of the U_BT_LE_BOND_ERR_x constants. + */ +typedef void (*uBleGapBondCompleteCallback_t)(const char *pAddress, int32_t status); + /* ---------------------------------------------------------------- * FUNCTIONS * -------------------------------------------------------------- */ /** Get the mac address of the BLE device. * - * @param[in] devHandle the handle of the u-blox BLE device. + * @param devHandle the handle of the u-blox BLE device. * @param[out] pMac pointer to a string for the address. * Must at least be of size #U_SHORT_RANGE_BT_ADDRESS_SIZE * @return zero on success, on failure negative error code. */ int32_t uBleGapGetMac(uDeviceHandle_t devHandle, char *pMac); +/** Enable or disable pairing mode. The default mode if this function is not called + * is that the the device is pairable. + * + * @param devHandle the handle of the u-blox BLE device. + * @param isPairable set to true to enable pairing. + * @return zero on success, on failure negative error code. + */ +int32_t uBleGapSetPairable(uDeviceHandle_t devHandle, bool isPairable); + +/** Configure bonding security. If this function is not called before any bonding attempts + * the security level will be "Security disabled". + * + * @param devHandle the handle of the u-blox BLE device. + * @param ioCapabilities current device I/O capabilities. + * @param bondSecurity bonding security level. + * @param[in] confirmCb function to be called when bonding requires confirmation. + * Can be set to NULL when not applicable. + * @param[in] passKeyRequestCb function to be called when bonding requires passkey entry + * on the remote.device. Can be set to NULL when not applicable. + * @param[in] passKeyEntryCb function to be called when bonding requires passkey entry + * from the local device. Can be set to NULL when not applicable. + * @return zero on success, on failure negative error code. + */ +int32_t uBleSetBondParameters(uDeviceHandle_t devHandle, + int32_t ioCapabilities, + int32_t bondSecurity, + uBleGapBondConfirmCallback_t confirmCb, + uBleGapBondPasskeyRequestCallback_t passKeyRequestCb, + uBleGapBondPasskeyEntryCallback_t passKeyEntryCb); + +/** Request bonding with a peripheral when in central mode. + * + * @param devHandle the handle of the u-blox BLE device. + * @param[in] pAddress mac address of the peripheral. + * @param[in] cb callback when bonding has completed. + * @return zero on success, on failure negative error code. + */ +int32_t uBleGapBond(uDeviceHandle_t devHandle, const char *pAddress, + uBleGapBondCompleteCallback_t cb); + +/** Remove bonding from this device. + * + * @param devHandle the handle of the u-blox BLE device. + * @param[in] pAddress mac address of the bonded device, + * can be set to NULL to remove all bonded devices. + * @return zero on success, on failure negative error code. + */ +int32_t uBleGapRemoveBond(uDeviceHandle_t devHandle, const char *pAddress); + +/** Confirm or deny bonding from a central. This function shoule be called after that the + * function "yesNoCallback" earlier specified in uBleSetBondParameters() has been called + * (and only then). + * + * @param devHandle the handle of the u-blox BLE device. + * @param confirm set to true to confirm or false to deny. + * @param[in] pAddress mac address of the central requesting a bond. + * @return zero on success, on failure negative error code. + */ +int32_t uBleGapBondConfirm(uDeviceHandle_t devHandle, bool confirm, const char *pAddress); + +/** Confirm or deny bonding by specifying a passkey. This function should be called after + * that the function "confirmCb" earlier specified in uBleSetBondParameters() has been + * called (and only then). + * + * @param devHandle the handle of the u-blox BLE device. + * @param confirm set to true to confirm or false to deny. + * @param[in] pAddress mac address of the central requesting a bond. + * @param passkey passkey used to confirm bonding, ignored if confirm is false. + * @return zero on success, on failure negative error code. + */ +int32_t uBleGapBondEnterPasskey(uDeviceHandle_t devHandle, bool confirm, + const char *pAddress, int32_t passkey); + /** Set callback for connection events. These can occur both when in central and * peripheral mode. * - * @param[in] devHandle the handle of the u-blox BLE device. + * @param devHandle the handle of the u-blox BLE device. * @param[in] cb the callback routine, set to NULL to remove the callback. * @return zero on success, on failure negative error code. */ @@ -162,61 +317,78 @@ int32_t uBleGapSetConnectCallback(uDeviceHandle_t devHandle, uBleGapConnectCallb * can be performed in the callback. * Requires the BLE device to be in central mode. * - * @param[in] devHandle the handle of the u-blox BLE device. - * @param[in] discType type of scan to perform. - * @param[in] activeScan active or passive scan. - * @param[in] timeousMs total time interval in milliseconds used for the scan. + * @param devHandle the handle of the u-blox BLE device. + * @param discType type of scan to perform. + * @param activeScan active or passive scan. + * @param timeousMs total time interval in milliseconds used for the scan. * @param[in] cb a callback routine for the found devices. * @return zero on success, on failure negative error code. */ -int32_t uBleGapScan(uDeviceHandle_t devHandle, - uBleGapDiscoveryType_t discType, - bool activeScan, - uint32_t timeousMs, - uBleGapScanCallback_t cb); +int32_t uBleGapScan(uDeviceHandle_t devHandle, uBleGapDiscoveryType_t discType, bool activeScan, + uint32_t timeousMs, uBleGapScanCallback_t cb); + +/** Set the connection configuration parameters to be used for the next call to uBleGapConnect. + * If not called then the module's default ones will be used. + * + * @param devHandle the handle of the u-blox BLE device. + * @param[in] pConfig connection configuration parameters. + * @return zero on success, on failure negative error code. + */ +int32_t uBleGapSetConnectParams(uDeviceHandle_t devHandle, uBleGapConnectConfig_t *pConfig); /** Try connecting to another peripheral BLE device. * If a connection callback has been set via uBleGapSetConnectCallback() then * this will be called when the connection has been completed. * Requires the BLE device to be in central mode. * - * @param[in] devHandle the handle of the u-blox BLE device. + * @param devHandle the handle of the u-blox BLE device. * @param[in] pAddress mac address of the peripheral. * @return zero on success, on failure negative error code. */ int32_t uBleGapConnect(uDeviceHandle_t devHandle, const char *pAddress); +/** Request a new PHY configuration for an existing BLE connection. + * + * @param devHandle the handle of the u-blox BLE device. + * @param connHandle the connection handle received when connection was made. + * @param txPhy transmitter PHY. + * @param rxPhy receiver PHY. + * @param[in] cb callback for the result of the request. + * @return zero on success, on failure negative error code. + */ +int32_t uBleGapRequestPhyChange(uDeviceHandle_t devHandle, int32_t connHandle, + int32_t txPhy, int32_t rxPhy, uBleGapPhyUpdateCallback_t cb); + /** Start to disconnect a connected peripheral BLE device. * If a connection callback has been set via uBleGapSetConnectCallback() then * this will be called when the devices have completed the disconnect. * - * @param[in] devHandle the handle of the u-blox BLE device. - * @param[in] connHandle the connection handle received when connection was made. + * @param devHandle the handle of the u-blox BLE device. + * @param connHandle the connection handle received when connection was made. * @return zero on success, on failure negative error code. */ int32_t uBleGapDisconnect(uDeviceHandle_t devHandle, int32_t connHandle); /** Convenience routine for creating advertisement data with a full name - * or manufacturer data or both. This data can then be used for uBleGapAdvertiseStart. + * or manufacturer data or both. This data can then be used for uBleGapAdvertiseStart(). * Set possible unused parameter to NULL. * * @param[in] pName name string, or NULL. * @param[in] pManufData pointer to manufacturer data or NULL. - * @param[in] manufDataSize size of manufacturer data. + * @param manufDataSize size of manufacturer data. * @param[out] pAdvData pointer to advertisement storage. - * @param[in] advDataSize max size of the advertisement storage. + * @param advDataSize max size of the advertisement storage. * @return size of the created package, on failure negative error code. */ -int32_t uBleGapSetAdvData(const char *pName, - const uint8_t *pManufData, uint8_t manufDataSize, +int32_t uBleGapSetAdvData(const char *pName, const uint8_t *pManufData, uint8_t manufDataSize, uint8_t *pAdvData, uint8_t advDataSize); /** Start BLE advertisement using the the specified configuration. * Requires the BLE device to be in peripheral mode. * If the device is set to connectable and a connection callback has been set - * via uBleGapSetConnectCallback, then this will be called if a central connects. + * via uBleGapSetConnectCallback(), then this will be called if a central connects. * - * @param[in] devHandle the handle of the u-blox BLE device. + * @param devHandle the handle of the u-blox BLE device. * @param[in] pConfig advertisement configuration. * @return zero on success, on failure negative error code. */ @@ -224,14 +396,14 @@ int32_t uBleGapAdvertiseStart(uDeviceHandle_t devHandle, const uBleGapAdvConfig_ /** Stop ongoing BLE advertisement. * - * @param[in] devHandle the handle of the u-blox BLE device. + * @param devHandle the handle of the u-blox BLE device. * @return zero on success, on failure negative error code. */ int32_t uBleGapAdvertiseStop(uDeviceHandle_t devHandle); /** Reset all GAP settings on the BLE device to factory values. * - * @param[in] devHandle the handle of the u-blox BLE device. + * @param devHandle the handle of the u-blox BLE device. * @return zero on success, on failure negative error code. */ int32_t uBleGapReset(uDeviceHandle_t devHandle); diff --git a/ble/src/gen2/u_ble_cfg_extmod.c b/ble/src/gen2/u_ble_cfg_extmod.c index 38529260..8c9098e3 100644 --- a/ble/src/gen2/u_ble_cfg_extmod.c +++ b/ble/src/gen2/u_ble_cfg_extmod.c @@ -40,6 +40,8 @@ #include "u_cfg_sw.h" #include "u_port_os.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_short_range_module_type.h" diff --git a/ble/src/gen2/u_ble_gap_extmod.c b/ble/src/gen2/u_ble_gap_extmod.c index 7ad29ccf..49397ded 100644 --- a/ble/src/gen2/u_ble_gap_extmod.c +++ b/ble/src/gen2/u_ble_gap_extmod.c @@ -37,6 +37,7 @@ #include "stdlib.h" // strol(), atoi(), strol(), strtof() #include "string.h" // memset(), strncpy(), strtok_r(), strtol() #include "u_error_common.h" +#include "u_timeout.h" #include "u_at_client.h" #include "u_ble.h" #include "u_ble_cfg.h" diff --git a/ble/src/gen2/u_ble_gatt_extmod.c b/ble/src/gen2/u_ble_gatt_extmod.c index 6a84a878..cacfed6a 100644 --- a/ble/src/gen2/u_ble_gatt_extmod.c +++ b/ble/src/gen2/u_ble_gatt_extmod.c @@ -37,6 +37,7 @@ #include "stdlib.h" // strol(), atoi(), strol(), strtof() #include "string.h" // memset(), strncpy(), strtok_r(), strtol() #include "u_error_common.h" +#include "u_timeout.h" #include "u_at_client.h" #include "u_ble.h" #include "u_ble_cfg.h" diff --git a/ble/src/gen2/u_ble_sps_extmod.c b/ble/src/gen2/u_ble_sps_extmod.c index 43272431..96099100 100644 --- a/ble/src/gen2/u_ble_sps_extmod.c +++ b/ble/src/gen2/u_ble_sps_extmod.c @@ -45,6 +45,7 @@ #include "u_port_event_queue.h" #include "u_cfg_os_platform_specific.h" +#include "u_timeout.h" #include "u_at_client.h" #include "u_ble_sps.h" #include "u_ble_private.h" diff --git a/ble/src/u_ble_cfg_extmod.c b/ble/src/u_ble_cfg_extmod.c index b79dd7ba..8718f3b6 100644 --- a/ble/src/u_ble_cfg_extmod.c +++ b/ble/src/u_ble_cfg_extmod.c @@ -40,6 +40,8 @@ #include "u_cfg_sw.h" #include "u_port_os.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_short_range_module_type.h" diff --git a/ble/src/u_ble_gap_extmod.c b/ble/src/u_ble_gap_extmod.c index 407f2c7d..3d3f4dd1 100644 --- a/ble/src/u_ble_gap_extmod.c +++ b/ble/src/u_ble_gap_extmod.c @@ -37,6 +37,7 @@ #include "stdlib.h" // strol(), atoi(), strol(), strtof() #include "string.h" // memset(), strncpy(), strtok_r(), strtol() #include "u_error_common.h" +#include "u_timeout.h" #include "u_at_client.h" #include "u_ble.h" #include "u_ble_cfg.h" diff --git a/ble/src/u_ble_gatt_extmod.c b/ble/src/u_ble_gatt_extmod.c index d8f90138..a7dcef00 100644 --- a/ble/src/u_ble_gatt_extmod.c +++ b/ble/src/u_ble_gatt_extmod.c @@ -37,6 +37,7 @@ #include "stdlib.h" // strol(), atoi(), strol(), strtof() #include "string.h" // memset(), strncpy(), strtok_r(), strtol() #include "u_error_common.h" +#include "u_timeout.h" #include "u_at_client.h" #include "u_ble.h" #include "u_ble_cfg.h" diff --git a/ble/src/u_ble_nus.c b/ble/src/u_ble_nus.c index f8817b92..dd62c88e 100644 --- a/ble/src/u_ble_nus.c +++ b/ble/src/u_ble_nus.c @@ -37,6 +37,7 @@ #include "stdlib.h" // strol(), atoi(), strol(), strtof() #include "string.h" // memset(), strncpy(), strtok_r(), strtol() #include "u_error_common.h" +#include "u_timeout.h" #include "u_at_client.h" #include "u_ble.h" #include "u_ble_cfg.h" diff --git a/ble/src/u_ble_sps_extmod.c b/ble/src/u_ble_sps_extmod.c index a2085085..a7803d7c 100644 --- a/ble/src/u_ble_sps_extmod.c +++ b/ble/src/u_ble_sps_extmod.c @@ -45,6 +45,7 @@ #include "u_port_event_queue.h" #include "u_cfg_os_platform_specific.h" +#include "u_timeout.h" #include "u_at_client.h" #include "u_ble_sps.h" #include "u_ble_private.h" diff --git a/ble/src/u_ble_sps_intmod.c b/ble/src/u_ble_sps_intmod.c index 32a7ae71..bbbae788 100644 --- a/ble/src/u_ble_sps_intmod.c +++ b/ble/src/u_ble_sps_intmod.c @@ -39,6 +39,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_device_shared.h" #include "u_cfg_sw.h" @@ -1240,7 +1242,7 @@ int32_t uBleSpsSend(uDeviceHandle_t devHandle, int32_t channel, const char *pDat int32_t time = startTime; // Note: this loop is constructed slightly differently to usual - // and so can't use uPortTickTimeExpiredMs() but it + // and so can't use uTimeoutExpiredMs() but it // _does_ perform tick time comparisons in a wrap-safe manner while ((bytesLeftToSend > 0) && (time - startTimeMs < timeout)) { int32_t bytesToSendNow = bytesLeftToSend; diff --git a/ble/test/u_ble_bond_test.c b/ble/test/u_ble_bond_test.c new file mode 100644 index 00000000..0e8235c7 --- /dev/null +++ b/ble/test/u_ble_bond_test.c @@ -0,0 +1,574 @@ +/* + * Copyright 2024 u-blox + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Only #includes of u_* and the C standard library are allowed here, + * no platform stuff and no OS stuff. Anything required from + * the platform/OS must be brought in through u_port* to maintain + * portability. + */ + +/** @file + * @brief Tests for the BLE bonding API: these should pass on all + * platforms where two UARTs are available. + * IMPORTANT: Please note that two modules are required for this test. + * This means that it can only run by default on a host which have the feature + * short_range_gen2 enabled. However it is also possible to run this test with + * modules which have the older version of u-connectXpress but it requires some + * trickery, se more below and in this case the test can only be executed on + * Windows or Linux. + * IMPORTANT: see notes in u_cfg_test_platform_specific.h for the + * naming rules that must be followed when using the U_PORT_TEST_FUNCTION() + * macro. + */ +#ifdef U_CFG_OVERRIDE +#include "u_cfg_override.h" // For a customer's configuration override +#endif + +#include "stdint.h" // int32_t etc. +#include "stddef.h" +#include "stdbool.h" +#include "string.h" +#include "stdlib.h" +#ifdef __linux__ +# include "unistd.h" +#endif + +// Must always be included before u_short_range_test_selector.h +// lint -efile(766, u_ble_module_type.h) +#include "u_ble_module_type.h" +#include "u_short_range_test_selector.h" + +#include "u_cfg_sw.h" +#include "u_cfg_app_platform_specific.h" +#include "u_cfg_test_platform_specific.h" + +#include "u_error_common.h" + +#include "u_port.h" +#include "u_port_debug.h" +#include "u_port_os.h" +#include "u_port_uart.h" + +#include "u_test_util_resource_check.h" + +#include "u_timeout.h" + +#include "u_at_client.h" +#include "u_short_range_pbuf.h" +#include "u_short_range.h" +#include "u_short_range_cfg.h" +#include "u_short_range_private.h" + +#include "u_network.h" +#include "u_network_config_ble.h" + +#include "u_ble_cfg.h" +#include "u_ble.h" +#include "u_ble_gap.h" +#include "u_port_named_pipe.h" + +#if U_SHORT_RANGE_TEST_BLE() && \ + defined(U_CFG_TEST_SHORT_RANGE_MODULE_TYPE) && \ + defined(U_CFG_APP_SHORT_RANGE_UART2) + +/* ---------------------------------------------------------------- + * COMPILE-TIME MACROS + * -------------------------------------------------------------- */ + +/** The string to put at the start of all prints from this test. + */ +#define U_TEST_PREFIX "U_BLE_BOND_TEST" + +/** Print a whole line, with terminator, prefixed for this test file. + */ +#define U_TEST_PRINT_LINE(format, ...) uPortLog("%s" format "\n", gTestPrefix, ##__VA_ARGS__) + +/* Second module uart definitions */ +#ifndef U_CFG_APP_PIN_SHORT_RANGE_TXD2 +# define U_CFG_APP_PIN_SHORT_RANGE_TXD2 -1 +#endif + +#ifndef U_CFG_APP_PIN_SHORT_RANGE_RXD2 +# define U_CFG_APP_PIN_SHORT_RANGE_RXD2 -1 +#endif + +#ifndef U_CFG_APP_PIN_SHORT_RANGE_CTS2 +# define U_CFG_APP_PIN_SHORT_RANGE_CTS2 -1 +#endif + +#ifndef U_CFG_APP_PIN_SHORT_RANGE_RTS2 +# define U_CFG_APP_PIN_SHORT_RANGE_RTS2 -1 +#endif + +#ifndef U_CFG_TEST_SHORT_RANGE_MODULE_TYPE2 +# define U_CFG_TEST_SHORT_RANGE_MODULE_TYPE2 U_CFG_TEST_SHORT_RANGE_MODULE_TYPE +#endif + +#define PIPE_NAME "ubx_ble_bond_test" + +// Command handling when running in separate program instances +#define CMD_SETPARAM_FORM "%d,%d,%d,%d" +#define CMD_SETPARAM 0 +#define CMD_RESP_MAC 1 +#define CMD_INIT_MAC 2 +#define CMD_ENTER_PASS 3 +#define CMD_REM_BOND 4 +#define CMD_EXIT 5 + +/* ---------------------------------------------------------------- + * TYPES + * -------------------------------------------------------------- */ + +/* ---------------------------------------------------------------- + * VARIABLES + * -------------------------------------------------------------- */ + +static uDeviceHandle_t gInitiatorDeviceHandle = NULL; +static uDeviceCfg_t gInitiatorDeviceCfg = { + .deviceType = U_DEVICE_TYPE_SHORT_RANGE, + .deviceCfg = {.cfgSho = {.moduleType = U_CFG_TEST_SHORT_RANGE_MODULE_TYPE}}, + .transportType = U_DEVICE_TRANSPORT_TYPE_UART, + .transportCfg = { + .cfgUart = { + .uart = U_CFG_APP_SHORT_RANGE_UART, + .baudRate = U_SHORT_RANGE_UART_BAUD_RATE, + .pinTxd = U_CFG_APP_PIN_SHORT_RANGE_TXD, + .pinRxd = U_CFG_APP_PIN_SHORT_RANGE_RXD, + .pinCts = U_CFG_APP_PIN_SHORT_RANGE_CTS, + .pinRts = U_CFG_APP_PIN_SHORT_RANGE_RTS, +#ifdef U_CFG_APP_UART_PREFIX + .pPrefix = U_PORT_STRINGIFY_QUOTED(U_CFG_APP_UART_PREFIX) // Relevant for Linux only +#else + .pPrefix = NULL +#endif + } + } +}; + +static uDeviceHandle_t gResponderDeviceHandle = NULL; +static uDeviceCfg_t gResponderDeviceCfg = { + .deviceType = U_DEVICE_TYPE_SHORT_RANGE, + .deviceCfg = {.cfgSho = {.moduleType = U_CFG_TEST_SHORT_RANGE_MODULE_TYPE2}}, + .transportType = U_DEVICE_TRANSPORT_TYPE_UART, + .transportCfg = { + .cfgUart = { + .uart = U_CFG_APP_SHORT_RANGE_UART2, + .baudRate = U_SHORT_RANGE_UART_BAUD_RATE, + .pinTxd = U_CFG_APP_PIN_SHORT_RANGE_TXD2, + .pinRxd = U_CFG_APP_PIN_SHORT_RANGE_RXD2, + .pinCts = U_CFG_APP_PIN_SHORT_RANGE_CTS2, + .pinRts = U_CFG_APP_PIN_SHORT_RANGE_RTS2, +#ifdef U_CFG_APP_UART_PREFIX + .pPrefix = U_PORT_STRINGIFY_QUOTED(U_CFG_APP_UART_PREFIX) // Relevant for Linux only +#else + .pPrefix = NULL +#endif + } + } +}; + +static uNetworkCfgBle_t gInitiatorNetworkCfg = { + .type = U_NETWORK_TYPE_BLE, + .role = U_BLE_CFG_ROLE_CENTRAL, + .spsServer = false, +}; + +static uNetworkCfgBle_t gResponderNetworkCfg = { + .type = U_NETWORK_TYPE_BLE, + .role = U_BLE_CFG_ROLE_PERIPHERAL, + .spsServer = false, +}; + +static uBleGapAdvConfig_t gAdvCfg = {.minIntervalMs = 200, + .maxIntervalMs = 200, + .connectable = true, + .maxClients = 1, + .pAdvData = NULL, + .advDataLength = 0, + .pRespData = NULL, + .respDataLength = 0 + }; + +char gInitiatorMacAddr[U_SHORT_RANGE_BT_ADDRESS_SIZE]; +char gResponderMacAddr[U_SHORT_RANGE_BT_ADDRESS_SIZE]; +static uPortSemaphoreHandle_t gBondCompleteSemaphore = NULL; +static uPortSemaphoreHandle_t gSyncSemaphore = NULL; +static volatile int32_t gBondStatus; +static volatile int32_t gPasskey; + +/** This test can be run in different ways. + * It requires two separate modules. + * The default option is to run both bonding initiator and responder + * in the same program. This can only be used when both the two modules + * have u-connectXpress second generation, i.e. short_range_gen2 is defined + * in UBXLIB_FEATURES. + * For testing earlier version of u-connectXpress this test has to be + * run in two different application instances, one acting as the initiator + * and one as the responder. This is handled here by spawning a new instance + * but with proper environment variables to ensure that only the responder + * variant of this test is run. The initiator will terminate the responder + * when the test has completed. The output from the responder is merged with + * that from the initiator. + */ + +static int32_t gTestOption = 0; +static uPortNamePipeHandle_t gPipe = NULL; + +static int32_t gResourceCountStart; +static char gTestPrefix[50]; + +/* ---------------------------------------------------------------- + * STATIC FUNCTIONS + * -------------------------------------------------------------- */ + +// Write integer to a temporary string. +static const char *pIntToStr(uint32_t i) +{ + static char result[10]; + snprintf(result, sizeof(result), "%d", i); + return result; +} + +static void preamble() +{ + uPortDeinit(); + gResourceCountStart = uTestUtilGetDynamicResourceCount(); + if (gBondCompleteSemaphore == NULL) { + U_PORT_TEST_ASSERT(uPortSemaphoreCreate(&gBondCompleteSemaphore, 0, 1) == 0); + } + if (gSyncSemaphore == NULL) { + U_PORT_TEST_ASSERT(uPortSemaphoreCreate(&gSyncSemaphore, 0, 1) == 0); + } + U_PORT_TEST_ASSERT(uPortInit() == 0); + U_PORT_TEST_ASSERT(uDeviceInit() == 0); + + if (gTestOption != 0) { + U_PORT_TEST_ASSERT(uPortNamedPipeCreate(&gPipe, PIPE_NAME, gTestOption == 1) == 0); + } + + if (gTestOption < 2) { + U_TEST_PRINT_LINE("initiating the bonding initiator module"); + U_PORT_TEST_ASSERT(uDeviceOpen(&gInitiatorDeviceCfg, &gInitiatorDeviceHandle) == 0); + U_TEST_PRINT_LINE("initiating bonding initiator BLE"); + U_PORT_TEST_ASSERT(uNetworkInterfaceUp(gInitiatorDeviceHandle, U_NETWORK_TYPE_BLE, + &gInitiatorNetworkCfg) == 0); + U_PORT_TEST_ASSERT(uBleGapRemoveBond(gInitiatorDeviceHandle, NULL) == 0); + uBleGapGetMac(gInitiatorDeviceHandle, gInitiatorMacAddr); + U_PORT_TEST_ASSERT(uBleGapSetPairable(gInitiatorDeviceHandle, true) == 0); + } + + if (gTestOption != 1) { + U_TEST_PRINT_LINE("initiating the bonding responder module"); + U_PORT_TEST_ASSERT(uDeviceOpen(&gResponderDeviceCfg, &gResponderDeviceHandle) == 0); + U_TEST_PRINT_LINE("initiating bonding responder BLE"); + U_PORT_TEST_ASSERT(uNetworkInterfaceUp(gResponderDeviceHandle, U_NETWORK_TYPE_BLE, + &gResponderNetworkCfg) == 0); + // U_PORT_TEST_ASSERT(uBleGapReset(gResponderDeviceHandle) == 0); + U_PORT_TEST_ASSERT(uBleGapRemoveBond(gResponderDeviceHandle, NULL) == 0); + uint8_t advData[32]; + gAdvCfg.pAdvData = advData; + int32_t res = uBleGapSetAdvData("BondResp", NULL, 0, advData, sizeof(advData)); + U_PORT_TEST_ASSERT(res > 0); + gAdvCfg.advDataLength = (uint8_t)res; + U_PORT_TEST_ASSERT(uBleGapAdvertiseStart(gResponderDeviceHandle, &gAdvCfg) == 0); + U_PORT_TEST_ASSERT(uBleGapSetPairable(gResponderDeviceHandle, true) == 0); + uBleGapGetMac(gResponderDeviceHandle, gResponderMacAddr); + } else { + // Launch a new instance. By using popen the stdout of the initiator is inherited + // to the responder and hence all output is merged. + U_TEST_PRINT_LINE("launching responder application instance..."); + putenv("U_CFG_APP_FILTER=bleBond"); + putenv("U_CFG_TEST_BLE_BOND_OP=2"); + putenv("U_CFG_TEST_SPAWNED=1"); + FILE *procPipe = NULL; +#if defined(_WIN32) + char *exePath; + U_PORT_TEST_ASSERT(_get_pgmptr(&exePath) == 0); + procPipe = _popen(exePath, "w"); + U_PORT_TEST_ASSERT(procPipe != NULL); +#elif defined(__linux__) + char exePath[100]; + U_PORT_TEST_ASSERT(readlink("/proc/self/exe", exePath, sizeof(exePath)) > 0); + procPipe = popen(exePath, "w"); +#endif + U_PORT_TEST_ASSERT(procPipe != NULL); + putenv("U_CFG_TEST_SPAWNED="); + + // Wait for responder to start up. + char buff[20]; + U_PORT_TEST_ASSERT(uPortNamedPipeReadStr(gPipe, buff, sizeof(buff)) > 0); + + // Exchange mac addresses. + U_PORT_TEST_ASSERT(uPortNamedPipeWriteStr(gPipe, pIntToStr(CMD_RESP_MAC)) == 0); + U_PORT_TEST_ASSERT(uPortNamedPipeReadStr(gPipe, gResponderMacAddr, sizeof(gResponderMacAddr)) > 0); + snprintf(buff, sizeof(buff), "%d,%s", CMD_INIT_MAC, gInitiatorMacAddr); + U_PORT_TEST_ASSERT(uPortNamedPipeWriteStr(gPipe, buff) == 0); + } +} + +static void postamble() +{ + U_TEST_PRINT_LINE("closing down the modules"); + if (gInitiatorDeviceHandle != NULL) { + U_PORT_TEST_ASSERT(uNetworkInterfaceDown(gInitiatorDeviceHandle, U_NETWORK_TYPE_BLE) == 0); + U_PORT_TEST_ASSERT(uDeviceClose(gInitiatorDeviceHandle, false) == 0); + } + + if (gResponderDeviceHandle != NULL) { + U_PORT_TEST_ASSERT(uNetworkInterfaceDown(gResponderDeviceHandle, U_NETWORK_TYPE_BLE) == 0); + U_PORT_TEST_ASSERT(uDeviceClose(gResponderDeviceHandle, false) == 0); + } + + if (gBondCompleteSemaphore != NULL) { + uPortSemaphoreDelete(gBondCompleteSemaphore); + gBondCompleteSemaphore = NULL; + } + if (gSyncSemaphore != NULL) { + uPortSemaphoreDelete(gSyncSemaphore); + gSyncSemaphore = NULL; + } + + if (gTestOption == 1) { + // Close down the spawned responder. + char buff[10]; + U_PORT_TEST_ASSERT(uPortNamedPipeWriteStr(gPipe, pIntToStr(CMD_EXIT)) == 0); + // Wait for confirmation on close. + U_PORT_TEST_ASSERT(uPortNamedPipeReadStr(gPipe, buff, sizeof(buff)) > 0); + // Wait a while, initiator final printout should come last and we can't + // sync as the named pipe must be removed before leakage check. + U_TEST_PRINT_LINE("waiting for responder to close."); + uPortTaskBlock(5000); + } else if (gTestOption == 2) { + // Send confirmation on close. + U_PORT_TEST_ASSERT(uPortNamedPipeWriteStr(gPipe, "Done") == 0); + } + + if (gTestOption != 0) { + U_PORT_TEST_ASSERT(uPortNamedPipeDelete(gPipe) == 0); + } + + uDeviceDeinit(); + uPortDeinit(); + uTestUtilResourceCheck(gTestPrefix, NULL, true); + int32_t resourceCount = gResourceCountStart - uTestUtilGetDynamicResourceCount(); + U_TEST_PRINT_LINE("we have leaked %d resource(s).", resourceCount); + U_PORT_TEST_ASSERT(resourceCount <= 0); +} + +/** Different handling for signaling bonding complete has to be applied for old and +* new u-connectXpress. In the old version the module is disconnected after bonding +* and we must wait for that before signaling in order to be able to do subsequent +* bonding operations. In the newer version the connection remains so we signal +* complete directly on the status callback. +*/ +static void bondResultCallback(const char *pAddress, int32_t status) +{ + gBondStatus = status; +#ifdef U_UCONNECT_GEN2 + uPortSemaphoreGive(gBondCompleteSemaphore); +#endif +} + +static void connectCallback(int32_t connHandle, char *pAddress, bool connected) +{ + (void)connHandle; + (void)pAddress; +#ifndef U_UCONNECT_GEN2 + if (!connected) { + uPortSemaphoreGive(gBondCompleteSemaphore); + } +#endif +} + +static void doBond(bool expectSuccess) +{ + // Remove old bonds + U_PORT_TEST_ASSERT(uBleGapRemoveBond(gInitiatorDeviceHandle, NULL) == 0); + if (gTestOption == 0) { + U_PORT_TEST_ASSERT(uBleGapRemoveBond(gResponderDeviceHandle, NULL) == 0); + } else { + U_PORT_TEST_ASSERT(uPortNamedPipeWriteStr(gPipe, pIntToStr(CMD_REM_BOND)) == 0); + } + // Start and wait for result callback + U_PORT_TEST_ASSERT( + (uBleGapBond(gInitiatorDeviceHandle, gResponderMacAddr, bondResultCallback) == 0) || + !expectSuccess + ); + U_PORT_TEST_ASSERT(uPortSemaphoreTryTake(gBondCompleteSemaphore, 10000) == 0); + if (expectSuccess) { + U_PORT_TEST_ASSERT(gBondStatus == U_BT_LE_BOND_ERR_SUCCESS); + } else { + U_PORT_TEST_ASSERT(gBondStatus != U_BT_LE_BOND_ERR_SUCCESS); + } +} + +static uDeviceHandle_t oppositeHandle(const char *pAddress) +{ + return (strstr(pAddress, gInitiatorMacAddr) != NULL) ? + gResponderDeviceHandle : + gInitiatorDeviceHandle; +} + +static void confirmNumber(const char *pAddress, int32_t numericValue) +{ + // Confirm the specified number + uBleGapBondConfirm(oppositeHandle(pAddress), true, pAddress); +} + +static void passKeyEntryCallback(const char *pAddress, int32_t numericValue) +{ + // Incoming passkey + gPasskey = numericValue; + if (gTestOption == 0) { + uPortSemaphoreGive(gSyncSemaphore); + } else { + // Send to remote + char buff[20]; + snprintf(buff, sizeof(buff), "%d,%d", CMD_ENTER_PASS, gPasskey); + U_PORT_TEST_ASSERT(uPortNamedPipeWriteStr(gPipe, buff) == 0); + } +} + +static void passkeyRequestCallback(const char *pAddress) +{ + // Wait for and then send the passkey received from the counterpart + if (gTestOption != 2) { + U_PORT_TEST_ASSERT(uPortSemaphoreTryTake(gSyncSemaphore, 10000) == 0); + uBleGapBondEnterPasskey(oppositeHandle(pAddress), true, pAddress, gPasskey); + } +} + +static void setParams(uDeviceHandle_t handle, int32_t cap, int32_t sec, bool pairable) +{ + if (handle != NULL) { + U_PORT_TEST_ASSERT(uBleSetBondParameters( + handle, + cap, + sec, + confirmNumber, + passkeyRequestCallback, + passKeyEntryCallback + ) == 0); + U_PORT_TEST_ASSERT(uBleGapSetPairable(handle, pairable) == 0); + } else if (gInitiatorDeviceHandle != NULL) { + char buff[20]; + memset(buff, 0, sizeof(buff)); + snprintf(buff, sizeof(buff) - 1, CMD_SETPARAM_FORM, CMD_SETPARAM, cap, sec, pairable); + U_PORT_TEST_ASSERT(uPortNamedPipeWriteStr(gPipe, buff) == 0); + } +} + +static void runAsInitiator() +{ + uBleGapSetConnectCallback(gInitiatorDeviceHandle, connectCallback); + // Test some of the combinations from the bonding matrix at: + // https://www.bluetooth.com/blog/bluetooth-pairing-part-2-key-generation-methods/ + + // -- No security -- + + // Pairing + + U_TEST_PRINT_LINE("Pairing enabled only on one side, should fail"); + setParams(gInitiatorDeviceHandle, U_BT_LE_IO_NONE, U_BT_LE_BOND_NO_SEC, true); + setParams(gResponderDeviceHandle, U_BT_LE_IO_NONE, U_BT_LE_BOND_NO_SEC, false); + doBond(false); + U_TEST_PRINT_LINE("Pairing enabled on both sides"); + setParams(gResponderDeviceHandle, U_BT_LE_IO_NONE, U_BT_LE_BOND_NO_SEC, true); + doBond(true); + + U_TEST_PRINT_LINE("Just works"); + setParams(gInitiatorDeviceHandle, U_BT_LE_IO_NONE, U_BT_LE_BOND_UNAUTH, true); + setParams(gResponderDeviceHandle, U_BT_LE_IO_NONE, U_BT_LE_BOND_UNAUTH, true); + doBond(true); + + // -- Security -- + + U_TEST_PRINT_LINE("Security, initiator DISP_ONLY, responder KEYB_ONLY"); + setParams(gInitiatorDeviceHandle, U_BT_LE_IO_DISP_ONLY, U_BT_LE_BOND_AUTH, true); + setParams(gResponderDeviceHandle, U_BT_LE_IO_KEYB_ONLY, U_BT_LE_BOND_AUTH, true); + doBond(true); + + U_TEST_PRINT_LINE("Security MITM protection, initiator YES_NO, responder YES_NO"); + setParams(gInitiatorDeviceHandle, U_BT_LE_IO_DISP_YES_NO, U_BT_LE_BOND_AUTH_ENCR, true); + setParams(gResponderDeviceHandle, U_BT_LE_IO_DISP_YES_NO, U_BT_LE_BOND_AUTH_ENCR, true); + doBond(true); +} + +static void runAsResponder() +{ + char cmd[50]; + U_PORT_TEST_ASSERT(uPortNamedPipeWriteStr(gPipe, "Ready") == 0); + while (uPortNamedPipeReadStr(gPipe, cmd, sizeof(cmd)) >= 0) { + if (strlen(cmd) > 0) { + // Incoming command + int32_t op; + U_PORT_TEST_ASSERT(sscanf(cmd, "%d", &op) == 1); + if (op == CMD_SETPARAM) { + int32_t cap, sec, pairable; + int cnt = sscanf(cmd, CMD_SETPARAM_FORM, &op, &cap, &sec, &pairable); + U_PORT_TEST_ASSERT(cnt == 4); + setParams(gResponderDeviceHandle, cap, sec, pairable == 1); + } else if (op == CMD_RESP_MAC) { + U_PORT_TEST_ASSERT(uPortNamedPipeWriteStr(gPipe, gResponderMacAddr) == 0); + } else if (op == CMD_INIT_MAC) { + U_PORT_TEST_ASSERT(sscanf(cmd, "%d,%s", &op, gInitiatorMacAddr) == 2); + } else if (op == CMD_ENTER_PASS) { + sscanf(cmd + 2, "%d", &gPasskey); + uBleGapBondEnterPasskey(gResponderDeviceHandle, true, gInitiatorMacAddr, gPasskey); + } else if (op == CMD_REM_BOND) { + U_PORT_TEST_ASSERT(uBleGapRemoveBond(gResponderDeviceHandle, NULL) == 0); + } else { + // Exit or unknown command + break; + } + } + } +} + +/* ---------------------------------------------------------------- + * PUBLIC FUNCTIONS + * -------------------------------------------------------------- */ + +/** BLE bonding test. + */ +U_PORT_TEST_FUNCTION("[bleBond]", "bleBond") +{ + const char *envOpt = getenv("U_CFG_TEST_BLE_BOND_OP"); + if (envOpt != NULL) { + U_PORT_TEST_ASSERT(sscanf(envOpt, "%d", &gTestOption) == 1); + } else { +#ifndef U_UCONNECT_GEN2 + // Older versions of u-connectXpress can only run in separate instances + gTestOption = 1; +#endif + } + if (gTestOption == 0) { + snprintf(gTestPrefix, sizeof(gTestPrefix) - 1, "%s: ", U_TEST_PREFIX); + } else { + snprintf(gTestPrefix, sizeof(gTestPrefix) - 1, "%s(%d): ", U_TEST_PREFIX, gTestOption); + } + preamble(); + if (gInitiatorDeviceHandle != NULL) { + runAsInitiator(); + } else { + runAsResponder(); + } + postamble(); +} + +#endif + +// End of file diff --git a/cell/src/u_cell.c b/cell/src/u_cell.c index 2813b05e..359e6172 100644 --- a/cell/src/u_cell.c +++ b/cell/src/u_cell.c @@ -43,6 +43,8 @@ #include "u_port_heap.h" #include "u_port_gpio.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_ringbuffer.h" @@ -298,8 +300,8 @@ int32_t uCellAdd(uCellModuleType_t moduleType, pInstance->pinPwrOn = pinPwrOn; pInstance->pinVInt = pinVInt; pInstance->pinDtrPowerSaving = -1; - pInstance->lastCfunFlipTimeMs = uPortGetTickTimeMs(); - pInstance->lastDtrPinToggleTimeMs = uPortGetTickTimeMs(); + pInstance->lastCfunFlipTime = uTimeoutStart(); + pInstance->lastDtrPinToggleTime = uTimeoutStart(); for (size_t x = 0; x < sizeof(pInstance->networkStatus) / sizeof(pInstance->networkStatus[0]); x++) { diff --git a/cell/src/u_cell_cfg.c b/cell/src/u_cell_cfg.c index 3f6a4f61..4ad7dc30 100644 --- a/cell/src/u_cell_cfg.c +++ b/cell/src/u_cell_cfg.c @@ -46,6 +46,8 @@ #include "u_port_os.h" #include "u_port_heap.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" diff --git a/cell/src/u_cell_file.c b/cell/src/u_cell_file.c index 1ca9b75b..8ecd02cc 100644 --- a/cell/src/u_cell_file.c +++ b/cell/src/u_cell_file.c @@ -39,6 +39,7 @@ #include "u_error_common.h" #include "u_port.h" #include "u_port_os.h" +#include "u_timeout.h" #include "u_at_client.h" #include "u_cell_module_type.h" #include "u_cell_net.h" diff --git a/cell/src/u_cell_fota.c b/cell/src/u_cell_fota.c index f4b41b3c..d6a21c08 100644 --- a/cell/src/u_cell_fota.c +++ b/cell/src/u_cell_fota.c @@ -41,6 +41,8 @@ #include "u_port_os.h" #include "u_port_heap.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" diff --git a/cell/src/u_cell_geofence.c b/cell/src/u_cell_geofence.c index 69f9ee0c..7c108449 100644 --- a/cell/src/u_cell_geofence.c +++ b/cell/src/u_cell_geofence.c @@ -37,6 +37,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_linked_list.h" diff --git a/cell/src/u_cell_gpio.c b/cell/src/u_cell_gpio.c index 940639b3..635f248d 100644 --- a/cell/src/u_cell_gpio.c +++ b/cell/src/u_cell_gpio.c @@ -42,6 +42,8 @@ #include "u_port_os.h" #include "u_port_heap.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" diff --git a/cell/src/u_cell_http.c b/cell/src/u_cell_http.c index ccbf950d..a03321c0 100644 --- a/cell/src/u_cell_http.c +++ b/cell/src/u_cell_http.c @@ -51,6 +51,8 @@ #include "u_port_debug.h" #include "u_port_event_queue.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_sock.h" diff --git a/cell/src/u_cell_info.c b/cell/src/u_cell_info.c index 263b4a84..99e8bd4a 100644 --- a/cell/src/u_cell_info.c +++ b/cell/src/u_cell_info.c @@ -49,6 +49,8 @@ #include "u_port_os.h" #include "u_port_uart.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_device_shared.h" diff --git a/cell/src/u_cell_loc.c b/cell/src/u_cell_loc.c index 1d35535b..f2a1ff7f 100644 --- a/cell/src/u_cell_loc.c +++ b/cell/src/u_cell_loc.c @@ -51,6 +51,8 @@ #include "u_port_heap.h" #include "u_port_debug.h" +#include "u_timeout.h" + #include "u_time.h" #include "u_at_client.h" @@ -1730,7 +1732,7 @@ int32_t uCellLocGet(uDeviceHandle_t cellHandle, uCellPrivateLocContext_t *pContext; uCellLocFixDataStorage_t *pFixDataStorage; volatile uCellLocFixDataStorageBlock_t fixDataStorageBlock = {0}; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; fixDataStorageBlock.errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; @@ -1777,10 +1779,10 @@ int32_t uCellLocGet(uDeviceHandle_t cellHandle, uPortLog("U_CELL_LOC: waiting for the answer...\n"); // Wait for the callback called by the URC to set // errorCode inside our block to success - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((fixDataStorageBlock.errorCode == (int32_t) U_ERROR_COMMON_TIMEOUT) && (((pKeepGoingCallback == NULL) && - !uPortTickTimeExpiredMs(startTimeMs, U_CELL_LOC_TIMEOUT_SECONDS * 1000)) || + !uTimeoutExpiredSeconds(timeoutStart, U_CELL_LOC_TIMEOUT_SECONDS)) || ((pKeepGoingCallback != NULL) && pKeepGoingCallback(cellHandle)))) { // Relax a little uPortTaskBlock(1000); diff --git a/cell/src/u_cell_mno_db.c b/cell/src/u_cell_mno_db.c index e7c32024..7cce4096 100644 --- a/cell/src/u_cell_mno_db.c +++ b/cell/src/u_cell_mno_db.c @@ -34,6 +34,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_port.h" diff --git a/cell/src/u_cell_mqtt.c b/cell/src/u_cell_mqtt.c index 9794dbbf..8609b341 100644 --- a/cell/src/u_cell_mqtt.c +++ b/cell/src/u_cell_mqtt.c @@ -51,6 +51,8 @@ #include "u_port_heap.h" #include "u_port_debug.h" +#include "u_timeout.h" + #include "u_hex_bin_convert.h" #include "u_at_client.h" @@ -1071,7 +1073,7 @@ static int32_t doSaraR4OldSyntaxUmqttQuery(const uCellPrivateInstance_t *pInstan uAtClientHandle_t atHandle = pInstance->atHandle; char buffer[13]; // Enough room for "AT+UMQTT=x?" int32_t status; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; // The old SARA-R4 MQTT AT interface syntax gets very // peculiar here. @@ -1098,10 +1100,10 @@ static int32_t doSaraR4OldSyntaxUmqttQuery(const uCellPrivateInstance_t *pInstan // Wait for the URC to capture the answer // This is just a local thing so set a short timeout // and don't bother with keepGoingCallback - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((!checkUrcStatusField(pUrcStatus, number)) && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_MQTT_LOCAL_URC_TIMEOUT_MS)) { + !uTimeoutExpiredMs(timeoutStart, + U_CELL_MQTT_LOCAL_URC_TIMEOUT_MS)) { uPortTaskBlock(250); } if (checkUrcStatusField(pUrcStatus, number)) { @@ -1333,7 +1335,7 @@ static int32_t connect(const uCellPrivateInstance_t *pInstance, bool mqttSn; volatile uCellMqttUrcStatus_t *pUrcStatus; uAtClientHandle_t atHandle; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t status = 1; size_t tryCount = 0; @@ -1347,8 +1349,8 @@ static int32_t connect(const uCellPrivateInstance_t *pInstance, // take a little while to find out that the connection // has actually been made and hence we wait here for // it to be ready to connect - while (!uPortTickTimeExpiredMs(pInstance->connectedAtMs, - U_CELL_MQTT_CONNECT_DELAY_MILLISECONDS)) { + while (!uTimeoutExpiredMs(pInstance->connectedAt, + U_CELL_MQTT_CONNECT_DELAY_MILLISECONDS)) { uPortTaskBlock(100); } } @@ -1399,10 +1401,10 @@ static int32_t connect(const uCellPrivateInstance_t *pInstance, " second(s)...\n", U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS); errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while (((pUrcStatus->flagsBitmap & (1 << U_CELL_MQTT_URC_FLAG_CONNECT_UPDATED)) == 0) && - !uPortTickTimeExpiredMs(startTimeMs, - U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000) && + !uTimeoutExpiredSeconds(timeoutStart, + U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS) && ((pContext->pKeepGoingCallback == NULL) || pContext->pKeepGoingCallback())) { uPortTaskBlock(1000); @@ -1410,7 +1412,7 @@ static int32_t connect(const uCellPrivateInstance_t *pInstance, if ((int32_t) onNotOff == pContext->connected) { uPortLog("U_CELL_MQTT: %s after %d second(s).\n", onNotOff ? "connected" : "disconnected", - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(timeoutStart)); errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; } else { printErrorCodes(pInstance); @@ -1537,7 +1539,7 @@ static int32_t publish(const uCellPrivateInstance_t *pInstance, int32_t status = 1; bool isAscii; bool messageWritten = false; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t promptTimeoutSeconds = U_CELL_MQTT_PROMPT_TIMEOUT_NORMAL_SECONDS; size_t tryCount = 0; @@ -1700,10 +1702,10 @@ static int32_t publish(const uCellPrivateInstance_t *pInstance, // Wait for a URC to say that the publish // has succeeded errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while (((pUrcStatus->flagsBitmap & (1 << U_CELL_MQTT_URC_FLAG_PUBLISH_UPDATED)) == 0) && - !uPortTickTimeExpiredMs(startTimeMs, - U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000) && + !uTimeoutExpiredSeconds(timeoutStart, + U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS) && ((pContext->pKeepGoingCallback == NULL) || pContext->pKeepGoingCallback())) { uPortTaskBlock(1000); @@ -1749,7 +1751,7 @@ static int32_t subscribe(const uCellPrivateInstance_t *pInstance, volatile uCellMqttUrcStatus_t *pUrcStatus; uAtClientHandle_t atHandle; int32_t status = 1; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; size_t tryCount = 0; pContext = (volatile uCellMqttContext_t *) pInstance->pMqttContext; @@ -1807,10 +1809,10 @@ static int32_t subscribe(const uCellPrivateInstance_t *pInstance, // On all platforms need to wait for a URC to // say that the subscribe has succeeded errorCodeOrQos = (int32_t) U_ERROR_COMMON_TIMEOUT; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while (((pUrcStatus->flagsBitmap & (1 << U_CELL_MQTT_URC_FLAG_SUBSCRIBE_UPDATED)) == 0) && - !uPortTickTimeExpiredMs(startTimeMs, - U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000) && + !uTimeoutExpiredSeconds(timeoutStart, + U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS) && ((pContext->pKeepGoingCallback == NULL) || pContext->pKeepGoingCallback())) { uPortTaskBlock(1000); @@ -1846,7 +1848,7 @@ static int32_t unsubscribe(const uCellPrivateInstance_t *pInstance, volatile uCellMqttUrcStatus_t *pUrcStatus; uAtClientHandle_t atHandle; int32_t status = 1; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; size_t tryCount = 0; pContext = (volatile uCellMqttContext_t *) pInstance->pMqttContext; @@ -1896,10 +1898,10 @@ static int32_t unsubscribe(const uCellPrivateInstance_t *pInstance, // If this is the new syntax we need to wait // for a URC to say that the unsubscribe has succeeded errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while (((pUrcStatus->flagsBitmap & (1 << U_CELL_MQTT_URC_FLAG_UNSUBSCRIBE_UPDATED)) == 0) && - !uPortTickTimeExpiredMs(startTimeMs, - U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000) && + !uTimeoutExpiredSeconds(timeoutStart, + U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS) && ((pContext->pKeepGoingCallback == NULL) || pContext->pKeepGoingCallback())) { uPortTaskBlock(1000); @@ -1936,7 +1938,7 @@ static int32_t readMessage(const uCellPrivateInstance_t *pInstance, uAtClientHandle_t atHandle; size_t messageSizeBytes = 0; int32_t status; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; uCellMqttQos_t qos; int32_t topicNameType = -1; int32_t topicNameBytesRead = -1; @@ -1986,10 +1988,10 @@ static int32_t readMessage(const uCellPrivateInstance_t *pInstance, if ((uAtClientUnlock(atHandle) == 0) && (status == 1)) { // Wait for a URC containing the message errorCode = (int32_t) U_ERROR_COMMON_EMPTY; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while (!pUrcMessage->messageRead && - !uPortTickTimeExpiredMs(startTimeMs, - U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000) && + !uTimeoutExpiredSeconds(timeoutStart, + U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS) && ((pContext->pKeepGoingCallback == NULL) || pContext->pKeepGoingCallback())) { uPortTaskBlock(1000); @@ -3356,7 +3358,7 @@ int32_t uCellMqttSnRegisterNormalTopic(uDeviceHandle_t cellHandle, volatile uCellMqttContext_t *pContext; volatile uCellMqttUrcStatus_t *pUrcStatus; uAtClientHandle_t atHandle; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; size_t tryCount = 0; U_CELL_MQTT_ENTRY_FUNCTION(cellHandle, &pInstance, &errorCode, true); @@ -3387,10 +3389,10 @@ int32_t uCellMqttSnRegisterNormalTopic(uDeviceHandle_t cellHandle, if (uAtClientUnlock(atHandle) == 0) { // Wait for a URC to get the ID errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while (((pUrcStatus->flagsBitmap & (1 << U_CELL_MQTT_URC_FLAG_REGISTER_UPDATED)) == 0) && - !uPortTickTimeExpiredMs(startTimeMs, - U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000) && + !uTimeoutExpiredSeconds(timeoutStart, + U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS) && ((pContext->pKeepGoingCallback == NULL) || pContext->pKeepGoingCallback())) { uPortTaskBlock(1000); @@ -3625,7 +3627,7 @@ int32_t uCellMqttSnSetWillMessaage(uDeviceHandle_t cellHandle, volatile uCellMqttContext_t *pContext; volatile uCellMqttUrcStatus_t *pUrcStatus; uAtClientHandle_t atHandle; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; size_t tryCount = 0; U_CELL_MQTT_ENTRY_FUNCTION(cellHandle, &pInstance, &errorCode, true); @@ -3657,10 +3659,10 @@ int32_t uCellMqttSnSetWillMessaage(uDeviceHandle_t cellHandle, if (uAtClientUnlock(atHandle) == 0) { // Wait for a URC to indicate success errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while (((pUrcStatus->flagsBitmap & (1 << U_CELL_MQTT_URC_FLAG_WILL_MESSAGE_UPDATED)) == 0) && - !uPortTickTimeExpiredMs(startTimeMs, - U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000) && + !uTimeoutExpiredSeconds(timeoutStart, + U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS) && ((pContext->pKeepGoingCallback == NULL) || pContext->pKeepGoingCallback())) { uPortTaskBlock(1000); @@ -3694,7 +3696,7 @@ int32_t uCellMqttSnSetWillParameters(uDeviceHandle_t cellHandle, volatile uCellMqttContext_t *pContext; volatile uCellMqttUrcStatus_t *pUrcStatus; uAtClientHandle_t atHandle; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; size_t tryCount = 0; U_CELL_MQTT_ENTRY_FUNCTION(cellHandle, &pInstance, &errorCode, true); @@ -3733,10 +3735,10 @@ int32_t uCellMqttSnSetWillParameters(uDeviceHandle_t cellHandle, if (uAtClientUnlock(atHandle) == 0) { // Wait for a URC to indicate success errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while (((pUrcStatus->flagsBitmap & (1 << U_CELL_MQTT_URC_FLAG_WILL_PARAMETERS_UPDATED)) == 0) && - !uPortTickTimeExpiredMs(startTimeMs, - U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000) && + !uTimeoutExpiredSeconds(timeoutStart, + U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS) && ((pContext->pKeepGoingCallback == NULL) || pContext->pKeepGoingCallback())) { uPortTaskBlock(1000); diff --git a/cell/src/u_cell_mux.c b/cell/src/u_cell_mux.c index 7f4d57f0..c7d2682c 100644 --- a/cell/src/u_cell_mux.c +++ b/cell/src/u_cell_mux.c @@ -73,6 +73,8 @@ #include "u_interface.h" #include "u_ringbuffer.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_device_shared.h" @@ -232,7 +234,7 @@ static int32_t sendEvent(uCellMuxPrivateContext_t *pContext, uCellMuxPrivateEventCallback_t *pEventCallback; uCellMuxEventTrampoline_t trampolineData; uint32_t eventCallbackFilter; - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); bool irqSupported; if ((pContext != NULL) && (pChannelContext != NULL) && !pChannelContext->markedForDeletion) { @@ -252,7 +254,7 @@ static int32_t sendEvent(uCellMuxPrivateContext_t *pContext, uPortTaskBlock(U_CFG_OS_YIELD_MS); irqSupported = (errorCode != (int32_t) U_ERROR_COMMON_NOT_IMPLEMENTED) && (errorCode != (int32_t) U_ERROR_COMMON_NOT_SUPPORTED); - } while (irqSupported && !uPortTickTimeExpiredMs(startTimeMs, delayMs)); + } while (irqSupported && !uTimeoutExpiredMs(timeoutStart, delayMs)); if (!irqSupported) { // If IRQ is not supported, just gotta do the normal send @@ -363,7 +365,7 @@ static int32_t serialWriteInnards(struct uDeviceSerial_t *pDeviceSerial, size_t sizeWritten = 0; int32_t thisLengthWritten; size_t lengthWritten; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; bool activityPinIsSet = false; // Encode the CMUX frame in chunks of the maximum information @@ -378,10 +380,9 @@ static int32_t serialWriteInnards(struct uDeviceSerial_t *pDeviceSerial, activityPinIsSet = true; uCellPrivateSetPinDtr(pInstance, true); } - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((sizeWritten < sizeBytes) && (sizeOrErrorCode >= 0) && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_MUX_WRITE_TIMEOUT_MS)) { + !uTimeoutExpiredMs(timeoutStart, U_CELL_MUX_WRITE_TIMEOUT_MS)) { // Encode a chunk as UIH thisChunkSize = sizeBytes - sizeWritten; if (thisChunkSize > U_CELL_MUX_PRIVATE_INFORMATION_LENGTH_MAX_BYTES) { @@ -394,8 +395,7 @@ static int32_t serialWriteInnards(struct uDeviceSerial_t *pDeviceSerial, if (sizeOrErrorCode >= 0) { lengthWritten = 0; while ((sizeOrErrorCode >= 0) && (lengthWritten < (size_t) sizeOrErrorCode) && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_MUX_WRITE_TIMEOUT_MS)) { + !uTimeoutExpiredMs(timeoutStart, U_CELL_MUX_WRITE_TIMEOUT_MS)) { if (!pChannelContext->traffic.txIsFlowControlledOff) { // Send the data thisLengthWritten = uPortUartWrite(pChannelContext->pContext->underlyingStreamHandle, @@ -491,7 +491,7 @@ static int32_t sendCommandCheckResponse(uDeviceSerial_t *pDeviceSerial, char buffer[U_CELL_MUX_PRIVATE_FRAME_OVERHEAD_MAX_BYTES + sizeof(pFrameSend->information)]; char *pTmp; int32_t length; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; // Flush out any existing information field data while (serialReadInnards(pTraffic, buffer, sizeof(buffer)) > 0) {} @@ -511,50 +511,57 @@ static int32_t sendCommandCheckResponse(uDeviceSerial_t *pDeviceSerial, } uPortLog(".\n"); #endif - errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; - // Wait for a response - startTimeMs = uPortGetTickTimeMs(); - while ((pTraffic->wantedResponseFrameType != U_CELL_MUX_PRIVATE_FRAME_TYPE_NONE) && - !uPortTickTimeExpiredMs(startTimeMs, timeoutMs)) { - uPortTaskBlock(10); - } - if (pTraffic->wantedResponseFrameType == U_CELL_MUX_PRIVATE_FRAME_TYPE_NONE) { -#ifdef U_CELL_MUX_ENABLE_DEBUG - if (pChannelContext->channel == 0) { - // For the control channel we need to print the frame type out - // here as the message is removed before it gets to cmuxDecode() - uPortLog("U_CELL_CMUX_%d: rx frame type 0x%02x.\n", pChannelContext->channel, - pFrameCheck->type); + errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; + if (timeoutMs > 0) { + errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; + // Wait for a response + timeoutStart = uTimeoutStart(); + while ((pTraffic->wantedResponseFrameType != U_CELL_MUX_PRIVATE_FRAME_TYPE_NONE) && + !uTimeoutExpiredMs(timeoutStart, timeoutMs)) { + uPortTaskBlock(10); } -#endif - if (pFrameCheck->informationLengthBytes > 0) { - // Need to look for the right information field contents also - length = serialReadInnards(pTraffic, buffer, sizeof(buffer)); - pTmp = buffer; - while ((length >= (int32_t) pFrameCheck->informationLengthBytes) && - (memcmp(pTmp, pFrameCheck->information, - pFrameCheck->informationLengthBytes) != 0)) { - pTmp++; - length--; - } - if (length >= (int32_t) pFrameCheck->informationLengthBytes) { + if (pTraffic->wantedResponseFrameType == U_CELL_MUX_PRIVATE_FRAME_TYPE_NONE) { #ifdef U_CELL_MUX_ENABLE_DEBUG - uPortLog("U_CELL_CMUX_%d: decoded I-field %d byte(s):", - pChannelContext->channel, - pFrameCheck->informationLengthBytes); - for (size_t x = 0; x < pFrameCheck->informationLengthBytes; x++) { - uPortLog(" %02x", *(pTmp + x)); + if (pChannelContext->channel == 0) { + // For the control channel we need to print the frame type out + // here as the message is removed before it gets to cmuxDecode() + uPortLog("U_CELL_CMUX_%d: rx frame type 0x%02x.\n", pChannelContext->channel, + pFrameCheck->type); + } +#endif + if (pFrameCheck->informationLengthBytes > 0) { + // Need to look for the right information field contents also + length = serialReadInnards(pTraffic, buffer, sizeof(buffer)); + pTmp = buffer; + while ((length >= (int32_t) pFrameCheck->informationLengthBytes) && + (memcmp(pTmp, pFrameCheck->information, + pFrameCheck->informationLengthBytes) != 0)) { + pTmp++; + length--; } - uPortLog(".\n"); + if (length >= (int32_t) pFrameCheck->informationLengthBytes) { +#ifdef U_CELL_MUX_ENABLE_DEBUG + uPortLog("U_CELL_CMUX_%d: decoded I-field %d byte(s):", + pChannelContext->channel, + pFrameCheck->informationLengthBytes); + for (size_t x = 0; x < pFrameCheck->informationLengthBytes; x++) { + uPortLog(" %02x", *(pTmp + x)); + } + uPortLog(".\n"); #endif + errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; + } + } else { errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; } } else { - errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; +#ifdef U_CELL_MUX_ENABLE_DEBUG + uPortLog("U_CELL_CMUX_%d: no response.\n", pChannelContext->channel); +#endif } } else { #ifdef U_CELL_MUX_ENABLE_DEBUG - uPortLog("U_CELL_CMUX_%d: no response.\n", pChannelContext->channel); + uPortLog("U_CELL_CMUX_%d: not waiting for a response.\n", pChannelContext->channel); #endif } } @@ -655,13 +662,13 @@ static void serialClose(struct uDeviceSerial_t *pDeviceSerial) memcpy(frameCheck.information, gMuxCldResponse, x); frameCheck.informationLengthBytes = sizeof(gMuxCldResponse); sendCommandCheckResponse(pDeviceSerial, &frameSend, &frameCheck, - U_CELL_MUX_DISC_TIMEOUT_MS); + pChannelContext->discTimeoutMs); } else { // For any other channel, send DISC and wait for UA frameSend.type = U_CELL_MUX_PRIVATE_FRAME_TYPE_DISC_COMMAND; frameCheck.type = U_CELL_MUX_PRIVATE_FRAME_TYPE_UA_RESPONSE; sendCommandCheckResponse(pDeviceSerial, &frameSend, &frameCheck, - U_CELL_MUX_DISC_TIMEOUT_MS); + pChannelContext->discTimeoutMs); } pChannelContext->state = U_CELL_MUX_PRIVATE_CHANNEL_STATE_NULL; @@ -1149,6 +1156,12 @@ static int32_t openChannel(uCellMuxPrivateContext_t *pContext, pChannelContext->pContext = pContext; pChannelContext->channel = channel; pChannelContext->markedForDeletion = false; + pChannelContext->discTimeoutMs = 0; + if ((channel == 0) || + U_CELL_PRIVATE_HAS(pContext->pInstance->pModule, + U_CELL_PRIVATE_FEATURE_CMUX_CHANNEL_CLOSE)) { + pChannelContext->discTimeoutMs = U_CELL_MUX_DISC_TIMEOUT_MS; + } memset(&(pChannelContext->traffic), 0, sizeof(pChannelContext->traffic)); memset(&(pChannelContext->eventCallback), 0, sizeof(pChannelContext->eventCallback)); errorCode = pDeviceSerial->open(pDeviceSerial, NULL, receiveBufferSizeBytes); @@ -1402,7 +1415,7 @@ static void cmuxDecode(uCellMuxPrivateContext_t *pContext, uint32_t eventBitMap) parserContext.informationLengthBytes = bufferLength; } #ifdef U_CELL_MUX_ENABLE_DEBUG - uPortLog("U_CELL_CMUX_%d: writing %d byte(s) of decode I-field, buffer %d/%d.\n", + uPortLog("U_CELL_CMUX_%d: writing %d byte(s) of decoded I-field, buffer %d/%d.\n", pChannelContext->channel, parserContext.informationLengthBytes, serialGetReceiveSizeInnards(pDeviceSerial), diff --git a/cell/src/u_cell_mux_private.c b/cell/src/u_cell_mux_private.c index 99adaded..9f7459ef 100644 --- a/cell/src/u_cell_mux_private.c +++ b/cell/src/u_cell_mux_private.c @@ -49,6 +49,8 @@ #include "u_ringbuffer.h" #include "u_interface.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_device_serial.h" diff --git a/cell/src/u_cell_net.c b/cell/src/u_cell_net.c index 46b6ebfe..f4174218 100644 --- a/cell/src/u_cell_net.c +++ b/cell/src/u_cell_net.c @@ -51,6 +51,8 @@ #include "u_port_heap.h" #include "u_port_debug.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_sock.h" @@ -748,9 +750,8 @@ static bool keepGoingLocalCb(const uCellPrivateInstance_t *pInstance) if (pInstance->pKeepGoingCallback != NULL) { keepGoing = pInstance->pKeepGoingCallback(pInstance->cellHandle); } else { - if ((pInstance->startTimeMs > 0) && - !uPortTickTimeExpiredMs(pInstance->startTimeMs, - U_CELL_NET_CONNECT_TIMEOUT_SECONDS * 1000)) { + if (!uTimeoutExpiredSeconds(pInstance->timeoutStart, + U_CELL_NET_CONNECT_TIMEOUT_SECONDS)) { keepGoing = false; } } @@ -770,8 +771,8 @@ static int32_t radioOff(uCellPrivateInstance_t *pInstance) pInstance->profileState = U_CELL_PRIVATE_PROFILE_STATE_SHOULD_BE_DOWN; for (size_t x = 3; (x > 0) && (errorCode < 0); x--) { // Wait for flip time to expire - while (!uPortTickTimeExpiredMs(pInstance->lastCfunFlipTimeMs, - U_CELL_PRIVATE_AT_CFUN_FLIP_DELAY_SECONDS * 1000)) { + while (!uTimeoutExpiredSeconds(pInstance->lastCfunFlipTime, + U_CELL_PRIVATE_AT_CFUN_FLIP_DELAY_SECONDS)) { uPortTaskBlock(1000); } uAtClientLock(atHandle); @@ -800,7 +801,7 @@ static int32_t radioOff(uCellPrivateInstance_t *pInstance) } if (errorCode == 0) { - pInstance->lastCfunFlipTimeMs = uPortGetTickTimeMs(); + pInstance->lastCfunFlipTime = uTimeoutStart(); } return errorCode; @@ -1242,8 +1243,8 @@ static int32_t registerNetwork(uCellPrivateInstance_t *pInstance, // Come out of airplane mode and try to register // Wait for flip time to expire first though - while (!uPortTickTimeExpiredMs(pInstance->lastCfunFlipTimeMs, - U_CELL_PRIVATE_AT_CFUN_FLIP_DELAY_SECONDS * 1000)) { + while (!uTimeoutExpiredSeconds(pInstance->lastCfunFlipTime, + U_CELL_PRIVATE_AT_CFUN_FLIP_DELAY_SECONDS)) { uPortTaskBlock(1000); } // Reset the current registration status @@ -1256,7 +1257,7 @@ static int32_t registerNetwork(uCellPrivateInstance_t *pInstance, uAtClientCommandStopReadResponse(atHandle); errorCode = uAtClientUnlock(atHandle); if ((errorCode == 0) && (pMccMnc != NULL)) { - pInstance->lastCfunFlipTimeMs = uPortGetTickTimeMs(); + pInstance->lastCfunFlipTime = uTimeoutStart(); // A network was given, so automatic // mode is not enough. In manual mode // the AT command does not return until @@ -1718,7 +1719,7 @@ static int32_t activateContextUpsd(const uCellPrivateInstance_t *pInstance, int32_t errorCode; uAtClientHandle_t atHandle = pInstance->atHandle; uAtClientDeviceError_t deviceError; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; bool activated = false; // SARA-U2 pattern: everything is done through AT+UPSD @@ -1794,7 +1795,7 @@ static int32_t activateContextUpsd(const uCellPrivateInstance_t *pInstance, uAtClientLock(atHandle); // Set timeout to 1 second and we can spin around // the loop - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); uAtClientTimeoutSet(atHandle, 1000); uAtClientCommandStart(atHandle, "AT+UPSDA="); uAtClientWriteInt(atHandle, profileId); @@ -1804,8 +1805,8 @@ static int32_t activateContextUpsd(const uCellPrivateInstance_t *pInstance, deviceError.type = U_AT_CLIENT_DEVICE_ERROR_TYPE_NO_ERROR; while (!activated && keepGoingLocalCb(pInstance) && (deviceError.type == U_AT_CLIENT_DEVICE_ERROR_TYPE_NO_ERROR) && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_NET_UPSD_CONTEXT_ACTIVATION_TIME_SECONDS * 1000)) { + !uTimeoutExpiredSeconds(timeoutStart, + U_CELL_NET_UPSD_CONTEXT_ACTIVATION_TIME_SECONDS)) { uAtClientClearError(atHandle); uAtClientResponseStart(atHandle, NULL); activated = (uAtClientErrorGet(atHandle) == 0); @@ -2379,7 +2380,7 @@ int32_t uCellNetConnect(uDeviceHandle_t cellHandle, pApnConfig = pApnGetConfig(buffer); } pInstance->pKeepGoingCallback = pKeepGoingCallback; - pInstance->startTimeMs = uPortGetTickTimeMs(); + pInstance->timeoutStart = uTimeoutStart(); // Now try to connect, potentially multiple times do { if (pApnConfig != NULL) { @@ -2536,20 +2537,19 @@ int32_t uCellNetConnect(uDeviceHandle_t cellHandle, memcpy(pInstance->mccMnc, pMccMnc, sizeof(pInstance->mccMnc)); } pInstance->profileState = U_CELL_PRIVATE_PROFILE_STATE_SHOULD_BE_UP; - pInstance->connectedAtMs = uPortGetTickTimeMs(); + pInstance->connectedAt = uTimeoutStart(); uPortLog("U_CELL_NET: connected after %d second(s).\n", - (uPortGetTickTimeMs() - pInstance->startTimeMs) / 1000); + uTimeoutElapsedSeconds(pInstance->timeoutStart)); } else { // Switch radio off after failure radioOff(pInstance); uPortLog("U_CELL_NET: connection attempt stopped after" " %d second(s).\n", - (uPortGetTickTimeMs() - pInstance->startTimeMs) / 1000); + uTimeoutElapsedSeconds(pInstance->timeoutStart)); } // Take away the callback again pInstance->pKeepGoingCallback = NULL; - pInstance->startTimeMs = 0; } } else { uPortLog("U_CELL_NET: already connected.\n"); @@ -2587,7 +2587,7 @@ int32_t uCellNetRegister(uDeviceHandle_t cellHandle, errorCode = prepareConnect(pInstance); if (errorCode == 0) { pInstance->pKeepGoingCallback = pKeepGoingCallback; - pInstance->startTimeMs = uPortGetTickTimeMs(); + pInstance->timeoutStart = uTimeoutStart(); if (pMccMnc == NULL) { // If no MCC/MNC is given, make sure we are in // automatic network selection mode @@ -2626,18 +2626,17 @@ int32_t uCellNetRegister(uDeviceHandle_t cellHandle, memcpy(pInstance->mccMnc, pMccMnc, sizeof(pInstance->mccMnc)); } uPortLog("U_CELL_NET: registered after %d second(s).\n", - (uPortGetTickTimeMs() - pInstance->startTimeMs) / 1000); + uTimeoutElapsedSeconds(pInstance->timeoutStart)); } else { // Switch radio off after failure radioOff(pInstance); uPortLog("U_CELL_NET: registration attempt stopped after" " %d second(s).\n", - (uPortGetTickTimeMs() - pInstance->startTimeMs) / 1000); + uTimeoutElapsedSeconds(pInstance->timeoutStart)); } // Take away the callback again pInstance->pKeepGoingCallback = NULL; - pInstance->startTimeMs = 0; } } @@ -2689,7 +2688,7 @@ int32_t uCellNetActivate(uDeviceHandle_t cellHandle, if (errorCode != 0) { // No, get to work pInstance->pKeepGoingCallback = pKeepGoingCallback; - pInstance->startTimeMs = uPortGetTickTimeMs(); + pInstance->timeoutStart = uTimeoutStart(); if ((pApn == NULL) && (uCellPrivateGetImsi(pInstance, imsi) == 0)) { // Set up the APN look-up since none is specified @@ -2783,12 +2782,11 @@ int32_t uCellNetActivate(uDeviceHandle_t cellHandle, // Take away the callback again pInstance->pKeepGoingCallback = NULL; - pInstance->startTimeMs = 0; } if (errorCode == 0) { pInstance->profileState = U_CELL_PRIVATE_PROFILE_STATE_SHOULD_BE_UP; - pInstance->connectedAtMs = uPortGetTickTimeMs(); + pInstance->connectedAt = uTimeoutStart(); if (pApn != NULL) { uPortLog("U_CELL_NET: activated on APN \"%s\".\n", pApn); } else { @@ -2931,7 +2929,7 @@ int32_t uCellNetScanGetFirst(uDeviceHandle_t cellHandle, char *pBuffer; int32_t bytesRead; int32_t mode; - int32_t innerStartTimeMs; + uTimeoutStart_t innerTimeoutStart; uAtClientDeviceError_t deviceError; bool gotAnswer = false; char *pSaved; @@ -2969,7 +2967,7 @@ int32_t uCellNetScanGetFirst(uDeviceHandle_t cellHandle, // (,,,[,]) // it will be at longer than that hence we set // a threshold for readBytes of > 12 characters. - pInstance->startTimeMs = uPortGetTickTimeMs(); + pInstance->timeoutStart = uTimeoutStart(); for (size_t x = U_CELL_NET_SCAN_RETRIES + 1; (x > 0) && (errorCodeOrNumber <= 0) && ((pKeepGoingCallback == NULL) || (pKeepGoingCallback(cellHandle))); @@ -2988,10 +2986,10 @@ int32_t uCellNetScanGetFirst(uDeviceHandle_t cellHandle, // Sit in a loop waiting for a response // of some form to arrive bytesRead = -1; - innerStartTimeMs = uPortGetTickTimeMs(); + innerTimeoutStart = uTimeoutStart(); while ((bytesRead <= 0) && - !uPortTickTimeExpiredMs(innerStartTimeMs, - U_CELL_NET_SCAN_TIME_SECONDS * 1000) && + !uTimeoutExpiredSeconds(innerTimeoutStart, + U_CELL_NET_SCAN_TIME_SECONDS) && ((pKeepGoingCallback == NULL) || (pKeepGoingCallback(cellHandle)))) { uAtClientResponseStart(atHandle, "+COPS:"); // We use uAtClientReadBytes() here because the @@ -3126,7 +3124,7 @@ int32_t uCellNetDeepScan(uDeviceHandle_t cellHandle, bool keepGoing = true; int32_t number; int32_t cFunMode; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; if (gUCellPrivateMutex != NULL) { @@ -3145,11 +3143,11 @@ int32_t uCellNetDeepScan(uDeviceHandle_t cellHandle, // to do a network search, as it might be if // we've just come out of airplane mode, // it may return "Temporary Failure" - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); for (size_t x = U_CELL_NET_DEEP_SCAN_RETRIES + 1; (x > 0) && (errorCodeOrNumber < 0) && keepGoing && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_NET_DEEP_SCAN_TIME_SECONDS * 1000); + !uTimeoutExpiredSeconds(timeoutStart, + U_CELL_NET_DEEP_SCAN_TIME_SECONDS); x--) { number = 0; errorCodeOrNumber = (int32_t) U_ERROR_COMMON_TIMEOUT; @@ -3166,8 +3164,8 @@ int32_t uCellNetDeepScan(uDeviceHandle_t cellHandle, // want to be able to stop the command part way through, // hence the AT handling code below is more complex than usual. while ((errorCodeOrNumber == (int32_t) U_ERROR_COMMON_TIMEOUT) && keepGoing && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_NET_DEEP_SCAN_TIME_SECONDS * 1000)) { + !uTimeoutExpiredSeconds(timeoutStart, + U_CELL_NET_DEEP_SCAN_TIME_SECONDS)) { if (uAtClientResponseStart(atHandle, NULL) == 0) { // See if we have a line errorCodeOrNumber = parseDeepScanLine(atHandle, &cell); diff --git a/cell/src/u_cell_ppp.c b/cell/src/u_cell_ppp.c index 38036de8..e63166ab 100644 --- a/cell/src/u_cell_ppp.c +++ b/cell/src/u_cell_ppp.c @@ -52,6 +52,8 @@ #include "u_interface.h" #include "u_ringbuffer.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_device_shared.h" @@ -202,7 +204,7 @@ static int32_t sendExpect(uCellPppContext_t *pContext, uDeviceHandle_t cellHandle = pContext->cellHandle; char buffer[64]; int32_t timeoutMs = timeoutSeconds * 1000; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t x = 0; int32_t y = 0; @@ -218,9 +220,9 @@ static int32_t sendExpect(uCellPppContext_t *pContext, if (pResponse != NULL) { // Wait for a response to come back errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((errorCode == (int32_t) U_ERROR_COMMON_TIMEOUT) && - (uPortGetTickTimeMs() - startTimeMs < timeoutMs) && + !uTimeoutExpiredMs(timeoutStart, timeoutMs) && ((pKeepGoingCallback == NULL) || (pKeepGoingCallback(cellHandle)))) { x = pDeviceSerial->read(pDeviceSerial, buffer + y, sizeof(buffer) - y); if (x > 0) { diff --git a/cell/src/u_cell_private.c b/cell/src/u_cell_private.c index a96d5152..ab87ce90 100644 --- a/cell/src/u_cell_private.c +++ b/cell/src/u_cell_private.c @@ -45,6 +45,8 @@ #include "u_port_event_queue.h" #include "u_port_debug.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_sock.h" @@ -819,15 +821,15 @@ int32_t uCellPrivateCFunOne(uCellPrivateInstance_t *pInstance) // Set powered-up mode if it wasn't already if (errorCodeOrMode != 1) { // Wait for flip time to expire - while (!uPortTickTimeExpiredMs(pInstance->lastCfunFlipTimeMs, - U_CELL_PRIVATE_AT_CFUN_FLIP_DELAY_SECONDS * 1000)) { + while (!uTimeoutExpiredSeconds(pInstance->lastCfunFlipTime, + U_CELL_PRIVATE_AT_CFUN_FLIP_DELAY_SECONDS)) { uPortTaskBlock(1000); } uAtClientLock(atHandle); uAtClientCommandStart(atHandle, "AT+CFUN=1"); uAtClientCommandStopReadResponse(atHandle); if (uAtClientUnlock(atHandle) == 0) { - pInstance->lastCfunFlipTimeMs = uPortGetTickTimeMs(); + pInstance->lastCfunFlipTime = uTimeoutStart(); // And don't do anything for a second, // as the module might not be quite ready yet uPortTaskBlock(1000); @@ -844,8 +846,8 @@ void uCellPrivateCFunMode(uCellPrivateInstance_t *pInstance, uAtClientHandle_t atHandle = pInstance->atHandle; // Wait for flip time to expire - while (!uPortTickTimeExpiredMs(pInstance->lastCfunFlipTimeMs, - U_CELL_PRIVATE_AT_CFUN_FLIP_DELAY_SECONDS * 1000)) { + while (!uTimeoutExpiredSeconds(pInstance->lastCfunFlipTime, + U_CELL_PRIVATE_AT_CFUN_FLIP_DELAY_SECONDS)) { uPortTaskBlock(1000); } uAtClientLock(atHandle); @@ -860,7 +862,7 @@ void uCellPrivateCFunMode(uCellPrivateInstance_t *pInstance, uAtClientWriteInt(atHandle, mode); uAtClientCommandStopReadResponse(atHandle); if (uAtClientUnlock(atHandle) == 0) { - pInstance->lastCfunFlipTimeMs = uPortGetTickTimeMs(); + pInstance->lastCfunFlipTime = uTimeoutStart(); } } @@ -1453,12 +1455,12 @@ void uCellPrivateSetPinDtr(uCellPrivateInstance_t *pInstance, bool doNotPowerSav if (!doNotPowerSave) { targetState = !targetState; } - while (!uPortTickTimeExpiredMs(pInstance->lastDtrPinToggleTimeMs, - U_CELL_PWR_UART_POWER_SAVING_DTR_HYSTERESIS_MS)) { + while (!uTimeoutExpiredMs(pInstance->lastDtrPinToggleTime, + U_CELL_PWR_UART_POWER_SAVING_DTR_HYSTERESIS_MS)) { uPortTaskBlock(U_CELL_PRIVATE_DTR_PIN_HYSTERESIS_INTERVAL_MS); } if (uPortGpioSet(pInstance->pinDtrPowerSaving, targetState) == 0) { - pInstance->lastDtrPinToggleTimeMs = uPortGetTickTimeMs(); + pInstance->lastDtrPinToggleTime = uTimeoutStart(); uPortTaskBlock(U_CELL_PWR_UART_POWER_SAVING_DTR_READY_MS); } } diff --git a/cell/src/u_cell_private.h b/cell/src/u_cell_private.h index 6cee2e1a..a90c9d64 100644 --- a/cell/src/u_cell_private.h +++ b/cell/src/u_cell_private.h @@ -438,20 +438,20 @@ typedef struct uCellPrivateInstance_t { been requested (set to zeroes for automatic mode). */ - int32_t lastCfunFlipTimeMs; /**< The last time a flip of state from + uTimeoutStart_t lastCfunFlipTime; /**< The last time a flip of state from "off" (AT+CFUN=0/4) to "on" (AT+CFUN=1) or back was performed. */ - int32_t lastDtrPinToggleTimeMs; /**< The last time DTR was toggled for power-saving. */ + uTimeoutStart_t lastDtrPinToggleTime; /**< The last time DTR was toggled for power-saving. */ uCellNetStatus_t networkStatus[U_CELL_PRIVATE_NET_REG_TYPE_MAX_NUM]; /**< Registation status for each type, separating CREG, CGREG and CEREG. */ uCellNetRat_t rat[U_CELL_PRIVATE_NET_REG_TYPE_MAX_NUM]; /**< The active RAT for each registration type. */ int32_t lastEmmRejectCause; /**< Used by uCellNetGetLastEmmRejectCause() only. */ uCellPrivateRadioParameters_t radioParameters; /**< The radio parameters. */ - int32_t startTimeMs; /**< Used while connecting and scanning. */ - int32_t connectedAtMs; /**< When a connection was last established, - can be used for offsetting from that time; - does NOT mean that we are currently connected. */ + uTimeoutStart_t timeoutStart; /**< Used while connecting and scanning. */ + uTimeoutStart_t connectedAt; /**< When a connection was last established, + can be used for offsetting from that time; + does NOT mean that we are currently connected. */ bool rebootIsRequired; /**< Set to true if a reboot of the module is required, e.g. as a result of a configuration change. */ diff --git a/cell/src/u_cell_pwr.c b/cell/src/u_cell_pwr.c index 3f078d08..cf25a310 100644 --- a/cell/src/u_cell_pwr.c +++ b/cell/src/u_cell_pwr.c @@ -48,6 +48,8 @@ #include "u_ringbuffer.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" @@ -1116,8 +1118,8 @@ static int32_t moduleConfigure(uCellPrivateInstance_t *pInstance, if (andRadioOff) { // Switch the radio off until commanded to connect // Wait for flip time to expire - while (!uPortTickTimeExpiredMs(pInstance->lastCfunFlipTimeMs, - U_CELL_PRIVATE_AT_CFUN_FLIP_DELAY_SECONDS * 1000)) { + while (!uTimeoutExpiredSeconds(pInstance->lastCfunFlipTime, + U_CELL_PRIVATE_AT_CFUN_FLIP_DELAY_SECONDS)) { uPortTaskBlock(1000); } uAtClientLock(atHandle); @@ -1126,7 +1128,7 @@ static int32_t moduleConfigure(uCellPrivateInstance_t *pInstance, pInstance->pModule->radioOffCfun); uAtClientCommandStopReadResponse(atHandle); if (uAtClientUnlock(atHandle) == 0) { - pInstance->lastCfunFlipTimeMs = uPortGetTickTimeMs(); + pInstance->lastCfunFlipTime = uTimeoutStart(); errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; } } else { @@ -1143,11 +1145,11 @@ static void waitForPowerOff(uCellPrivateInstance_t *pInstance, { uAtClientHandle_t atHandle = pInstance->atHandle; bool moduleIsOff = false; - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); while (!moduleIsOff && - !uPortTickTimeExpiredMs(startTimeMs, - pInstance->pModule->powerDownWaitSeconds * 1000) && + !uTimeoutExpiredSeconds(timeoutStart, + pInstance->pModule->powerDownWaitSeconds) && ((pKeepGoingCallback == NULL) || pKeepGoingCallback(pInstance->cellHandle))) { if (pInstance->pinVInt >= 0) { // If we have a VInt pin then wait until that @@ -2160,8 +2162,8 @@ int32_t uCellPwrReboot(uDeviceHandle_t cellHandle, if (pInstance != NULL) { uPortLog("U_CELL_PWR: rebooting.\n"); // Wait for flip time to expire - while (!uPortTickTimeExpiredMs(pInstance->lastCfunFlipTimeMs, - U_CELL_PRIVATE_AT_CFUN_FLIP_DELAY_SECONDS * 1000)) { + while (!uTimeoutExpiredSeconds(pInstance->lastCfunFlipTime, + U_CELL_PRIVATE_AT_CFUN_FLIP_DELAY_SECONDS)) { uPortTaskBlock(1000); } // Sleep is no longer available @@ -2266,7 +2268,7 @@ int32_t uCellPwrResetHard(uDeviceHandle_t cellHandle, int32_t pinReset) uCellPrivateInstance_t *pInstance; int32_t platformError; uPortGpioConfig_t gpioConfig; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t resetHoldMilliseconds; int32_t pinResetToggleToState = (pinReset & U_CELL_PIN_INVERTED) ? !U_CELL_RESET_PIN_TOGGLE_TO_STATE : U_CELL_RESET_PIN_TOGGLE_TO_STATE; @@ -2322,8 +2324,8 @@ int32_t uCellPwrResetHard(uDeviceHandle_t cellHandle, int32_t pinReset) if (platformError == 0) { // We have rebooted pInstance->rebootIsRequired = false; - startTimeMs = uPortGetTickTimeMs(); - while (!uPortTickTimeExpiredMs(startTimeMs, resetHoldMilliseconds)) { + timeoutStart = uTimeoutStart(); + while (!uTimeoutExpiredMs(timeoutStart, resetHoldMilliseconds)) { uPortTaskBlock(100); } // Set the pin back to the "non RESET" state @@ -2339,7 +2341,7 @@ int32_t uCellPwrResetHard(uDeviceHandle_t cellHandle, int32_t pinReset) uAtClientFlush(pInstance->atHandle); } // Wait for the module to return to life and configure it - pInstance->lastCfunFlipTimeMs = uPortGetTickTimeMs(); + pInstance->lastCfunFlipTime = uTimeoutStart(); errorCode = uCellPwrPrivateIsAlive(pInstance, U_CELL_PWR_IS_ALIVE_ATTEMPTS_POWER_ON); if (errorCode == 0) { diff --git a/cell/src/u_cell_sec.c b/cell/src/u_cell_sec.c index 6aef65c1..4611c697 100644 --- a/cell/src/u_cell_sec.c +++ b/cell/src/u_cell_sec.c @@ -39,6 +39,8 @@ #include "u_port_os.h" #include "u_port_heap.h" +#include "u_timeout.h" + #include "u_hex_bin_convert.h" #include "u_at_client.h" diff --git a/cell/src/u_cell_sec_tls.c b/cell/src/u_cell_sec_tls.c index 29514d1e..07d3dae9 100644 --- a/cell/src/u_cell_sec_tls.c +++ b/cell/src/u_cell_sec_tls.c @@ -41,6 +41,8 @@ #include "u_port_os.h" #include "u_port_heap.h" +#include "u_timeout.h" + #include "u_hex_bin_convert.h" #include "u_at_client.h" diff --git a/cell/src/u_cell_sim.c b/cell/src/u_cell_sim.c index 32c1c733..968095a5 100644 --- a/cell/src/u_cell_sim.c +++ b/cell/src/u_cell_sim.c @@ -42,6 +42,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_hex_bin_convert.h" diff --git a/cell/src/u_cell_sock.c b/cell/src/u_cell_sock.c index 42d97fd1..0a6f9ce4 100644 --- a/cell/src/u_cell_sock.c +++ b/cell/src/u_cell_sock.c @@ -43,6 +43,8 @@ #include "u_port_heap.h" #include "u_port_debug.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_hex_bin_convert.h" @@ -1961,7 +1963,7 @@ int32_t uCellSockGetHostByName(uDeviceHandle_t cellHandle, int32_t bytesRead = 0; char buffer[U_SOCK_ADDRESS_STRING_MAX_LENGTH_BYTES]; uSockAddress_t address; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t tries = 0; memset(&address, 0, sizeof(address)); @@ -1982,17 +1984,17 @@ int32_t uCellSockGetHostByName(uDeviceHandle_t cellHandle, // instead of "+UDNSRN" (i.e. it adds an extra "U") // so, if parsing for the correct response fails and // we're on LENA-R8 then allow one retry. - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while (((atError < 0) || (bytesRead <= 0)) && - (!uPortTickTimeExpiredMs(startTimeMs, - U_CELL_SOCK_DNS_SHOULD_RETRY_MS) || + (!uTimeoutExpiredMs(timeoutStart, + U_CELL_SOCK_DNS_SHOULD_RETRY_MS) || ((pInstance->pModule->moduleType == U_CELL_MODULE_TYPE_LENA_R8) && (tries < 2)))) { if (pInstance->pModule->moduleType == U_CELL_MODULE_TYPE_SARA_R422) { // SARA-R422 can get upset if UDNSRN is sent very quickly // after a connection is made so we add a short delay here - while (!uPortTickTimeExpiredMs(pInstance->connectedAtMs, - U_CELL_SOCK_SARA_R422_DNS_DELAY_MILLISECONDS)) { + while (!uTimeoutExpiredMs(pInstance->connectedAt, + U_CELL_SOCK_SARA_R422_DNS_DELAY_MILLISECONDS)) { uPortTaskBlock(100); } } diff --git a/cell/src/u_cell_time.c b/cell/src/u_cell_time.c index de5afb9e..f708d3b3 100644 --- a/cell/src/u_cell_time.c +++ b/cell/src/u_cell_time.c @@ -48,6 +48,8 @@ #include "u_port_heap.h" #include "u_port_uart.h" +#include "u_timeout.h" + #include "u_time.h" #include "u_at_client.h" @@ -680,7 +682,7 @@ int32_t uCellTimeSyncCellEnable(uDeviceHandle_t cellHandle, uCellTimeCellSyncPrivateContext_t *pContext; uAtClientHandle_t atHandle; char buffer[7]; // Enough room for MCC/MNC plus a null terminator - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; if (gUCellPrivateMutex != NULL) { @@ -726,11 +728,11 @@ int32_t uCellTimeSyncCellEnable(uDeviceHandle_t cellHandle, errorCode = uAtClientUnlock(atHandle); if (errorCode == 0) { // Wait for the URC for the outcome - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; while ((pContext->errorCode == INT_MIN) && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_TIME_SYNC_TIME_SECONDS * 1000)) { + !uTimeoutExpiredSeconds(timeoutStart, + U_CELL_TIME_SYNC_TIME_SECONDS)) { uPortTaskBlock(1000); } if (pContext->errorCode != INT_MIN) { @@ -764,7 +766,7 @@ int32_t uCellTimeSyncCellDisable(uDeviceHandle_t cellHandle) uCellPrivateInstance_t *pInstance; uCellTimeCellSyncPrivateContext_t *pContext; uAtClientHandle_t atHandle; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; if (gUCellPrivateMutex != NULL) { @@ -789,11 +791,11 @@ int32_t uCellTimeSyncCellDisable(uDeviceHandle_t cellHandle) errorCode = uAtClientUnlock(atHandle); if (errorCode == 0) { // Have to wait for the URC for the outcome - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; while ((pContext->errorCode != (int32_t) U_ERROR_COMMON_CANCELLED) && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_TIME_SYNC_TIME_SECONDS * 1000)) { + !uTimeoutExpiredSeconds(timeoutStart, + U_CELL_TIME_SYNC_TIME_SECONDS)) { uPortTaskBlock(1000); } if (pContext->errorCode != INT_MIN) { diff --git a/cell/test/u_cell_cfg_test.c b/cell/test/u_cell_cfg_test.c index 02cdd23f..516adac2 100644 --- a/cell/test/u_cell_cfg_test.c +++ b/cell/test/u_cell_cfg_test.c @@ -56,6 +56,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" @@ -136,7 +138,7 @@ /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** The GNSS profile bit map. */ @@ -157,7 +159,8 @@ static bool keepGoingCallback(uDeviceHandle_t unused) (void) unused; - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -756,8 +759,8 @@ U_PORT_TEST_FUNCTION("[cellCfg]", "cellCfgGetSetMnoProfile") if (U_CELL_PRIVATE_HAS(pModule, U_CELL_PRIVATE_FEATURE_MNO_PROFILE)) { U_TEST_PRINT_LINE("trying to set MNO profile while connected..."); - gStopTimeMs = uPortGetTickTimeMs() + - (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; U_PORT_TEST_ASSERT(uCellNetRegister(cellHandle, NULL, keepGoingCallback) == 0); U_PORT_TEST_ASSERT(uCellNetIsRegistered(cellHandle)); diff --git a/cell/test/u_cell_file_test.c b/cell/test/u_cell_file_test.c index 1de9dd56..311b5711 100644 --- a/cell/test/u_cell_file_test.c +++ b/cell/test/u_cell_file_test.c @@ -56,6 +56,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" diff --git a/cell/test/u_cell_fota_test.c b/cell/test/u_cell_fota_test.c index 284b45d8..a7f83dbb 100644 --- a/cell/test/u_cell_fota_test.c +++ b/cell/test/u_cell_fota_test.c @@ -52,6 +52,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" diff --git a/cell/test/u_cell_geofence_test.c b/cell/test/u_cell_geofence_test.c index 9d72c675..c1f42a7d 100644 --- a/cell/test/u_cell_geofence_test.c +++ b/cell/test/u_cell_geofence_test.c @@ -51,6 +51,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_location.h" @@ -144,7 +146,7 @@ static uGeofence_t *gpFenceB = NULL; /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** Variable to track the errors in the callback. */ @@ -176,7 +178,8 @@ static bool keepGoingCallback(uDeviceHandle_t cellHandle) bool keepGoing = true; U_PORT_TEST_ASSERT(cellHandle == gHandles.cellHandle); - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -267,7 +270,6 @@ U_PORT_TEST_FUNCTION("[cellGeofence]", "cellGeofenceLive") #if defined(U_CFG_APP_CELL_LOC_AUTHENTICATION_TOKEN) && defined(U_CFG_TEST_CELL_GEOFENCE) uDeviceHandle_t cellHandle; int32_t resourceCount; - int32_t startTime; int32_t x; size_t badStatusCount; @@ -313,7 +315,8 @@ U_PORT_TEST_FUNCTION("[cellGeofence]", "cellGeofenceLive") U_PORT_TEST_ASSERT(x == 0); // Make sure we are connected to a network - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_GEOFENCE_TEST_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_GEOFENCE_TEST_TIMEOUT_SECONDS * 1000; x = uCellNetConnect(cellHandle, NULL, # ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), @@ -367,8 +370,8 @@ U_PORT_TEST_FUNCTION("[cellGeofence]", "cellGeofenceLive") // Get position, blocking version U_TEST_PRINT_LINE("cell locate, blocking version."); - startTime = uPortGetTickTimeMs(); - gStopTimeMs = startTime + U_CELL_GEOFENCE_TEST_TIMEOUT_SECONDS * 1000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_GEOFENCE_TEST_TIMEOUT_SECONDS * 1000; x = uCellLocGet(cellHandle, NULL, NULL, NULL, NULL, NULL, NULL, NULL, keepGoingCallback); U_TEST_PRINT_LINE("result was %d, gErrorCode was %d.", x, gErrorCode); @@ -377,7 +380,7 @@ U_PORT_TEST_FUNCTION("[cellGeofence]", "cellGeofenceLive") gpPositionStateString[gPositionStateB]); if (x == 0) { U_TEST_PRINT_LINE("location establishment took %d second(s).", - (uPortGetTickTimeMs() - startTime) / 1000); + uTimeoutElapsedSeconds(gTimeoutStop.timeoutStart)); } U_PORT_TEST_ASSERT(x == 0); @@ -394,14 +397,15 @@ U_PORT_TEST_FUNCTION("[cellGeofence]", "cellGeofenceLive") for (int32_t y = 3; (y > 0) && (gErrorCode == 0); y--) { gPositionStateA = U_GEOFENCE_POSITION_STATE_NONE; gPositionStateB = U_GEOFENCE_POSITION_STATE_NONE; - gStopTimeMs = startTime + U_CELL_GEOFENCE_TEST_TIMEOUT_SECONDS * 1000; - startTime = uPortGetTickTimeMs(); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_GEOFENCE_TEST_TIMEOUT_SECONDS * 1000; U_PORT_TEST_ASSERT(uCellLocGetStart(cellHandle, posCallback) == 0); U_TEST_PRINT_LINE("waiting up to %d second(s) for results from asynchonous API...", U_CELL_GEOFENCE_TEST_TIMEOUT_SECONDS); badStatusCount = 0; while ((gErrorCode >= 0) && (gErrorCode < 2) && - (uPortGetTickTimeMs() < gStopTimeMs) && + (!uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) && (badStatusCount < U_CELL_GEOFENCE_TEST_BAD_STATUS_LIMIT)) { x = uCellLocGetStatus(cellHandle); U_PORT_TEST_ASSERT((x >= U_LOCATION_STATUS_UNKNOWN) && @@ -418,7 +422,7 @@ U_PORT_TEST_FUNCTION("[cellGeofence]", "cellGeofenceLive") } if (gErrorCode == 2) { U_TEST_PRINT_LINE("location establishment took %d second(s).", - (uPortGetTickTimeMs() - startTime) / 1000); + uTimeoutElapsedSeconds(gTimeoutStop.timeoutStart)); U_TEST_PRINT_LINE("result was %d, gErrorCode was %d.", x, gErrorCode); U_TEST_PRINT_LINE("%s fence A, %s fence B.", gpPositionStateString[gPositionStateA], diff --git a/cell/test/u_cell_gpio_test.c b/cell/test/u_cell_gpio_test.c index 7dd77354..d618f63a 100644 --- a/cell/test/u_cell_gpio_test.c +++ b/cell/test/u_cell_gpio_test.c @@ -54,6 +54,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" diff --git a/cell/test/u_cell_http_test.c b/cell/test/u_cell_http_test.c index ebd602b1..85dbf616 100644 --- a/cell/test/u_cell_http_test.c +++ b/cell/test/u_cell_http_test.c @@ -62,6 +62,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" @@ -131,7 +133,7 @@ typedef struct { /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** Handles. */ @@ -183,7 +185,8 @@ static bool keepGoingCallback(uDeviceHandle_t unused) (void) unused; - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -293,11 +296,11 @@ static bool waitCheckHttpResponse(int32_t timeoutSeconds, const char *pFileNameResponse) { bool isOk = false; - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); U_TEST_PRINT_LINE("waiting up to %d second(s) for response to request type %s...", timeoutSeconds, pHttpRequestTypeStr(requestType)); - while (!uPortTickTimeExpiredMs(startTimeMs, timeoutSeconds * 1000) && + while (!uTimeoutExpiredSeconds(timeoutStart, timeoutSeconds) && !pCallbackData->called) { uPortTaskBlock(100); } @@ -306,7 +309,7 @@ static bool waitCheckHttpResponse(int32_t timeoutSeconds, isOk = true; // The callback was called, check everything U_TEST_PRINT_LINE("response received after %d millisecond(s).", - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(timeoutStart)); if (pCallbackData->cellHandle != cellHandle) { U_TEST_PRINT_LINE("expected cell handle 0x%08x, got 0x%08x.", cellHandle, pCallbackData->cellHandle); @@ -345,7 +348,7 @@ static bool waitCheckHttpResponse(int32_t timeoutSeconds, } } else { U_TEST_PRINT_LINE("callback not called after %d second(s).", - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(timeoutStart)); } // Reset for next time @@ -408,8 +411,8 @@ U_PORT_TEST_FUNCTION("[cellHttp]", "cellHttp") // Make a cellular connection, since we will need to do a // DNS look-up on the HTTP server domain name - gStopTimeMs = uPortGetTickTimeMs() + - (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; y = uCellNetConnect(cellHandle, NULL, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), diff --git a/cell/test/u_cell_info_test.c b/cell/test/u_cell_info_test.c index 34441ce4..a87a70da 100644 --- a/cell/test/u_cell_info_test.c +++ b/cell/test/u_cell_info_test.c @@ -54,6 +54,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" @@ -102,7 +104,7 @@ /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** Handles. */ @@ -119,7 +121,8 @@ static bool keepGoingCallback(uDeviceHandle_t unused) (void) unused; - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -340,8 +343,8 @@ U_PORT_TEST_FUNCTION("[cellInfo]", "cellInfoRadioParameters") } U_TEST_PRINT_LINE("checking values after registration..."); - gStopTimeMs = uPortGetTickTimeMs() + - (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; U_PORT_TEST_ASSERT(uCellNetRegister(cellHandle, NULL, keepGoingCallback) == 0); U_PORT_TEST_ASSERT(uCellNetIsRegistered(cellHandle)); @@ -432,8 +435,8 @@ U_PORT_TEST_FUNCTION("[cellInfo]", "cellInfoTime") cellHandle = gHandles.cellHandle; U_TEST_PRINT_LINE("registering to check the time..."); - gStopTimeMs = uPortGetTickTimeMs() + - (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; U_PORT_TEST_ASSERT(uCellNetRegister(cellHandle, NULL, keepGoingCallback) == 0); U_TEST_PRINT_LINE("fetching the UTC time..."); diff --git a/cell/test/u_cell_loc_test.c b/cell/test/u_cell_loc_test.c index aaac58b7..e4967f0e 100644 --- a/cell/test/u_cell_loc_test.c +++ b/cell/test/u_cell_loc_test.c @@ -57,6 +57,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #ifdef U_CFG_TEST_GNSS_MODULE_TYPE @@ -196,7 +198,7 @@ static const char *gpAssistNowDataType[] = {"U_GNSS_MGA_DATA_TYPE_EPHEMERIS", /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** Cell handle as seen by posCallback(). */ @@ -248,7 +250,8 @@ static bool keepGoingCallback(uDeviceHandle_t param) (void) param; - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -649,7 +652,6 @@ U_PORT_TEST_FUNCTION("[cellLoc]", "cellLocLoc") #if defined(U_CFG_APP_CELL_LOC_AUTHENTICATION_TOKEN) && defined(U_CFG_TEST_CELL_LOCATE) uDeviceHandle_t cellHandle; int32_t resourceCount; - int32_t startTimeMs; int32_t latitudeX1e7 = INT_MIN; int32_t longitudeX1e7 = INT_MIN; int32_t altitudeMillimetres = INT_MIN; @@ -705,7 +707,8 @@ U_PORT_TEST_FUNCTION("[cellLoc]", "cellLocLoc") U_PORT_TEST_ASSERT(x == 0); // Make sure we are connected to a network - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_LOC_TEST_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_LOC_TEST_TIMEOUT_SECONDS * 1000; x = uCellNetConnect(cellHandle, NULL, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), @@ -727,8 +730,8 @@ U_PORT_TEST_FUNCTION("[cellLoc]", "cellLocLoc") // Get position, blocking version U_TEST_PRINT_LINE("location establishment, blocking version."); - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + U_CELL_LOC_TEST_TIMEOUT_SECONDS * 1000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_LOC_TEST_TIMEOUT_SECONDS * 1000; x = uCellLocGet(cellHandle, &latitudeX1e7, &longitudeX1e7, &altitudeMillimetres, &radiusMillimetres, &speedMillimetresPerSecond, &svs, @@ -738,7 +741,7 @@ U_PORT_TEST_FUNCTION("[cellLoc]", "cellLocLoc") // we should always get time if (x == 0) { U_TEST_PRINT_LINE("location establishment took %d second(s).", - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(gTimeoutStop.timeoutStart)); if ((radiusMillimetres > 0) && (radiusMillimetres <= U_CELL_LOC_TEST_MAX_RADIUS_MILLIMETRES)) { prefix[0] = latLongToBits(latitudeX1e7, &(whole[0]), &(fraction[0])); @@ -770,13 +773,15 @@ U_PORT_TEST_FUNCTION("[cellLoc]", "cellLocLoc") // location again quickly after returning an answer for (int32_t y = 3; (y > 0) && (gErrorCode != 0); y--) { gErrorCode = 0xFFFFFFFF; - gStopTimeMs = startTimeMs + U_CELL_LOC_TEST_TIMEOUT_SECONDS * 1000; - startTimeMs = uPortGetTickTimeMs(); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_LOC_TEST_TIMEOUT_SECONDS * 1000; U_PORT_TEST_ASSERT(uCellLocGetStart(cellHandle, posCallback) == 0); U_TEST_PRINT_LINE("waiting up to %d second(s) for results from asynchonous API...", U_CELL_LOC_TEST_TIMEOUT_SECONDS); badStatusCount = 0; - while ((gErrorCode == 0xFFFFFFFF) && (uPortGetTickTimeMs() < gStopTimeMs) && + while ((gErrorCode == 0xFFFFFFFF) && + !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs) && (badStatusCount < U_CELL_LOC_TEST_BAD_STATUS_LIMIT)) { x = uCellLocGetStatus(cellHandle); U_PORT_TEST_ASSERT((x >= U_LOCATION_STATUS_UNKNOWN) && @@ -796,15 +801,13 @@ U_PORT_TEST_FUNCTION("[cellLoc]", "cellLocLoc") // we should always get time if (gErrorCode == 0) { U_TEST_PRINT_LINE("location establishment took %d second(s).", - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(gTimeoutStop.timeoutStart)); U_PORT_TEST_ASSERT(gCellHandle == cellHandle); if ((radiusMillimetres > 0) && (radiusMillimetres <= U_CELL_LOC_TEST_MAX_RADIUS_MILLIMETRES)) { x = uCellLocGetStatus(cellHandle); U_PORT_TEST_ASSERT((x >= U_LOCATION_STATUS_UNKNOWN) && (x < U_LOCATION_STATUS_MAX_NUM)); - U_TEST_PRINT_LINE("location establishment took %d second(s).", - (uPortGetTickTimeMs() - startTimeMs) / 1000); U_PORT_TEST_ASSERT(gLatitudeX1e7 > INT_MIN); U_PORT_TEST_ASSERT(gLongitudeX1e7 > INT_MIN); U_PORT_TEST_ASSERT(gAltitudeMillimetres > INT_MIN); diff --git a/cell/test/u_cell_mqtt_test.c b/cell/test/u_cell_mqtt_test.c index abb91e00..205b98ce 100644 --- a/cell/test/u_cell_mqtt_test.c +++ b/cell/test/u_cell_mqtt_test.c @@ -57,6 +57,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" @@ -128,7 +130,7 @@ /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** Generic handles. */ @@ -162,7 +164,8 @@ static bool keepGoingCallback(uDeviceHandle_t unused) (void) unused; - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -219,7 +222,8 @@ U_PORT_TEST_FUNCTION("[cellMqtt]", "cellMqtt") // Make a cellular connection, since we will need to do a // DNS look-up on the MQTT broker domain name - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; x = uCellNetConnect(cellHandle, NULL, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), @@ -533,7 +537,8 @@ U_PORT_TEST_FUNCTION("[cellMqtt]", "cellMqttSn") // Make a cellular connection, since we will need to do a // DNS look-up on the MQTT-SN broker domain name - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; x = uCellNetConnect(cellHandle, NULL, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), diff --git a/cell/test/u_cell_mux_private_test.c b/cell/test/u_cell_mux_private_test.c index cc11a762..4fe9626d 100644 --- a/cell/test/u_cell_mux_private_test.c +++ b/cell/test/u_cell_mux_private_test.c @@ -46,6 +46,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_ringbuffer.h" diff --git a/cell/test/u_cell_mux_test.c b/cell/test/u_cell_mux_test.c index 3cd36978..685fbacc 100644 --- a/cell/test/u_cell_mux_test.c +++ b/cell/test/u_cell_mux_test.c @@ -64,6 +64,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_sock.h" @@ -168,7 +170,7 @@ typedef struct { /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** Handles. */ @@ -226,7 +228,8 @@ static bool keepGoingCallback(uDeviceHandle_t unused) (void) unused; - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -248,8 +251,8 @@ static void printBuffer(const char *pBuffer, size_t length) // Make a cellular connection static int32_t connect(uDeviceHandle_t cellHandle) { - gStopTimeMs = uPortGetTickTimeMs() + - (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; return uCellNetConnect(cellHandle, NULL, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), @@ -379,11 +382,11 @@ static bool httpWaitCheckResponse(int32_t timeoutSeconds, const char *pFileNameResponse) { bool isOk = false; - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); U_TEST_PRINT_LINE("waiting up to %d second(s) for response to HTTP request...", timeoutSeconds); - while (!uPortTickTimeExpiredMs(startTimeMs, timeoutSeconds * 1000) && + while (!uTimeoutExpiredSeconds(timeoutStart, timeoutSeconds) && !pCallbackData->called) { uPortTaskBlock(100); } @@ -392,7 +395,7 @@ static bool httpWaitCheckResponse(int32_t timeoutSeconds, isOk = true; // The callback was called, check everything U_TEST_PRINT_LINE("response received after %d millisecond(s).", - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(timeoutStart)); if (pCallbackData->cellHandle != cellHandle) { U_TEST_PRINT_LINE("expected cell handle 0x%08x, got 0x%08x.", cellHandle, pCallbackData->cellHandle); @@ -429,7 +432,7 @@ static bool httpWaitCheckResponse(int32_t timeoutSeconds, } } else { U_TEST_PRINT_LINE("callback not called after %d second(s).", - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedMs(timeoutStart)); } // Reset for next time @@ -705,7 +708,7 @@ U_PORT_TEST_FUNCTION("[cellMux]", "cellMuxMqtt") char topic[U_CELL_INFO_IMEI_SIZE + 1] = {0}; char *pMessageIn; char *pTopicStrIn; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; size_t messageSize = sizeof(gMqttSendData) - 1; uCellMqttQos_t qos; @@ -777,7 +780,7 @@ U_PORT_TEST_FUNCTION("[cellMux]", "cellMuxMqtt") U_CELL_MQTT_QOS_AT_MOST_ONCE) == 0); U_TEST_PRINT_LINE("publishing \"%s\" to topic \"%s\"...", gMqttSendData, topic); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); gMqttMessagesAvailable = 0; U_PORT_TEST_ASSERT(uCellMqttPublish(cellHandle, topic, gMqttSendData, sizeof(gMqttSendData) - 1, @@ -787,8 +790,8 @@ U_PORT_TEST_FUNCTION("[cellMux]", "cellMuxMqtt") U_TEST_PRINT_LINE("waiting %d second(s) for message to be sent back...", U_CELL_MUX_TEST_MQTT_RESPONSE_TIMEOUT_MS); while ((gMqttMessagesAvailable == 0) && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_MUX_TEST_MQTT_RESPONSE_TIMEOUT_MS)) { + !uTimeoutExpiredMs(timeoutStart, + U_CELL_MUX_TEST_MQTT_RESPONSE_TIMEOUT_MS)) { uPortTaskBlock(1000); } diff --git a/cell/test/u_cell_net_test.c b/cell/test/u_cell_net_test.c index d5f2c599..7a73588b 100644 --- a/cell/test/u_cell_net_test.c +++ b/cell/test/u_cell_net_test.c @@ -58,6 +58,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" @@ -91,7 +93,7 @@ /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** Handles. */ @@ -127,7 +129,8 @@ static bool keepGoingCallback(uDeviceHandle_t cellHandle) gCallbackErrorCode = 1; } - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -281,7 +284,8 @@ U_PORT_TEST_FUNCTION("[cellNet]", "cellNetConnectDisconnectPlus") // Connect with a very short time-out to show that aborts work U_TEST_PRINT_LINE("testing abort of connection attempt due to timeout."); - gStopTimeMs = uPortGetTickTimeMs() + 1000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = 1000; x = uCellNetConnect(cellHandle, NULL, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), @@ -302,7 +306,8 @@ U_PORT_TEST_FUNCTION("[cellNet]", "cellNetConnectDisconnectPlus") U_PORT_TEST_ASSERT(x < 0); // Now connect with a sensible timeout - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; x = uCellNetConnect(cellHandle, NULL, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), @@ -423,7 +428,8 @@ U_PORT_TEST_FUNCTION("[cellNet]", "cellNetConnectDisconnectPlus") // LENA-R8 which does not support reading the current APN // and hence can't tell if we're on the right one or not, // hence the timeout is larger than the 5 seconds it used to be - gStopTimeMs = uPortGetTickTimeMs() + 60000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = 60000; U_TEST_PRINT_LINE("connecting again with same APN..."); x = uCellNetConnect(cellHandle, NULL, #ifdef U_CELL_TEST_CFG_APN @@ -458,7 +464,8 @@ U_PORT_TEST_FUNCTION("[cellNet]", "cellNetConnectDisconnectPlus") // Don't try using an invalid APN with SARA-U201 as it // upsets it too much U_TEST_PRINT_LINE("connecting with different (invalid) APN..."); - gStopTimeMs = uPortGetTickTimeMs() + 10000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = 10000; x = uCellNetConnect(cellHandle, NULL, "flibble", # ifdef U_CELL_TEST_CFG_USERNAME U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_USERNAME), @@ -553,7 +560,8 @@ U_PORT_TEST_FUNCTION("[cellNet]", "cellNetScanRegActDeact") // user request, so give it several goes for (size_t x = 5; (x > 0) && (y <= 0); x--) { U_TEST_PRINT_LINE("scanning for networks..."); - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; memset(buffer, 0, sizeof(buffer)); memset(mccMnc, 0, sizeof(mccMnc)); for (int32_t z = uCellNetScanGetFirst(cellHandle, buffer, @@ -588,12 +596,14 @@ U_PORT_TEST_FUNCTION("[cellNet]", "cellNetScanRegActDeact") // since that is where the results can be used // Register with a very short time-out to show that aborts work - gStopTimeMs = uPortGetTickTimeMs() + 1000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = 1000; U_PORT_TEST_ASSERT(uCellNetRegister(cellHandle, NULL, keepGoingCallback) < 0); // Now register with a sensible timeout U_TEST_PRINT_LINE("registering..."); - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; U_PORT_TEST_ASSERT(uCellNetRegister(cellHandle, NULL, keepGoingCallback) == 0); // Check that we're registered @@ -614,12 +624,14 @@ U_PORT_TEST_FUNCTION("[cellNet]", "cellNetScanRegActDeact") // Register again: should come back with no error pretty much straight away U_TEST_PRINT_LINE("registering while already registered..."); - gStopTimeMs = uPortGetTickTimeMs() + 10000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = 10000; U_PORT_TEST_ASSERT(uCellNetRegister(cellHandle, NULL, keepGoingCallback) == 0); // Now activate a PDP context U_TEST_PRINT_LINE("activating context..."); - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONTEXT_ACTIVATION_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONTEXT_ACTIVATION_TIMEOUT_SECONDS * 1000; y = uCellNetActivate(cellHandle, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), @@ -659,7 +671,8 @@ U_PORT_TEST_FUNCTION("[cellNet]", "cellNetScanRegActDeact") U_CELL_PRIVATE_MODULE_IS_SARA_R4(pModule->moduleType)) { // If we were originally on LTE, or if this is a SARA-R4 // we will now be deregistered, so register again - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; U_PORT_TEST_ASSERT(uCellNetRegister(cellHandle, NULL, keepGoingCallback) == 0); } else { // Get the IP address again, should be gone in the non-LTE/R4 case @@ -668,7 +681,8 @@ U_PORT_TEST_FUNCTION("[cellNet]", "cellNetScanRegActDeact") // Check that we can activate the PDP context again U_TEST_PRINT_LINE("activating context..."); - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONTEXT_ACTIVATION_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONTEXT_ACTIVATION_TIMEOUT_SECONDS * 1000; y = uCellNetActivate(cellHandle, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), @@ -702,7 +716,8 @@ U_PORT_TEST_FUNCTION("[cellNet]", "cellNetScanRegActDeact") // uCellNetActivate() performs to see if the current context // is fine will fail and so we will detach and reattach here, // which takes longer - gStopTimeMs = uPortGetTickTimeMs() + 60000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = 60000; y = uCellNetActivate(cellHandle, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), @@ -737,7 +752,8 @@ U_PORT_TEST_FUNCTION("[cellNet]", "cellNetScanRegActDeact") // Don't do this for SARA-U201 as it upsets it rather a lot U_TEST_PRINT_LINE("activating context with different (invalid) APN..."); rat = uCellNetGetActiveRat(cellHandle); - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONTEXT_ACTIVATION_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONTEXT_ACTIVATION_TIMEOUT_SECONDS * 1000; y = uCellNetActivate(cellHandle, "flibble", # ifdef U_CELL_TEST_CFG_USERNAME U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_USERNAME), @@ -771,7 +787,8 @@ U_PORT_TEST_FUNCTION("[cellNet]", "cellNetScanRegActDeact") y = -1; for (size_t x = 2; (x > 0) && (y < 0); x--) { U_TEST_PRINT_LINE("connecting manually to network %s...", mccMnc); - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; y = uCellNetConnect(cellHandle, mccMnc, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), @@ -829,7 +846,8 @@ U_PORT_TEST_FUNCTION("[cellNet]", "cellNetScanRegActDeact") // Now register with manual network selection U_TEST_PRINT_LINE("registering manually on network %s...", mccMnc); - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; U_PORT_TEST_ASSERT(uCellNetRegister(cellHandle, mccMnc, keepGoingCallback) == 0); @@ -844,7 +862,8 @@ U_PORT_TEST_FUNCTION("[cellNet]", "cellNetScanRegActDeact") (status == U_CELL_NET_STATUS_REGISTERED_NO_CSFB_ROAMING)); // Now activate a PDP context - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; y = uCellNetActivate(cellHandle, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), diff --git a/cell/test/u_cell_ppp_test.c b/cell/test/u_cell_ppp_test.c index 9fd44385..b0a8c081 100644 --- a/cell/test/u_cell_ppp_test.c +++ b/cell/test/u_cell_ppp_test.c @@ -57,6 +57,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #ifdef U_CFG_TEST_GNSS_MODULE_TYPE @@ -118,7 +120,7 @@ /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** Handle. */ @@ -140,7 +142,8 @@ static bool keepGoingCallback(uDeviceHandle_t unused) (void) unused; - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -279,7 +282,8 @@ U_PORT_TEST_FUNCTION("[cellPpp]", "cellPppBasic") if (U_CELL_PRIVATE_HAS(pModule, U_CELL_PRIVATE_FEATURE_PPP)) { U_TEST_PRINT_LINE("testing PPP, first with no connection."); // First check before having connected: should return error - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_PPP_TEST_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_PPP_TEST_TIMEOUT_SECONDS * 1000; x = uCellPppOpen(cellHandle, NULL, NULL, gBuffer, sizeof(gBuffer), keepGoingCallback); U_TEST_PRINT_LINE("uCellPppOpen() returned %d.", x); @@ -290,8 +294,8 @@ U_PORT_TEST_FUNCTION("[cellPpp]", "cellPppBasic") U_TEST_PRINT_LINE("now with a connection."); // Now connect - gStopTimeMs = uPortGetTickTimeMs() + - (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; x = uCellNetConnect(cellHandle, NULL, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), @@ -311,7 +315,8 @@ U_PORT_TEST_FUNCTION("[cellPpp]", "cellPppBasic") keepGoingCallback); U_PORT_TEST_ASSERT (x == 0); - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_PPP_TEST_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_PPP_TEST_TIMEOUT_SECONDS * 1000; x = uCellPppOpen(cellHandle, NULL, NULL, gBuffer, sizeof(gBuffer), keepGoingCallback); U_TEST_PRINT_LINE("uCellPppOpen() returned %d.", x); diff --git a/cell/test/u_cell_pwr_test.c b/cell/test/u_cell_pwr_test.c index e2f26f06..2a09bd29 100644 --- a/cell/test/u_cell_pwr_test.c +++ b/cell/test/u_cell_pwr_test.c @@ -54,6 +54,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_sock.h" @@ -192,7 +194,7 @@ static uCellTestPrivate_t gHandles = U_CELL_TEST_PRIVATE_DEFAULTS; !defined(U_CFG_CELL_DISABLE_UART_POWER_SAVING) /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** A variable to track errors in the callbacks. */ @@ -241,7 +243,8 @@ static bool keepGoingCallback(uDeviceHandle_t cellHandle) gCallbackErrorCode = 1; } - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -350,7 +353,8 @@ static void testPowerAliveVInt(uCellTestPrivate_t *pHandles, // called here as we've no control over how long the // module takes to power off. pKeepGoingCallback = keepGoingCallback; - gStopTimeMs = uPortGetTickTimeMs() + ((pModule->powerDownWaitSeconds) * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = pModule->powerDownWaitSeconds * 1000; } # if U_CFG_APP_PIN_CELL_VINT < 0 timeMs = uPortGetTickTimeMs(); @@ -460,7 +464,8 @@ static void wakeCallback(uDeviceHandle_t cellHandle, void *pParam) // Connect to a cellular network. static int32_t connectNetwork(uDeviceHandle_t cellHandle) { - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; return uCellNetConnect(cellHandle, NULL, # ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), diff --git a/cell/test/u_cell_sec_tls_test.c b/cell/test/u_cell_sec_tls_test.c index c1b432be..13bfd92f 100644 --- a/cell/test/u_cell_sec_tls_test.c +++ b/cell/test/u_cell_sec_tls_test.c @@ -52,6 +52,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" diff --git a/cell/test/u_cell_sock_test.c b/cell/test/u_cell_sock_test.c index 41ac184f..de496efe 100644 --- a/cell/test/u_cell_sock_test.c +++ b/cell/test/u_cell_sock_test.c @@ -56,6 +56,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_sock.h" @@ -114,7 +116,7 @@ typedef struct { /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** Generic handles. */ @@ -459,7 +461,8 @@ static bool keepGoingCallback(uDeviceHandle_t unused) (void) unused; - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -588,7 +591,8 @@ U_PORT_TEST_FUNCTION("[cellSock]", "cellSockBasic") // for pModule from now on // Connect to the network - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; y = uCellNetConnect(cellHandle, NULL, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), @@ -959,7 +963,8 @@ U_PORT_TEST_FUNCTION("[cellSock]", "cellSockOptionSetGet") cellHandle = gHandles.cellHandle; // Connect to the network - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; y = uCellNetConnect(cellHandle, NULL, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), diff --git a/cell/test/u_cell_test_preamble.c b/cell/test/u_cell_test_preamble.c index 6e8168a0..37fad744 100644 --- a/cell/test/u_cell_test_preamble.c +++ b/cell/test/u_cell_test_preamble.c @@ -42,6 +42,8 @@ #include "u_port_debug.h" #include "u_port_os.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" diff --git a/cell/test/u_cell_test_private.c b/cell/test/u_cell_test_private.c index 43e62b04..5e36d554 100644 --- a/cell/test/u_cell_test_private.c +++ b/cell/test/u_cell_test_private.c @@ -43,6 +43,8 @@ #include "u_port_os.h" // Required by u_cell_private.h #include "u_port_uart.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" diff --git a/cell/test/u_cell_time_test.c b/cell/test/u_cell_time_test.c index 66c25e05..cc5e0930 100644 --- a/cell/test/u_cell_time_test.c +++ b/cell/test/u_cell_time_test.c @@ -55,6 +55,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" @@ -128,7 +130,7 @@ typedef struct uCellTimeTestCellInfoList_t { /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs = 0; +static uTimeoutStop_t gTimeoutStop; /** Handles. */ @@ -169,7 +171,10 @@ static bool keepGoingCallback(uDeviceHandle_t unused) (void) unused; - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + // Zero duration means abort in this case + if ((gTimeoutStop.durationMs == 0) || + uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -273,7 +278,8 @@ static bool cellInfoCallback(uDeviceHandle_t cellHandle, } } - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -344,7 +350,6 @@ U_PORT_TEST_FUNCTION("[cellTime]", "cellTimeBasic") const uCellPrivateModule_t *pModule; int32_t resourceCount; int32_t y; - int32_t startTimeMs; uCellTimeTestCellInfoList_t *pTmp; bool gnssIsInsideCell; #ifndef U_CELL_CFG_SARA_R5_00B @@ -372,8 +377,8 @@ U_PORT_TEST_FUNCTION("[cellTime]", "cellTimeBasic") // Make a cellular connection so that we can test that sync works // despite that - gStopTimeMs = uPortGetTickTimeMs() + - (U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TEST_CFG_CONNECT_TIMEOUT_SECONDS * 1000; y = uCellNetConnect(cellHandle, NULL, #ifdef U_CELL_TEST_CFG_APN U_PORT_STRINGIFY_QUOTED(U_CELL_TEST_CFG_APN), @@ -409,7 +414,8 @@ U_PORT_TEST_FUNCTION("[cellTime]", "cellTimeBasic") gEventCallback = INT_MIN; memset(&gEvent, 0xFF, sizeof(gEvent)); gEvent.synchronised = false; - startTimeMs = uPortGetTickTimeMs(); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TIME_TEST_GUARD_TIME_SECONDS * 1000; y = 0; // Give this a few goes as sync can fail randomly for (size_t x = 0; (y == 0) && !gEvent.synchronised && (x < U_CELL_TIME_TEST_RETRIES + 1); x++) { @@ -418,8 +424,8 @@ U_PORT_TEST_FUNCTION("[cellTime]", "cellTimeBasic") if (pModule->moduleType == U_CELL_MODULE_TYPE_SARA_R5) { U_PORT_TEST_ASSERT(y == 0); while (!gEvent.synchronised && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_TIME_TEST_GUARD_TIME_SECONDS * 1000)) { + !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(100); } U_TEST_PRINT_LINE("gEventCallback is %d.", gEventCallback); @@ -447,7 +453,8 @@ U_PORT_TEST_FUNCTION("[cellTime]", "cellTimeBasic") gEventCallback = INT_MIN; memset(&gEvent, 0xFF, sizeof(gEvent)); gEvent.synchronised = false; - startTimeMs = uPortGetTickTimeMs(); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TIME_TEST_GUARD_TIME_SECONDS * 1000; y = 0; // Give this a few goes as sync can fail randomly for (size_t x = 0; (y == 0) && !gEvent.synchronised && (x < U_CELL_TIME_TEST_RETRIES + 1); x++) { @@ -456,8 +463,8 @@ U_PORT_TEST_FUNCTION("[cellTime]", "cellTimeBasic") if (pModule->moduleType == U_CELL_MODULE_TYPE_SARA_R5) { U_PORT_TEST_ASSERT(y == 0); while (!gEvent.synchronised && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_TIME_TEST_GUARD_TIME_SECONDS * 1000)) { + !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(100); } U_TEST_PRINT_LINE("gEventCallback is %d.", gEventCallback); @@ -491,23 +498,25 @@ U_PORT_TEST_FUNCTION("[cellTime]", "cellTimeBasic") gEventCallback = INT_MIN; memset(&gEvent, 0xFF, sizeof(gEvent)); gEvent.synchronised = false; - startTimeMs = uPortGetTickTimeMs(); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TIME_TEST_GUARD_TIME_SECONDS * 1000; U_PORT_TEST_ASSERT(uCellTimeEnable(cellHandle, U_CELL_TIME_MODE_ONE_SHOT, !gnssIsInsideCell, 0, eventCallback, &gEventCallback) == 0); while (!gEvent.synchronised && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_TIME_TEST_GUARD_TIME_SECONDS * 1000)) { + !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(100); } U_TEST_PRINT_LINE("gEventCallback is %d.", gEventCallback); if (gEvent.synchronised) { U_PORT_TEST_ASSERT(gEventCallback == 0); printAndCheckEvent(&gEvent, !gnssIsInsideCell); - startTimeMs = uPortGetTickTimeMs(); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TIME_TEST_GUARD_TIME_SECONDS * 1000; while ((gTimeCallback == INT_MIN) && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_TIME_TEST_GUARD_TIME_SECONDS * 1000)) { + !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(100); } U_TEST_PRINT_LINE("gTimeCallback is %d.", gTimeCallback); @@ -542,7 +551,8 @@ U_PORT_TEST_FUNCTION("[cellTime]", "cellTimeBasic") gEventCallback = INT_MIN; memset(&gEvent, 0xFF, sizeof(gEvent)); gEvent.synchronised = false; - startTimeMs = uPortGetTickTimeMs(); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TIME_TEST_GUARD_TIME_SECONDS * 1000; y = 0; // Give this a few goes as sync can fail randomly for (size_t x = 0; (y == 0) && !gEvent.synchronised && (x < U_CELL_TIME_TEST_RETRIES + 1); x++) { @@ -550,18 +560,19 @@ U_PORT_TEST_FUNCTION("[cellTime]", "cellTimeBasic") !uCellLocGnssInsideCell(cellHandle), 0, eventCallback, &gEventCallback) == 0); while (!gEvent.synchronised && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_TIME_TEST_GUARD_TIME_SECONDS * 1000)) { + !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(100); } U_TEST_PRINT_LINE("gEventCallback is %d.", gEventCallback); if (gEvent.synchronised) { U_PORT_TEST_ASSERT(gEventCallback == 0); printAndCheckEvent(&gEvent, !gnssIsInsideCell); - startTimeMs = uPortGetTickTimeMs(); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TIME_TEST_GUARD_TIME_SECONDS * 1000; while ((gTimeCallback == INT_MIN) && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_TIME_TEST_GUARD_TIME_SECONDS * 1000)) { + !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(100); } U_TEST_PRINT_LINE("gTimeCallback is %d.", gTimeCallback); @@ -592,7 +603,7 @@ U_PORT_TEST_FUNCTION("[cellTime]", "cellTimeBasic") // ...and again with a callback, but abort immediately U_TEST_PRINT_LINE("adding a callback but aborting the deep scan."); gCellInfoCallback = INT_MIN; - gStopTimeMs = 0; + gTimeoutStop.durationMs = 0; y = uCellNetDeepScan(cellHandle, cellInfoCallback, &gpCellInfoList); U_TEST_PRINT_LINE("aborted uCellNetDeepScan() returned %d.", y); U_PORT_TEST_ASSERT(y < 0); @@ -606,7 +617,8 @@ U_PORT_TEST_FUNCTION("[cellTime]", "cellTimeBasic") // Do this a few times as the module can sometimes find nothing gCellInfoCallback = INT_MIN; for (size_t x = 0; ((gCellInfoCallback == INT_MIN) || (gpCellInfoList == NULL)) && (x < 3); x++) { - gStopTimeMs = uPortGetTickTimeMs() + (U_CELL_TIME_TEST_DEEP_SCAN_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TIME_TEST_DEEP_SCAN_TIMEOUT_SECONDS * 1000; y = uCellNetDeepScan(cellHandle, cellInfoCallback, &gpCellInfoList); U_TEST_PRINT_LINE("%d cell(s) found on try %d.", y, x + 1); if (y > 0) { @@ -660,12 +672,13 @@ U_PORT_TEST_FUNCTION("[cellTime]", "cellTimeBasic") gEventCallback = INT_MIN; memset(&gEvent, 0xFF, sizeof(gEvent)); gEvent.synchronised = false; - startTimeMs = uPortGetTickTimeMs(); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_CELL_TIME_TEST_GUARD_TIME_SECONDS * 1000; U_PORT_TEST_ASSERT(uCellTimeEnable(cellHandle, U_CELL_TIME_MODE_EXT_INT_TIMESTAMP, true, 0, eventCallback, &gEventCallback) == 0); while (!gEvent.synchronised && - !uPortTickTimeExpiredMs(startTimeMs, - U_CELL_TIME_TEST_GUARD_TIME_SECONDS * 1000)) { + !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(100); } U_TEST_PRINT_LINE("gEventCallback is %d.", gEventCallback); diff --git a/common/at_client/src/u_at_client.c b/common/at_client/src/u_at_client.c index 52b6dd33..bd47fd87 100644 --- a/common/at_client/src/u_at_client.c +++ b/common/at_client/src/u_at_client.c @@ -60,6 +60,8 @@ #include "u_device_serial.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_short_range_pbuf.h" #include "u_short_range_module_type.h" @@ -405,7 +407,7 @@ typedef struct { int32_t pin; int32_t readyMs; bool highIsOn; - int32_t lastToggleTime; + uTimeoutStart_t lastToggleTime; int32_t hysteresisMs; } uAtClientActivityPin_t; @@ -443,9 +445,9 @@ typedef struct uAtClientInstance_t { uAtClientTag_t stopTag; /** The stop tag for the current scope. */ uAtClientUrc_t *pUrcList; /** Linked-list anchor for URC handlers. */ uAtClientUrc_t *pUrcRead; /** Pointer used when reading the URC handlers. */ - int32_t lastResponseStopMs; /** The time the last response ended in milliseconds. */ + uTimeoutStart_t lastResponseStop; /** The time the last response ended in milliseconds. */ int32_t lockTimeMs; /** The time when the stream was locked. */ - int32_t lastTxTimeMs; /** The time when the last transmit activity was carried out. */ + uTimeoutStart_t lastTxTime; /** The time when the last transmit activity was carried out. */ size_t urcMaxStringLength; /** The longest URC string to monitor for. */ size_t maxRespLength; /** The max length of OK, (CME) (CMS) ERROR and URCs. */ bool delimiterRequired; /** Is a delimiter to be inserted before the next parameter or not. */ @@ -2262,8 +2264,8 @@ static size_t write(uAtClientInstance_t *pClient, (pClient->error == U_ERROR_COMMON_SUCCESS)) { lengthToWrite = length - (pData - pDataStart); if ((pClient->pWakeUp != NULL) && - uPortTickTimeExpiredMs(pClient->lastTxTimeMs, - pClient->pWakeUp->inactivityTimeoutMs) && + uTimeoutExpiredMs(pClient->lastTxTime, + pClient->pWakeUp->inactivityTimeoutMs) && (uPortMutexTryLock(pClient->pWakeUp->inWakeUpHandlerMutex, 0) == 0)) { // We have a wake-up handler, the inactivity timeout // has expired and we've managed to lock the wake-up @@ -2371,7 +2373,7 @@ static size_t write(uAtClientInstance_t *pClient, if (thisLengthWritten > 0) { pDataToWrite += thisLengthWritten; lengthToWrite -= thisLengthWritten; - pClient->lastTxTimeMs = uPortGetTickTimeMs(); + pClient->lastTxTime = uTimeoutStart(); } else { setError(pClient, U_ERROR_COMMON_DEVICE_ERROR); } @@ -2446,13 +2448,13 @@ static uPortMutexHandle_t tryLock(uAtClientInstance_t *pClient) pClient->lockTimeMs = uPortGetTickTimeMs(); if (pClient->pActivityPin != NULL) { // If an activity pin is set then switch it on - while (!uPortTickTimeExpiredMs(pClient->pActivityPin->lastToggleTime, - pClient->pActivityPin->hysteresisMs)) { + while (!uTimeoutExpiredMs(pClient->pActivityPin->lastToggleTime, + pClient->pActivityPin->hysteresisMs)) { uPortTaskBlock(U_AT_CLIENT_ACTIVITY_PIN_HYSTERESIS_INTERVAL_MS); } if (uPortGpioSet(pClient->pActivityPin->pin, (int32_t) pClient->pActivityPin->highIsOn) == 0) { - pClient->pActivityPin->lastToggleTime = uPortGetTickTimeMs(); + pClient->pActivityPin->lastToggleTime = uTimeoutStart(); uPortTaskBlock(pClient->pActivityPin->readyMs); } } @@ -2489,13 +2491,13 @@ static void unlockNoDataCheck(uAtClientInstance_t *pClient, if (pClient->pActivityPin != NULL) { // If an activity pin is set then switch it off - while (!uPortTickTimeExpiredMs(pClient->pActivityPin->lastToggleTime, - pClient->pActivityPin->hysteresisMs)) { + while (!uTimeoutExpiredMs(pClient->pActivityPin->lastToggleTime, + pClient->pActivityPin->hysteresisMs)) { uPortTaskBlock(U_AT_CLIENT_ACTIVITY_PIN_HYSTERESIS_INTERVAL_MS); } if (uPortGpioSet(pClient->pActivityPin->pin, (int32_t) !pClient->pActivityPin->highIsOn) == 0) { - pClient->pActivityPin->lastToggleTime = uPortGetTickTimeMs(); + pClient->pActivityPin->lastToggleTime = uTimeoutStart(); } } } @@ -2815,10 +2817,10 @@ static uAtClientHandle_t clientAdd(const uAtClientStreamHandle_t *pStream, clearError(pClient); // This will also set stopTag setScope(pClient, U_AT_CLIENT_SCOPE_NONE); - pClient->lastTxTimeMs = uPortGetTickTimeMs(); + pClient->lastTxTime = uTimeoutStart(); pClient->urcMaxStringLength = U_AT_CLIENT_INITIAL_URC_LENGTH; pClient->maxRespLength = U_AT_CLIENT_MAX_LENGTH_INFORMATION_RESPONSE_PREFIX; - pClient->lastResponseStopMs = uPortGetTickTimeMs(); + pClient->lastResponseStop = uTimeoutStart(); // Set up the buffer and its protection markers pClient->pReceiveBuffer->dataBufferSize = receiveBufferSize - U_AT_CLIENT_BUFFER_OVERHEAD_BYTES; @@ -3259,14 +3261,14 @@ void uAtClientLock(uAtClientHandle_t atHandle) streamMutex = streamLock(pClient); mutexStackPush(&(pClient->lockedStreamMutexStack), streamMutex); if (pClient->pActivityPin != NULL) { - while (!uPortTickTimeExpiredMs(pClient->pActivityPin->lastToggleTime, - pClient->pActivityPin->hysteresisMs)) { + while (!uTimeoutExpiredMs(pClient->pActivityPin->lastToggleTime, + pClient->pActivityPin->hysteresisMs)) { uPortTaskBlock(U_AT_CLIENT_ACTIVITY_PIN_HYSTERESIS_INTERVAL_MS); } // If an activity pin is set then switch it on if (uPortGpioSet(pClient->pActivityPin->pin, (int32_t) pClient->pActivityPin->highIsOn) == 0) { - pClient->pActivityPin->lastToggleTime = uPortGetTickTimeMs(); + pClient->pActivityPin->lastToggleTime = uTimeoutStart(); uPortTaskBlock(pClient->pActivityPin->readyMs); } } @@ -3389,8 +3391,8 @@ void uAtClientCommandStart(uAtClientHandle_t atHandle, if (pClient->error == U_ERROR_COMMON_SUCCESS) { // Wait for delay period if required if (pClient->delayMs > 0) { - while (!uPortTickTimeExpiredMs(pClient->lastResponseStopMs, - pClient->delayMs)) { + while (!uTimeoutExpiredMs(pClient->lastResponseStop, + pClient->delayMs)) { uPortTaskBlock(10); } } @@ -3789,7 +3791,7 @@ void uAtClientResponseStop(uAtClientHandle_t atHandle) setScope(pClient, U_AT_CLIENT_SCOPE_NONE); } - pClient->lastResponseStopMs = uPortGetTickTimeMs(); + pClient->lastResponseStop = uTimeoutStart(); U_AT_CLIENT_UNLOCK_CLIENT_MUTEX(pClient); } @@ -3906,7 +3908,7 @@ int32_t uAtClientWaitCharacter(uAtClientHandle_t atHandle, uErrorCode_t errorCode = U_ERROR_COMMON_INVALID_PARAMETER; uAtClientInstance_t *pClient = (uAtClientInstance_t *) atHandle; uAtClientReceiveBuffer_t *pReceiveBuffer = pClient->pReceiveBuffer; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; bool urcFound; // IMPORTANT: this can't lock pClient->mutex as it @@ -3924,7 +3926,7 @@ int32_t uAtClientWaitCharacter(uAtClientHandle_t atHandle, // gets to zero (in which case we won't call bufferFill()) // and hence, for safety, we run our own AT timeout guard // on the loop as well - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((errorCode != U_ERROR_COMMON_SUCCESS) && (pClient->error == U_ERROR_COMMON_SUCCESS)) { // Continue to look for URCs, you never @@ -3966,7 +3968,7 @@ int32_t uAtClientWaitCharacter(uAtClientHandle_t atHandle, pClient->numConsecutiveAtTimeouts = 0; } } else { - if (uPortTickTimeExpiredMs(startTimeMs, pClient->atTimeoutMs)) { + if (uTimeoutExpiredMs(timeoutStart, pClient->atTimeoutMs)) { // If we're stuck, set an error setError(pClient, U_ERROR_COMMON_DEVICE_ERROR); consecutiveTimeout(pClient); @@ -4567,7 +4569,7 @@ int32_t uAtClientSetActivityPin(uAtClientHandle_t atHandle, pClient->pActivityPin->pin = pin; pClient->pActivityPin->readyMs = readyMs; pClient->pActivityPin->highIsOn = highIsOn; - pClient->pActivityPin->lastToggleTime = uPortGetTickTimeMs(); + pClient->pActivityPin->lastToggleTime = uTimeoutStart(); pClient->pActivityPin->hysteresisMs = hysteresisMs; errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; } diff --git a/common/at_client/test/u_at_client_test.c b/common/at_client/test/u_at_client_test.c index b45f0048..781545d8 100644 --- a/common/at_client/test/u_at_client_test.c +++ b/common/at_client/test/u_at_client_test.c @@ -57,6 +57,7 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" #include "u_at_client.h" #include "u_at_client_test.h" #include "u_at_client_test_data.h" @@ -284,13 +285,13 @@ static bool atTimeoutIsObeyed(uAtClientHandle_t atClientHandle, int32_t timeoutMs) { bool success = false; - int32_t startTimeMs; - int32_t duration; + uTimeoutStart_t timeoutStart; + int32_t durationMs; int32_t consecutiveTimeouts; int32_t x; int32_t y; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); uAtClientLock(atClientHandle); // Send nothing consecutiveTimeouts = gConsecutiveTimeout; @@ -309,11 +310,11 @@ static bool atTimeoutIsObeyed(uAtClientHandle_t atClientHandle, uPortTaskBlock(10); if ((x < 0) && (y < 0) && (gConsecutiveTimeout == consecutiveTimeouts + 1)) { - duration = uPortGetTickTimeMs() - startTimeMs; - if ((duration < timeoutMs) || - (duration > timeoutMs + U_AT_CLIENT_TEST_AT_TIMEOUT_TOLERANCE_MS)) { + durationMs = uTimeoutElapsedMs(timeoutStart); + if ((durationMs < timeoutMs) || + (durationMs > timeoutMs + U_AT_CLIENT_TEST_AT_TIMEOUT_TOLERANCE_MS)) { U_TEST_PRINT_LINE("AT timeout was not obeyed (%d ms as opposed" - " to %d ms).", (int) duration, timeoutMs); + " to %d ms).", (int) durationMs, timeoutMs); } else { success = true; } diff --git a/common/at_client/test/u_at_client_test_data.c b/common/at_client/test/u_at_client_test_data.c index 81dcac93..2cbe2f9e 100644 --- a/common/at_client/test/u_at_client_test_data.c +++ b/common/at_client/test/u_at_client_test_data.c @@ -42,6 +42,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_port_clib_platform_specific.h" /* Integer stdio, must be included before the other port files if any print or scan function is used. */ @@ -869,15 +871,15 @@ static int32_t handleReadOnError(uAtClientHandle_t atClientHandle, { int32_t lastError; uint64_t uint64; - int32_t startTimeMs; - int32_t duration; + uTimeoutStart_t timeoutStart; + int32_t durationMs; const uAtClientTestEchoError_t *pError; #if !U_CFG_ENABLE_LOGGING (void) index; #endif - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); pError = (const uAtClientTestEchoError_t *) pParameter; U_TEST_PRINT_LINE_X("checking that parameter reads return error when" @@ -940,20 +942,20 @@ static int32_t handleReadOnError(uAtClientHandle_t atClientHandle, } // The errors should be returned within the guard times - duration = uPortGetTickTimeMs() - startTimeMs; + durationMs = uTimeoutElapsedMs(timeoutStart); if (lastError == 0) { - if (duration < pError->timeMinMs) { + if (durationMs < pError->timeMinMs) { U_TEST_PRINT_LINE_X("reads took %d ms when a minimum of %d ms was" - " expected.", index + 1, duration, + " expected.", index + 1, durationMs, pError->timeMinMs); lastError = 6; } } if (lastError == 0) { - if (duration > pError->timeMaxMs) { + if (durationMs > pError->timeMaxMs) { U_TEST_PRINT_LINE_X("reads took %d ms when a maximum of %d ms" - " was expected.", index + 1, duration, + " was expected.", index + 1, durationMs, pError->timeMaxMs); lastError = 7; } diff --git a/common/device/src/u_device_private_cell.c b/common/device/src/u_device_private_cell.c index 381a0748..19d827b7 100644 --- a/common/device/src/u_device_private_cell.c +++ b/common/device/src/u_device_private_cell.c @@ -37,6 +37,8 @@ #include "u_device.h" #include "u_device_shared.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_cell_module_type.h" @@ -79,7 +81,8 @@ static bool keepGoingCallback(uDeviceHandle_t devHandle) if (uDeviceGetInstance(devHandle, &pInstance) == 0) { pContext = (uDeviceCellContext_t *) pInstance->pContext; if ((pContext == NULL) || - !uPortTickTimeBeyondStopMs(pContext->stopTimeMs)) { + !uTimeoutExpiredMs(pContext->timeoutStop.timeoutStart, + pContext->timeoutStop.durationMs)) { keepGoing = true; } } @@ -168,8 +171,8 @@ static int32_t addDevice(const uDeviceCfgUart_t *pCfgUart, pDeviceHandle); if (errorCode == 0) { // Set the timeout - pContext->stopTimeMs = uPortGetTickTimeMs() + - (U_DEVICE_PRIVATE_CELL_POWER_ON_GUARD_TIME_SECONDS * 1000); + pContext->timeoutStop.timeoutStart = uTimeoutStart(); + pContext->timeoutStop.durationMs = U_DEVICE_PRIVATE_CELL_POWER_ON_GUARD_TIME_SECONDS * 1000; // Remember the PWR_ON pin 'cos we need it during power down pContext->pinPwrOn = pCfgCell->pinPwrOn; // Hook our context data off the device handle diff --git a/common/device/src/u_device_shared_cell.h b/common/device/src/u_device_shared_cell.h index 485c49cf..bea34e97 100644 --- a/common/device/src/u_device_shared_cell.h +++ b/common/device/src/u_device_shared_cell.h @@ -46,7 +46,7 @@ extern "C" { typedef struct { int32_t uart; uAtClientHandle_t at; - int32_t stopTimeMs; + uTimeoutStop_t timeoutStop; int32_t pinPwrOn; } uDeviceCellContext_t; diff --git a/common/geofence/src/u_geofence.c b/common/geofence/src/u_geofence.c index fdc20137..3ba3cb36 100644 --- a/common/geofence/src/u_geofence.c +++ b/common/geofence/src/u_geofence.c @@ -146,6 +146,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_linked_list.h" @@ -1258,21 +1260,18 @@ static uGeofencePositionState_t testSquareExtent(const uGeofenceSquare_t *pSquar static uGeofencePositionState_t testSpeed(const uGeofenceDynamic_t *pPreviousDistance) { uGeofencePositionState_t positionState = U_GEOFENCE_POSITION_STATE_NONE; - int32_t timeDifferenceMs; + uint32_t timeDifferenceMs; int64_t distanceTravelledMillimetres; if ((pPreviousDistance->lastStatus.distanceMillimetres != LLONG_MIN) && (pPreviousDistance->maxHorizontalSpeedMillimetresPerSecond >= 0)) { // Work out how far we can have travelled in the time - timeDifferenceMs = uPortGetTickTimeMs() - pPreviousDistance->lastStatus.timeMs; - // Guard against wrap - if (timeDifferenceMs > 0) { - // Divide by 1000 below to get per second - distanceTravelledMillimetres = ((int64_t) timeDifferenceMs) * - pPreviousDistance->maxHorizontalSpeedMillimetresPerSecond / 1000; - if (distanceTravelledMillimetres < pPreviousDistance->lastStatus.distanceMillimetres) { - positionState = U_GEOFENCE_POSITION_STATE_OUTSIDE; - } + timeDifferenceMs = uTimeoutElapsedMs(pPreviousDistance->lastStatus.timeoutStart); + // Divide by 1000 below to get per second + distanceTravelledMillimetres = ((int64_t) timeDifferenceMs) * + pPreviousDistance->maxHorizontalSpeedMillimetresPerSecond / 1000; + if (distanceTravelledMillimetres < pPreviousDistance->lastStatus.distanceMillimetres) { + positionState = U_GEOFENCE_POSITION_STATE_OUTSIDE; } } @@ -1655,7 +1654,7 @@ bool testPosition(const uGeofence_t *pFence, } else { if (distanceMinMetres == distanceMinMetres) { // NAN test pDynamic->lastStatus.distanceMillimetres = (int64_t) (distanceMinMetres * 1000); - pDynamic->lastStatus.timeMs = uPortGetTickTimeMs(); + pDynamic->lastStatus.timeoutStart = uTimeoutStart(); } } } @@ -1697,7 +1696,7 @@ int32_t uGeofenceContextEnsure(uGeofenceContext_t **ppFenceContext) if (*ppFenceContext != NULL) { memset(*ppFenceContext, 0, sizeof(**ppFenceContext)); (*ppFenceContext)->dynamic.lastStatus.distanceMillimetres = LLONG_MIN; - (*ppFenceContext)->dynamic.lastStatus.timeMs = uPortGetTickTimeMs(); + (*ppFenceContext)->dynamic.lastStatus.timeoutStart = uTimeoutStart(); (*ppFenceContext)->dynamic.maxHorizontalSpeedMillimetresPerSecond = -1; errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; } @@ -1903,7 +1902,6 @@ uGeofencePositionState_t uGeofenceContextTest(uDeviceHandle_t devHandle, if ((dynamic.lastStatus.distanceMillimetres != LLONG_MIN) && (dynamic.lastStatus.distanceMillimetres < dynamicsMinDistance.lastStatus.distanceMillimetres)) { dynamicsMinDistance.lastStatus.distanceMillimetres = dynamic.lastStatus.distanceMillimetres; - dynamicsMinDistance.lastStatus.distanceMillimetres = uPortGetTickTimeMs(); } if ((pFenceContext->pCallback != NULL) && (devHandle != NULL)) { pFenceContext->pCallback(devHandle, pFence, pFence->pNameStr, diff --git a/common/geofence/src/u_geofence_shared.h b/common/geofence/src/u_geofence_shared.h index cadb552f..766ef137 100644 --- a/common/geofence/src/u_geofence_shared.h +++ b/common/geofence/src/u_geofence_shared.h @@ -42,7 +42,7 @@ extern "C" { */ typedef struct { int64_t distanceMillimetres; /**< use LLONG_MIN to mean "not known". */ - int32_t timeMs; /**< populated from uPortGetTickTimeMs(). */ + uTimeoutStart_t timeoutStart; /**< populated from uTimeoutStart(). */ } uGeofenceDynamicStatus_t; /** Structure to hold the maximum speed that a device will travel diff --git a/common/geofence/test/u_geofence_test.c b/common/geofence/test/u_geofence_test.c index e2c6edda..f477e7ac 100644 --- a/common/geofence/test/u_geofence_test.c +++ b/common/geofence/test/u_geofence_test.c @@ -51,6 +51,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_linked_list.h" #include "u_port_clib_platform_specific.h" /* must be included before the other @@ -642,7 +644,7 @@ U_PORT_TEST_FUNCTION("[geofence]", "geofenceBasic") uGeofencePositionState_t positionState; bool newPolygon; char prefixBuffer[32]; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; size_t numEdges; size_t numShapes; size_t numFailedCalculations; @@ -777,7 +779,7 @@ U_PORT_TEST_FUNCTION("[geofence]", "geofenceBasic") // Test the point(s) against the fence in all permutations of parameters, // do it twice, once with prints and then without to get an accurate timing for (size_t t = 0; t < 2; t++) { - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); // We take all of the points and test one parameter combination, then // take all of the points and repeat for the next parameter combination, // etc., rather than doing all of the parameter combinations for one @@ -859,7 +861,7 @@ U_PORT_TEST_FUNCTION("[geofence]", "geofenceBasic") " %d times each (print time excluded), averaged %d us per point", (char) (x + 0x41), numShapes, numEdges, pTestData->numPoints, sizeof(gTestParameters) / sizeof(gTestParameters[0]), - (((uPortGetTickTimeMs() - startTimeMs) * 1000) / + (uTimeoutElapsedSeconds(timeoutStart) / (pTestData->numPoints * sizeof(gTestParameters) / sizeof(gTestParameters[0])))); if (numFailedCalculations > 0) { uPortLog(" AND %d CALCULATION(S) FAILED.\n", numFailedCalculations); diff --git a/common/http_client/src/u_http_client.c b/common/http_client/src/u_http_client.c index 69a77811..927b716e 100644 --- a/common/http_client/src/u_http_client.c +++ b/common/http_client/src/u_http_client.c @@ -67,6 +67,8 @@ #include "u_assert.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_device_shared.h" @@ -675,12 +677,12 @@ static void exitFunctionRequest(uHttpClientContext_t *pContext, int32_t errorCod static int32_t block(volatile uHttpClientContext_t *pContext) { int32_t errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t statusCodeOrError = 0; if (pContext->pResponseCallback == NULL) { // We're blocking - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; // Wait for the underlying layer to give a response // or pKeepGoingCallback=false or a timeout of twice the @@ -689,7 +691,7 @@ static int32_t block(volatile uHttpClientContext_t *pContext) // HTTP status code while ((statusCodeOrError == 0) && ((pContext->pKeepGoingCallback == NULL) || pContext->pKeepGoingCallback()) && - !uPortTickTimeExpiredMs(startTimeMs, pContext->timeoutSeconds * 2 * 1000)) { + !uTimeoutExpiredSeconds(timeoutStart, pContext->timeoutSeconds * 2)) { if (uPortSemaphoreTryTake((uPortSemaphoreHandle_t) pContext->semaphoreHandle, 100) == 0) { statusCodeOrError = pContext->statusCodeOrError; } diff --git a/common/http_client/test/u_http_client_test.c b/common/http_client/test/u_http_client_test.c index 3f5fae98..b89b0621 100644 --- a/common/http_client/test/u_http_client_test.c +++ b/common/http_client/test/u_http_client_test.c @@ -63,6 +63,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_network.h" #include "u_network_test_shared_cfg.h" #include "u_http_client_test_shared_cfg.h" @@ -400,7 +402,7 @@ static int32_t checkResponse(uHttpClientTestOperation_t operation, bool checkBinary, bool rtsFlowControlEnabled) { int32_t outcome = (int32_t) U_ERROR_COMMON_SUCCESS; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t x; const char *pTmp; int32_t y; @@ -429,21 +431,21 @@ static int32_t checkResponse(uHttpClientTestOperation_t operation, // For the non-blocking case, should have an initial // error code of zero if (errorOrStatusCode == 0) { - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); // Wait for twice as long as the timeout as a guard U_TEST_PRINT_LINE("waiting for asynchronous response for up to" " %d second(s)...", (pConnection->timeoutSeconds * 2) + U_HTTP_CLIENT_TEST_RESPONSE_TIMEOUT_EXTRA_SECONDS); while (!pCallbackData->called && - !uPortTickTimeExpiredMs(startTimeMs, ((pConnection->timeoutSeconds * 2) + - U_HTTP_CLIENT_TEST_RESPONSE_TIMEOUT_EXTRA_SECONDS) * 1000)) { + !uTimeoutExpiredSeconds(timeoutStart, (pConnection->timeoutSeconds * 2) + + U_HTTP_CLIENT_TEST_RESPONSE_TIMEOUT_EXTRA_SECONDS)) { uPortTaskBlock(100); } if (pCallbackData->called) { responseSize = pCallbackData->responseSize; U_TEST_PRINT_LINE("response received in %d ms.\n", - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(timeoutStart)); if (pCallbackData->statusCodeOrError != expectedStatusCode) { U_TEST_PRINT_LINE("expected status code %d, got %d.\n", expectedStatusCode, pCallbackData->statusCodeOrError); @@ -457,7 +459,7 @@ static int32_t checkResponse(uHttpClientTestOperation_t operation, } } else { U_TEST_PRINT_LINE("callback not called after %d second(s).\n", - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(timeoutStart)); outcome = (int32_t) U_ERROR_COMMON_TIMEOUT; } } else { diff --git a/common/location/src/u_location_private_cloud_locate.c b/common/location/src/u_location_private_cloud_locate.c index dd8e9671..ea79e7f3 100644 --- a/common/location/src/u_location_private_cloud_locate.c +++ b/common/location/src/u_location_private_cloud_locate.c @@ -47,6 +47,8 @@ #include "u_port_heap.h" #include "u_port_debug.h" +#include "u_timeout.h" + #include "u_time.h" #include "u_ubx_protocol.h" @@ -363,7 +365,7 @@ int32_t uLocationPrivateCloudLocate(uDeviceHandle_t devHandle, char topicBuffer[U_LOCATION_PRIVATE_CLOUD_LOCATE_SUBSCRIBE_TOPIC_LENGTH_BYTES]; char *pTopicBufferRead; char *pMessageRead; - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); bool subscribed = false; size_t z; @@ -447,7 +449,7 @@ int32_t uLocationPrivateCloudLocate(uDeviceHandle_t devHandle, " location from server...\n"); while ((errorCode == (int32_t) U_ERROR_COMMON_TIMEOUT) && (((pKeepGoingCallback == NULL) && - !uPortTickTimeExpiredMs(startTimeMs, U_LOCATION_TIMEOUT_SECONDS * 1000)) || + !uTimeoutExpiredSeconds(timeoutStart, U_LOCATION_TIMEOUT_SECONDS)) || ((pKeepGoingCallback != NULL) && pKeepGoingCallback(devHandle)))) { if (uMqttClientGetUnread(pMqttClientContext) > 0) { z = U_LOCATION_PRIVATE_CLOUD_LOCATE_READ_MESSAGE_LENGTH_BYTES; diff --git a/common/location/src/u_location_stub_wifi.c b/common/location/src/u_location_stub_wifi.c index ae09f81d..d2b49335 100644 --- a/common/location/src/u_location_stub_wifi.c +++ b/common/location/src/u_location_stub_wifi.c @@ -38,6 +38,7 @@ #include "u_compiler.h" // U_WEAK #include "u_error_common.h" +#include "u_timeout.h" #include "u_port_os.h" #include "u_location.h" #include "u_short_range_module_type.h" diff --git a/common/location/test/u_location_test.c b/common/location/test/u_location_test.c index a31b26e0..d2d7bddf 100644 --- a/common/location/test/u_location_test.c +++ b/common/location/test/u_location_test.c @@ -63,6 +63,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_network.h" #include "u_network_test_shared_cfg.h" @@ -117,7 +119,7 @@ /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs = 0; +static uTimeoutStop_t gTimeoutStop; /** Keep track of the current network handle so that the * keepGoingCallback() can check it. @@ -177,7 +179,8 @@ static bool keepGoingCallback(uDeviceHandle_t devHandle) bool keepGoing = true; U_PORT_TEST_ASSERT((gDevHandle == NULL) || (devHandle == gDevHandle)); - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -286,17 +289,17 @@ static bool httpPostCheck(uLocationType_t locationType, volatile int32_t *pHttpStatusCode) { bool success = true; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; if ((pHttpContext != NULL) && ((locationType == U_LOCATION_TYPE_CLOUD_GOOGLE) || (locationType == U_LOCATION_TYPE_CLOUD_SKYHOOK) || (locationType == U_LOCATION_TYPE_CLOUD_HERE))) { success = false; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((*pHttpStatusCode != 200) && - !uPortTickTimeExpiredMs(startTimeMs, - U_LOCATION_TEST_HTTP_TIMEOUT_SECONDS * 1000)) { + !uTimeoutExpiredSeconds(timeoutStart, + U_LOCATION_TEST_HTTP_TIMEOUT_SECONDS)) { uPortTaskBlock(100); } if (*pHttpStatusCode != 200) { @@ -329,7 +332,6 @@ static void testBlocking(uDeviceHandle_t devHandle, const uLocationTestCfg_t *pLocationCfg) { uLocation_t location; - int32_t startTimeMs = 0; int32_t timeoutMs = U_LOCATION_TEST_CFG_TIMEOUT_SECONDS * 1000; int32_t y; const uLocationAssist_t *pLocationAssist = NULL; @@ -357,8 +359,8 @@ static void testBlocking(uDeviceHandle_t devHandle, // WiFi can sometimes fail y = -1; for (int32_t x = 0; (x < 3) && (y != 0); x++) { - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + timeoutMs; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = timeoutMs; y = uLocationGet(devHandle, locationType, pLocationAssist, pAuthenticationTokenStr, @@ -382,7 +384,7 @@ static void testBlocking(uDeviceHandle_t devHandle, } } U_TEST_PRINT_LINE("location establishment took %d second(s).", - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(gTimeoutStop.timeoutStart)); // If we are running on a test cellular network we won't get position but // we should always get time if ((location.radiusMillimetres > 0) && @@ -454,7 +456,7 @@ static void testOneShot(uDeviceHandle_t devHandle, uLocationType_t locationType, const uLocationTestCfg_t *pLocationCfg) { - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t y; int32_t timeoutMs = U_LOCATION_TEST_CFG_TIMEOUT_SECONDS * 1000; const uLocationAssist_t *pLocationAssist = NULL; @@ -468,7 +470,7 @@ static void testOneShot(uDeviceHandle_t devHandle, pAuthenticationTokenStr = pLocationCfg->pAuthenticationTokenStr; pLocationAssist = pLocationCfg->pLocationAssist; } - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); uLocationTestResetLocation(&gLocation); if (pLocationCfg != NULL) { @@ -490,7 +492,7 @@ static void testOneShot(uDeviceHandle_t devHandle, " one-shot API...", timeoutMs); while ((gErrorCode == INT_MIN) && - !uPortTickTimeExpiredMs(startTimeMs, timeoutMs)) { + !uTimeoutExpiredMs(timeoutStart, timeoutMs)) { // Location establishment status is only supported for cell locate y = uLocationGetStatus(devHandle); if (locationType == U_LOCATION_TYPE_CLOUD_CELL_LOCATE) { @@ -503,7 +505,7 @@ static void testOneShot(uDeviceHandle_t devHandle, if (gErrorCode == 0) { U_TEST_PRINT_LINE("location establishment took %d second(s).", - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(timeoutStart)); // If we are running on a cellular test network we might not // get position but we should always get time U_PORT_TEST_ASSERT(gDevHandle == devHandle); @@ -586,7 +588,7 @@ static void testContinuous(uDeviceHandle_t devHandle, uLocationType_t locationType, const uLocationTestCfg_t *pLocationCfg) { - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t timeoutMs = U_LOCATION_TEST_CFG_TIMEOUT_SECONDS * 1000; int32_t y; const uLocationAssist_t *pLocationAssist = NULL; @@ -600,7 +602,7 @@ static void testContinuous(uDeviceHandle_t devHandle, pAuthenticationTokenStr = pLocationCfg->pAuthenticationTokenStr; pLocationAssist = pLocationCfg->pLocationAssist; } - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); uLocationTestResetLocation(&gLocation); if (pLocationCfg != NULL) { @@ -622,7 +624,7 @@ static void testContinuous(uDeviceHandle_t devHandle, timeoutMs * U_LOCATION_TEST_CFG_CONTINUOUS_COUNT, U_LOCATION_TEST_CFG_CONTINUOUS_COUNT); while ((gCount < U_LOCATION_TEST_CFG_CONTINUOUS_COUNT) && - !uPortTickTimeExpiredMs(startTimeMs, timeoutMs)) { + !uTimeoutExpiredMs(timeoutStart, timeoutMs)) { // Location establishment status is only supported for cell locate y = uLocationGetStatus(devHandle); if (locationType == U_LOCATION_TYPE_CLOUD_CELL_LOCATE) { @@ -633,14 +635,9 @@ static void testContinuous(uDeviceHandle_t devHandle, uPortTaskBlock(1000); } - // There has been something off going on with this test on Windows, - // so print a little extra diagnostic information here so that we - // can watch it - U_TEST_PRINT_LINE("startTimeMs is %d, ticks now is %d, gCount is %d.", - startTimeMs, uPortGetTickTimeMs(), gCount); if (gCount >= U_LOCATION_TEST_CFG_CONTINUOUS_COUNT) { U_TEST_PRINT_LINE("took %d second(s) to get location %d time(s).", - (uPortGetTickTimeMs() - startTimeMs) / 1000, + uTimeoutElapsedSeconds(timeoutStart), gCount); // If we are running on a cellular test network we might not // get position but we should always get time diff --git a/common/location/test/u_location_test_shared_cfg.c b/common/location/test/u_location_test_shared_cfg.c index 1320536d..cd7f1f87 100644 --- a/common/location/test/u_location_test_shared_cfg.c +++ b/common/location/test/u_location_test_shared_cfg.c @@ -43,6 +43,8 @@ #include "u_port_heap.h" #include "u_port_debug.h" +#include "u_timeout.h" + #include "u_network.h" #include "u_network_test_shared_cfg.h" diff --git a/common/mqtt_client/test/u_mqtt_client_test.c b/common/mqtt_client/test/u_mqtt_client_test.c index fe6683d6..4f3a7b05 100644 --- a/common/mqtt_client/test/u_mqtt_client_test.c +++ b/common/mqtt_client/test/u_mqtt_client_test.c @@ -63,6 +63,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_network.h" #include "u_network_test_shared_cfg.h" @@ -147,7 +149,7 @@ /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** The test MQTT context. */ @@ -183,7 +185,8 @@ static bool keepGoingCallback(void) { bool keepGoing = true; - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -279,7 +282,6 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClient") int32_t y; int32_t z; size_t s; - int32_t startTimeMs; char *pTopicOut; char *pTopicIn; char *pMessageOut; @@ -378,13 +380,13 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClient") // Connect it U_TEST_PRINT_LINE_MQTT("connecting to \"%s\"...", connection.pBrokerNameStr); - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + (U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000; y = uMqttClientConnect(gpMqttContextA, &connection); z = uMqttClientOpenResetLastError(); if (y == 0) { U_TEST_PRINT_LINE_MQTT("connect successful after %d ms.", - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(gTimeoutStop.timeoutStart)); U_PORT_TEST_ASSERT(z == 0); // Note: can't check the return value here as it is // utterly module specific, only really checking that it @@ -399,16 +401,16 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClient") &gNumUnread) == 0); U_TEST_PRINT_LINE_MQTT("subscribing to topic \"%s\"...", pTopicOut); - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + (U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000; y = uMqttClientSubscribe(gpMqttContextA, pTopicOut, U_MQTT_QOS_EXACTLY_ONCE); if (y >= 0) { U_TEST_PRINT_LINE_MQTT("subscribe successful after %d ms, QoS %d.", - uPortGetTickTimeMs() - startTimeMs, y); + uTimeoutElapsedMs(gTimeoutStop.timeoutStart), y); } else { U_TEST_PRINT_LINE_MQTT("subscribe returned error %d after %d ms," " module error %d.", y, - uPortGetTickTimeMs() - startTimeMs, + uTimeoutElapsedMs(gTimeoutStop.timeoutStart), uMqttClientGetLastErrorCode(gpMqttContextA)); //lint -e(506, 774) Suppress constant value Boolean U_PORT_TEST_ASSERT(false); @@ -434,8 +436,8 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClient") U_TEST_PRINT_LINE_MQTT("publishing %d byte(s) to topic \"%s\"...", U_MQTT_CLIENT_TEST_PUBLISH_MAX_LENGTH_BYTES, pTopicOut); - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + (U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000; // Fill in the outgoing message buffer with all possible things s = 0; y = U_MQTT_CLIENT_TEST_PUBLISH_MAX_LENGTH_BYTES; @@ -453,23 +455,24 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClient") U_MQTT_QOS_EXACTLY_ONCE, false); if (y == 0) { U_TEST_PRINT_LINE_MQTT("publish successful after %d ms.", - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(gTimeoutStop.timeoutStart)); // We've just sent a message U_PORT_TEST_ASSERT(uMqttClientGetTotalMessagesSent(gpMqttContextA) > 0); } else { U_TEST_PRINT_LINE_MQTT("publish returned error %d after %d ms, module" " error %d.", y, - uPortGetTickTimeMs() - startTimeMs, + uTimeoutElapsedMs(gTimeoutStop.timeoutStart), uMqttClientGetLastErrorCode(gpMqttContextA)); //lint -e(506, 774) Suppress constant value Boolean U_PORT_TEST_ASSERT(false); } U_TEST_PRINT_LINE_MQTT("waiting for an unread message indication..."); - startTimeMs = uPortGetTickTimeMs(); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000; while ((gNumUnread == 0) && - (uPortGetTickTimeMs() < startTimeMs + - (U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000))) { + !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(1000); } @@ -477,7 +480,7 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClient") U_TEST_PRINT_LINE_MQTT("%d message(s) unread.", gNumUnread); } else { U_TEST_PRINT_LINE_MQTT("no messages unread after %d ms.", - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(gTimeoutStop.timeoutStart)); //lint -e(506, 774) Suppress constant value Boolean U_PORT_TEST_ASSERT(false); } @@ -543,7 +546,8 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClient") // Cancel the subscribe U_TEST_PRINT_LINE_MQTT("unsubscribing from topic \"%s\"...", pTopicOut); - gStopTimeMs = uPortGetTickTimeMs() + (U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000; U_PORT_TEST_ASSERT(uMqttClientUnsubscribe(gpMqttContextA, pTopicOut) == 0); // Remove the callback @@ -565,7 +569,7 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClient") if (noTls) { U_TEST_PRINT_LINE_MQTT("connection failed after %d ms," " with error %d, module error %d.", - uPortGetTickTimeMs() - startTimeMs, z, + uTimeoutElapsedMs(gTimeoutStop.timeoutStart), z, uMqttClientGetLastErrorCode(gpMqttContextA)); //lint -e(506, 774) Suppress constant value Boolean U_PORT_TEST_ASSERT(false); @@ -627,7 +631,6 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClientSn") int32_t y; int32_t z; size_t s; - int32_t startTimeMs; char *pTopicNameOutMqtt; uMqttSnTopicName_t topicNameOut; uMqttSnTopicName_t topicNameIn; @@ -713,13 +716,13 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClientSn") // Connect it U_TEST_PRINT_LINE_MQTTSN("connecting to \"%s\"...", connection.pBrokerNameStr); - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + (U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000; y = uMqttClientConnect(gpMqttContextA, &connection); z = uMqttClientOpenResetLastError(); if (y == 0) { U_TEST_PRINT_LINE_MQTTSN("connect successful after %d ms.", - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(gTimeoutStop.timeoutStart)); U_PORT_TEST_ASSERT(z == 0); // Note: can't check the return value here as it is // utterly module specific, only really checking that it @@ -734,14 +737,14 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClientSn") &gNumUnread) == 0); U_TEST_PRINT_LINE_MQTTSN("subscribing to MQTT topic \"%s\"...", pTopicNameOutMqtt); - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + (U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000; memset(&topicNameOut, 0xFF, sizeof(topicNameOut)); y = uMqttClientSnSubscribeNormalTopic(gpMqttContextA, pTopicNameOutMqtt, U_MQTT_QOS_EXACTLY_ONCE, &topicNameOut); if (y >= 0) { U_TEST_PRINT_LINE_MQTTSN("subscribe successful after %d ms, topic ID \"%d\"," - " QoS %d.", uPortGetTickTimeMs() - startTimeMs, + " QoS %d.", uTimeoutElapsedMs(gTimeoutStop.timeoutStart), topicNameOut.name.id, y); U_PORT_TEST_ASSERT(uMqttClientSnGetTopicNameType(&topicNameOut) == U_MQTT_SN_TOPIC_NAME_TYPE_ID_NORMAL); @@ -750,7 +753,7 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClientSn") } else { U_TEST_PRINT_LINE_MQTTSN("subscribe returned error %d after %d ms," " module error %d.", y, - uPortGetTickTimeMs() - startTimeMs, + uTimeoutElapsedMs(gTimeoutStop.timeoutStart), uMqttClientGetLastErrorCode(gpMqttContextA)); //lint -e(506, 774) Suppress constant value Boolean U_PORT_TEST_ASSERT(false); @@ -774,8 +777,8 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClientSn") U_TEST_PRINT_LINE_MQTTSN("publishing %d byte(s) to topic \"%d\"...", U_MQTT_CLIENT_TEST_PUBLISH_MAX_LENGTH_BYTES, topicNameOut.name.id); - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + (U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000; // Fill in the outgoing message buffer with all possible things s = 0; y = U_MQTT_CLIENT_TEST_PUBLISH_MAX_LENGTH_BYTES; @@ -793,23 +796,24 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClientSn") U_MQTT_QOS_EXACTLY_ONCE, false); if (y == 0) { U_TEST_PRINT_LINE_MQTTSN("publish successful after %d ms.", - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(gTimeoutStop.timeoutStart)); // We've just sent a message U_PORT_TEST_ASSERT(uMqttClientGetTotalMessagesSent(gpMqttContextA) > 0); } else { U_TEST_PRINT_LINE_MQTTSN("publish returned error %d after %d ms, module" " error %d.", y, - uPortGetTickTimeMs() - startTimeMs, + uTimeoutElapsedMs(gTimeoutStop.timeoutStart), uMqttClientGetLastErrorCode(gpMqttContextA)); //lint -e(506, 774) Suppress constant value Boolean U_PORT_TEST_ASSERT(false); } U_TEST_PRINT_LINE_MQTTSN("waiting for an unread message indication..."); - startTimeMs = uPortGetTickTimeMs(); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000; while ((gNumUnread == 0) && - !uPortTickTimeExpiredMs(startTimeMs, - U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000)) { + !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(1000); } @@ -817,7 +821,7 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClientSn") U_TEST_PRINT_LINE_MQTTSN("%d message(s) unread.", gNumUnread); } else { U_TEST_PRINT_LINE_MQTTSN("no messages unread after %d ms.", - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(gTimeoutStop.timeoutStart)); //lint -e(506, 774) Suppress constant value Boolean U_PORT_TEST_ASSERT(false); } @@ -879,7 +883,8 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClientSn") // Cancel the subscribe U_TEST_PRINT_LINE_MQTTSN("unsubscribing from topic \"%d\"...", topicNameOut.name.id); - gStopTimeMs = uPortGetTickTimeMs() + (U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_MQTT_CLIENT_RESPONSE_WAIT_SECONDS * 1000; U_PORT_TEST_ASSERT(uMqttClientSnUnsubscribeNormalTopic(gpMqttContextA, pTopicNameOutMqtt) == 0); // Remove the callback @@ -943,7 +948,7 @@ U_PORT_TEST_FUNCTION("[mqttClient]", "mqttClientSn") } else { U_TEST_PRINT_LINE_MQTTSN("connection failed after %d ms," " with error %d, module error %d.", - uPortGetTickTimeMs() - startTimeMs, z, + uTimeoutElapsedMs(gTimeoutStop.timeoutStart), z, uMqttClientGetLastErrorCode(gpMqttContextA)); //lint -e(506, 774) Suppress constant value Boolean U_PORT_TEST_ASSERT(false); diff --git a/common/network/src/u_network_private_cell.c b/common/network/src/u_network_private_cell.c index 5efa8651..60911e87 100644 --- a/common/network/src/u_network_private_cell.c +++ b/common/network/src/u_network_private_cell.c @@ -40,6 +40,8 @@ #include "u_port.h" #include "u_port_uart.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_device.h" @@ -83,7 +85,8 @@ static bool keepGoingCallback(uDeviceHandle_t devHandle) if (uDeviceGetInstance(devHandle, &pDevInstance) == 0) { pContext = (uDeviceCellContext_t *) pDevInstance->pContext; if ((pContext == NULL) || - !uPortTickTimeBeyondStopMs(pContext->stopTimeMs)) { + !uTimeoutExpiredMs(pContext->timeoutStop.timeoutStart, + pContext->timeoutStop.durationMs)) { keepGoing = true; } } @@ -173,7 +176,8 @@ int32_t uNetworkPrivateChangeStateCell(uDeviceHandle_t devHandle, if (timeoutSeconds <= 0) { timeoutSeconds = U_CELL_NET_CONNECT_TIMEOUT_SECONDS; } - pContext->stopTimeMs = uPortGetTickTimeMs() + (timeoutSeconds * 1000); + pContext->timeoutStop.timeoutStart = uTimeoutStart(); + pContext->timeoutStop.durationMs = timeoutSeconds * 1000; } if (upNotDown) { // Set the authentication mode diff --git a/common/network/src/u_network_private_wifi.c b/common/network/src/u_network_private_wifi.c index 090b7b75..cea55001 100644 --- a/common/network/src/u_network_private_wifi.c +++ b/common/network/src/u_network_private_wifi.c @@ -40,6 +40,8 @@ #include "u_cfg_os_platform_specific.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_device_shared.h" @@ -249,8 +251,8 @@ static inline void statusQueueClear(const uPortQueueHandle_t queueHandle) static inline int32_t statusQueueWaitForWifiDisabled(const uPortQueueHandle_t queueHandle, int32_t timeoutSec) { - int32_t startTimeMs = uPortGetTickTimeMs(); - while (!uPortTickTimeExpiredMs(startTimeMs, timeoutSec * 1000)) { + uTimeoutStart_t timeoutStart = uTimeoutStart(); + while (!uTimeoutExpiredSeconds(timeoutStart, timeoutSec)) { uStatusMessage_t msg; int32_t errorCode = uPortQueueTryReceive(queueHandle, 1000, &msg); if ((errorCode == (int32_t) U_ERROR_COMMON_SUCCESS) && @@ -265,8 +267,8 @@ static inline int32_t statusQueueWaitForWifiDisabled(const uPortQueueHandle_t qu static inline int32_t statusQueueWaitForWifiConnected(const uPortQueueHandle_t queueHandle, int32_t timeoutSec) { - int32_t startTimeMs = uPortGetTickTimeMs(); - while (!uPortTickTimeExpiredMs(startTimeMs, timeoutSec * 1000)) { + uTimeoutStart_t timeoutStart = uTimeoutStart(); + while (!uTimeoutExpiredSeconds(timeoutStart, timeoutSec)) { uStatusMessage_t msg; int32_t errorCode = uPortQueueTryReceive(queueHandle, 1000, &msg); if ((errorCode == (int32_t) U_ERROR_COMMON_SUCCESS) && @@ -283,8 +285,8 @@ static inline int32_t statusQueueWaitForNetworkUp(const uPortQueueHandle_t queue static const uint32_t desiredNetStatusMask = U_WIFI_STATUS_MASK_IPV4_UP | U_WIFI_STATUS_MASK_IPV6_UP; uint32_t lastNetStatusMask = 0; - int32_t startTimeMs = uPortGetTickTimeMs(); - while (!uPortTickTimeExpiredMs(startTimeMs, timeoutSec * 1000)) { + uTimeoutStart_t timeoutStart = uTimeoutStart(); + while (!uTimeoutExpiredSeconds(timeoutStart, timeoutSec)) { uStatusMessage_t msg; int32_t errorCode = uPortQueueTryReceive(queueHandle, 1000, &msg); if (errorCode == (int32_t) U_ERROR_COMMON_SUCCESS) { diff --git a/common/network/test/u_network_test.c b/common/network/test/u_network_test.c index 337064b2..2febdb61 100644 --- a/common/network/test/u_network_test.c +++ b/common/network/test/u_network_test.c @@ -56,6 +56,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #ifdef U_CFG_TEST_CELL_MODULE_TYPE # include "u_cell_module_type.h" # include "u_cell_test_cfg.h" // For the cellular test macros @@ -184,7 +186,7 @@ static uPortSemaphoreHandle_t gBleConnectionSem = NULL; /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** Keep track of the current network handle so that the * keepGoingCallback() can check it. @@ -345,7 +347,8 @@ static bool keepGoingCallback(uDeviceHandle_t devHandle) bool keepGoing = true; U_PORT_TEST_ASSERT(devHandle == gDevHandle); - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -752,7 +755,6 @@ U_PORT_TEST_FUNCTION("[network]", "networkLoc") const uLocationTestCfg_t *pLocationCfg; int32_t y; uLocation_t location; - int32_t startTimeMs; int32_t resourceCount; // In case a previous test failed @@ -799,8 +801,8 @@ U_PORT_TEST_FUNCTION("[network]", "networkLoc") // Just take the first one, we don't care which as this // is a network test not a location test pLocationCfg = gpULocationTestCfg[pTmp->networkType]->pCfgData[0]; - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + (U_LOCATION_TEST_CFG_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_LOCATION_TEST_CFG_TIMEOUT_SECONDS * 1000; uLocationTestResetLocation(&location); U_TEST_PRINT_LINE("getting location using %s.", gpULocationTestTypeStr[pLocationCfg->locationType]); @@ -811,7 +813,7 @@ U_PORT_TEST_FUNCTION("[network]", "networkLoc") &location, keepGoingCallback); if (y == 0) { U_TEST_PRINT_LINE("location establishment took %d second(s).", - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(gTimeoutStop.timeoutStart)); } // If we are running on a local cellular network we won't get position but // we should always get time diff --git a/common/security/src/u_security_credential.c b/common/security/src/u_security_credential.c index 75d7c2c9..d898a285 100644 --- a/common/security/src/u_security_credential.c +++ b/common/security/src/u_security_credential.c @@ -50,6 +50,8 @@ #include "u_port_os.h" #include "u_port_heap.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_device_shared.h" diff --git a/common/security/test/u_security_test.c b/common/security/test/u_security_test.c index 62904d9c..22d9f39d 100644 --- a/common/security/test/u_security_test.c +++ b/common/security/test/u_security_test.c @@ -55,6 +55,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #ifdef U_CFG_TEST_CELL_MODULE_TYPE #include "u_cell_module_type.h" #include "u_cell_test_cfg.h" // For the cellular test macros @@ -94,7 +96,7 @@ #ifdef U_CFG_SECURITY_DEVICE_PROFILE_UID /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; #endif /* ---------------------------------------------------------------- @@ -107,7 +109,8 @@ static bool keepGoingCallback() { bool keepGoing = true; - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -224,7 +227,8 @@ U_PORT_TEST_FUNCTION("[security]", "securitySeal") " number \"%s\"...", U_PORT_STRINGIFY_QUOTED(U_CFG_SECURITY_DEVICE_PROFILE_UID), serialNumber); - gStopTimeMs = uPortGetTickTimeMs() + (U_SECURITY_TEST_SEAL_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_SECURITY_TEST_SEAL_TIMEOUT_SECONDS * 1000; if (uSecuritySealSet(devHandle, U_PORT_STRINGIFY_QUOTED(U_CFG_SECURITY_DEVICE_PROFILE_UID), serialNumber, keepGoingCallback) == 0) { diff --git a/common/security/test/u_security_tls_test.c b/common/security/test/u_security_tls_test.c index a18130e2..df75a67c 100644 --- a/common/security/test/u_security_tls_test.c +++ b/common/security/test/u_security_tls_test.c @@ -22,9 +22,11 @@ /** @file * @brief Test for the u-blox TLS security API: these should pass on all - * platforms. + * platforms that support transport security. */ +#ifndef U_CFG_TEST_TRANSPORT_SECURITY_DISABLE + #ifdef U_CFG_OVERRIDE # include "u_cfg_override.h" // For a customer's configuration override #endif @@ -41,6 +43,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_port.h" #include "u_port_os.h" #include "u_port_heap.h" @@ -147,6 +151,10 @@ static const char *const gpEchoServerCaCertPem = "-----BEGIN CERTIFICATE-----\r\ "iDO9Bnw=\r\n" "-----END CERTIFICATE-----"; +/** Hook to hold buffer for test data received. + */ +static char *gpDataReceived = NULL; + /* ---------------------------------------------------------------- * STATIC FUNCTIONS * -------------------------------------------------------------- */ @@ -157,12 +165,12 @@ static size_t send(uSockDescriptor_t descriptor, { int32_t x; size_t sentSizeBytes = 0; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; U_TEST_PRINT_LINE("sending %d byte(s) of data...", sizeBytes); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((sentSizeBytes < sizeBytes) && - !uPortTickTimeExpiredMs(startTimeMs, 10000)) { + !uTimeoutExpiredSeconds(timeoutStart, 10)) { x = uSockWrite(descriptor, (const void *) pData, sizeBytes - sentSizeBytes); if (x > 0) { @@ -207,8 +215,7 @@ U_PORT_TEST_FUNCTION("[securityTls]", "securityTlsSock") uDeviceHandle_t devHandle = NULL; uSockDescriptor_t descriptor = -1; uSockAddress_t remoteAddress; - char *pDataReceived; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; size_t sizeBytes; size_t offset; int32_t y; @@ -360,19 +367,20 @@ U_PORT_TEST_FUNCTION("[securityTls]", "securityTlsSock") sizeof(gData) - 1, (int32_t) uPortGetTickTimeMs()); // ...and capture them all again afterwards - pDataReceived = (char *) pUPortMalloc(sizeof(gData) - 1); - U_PORT_TEST_ASSERT(pDataReceived != NULL); + uPortFree(gpDataReceived); // In case the previous test failed + gpDataReceived = (char *) pUPortMalloc(sizeof(gData) - 1); + U_PORT_TEST_ASSERT(gpDataReceived != NULL); //lint -e(668) Suppress possible use of NULL pointer - // for pDataReceived - memset(pDataReceived, 0, sizeof(gData) - 1); - startTimeMs = uPortGetTickTimeMs(); + // for gpDataReceived + memset(gpDataReceived, 0, sizeof(gData) - 1); + timeoutStart = uTimeoutStart(); offset = 0; //lint -e{441} Suppress loop variable not found in // condition: we're using time instead for (y = 0; (offset < sizeof(gData) - 1) && - !uPortTickTimeExpiredMs(startTimeMs, 20000); y++) { + !uTimeoutExpiredSeconds(timeoutStart, 20); y++) { sizeBytes = uSockRead(descriptor, - pDataReceived + offset, + gpDataReceived + offset, (sizeof(gData) - 1) - offset); if (sizeBytes > 0) { U_TEST_PRINT_LINE("received %d byte(s) on secure TCP socket.", sizeBytes); @@ -382,17 +390,18 @@ U_PORT_TEST_FUNCTION("[securityTls]", "securityTlsSock") sizeBytes = offset; if (sizeBytes < sizeof(gData) - 1) { U_TEST_PRINT_LINE("only %d byte(s) received after %d ms.", sizeBytes, - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(timeoutStart)); } else { U_TEST_PRINT_LINE("all %d byte(s) received back after %d ms, checking" " if they were as expected...", sizeBytes, - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(timeoutStart)); } // Check that we reassembled everything correctly - U_PORT_TEST_ASSERT(memcmp(pDataReceived, gData, sizeof(gData) - 1) == 0); + U_PORT_TEST_ASSERT(memcmp(gpDataReceived, gData, sizeof(gData) - 1) == 0); - uPortFree(pDataReceived); + uPortFree(gpDataReceived); + gpDataReceived = NULL; // Close the socket if (!closeSock(descriptor)) { @@ -444,8 +453,7 @@ U_PORT_TEST_FUNCTION("[securityTls]", "securityTlsUdpSock") uDeviceHandle_t devHandle = NULL; uSockDescriptor_t descriptor = -1; uSockAddress_t remoteAddress; - char *pDataReceived; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; size_t sizeBytes; size_t offset; int32_t y; @@ -597,19 +605,20 @@ U_PORT_TEST_FUNCTION("[securityTls]", "securityTlsUdpSock") sizeof(gData) - 1, (int32_t) uPortGetTickTimeMs()); // ...and capture them all again afterwards - pDataReceived = (char *) pUPortMalloc(sizeof(gData) - 1); - U_PORT_TEST_ASSERT(pDataReceived != NULL); + uPortFree(gpDataReceived); // In case the previous test failed + gpDataReceived = (char *) pUPortMalloc(sizeof(gData) - 1); + U_PORT_TEST_ASSERT(gpDataReceived != NULL); //lint -e(668) Suppress possible use of NULL pointer - // for pDataReceived - memset(pDataReceived, 0, sizeof(gData) - 1); - startTimeMs = uPortGetTickTimeMs(); + // for gpDataReceived + memset(gpDataReceived, 0, sizeof(gData) - 1); + timeoutStart = uTimeoutStart(); offset = 0; //lint -e{441} Suppress loop variable not found in // condition: we're using time instead for (y = 0; (offset < sizeof(gData) - 1) && - !uPortTickTimeExpiredMs(startTimeMs, 20000); y++) { + !uTimeoutExpiredSeconds(timeoutStart, 20); y++) { sizeBytes = uSockRead(descriptor, - pDataReceived + offset, + gpDataReceived + offset, (sizeof(gData) - 1) - offset); if (sizeBytes > 0) { U_TEST_PRINT_LINE("received %d byte(s) on secure UDP socket.", sizeBytes); @@ -619,15 +628,18 @@ U_PORT_TEST_FUNCTION("[securityTls]", "securityTlsUdpSock") sizeBytes = offset; if (sizeBytes < sizeof(gData) - 1) { U_TEST_PRINT_LINE("only %d byte(s) received after %d ms.", sizeBytes, - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(timeoutStart)); } else { U_TEST_PRINT_LINE("all %d byte(s) received back after %d ms, checking" " if they were as expected...", sizeBytes, - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(timeoutStart)); } // Check that we reassembled everything correctly - U_PORT_TEST_ASSERT(memcmp(pDataReceived, gData, sizeof(gData) - 1) == 0); + U_PORT_TEST_ASSERT(memcmp(gpDataReceived, gData, sizeof(gData) - 1) == 0); + + uPortFree(gpDataReceived); + gpDataReceived = NULL; // Close the socket if (!closeSock(descriptor)) { @@ -684,6 +696,8 @@ U_PORT_TEST_FUNCTION("[securityTls]", "securityTlsCleanUp") // Clean-up the TLS security mutex uSecurityTlsCleanUp(); + uPortFree(gpDataReceived); + // The network test configuration is shared between // the network, sockets, security and location tests // so must reset the handles here in case the @@ -695,4 +709,6 @@ U_PORT_TEST_FUNCTION("[securityTls]", "securityTlsCleanUp") uTestUtilResourceCheck(U_TEST_PREFIX, NULL, true); } +#endif // #ifndef U_CFG_TEST_TRANSPORT_SECURITY_DISABLE + // End of file diff --git a/common/short_range/src/gen2/u_short_range.c b/common/short_range/src/gen2/u_short_range.c index 84358cd3..c1759164 100644 --- a/common/short_range/src/gen2/u_short_range.c +++ b/common/short_range/src/gen2/u_short_range.c @@ -49,6 +49,8 @@ #include "u_port_uart.h" #include "u_compiler.h" +#include "u_timeout.h" + #include "u_cx_at_client.h" #include "u_cx_general.h" #include "u_cx_system.h" diff --git a/common/short_range/src/gen2/u_short_range_cfg.c b/common/short_range/src/gen2/u_short_range_cfg.c index 4ba4fca6..f6bdb363 100644 --- a/common/short_range/src/gen2/u_short_range_cfg.c +++ b/common/short_range/src/gen2/u_short_range_cfg.c @@ -43,6 +43,8 @@ #include "u_port_heap.h" #include "u_port_debug.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_short_range.h" diff --git a/common/short_range/src/gen2/u_short_range_private.c b/common/short_range/src/gen2/u_short_range_private.c index 466ad299..a140e575 100644 --- a/common/short_range/src/gen2/u_short_range_private.c +++ b/common/short_range/src/gen2/u_short_range_private.c @@ -34,6 +34,8 @@ #include "u_port_os.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_device_shared.h" diff --git a/common/short_range/src/u_short_range.c b/common/short_range/src/u_short_range.c index 1b9b6dc9..8545778a 100644 --- a/common/short_range/src/u_short_range.c +++ b/common/short_range/src/u_short_range.c @@ -47,6 +47,8 @@ #include "u_port_gpio.h" #include "u_port_uart.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_linked_list.h" @@ -237,7 +239,7 @@ static int32_t uShortRangeAdd(uShortRangeModuleType_t moduleType, pInstance->devHandle = pDevInstance; pInstance->atHandle = atHandle; pInstance->mode = U_SHORT_RANGE_MODE_EDM; - pInstance->startTimeMs = 500; + pInstance->timeoutStart = uTimeoutStart(); pInstance->urcConHandlerSet = false; pInstance->sockNextLocalPort = -1; pInstance->uartHandle = uartHandle; diff --git a/common/short_range/src/u_short_range_cfg.c b/common/short_range/src/u_short_range_cfg.c index b9f4f0d5..bf7fbfba 100644 --- a/common/short_range/src/u_short_range_cfg.c +++ b/common/short_range/src/u_short_range_cfg.c @@ -43,6 +43,8 @@ #include "u_port_heap.h" #include "u_port_debug.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_short_range.h" diff --git a/common/short_range/src/u_short_range_edm_stream.c b/common/short_range/src/u_short_range_edm_stream.c index 862ed582..874c38bd 100644 --- a/common/short_range/src/u_short_range_edm_stream.c +++ b/common/short_range/src/u_short_range_edm_stream.c @@ -40,6 +40,7 @@ #include "u_port_event_queue.h" #include "u_port_uart.h" #include "u_port_debug.h" +#include "u_timeout.h" #include "u_at_client.h" #include "u_short_range_pbuf.h" #include "u_short_range_module_type.h" @@ -1398,8 +1399,7 @@ int32_t uShortRangeEdmStreamWrite(int32_t handle, int32_t channel, char head[U_SHORT_RANGE_EDM_DATA_HEAD_SIZE]; char tail[U_SHORT_RANGE_EDM_TAIL_SIZE]; sizeOrErrorCode = 0; - int32_t startTimeMs = uPortGetTickTimeMs(); - int32_t endTimeMs; + uTimeoutStart_t timeoutStart = uTimeoutStart(); do { send = ((int32_t)sizeBytes - sizeOrErrorCode); @@ -1431,9 +1431,8 @@ int32_t uShortRangeEdmStreamWrite(int32_t handle, int32_t channel, } else { sizeOrErrorCode += send; } - endTimeMs = uPortGetTickTimeMs(); } while (((int32_t)sizeBytes > sizeOrErrorCode) && - (endTimeMs - startTimeMs < (int32_t) timeoutMs)); + !uTimeoutExpiredMs(timeoutStart, timeoutMs)); } } U_PORT_MUTEX_UNLOCK(gMutex); diff --git a/common/short_range/src/u_short_range_private.c b/common/short_range/src/u_short_range_private.c index c7b7a75c..36dd9642 100644 --- a/common/short_range/src/u_short_range_private.c +++ b/common/short_range/src/u_short_range_private.c @@ -34,6 +34,8 @@ #include "u_port_os.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_device_shared.h" diff --git a/common/short_range/src/u_short_range_private.h b/common/short_range/src/u_short_range_private.h index e5a0f26a..ac7d0517 100644 --- a/common/short_range/src/u_short_range_private.h +++ b/common/short_range/src/u_short_range_private.h @@ -149,7 +149,7 @@ typedef struct uShortRangePrivateInstance_t { uAtClientHandle_t atHandle; /**< the AT client handle to use. */ int32_t streamHandle; /**< handle to the underlaying stream. */ uAtClientStream_t streamType; /**< stream type. */ - int32_t startTimeMs; /**< used while restarting. */ + uTimeoutStart_t timeoutStart; /**< used while restarting. */ int32_t ticksLastRestart; bool urcConHandlerSet; int32_t sockNextLocalPort; diff --git a/common/short_range/test/u_short_range_test.c b/common/short_range/test/u_short_range_test.c index e0e36ecb..5116346a 100644 --- a/common/short_range/test/u_short_range_test.c +++ b/common/short_range/test/u_short_range_test.c @@ -55,6 +55,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #ifdef U_CFG_TEST_SHORT_RANGE_MODULE_TYPE #include "u_ble_sps.h" #include "u_short_range_private.h" diff --git a/common/short_range/test/u_short_range_test_private.c b/common/short_range/test/u_short_range_test_private.c index 66016352..b100f2f2 100644 --- a/common/short_range/test/u_short_range_test_private.c +++ b/common/short_range/test/u_short_range_test_private.c @@ -42,6 +42,8 @@ #include "u_port_debug.h" #include "u_port_os.h" +#include "u_timeout.h" + #include "u_at_client.h" //lint -efile(766, u_ble_sps.h) diff --git a/common/sock/src/u_sock.c b/common/sock/src/u_sock.c index fead8428..3926733c 100644 --- a/common/sock/src/u_sock.c +++ b/common/sock/src/u_sock.c @@ -324,6 +324,8 @@ #include "u_device_shared.h" +#include "u_timeout.h" + #include "u_port_clib_platform_specific.h" /* struct timeval in some cases and integer stdio, must be included before the other port files if @@ -1208,7 +1210,7 @@ static int32_t receive(const uSockContainer_t *pContainer, uDeviceHandle_t devHandle = pContainer->socket.devHandle; int32_t sockHandle = pContainer->socket.sockHandle; int32_t negErrnoOrSize = -U_SOCK_ENOSYS; - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); int32_t devType = uDeviceGetDeviceType(devHandle); // Run around the loop until a packet of data turns up @@ -1250,8 +1252,8 @@ static int32_t receive(const uSockContainer_t *pContainer, } } while ((negErrnoOrSize < 0) && (pContainer->socket.blocking) && - !uPortTickTimeExpiredMs(startTimeMs, - pContainer->socket.receiveTimeoutMs)); + !uTimeoutExpiredMs(timeoutStart, + pContainer->socket.receiveTimeoutMs)); return negErrnoOrSize; } diff --git a/common/sock/test/u_sock_test.c b/common/sock/test/u_sock_test.c index 79a68826..f658838a 100644 --- a/common/sock/test/u_sock_test.c +++ b/common/sock/test/u_sock_test.c @@ -66,6 +66,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_network.h" // In order to provide a comms #include "u_network_test_shared_cfg.h" // path for the socket @@ -160,6 +162,15 @@ # define U_SOCK_TEST_TIME_MARGIN_MINUS_MS 100 #endif +#ifndef U_SOCK_TEST_RESOURCE_COUNT_LIMIT +/** To save time when testing we don't close the devices + * and hence it is difficult to do reliable resource + * checking, however we don't want resource usage to + * increase either hence we check against this threshold. + */ +# define U_SOCK_TEST_RESOURCE_COUNT_LIMIT 1 +#endif + // Do some cross-checking #ifdef U_AT_CLIENT_URC_TASK_PRIORITY # if (U_AT_CLIENT_URC_TASK_PRIORITY) <= (U_SOCK_TEST_TASK_PRIORITY) @@ -323,6 +334,14 @@ static const char gAllChars[] = "the quick brown fox jumps over the lazy dog " "\x1d\x1e!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\x7f" "\r\nOK\r\n \r\nERROR\r\n \r\nABORTED\r\n"; +/** Place to hook a buffer for received data. + */ +static char *gpDataReceived1 = NULL; + +/** Another place to hook a buffer for received data. + */ +static char *gpDataReceived2 = NULL; + /* ---------------------------------------------------------------- * STATIC FUNCTIONS * -------------------------------------------------------------- */ @@ -553,8 +572,6 @@ static int32_t doUdpEchoBasic(uSockDescriptor_t descriptor, const char *pSendData, size_t sendSizeBytes) { - char *pDataReceived = (char *) pUPortMalloc(sendSizeBytes + - (U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES * 2)); uSockAddress_t senderAddress; int32_t sentSizeBytes; int32_t receivedSizeBytes = 0; @@ -562,7 +579,10 @@ static int32_t doUdpEchoBasic(uSockDescriptor_t descriptor, int32_t timeNowMs; #endif - U_PORT_TEST_ASSERT(pDataReceived != NULL); + uPortFree(gpDataReceived2); + gpDataReceived2 = (char *) pUPortMalloc(sendSizeBytes + + (U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES * 2)); + U_PORT_TEST_ASSERT(gpDataReceived2 != NULL); // Retry this a few times, don't want to fail due to a flaky link for (size_t x = 0; (receivedSizeBytes != (int32_t)sendSizeBytes) && @@ -583,11 +603,11 @@ static int32_t doUdpEchoBasic(uSockDescriptor_t descriptor, timeNowMs = uPortGetTickTimeMs(); #endif //lint -e(668) Suppress possible use of NULL pointer - // for pDataReceived (it is checked above) - memset(pDataReceived, U_SOCK_TEST_FILL_CHARACTER, + // for gpDataReceived2 (it is checked above) + memset(gpDataReceived2, U_SOCK_TEST_FILL_CHARACTER, sendSizeBytes + (U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES * 2)); receivedSizeBytes = uSockReceiveFrom(descriptor, &senderAddress, - pDataReceived + + gpDataReceived2 + U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES, sendSizeBytes); if (receivedSizeBytes >= 0) { @@ -602,12 +622,12 @@ static int32_t doUdpEchoBasic(uSockDescriptor_t descriptor, errno = 0; } if (receivedSizeBytes == (int32_t)sendSizeBytes) { - U_PORT_TEST_ASSERT(memcmp(pSendData, pDataReceived + + U_PORT_TEST_ASSERT(memcmp(pSendData, gpDataReceived2 + U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES, sendSizeBytes) == 0); for (size_t y = 0; y < U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES; y++) { - U_PORT_TEST_ASSERT(*(pDataReceived + y) == (char) U_SOCK_TEST_FILL_CHARACTER); - U_PORT_TEST_ASSERT(*(pDataReceived + + U_PORT_TEST_ASSERT(*(gpDataReceived2 + y) == (char) U_SOCK_TEST_FILL_CHARACTER); + U_PORT_TEST_ASSERT(*(gpDataReceived2 + U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES + sendSizeBytes + y) == (char) U_SOCK_TEST_FILL_CHARACTER); } @@ -621,7 +641,8 @@ static int32_t doUdpEchoBasic(uSockDescriptor_t descriptor, } } - uPortFree(pDataReceived); + uPortFree(gpDataReceived2); + gpDataReceived2 = NULL; return receivedSizeBytes; } @@ -673,12 +694,12 @@ static size_t sendTcp(uSockDescriptor_t descriptor, { int32_t x; size_t sentSizeBytes = 0; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; U_TEST_PRINT_LINE("sending %d byte(s) of TCP data...", sizeBytes); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((sentSizeBytes < sizeBytes) && - !uPortTickTimeExpiredMs(startTimeMs, 10000)) { + !uTimeoutExpiredSeconds(timeoutStart, 10)) { x = uSockWrite(descriptor, (const void *) pData, sizeBytes - sentSizeBytes); if (x > 0) { @@ -700,20 +721,12 @@ static size_t sendTcp(uSockDescriptor_t descriptor, static uSockDescriptor_t openSocketAndUseIt(uDeviceHandle_t devHandle, const uSockAddress_t *pRemoteAddress, uSockType_t type, - uSockProtocol_t protocol, - int32_t *pHeapXxxSockInitLoss) + uSockProtocol_t protocol) { uSockDescriptor_t descriptor; U_TEST_PRINT_LINE("creating socket..."); - // Creating a socket may use heap in the underlying - // network layer which will be reclaimed when the - // network layer is closed but we don't do that here - // to save time so need to allow for it in the heap loss - // calculation - *pHeapXxxSockInitLoss += uPortGetHeapFree(); descriptor = uSockCreate(devHandle, type, protocol); - *pHeapXxxSockInitLoss -= uPortGetHeapFree(); U_TEST_PRINT_LINE("socket descriptor %d, errno %d.", descriptor, errno); if (descriptor >= 0) { U_PORT_TEST_ASSERT(errno == 0); @@ -918,9 +931,7 @@ U_PORT_TEST_FUNCTION("[sock]", "sockBasicUdp") bool dataCallbackCalled; size_t sizeBytes; bool success; - int32_t heapUsed; - int32_t heapSockInitLoss = 0; - int32_t heapXxxSockInitLoss = 0; + int32_t resourceCount; // In case a previous test failed uNetworkTestCleanUp(); @@ -933,31 +944,19 @@ U_PORT_TEST_FUNCTION("[sock]", "sockBasicUdp") // a network underneath us pList = pStdPreamble(); - // The first time rand() is called the C library may - // allocate memory, not something we can do anything - // about, so call it once here to move that number - // out of our sums. - rand(); - // Repeat for all bearers for (uNetworkTestList_t *pTmp = pList; pTmp != NULL; pTmp = pTmp->pNext) { devHandle = *pTmp->pDevHandle; - // Get the initial-ish heap - heapUsed = uPortGetHeapFree(); + resourceCount = uTestUtilGetDynamicResourceCount(); U_TEST_PRINT_LINE("doing basic UDP test on %s.", gpUNetworkTestTypeName[pTmp->networkType]); U_TEST_PRINT_LINE("looking up echo server \"%s\"...", U_SOCK_TEST_ECHO_UDP_SERVER_DOMAIN_NAME); // Look up the address of the server we use for UDP echo - // The first call to a sockets API needs to - // initialise the underlying sockets layer; take - // account of that initialisation heap cost here. - heapSockInitLoss = uPortGetHeapFree(); U_PORT_TEST_ASSERT(uSockGetHostByName(devHandle, U_SOCK_TEST_ECHO_UDP_SERVER_DOMAIN_NAME, &(remoteAddress.ipAddress)) == 0); - heapSockInitLoss -= uPortGetHeapFree(); // Add the port number we will use remoteAddress.port = U_SOCK_TEST_ECHO_UDP_SERVER_PORT; @@ -968,15 +967,8 @@ U_PORT_TEST_FUNCTION("[sock]", "sockBasicUdp") for (size_t retries = 2; !success && (retries > 0); retries--) { success = true; // Create a UDP socket - // Creating a socket may use heap in the underlying - // network layer which will be reclaimed when the - // network layer is closed but we don't do that here - // to save time so need to allow for it in the heap loss - // calculation - heapXxxSockInitLoss += uPortGetHeapFree(); descriptor = uSockCreate(devHandle, U_SOCK_TYPE_DGRAM, U_SOCK_PROTOCOL_UDP); - heapXxxSockInitLoss -= uPortGetHeapFree(); U_PORT_TEST_ASSERT(descriptor >= 0); U_PORT_TEST_ASSERT(errno == 0); @@ -1069,16 +1061,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockBasicUdp") U_PORT_TEST_ASSERT(uSockClose(descriptor) == 0); uSockCleanUp(); - if (uPortGetHeapFree() >= 0) { - // Check for memory leaks - heapUsed -= uPortGetHeapFree(); - U_TEST_PRINT_LINE("during this part of the test %d byte(s)" - " were lost to sockets initialisation; we" - " have leaked %d byte(s).", - heapSockInitLoss + heapXxxSockInitLoss, - heapUsed - (heapSockInitLoss + heapXxxSockInitLoss)); - U_PORT_TEST_ASSERT(heapUsed <= heapSockInitLoss + heapXxxSockInitLoss); - } + // Check that resource usage is not increasing + resourceCount = uTestUtilGetDynamicResourceCount() - resourceCount; + U_TEST_PRINT_LINE("%d resource(s) remain outstanding.", resourceCount); + U_PORT_TEST_ASSERT(resourceCount <= U_SOCK_TEST_RESOURCE_COUNT_LIMIT); } } @@ -1109,11 +1095,8 @@ U_PORT_TEST_FUNCTION("[sock]", "sockBasicTcp") size_t sizeBytes; size_t offset; int32_t y; - char *pDataReceived; - int32_t startTimeMs; - int32_t heapUsed; - int32_t heapSockInitLoss = 0; - int32_t heapXxxSockInitLoss = 0; + uTimeoutStart_t timeoutStart; + int32_t resourceCount; // Call clean up to release OS resources that may // have been left hanging by a previous failed test @@ -1123,17 +1106,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockBasicTcp") // a network underneath us pList = pStdPreamble(); - // The first time rand() is called the C library may - // allocate memory, not something we can do anything - // about, so call it once here to move that number - // out of our sums. - rand(); - // Repeat for all bearers for (uNetworkTestList_t *pTmp = pList; pTmp != NULL; pTmp = pTmp->pNext) { devHandle = *pTmp->pDevHandle; - // Get the initial-ish heap - heapUsed = uPortGetHeapFree(); + resourceCount = uTestUtilGetDynamicResourceCount(); U_TEST_PRINT_LINE("doing basic TCP test on %s.", gpUNetworkTestTypeName[pTmp->networkType]); @@ -1141,28 +1117,16 @@ U_PORT_TEST_FUNCTION("[sock]", "sockBasicTcp") U_SOCK_TEST_ECHO_TCP_SERVER_DOMAIN_NAME); // Look up the address of the server we use for TCP echo - // The first call to a sockets API needs to - // initialise the underlying sockets layer; take - // account of that initialisation heap cost here. - heapSockInitLoss = uPortGetHeapFree(); U_PORT_TEST_ASSERT(uSockGetHostByName(devHandle, U_SOCK_TEST_ECHO_TCP_SERVER_DOMAIN_NAME, &(remoteAddress.ipAddress)) == 0); - heapSockInitLoss -= uPortGetHeapFree(); // Add the port number we will use remoteAddress.port = U_SOCK_TEST_ECHO_TCP_SERVER_PORT; // Create a TCP socket - // Creating a socket may use heap in the underlying - // network layer which will be reclaimed when the - // network layer is closed but we don't do that here - // to save time so need to allow for it in the heap loss - // calculation - heapXxxSockInitLoss += uPortGetHeapFree(); descriptor = uSockCreate(devHandle, U_SOCK_TYPE_STREAM, U_SOCK_PROTOCOL_TCP); - heapXxxSockInitLoss -= uPortGetHeapFree(); U_PORT_TEST_ASSERT(descriptor >= 0); U_PORT_TEST_ASSERT(errno == 0); @@ -1232,22 +1196,23 @@ U_PORT_TEST_FUNCTION("[sock]", "sockBasicTcp") U_PORT_TEST_ASSERT(uSockGetTotalBytesSent(descriptor) == (int32_t)sizeBytes); // ...and capture them all again afterwards - pDataReceived = (char *) pUPortMalloc((sizeof(gSendData) - 1) + - (U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES * 2)); - U_PORT_TEST_ASSERT(pDataReceived != NULL); + uPortFree(gpDataReceived1); + gpDataReceived1 = (char *) pUPortMalloc((sizeof(gSendData) - 1) + + (U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES * 2)); + U_PORT_TEST_ASSERT(gpDataReceived1 != NULL); //lint -e(668) Suppress possible use of NULL pointer - // for pDataReceived - memset(pDataReceived, + // for gpDataReceived1 + memset(gpDataReceived1, U_SOCK_TEST_FILL_CHARACTER, (sizeof(gSendData) - 1) + (U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES * 2)); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); offset = 0; //lint -e{441} Suppress loop variable not found in // condition: we're using time instead for (y = 0; (offset < sizeof(gSendData) - 1) && - !uPortTickTimeExpiredMs(startTimeMs, 20000); y++) { + !uTimeoutExpiredSeconds(timeoutStart, 20); y++) { sizeBytes = uSockRead(descriptor, - pDataReceived + offset + + gpDataReceived1 + offset + U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES, (sizeof(gSendData) - 1) - offset); if (sizeBytes > 0) { @@ -1258,17 +1223,17 @@ U_PORT_TEST_FUNCTION("[sock]", "sockBasicTcp") sizeBytes = offset; if (sizeBytes < sizeof(gSendData) - 1) { U_TEST_PRINT_LINE("only %d byte(s) received after %d ms.", sizeBytes, - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(timeoutStart)); } else { U_TEST_PRINT_LINE("all %d byte(s) received back after %d ms," " checking if they were as expected...", sizeBytes, - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(timeoutStart)); } // Check that we reassembled everything correctly U_PORT_TEST_ASSERT(checkAgainstSentData(gSendData, sizeof(gSendData) - 1, - pDataReceived, + gpDataReceived1, sizeBytes)); U_TEST_PRINT_LINE("shutting down socket for read..."); @@ -1278,7 +1243,7 @@ U_PORT_TEST_FUNCTION("[sock]", "sockBasicTcp") U_PORT_TEST_ASSERT(errorCode >= 0); U_PORT_TEST_ASSERT(errno == 0); U_PORT_TEST_ASSERT(uSockRead(descriptor, - pDataReceived + + gpDataReceived1 + U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES, sizeof(gSendData) - 1) < 0); U_PORT_TEST_ASSERT(errno > 0); @@ -1306,16 +1271,13 @@ U_PORT_TEST_FUNCTION("[sock]", "sockBasicTcp") U_PORT_TEST_ASSERT(closedCallbackCalled); uSockCleanUp(); - uPortFree(pDataReceived); + uPortFree(gpDataReceived1); + gpDataReceived1 = NULL; - // Check for memory leaks - heapUsed -= uPortGetHeapFree(); - U_TEST_PRINT_LINE("during this part of the test %d byte(s) were" - " lost to sockets initialisation; we have" - " leaked %d byte(s).", - heapSockInitLoss + heapXxxSockInitLoss, - heapUsed - (heapSockInitLoss + heapXxxSockInitLoss)); - U_PORT_TEST_ASSERT(heapUsed <= heapSockInitLoss + heapXxxSockInitLoss); + // Check that resource usage is not increasing + resourceCount = uTestUtilGetDynamicResourceCount() - resourceCount; + U_TEST_PRINT_LINE("%d resource(s) remain outstanding.", resourceCount); + U_PORT_TEST_ASSERT(resourceCount <= U_SOCK_TEST_RESOURCE_COUNT_LIMIT); } // Remove each network type @@ -1341,9 +1303,7 @@ U_PORT_TEST_FUNCTION("[sock]", "sockMaxNumSockets") uDeviceHandle_t devHandle; uSockAddress_t remoteAddress; uSockDescriptor_t descriptor[U_SOCK_MAX_NUM_SOCKETS + 1]; - int32_t heapUsed; - int32_t heapSockInitLoss = 0; - int32_t heapXxxSockInitLoss = 0; + int32_t resourceCount; // Call clean up to release OS resources that may // have been left hanging by a previous failed test @@ -1356,22 +1316,16 @@ U_PORT_TEST_FUNCTION("[sock]", "sockMaxNumSockets") // Repeat for all bearers for (uNetworkTestList_t *pTmp = pList; pTmp != NULL; pTmp = pTmp->pNext) { devHandle = *pTmp->pDevHandle; - // Get the initial-ish heap - heapUsed = uPortGetHeapFree(); + resourceCount = uTestUtilGetDynamicResourceCount(); U_TEST_PRINT_LINE("testing max num sockets on %s.", gpUNetworkTestTypeName[pTmp->networkType]); U_TEST_PRINT_LINE("looking up echo server \"%s\"...", U_SOCK_TEST_ECHO_UDP_SERVER_DOMAIN_NAME); // Look up the address of the server we use for UDP echo - // The first call to a sockets API needs to - // initialise the underlying sockets layer; take - // account of that initialisation heap cost here. - heapSockInitLoss = uPortGetHeapFree(); U_PORT_TEST_ASSERT(uSockGetHostByName(devHandle, U_SOCK_TEST_ECHO_UDP_SERVER_DOMAIN_NAME, &(remoteAddress.ipAddress)) == 0); - heapSockInitLoss -= uPortGetHeapFree(); // Add the port number we will use remoteAddress.port = U_SOCK_TEST_ECHO_UDP_SERVER_PORT; @@ -1386,8 +1340,7 @@ U_PORT_TEST_FUNCTION("[sock]", "sockMaxNumSockets") descriptor[y] = openSocketAndUseIt(devHandle, &remoteAddress, U_SOCK_TYPE_DGRAM, - U_SOCK_PROTOCOL_UDP, - &heapXxxSockInitLoss); + U_SOCK_PROTOCOL_UDP); U_PORT_TEST_ASSERT(descriptor[y] >= 0); U_PORT_TEST_ASSERT(errno == 0); } @@ -1398,8 +1351,7 @@ U_PORT_TEST_FUNCTION("[sock]", "sockMaxNumSockets") sizeof(descriptor[0])) - 1] = openSocketAndUseIt(devHandle, &remoteAddress, U_SOCK_TYPE_DGRAM, - U_SOCK_PROTOCOL_UDP, - &heapXxxSockInitLoss); + U_SOCK_PROTOCOL_UDP); U_PORT_TEST_ASSERT(descriptor[(sizeof(descriptor) / sizeof(descriptor[0])) - 1] < 0); U_PORT_TEST_ASSERT(errno > 0); @@ -1417,8 +1369,7 @@ U_PORT_TEST_FUNCTION("[sock]", "sockMaxNumSockets") descriptor[0] = openSocketAndUseIt(devHandle, &remoteAddress, U_SOCK_TYPE_DGRAM, - U_SOCK_PROTOCOL_UDP, - &heapXxxSockInitLoss); + U_SOCK_PROTOCOL_UDP); U_PORT_TEST_ASSERT(descriptor[0] >= 0); U_PORT_TEST_ASSERT(errno == 0); @@ -1440,8 +1391,7 @@ U_PORT_TEST_FUNCTION("[sock]", "sockMaxNumSockets") descriptor[0] = openSocketAndUseIt(devHandle, &remoteAddress, U_SOCK_TYPE_DGRAM, - U_SOCK_PROTOCOL_UDP, - &heapXxxSockInitLoss); + U_SOCK_PROTOCOL_UDP); U_PORT_TEST_ASSERT(descriptor[0] >= 0); U_PORT_TEST_ASSERT(errno == 0); U_TEST_PRINT_LINE("closing socket %d again.", descriptor[0]); @@ -1452,15 +1402,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockMaxNumSockets") U_TEST_PRINT_LINE("cleaning up properly..."); uSockCleanUp(); - // Check for memory leaks - heapUsed -= uPortGetHeapFree(); - U_TEST_PRINT_LINE("during this part of the test 0 byte(s) of heap" - " were lost to the C library and %d byte(s) were" - " lost to sockets initialisation; we have leaked" - " %d byte(s).", - heapSockInitLoss + heapXxxSockInitLoss, - heapUsed - (heapSockInitLoss + heapXxxSockInitLoss)); - U_PORT_TEST_ASSERT(heapUsed <= heapSockInitLoss + heapXxxSockInitLoss); + // Check that resource usage is not increasing + resourceCount = uTestUtilGetDynamicResourceCount() - resourceCount; + U_TEST_PRINT_LINE("%d resource(s) remain outstanding.", resourceCount); + U_PORT_TEST_ASSERT(resourceCount <= U_SOCK_TEST_RESOURCE_COUNT_LIMIT); } // Remove each network type @@ -1488,12 +1433,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockOptionsSetGet") size_t *pLength; struct timeval timeout; char *pData[1]; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t timeoutMs; int32_t elapsedMs; - int32_t heapUsed; - int32_t heapSockInitLoss = 0; - int32_t heapXxxSockInitLoss = 0; + int32_t resourceCount; // Call clean up to release OS resources that may // have been left hanging by a previous failed test @@ -1506,22 +1449,16 @@ U_PORT_TEST_FUNCTION("[sock]", "sockOptionsSetGet") // Repeat for all bearers for (uNetworkTestList_t *pTmp = pList; pTmp != NULL; pTmp = pTmp->pNext) { devHandle = *pTmp->pDevHandle; - // Get the initial-ish heap - heapUsed = uPortGetHeapFree(); + resourceCount = uTestUtilGetDynamicResourceCount(); U_TEST_PRINT_LINE("doing socket options test on %s.", gpUNetworkTestTypeName[pTmp->networkType]); U_TEST_PRINT_LINE("looking up echo server \"%s\"...", U_SOCK_TEST_ECHO_UDP_SERVER_DOMAIN_NAME); // Look up the address of the server we use for UDP echo - // The first call to a sockets API needs to - // initialise the underlying sockets layer; take - // account of that initialisation heap cost here. - heapSockInitLoss = uPortGetHeapFree(); U_PORT_TEST_ASSERT(uSockGetHostByName(devHandle, U_SOCK_TEST_ECHO_UDP_SERVER_DOMAIN_NAME, &(remoteAddress.ipAddress)) == 0); - heapSockInitLoss -= uPortGetHeapFree(); // Add the port number we will use remoteAddress.port = U_SOCK_TEST_ECHO_UDP_SERVER_PORT; @@ -1529,15 +1466,8 @@ U_PORT_TEST_FUNCTION("[sock]", "sockOptionsSetGet") // Create a UDP socket, which is sufficient // for the options we can test here and doesn't // require a potentially long uSockClose() time. - // Creating a socket may use heap in the underlying - // network layer which will be reclaimed when the - // network layer is closed but we don't do that here - // to save time so need to allow for it in the heap loss - // calculation - heapXxxSockInitLoss += uPortGetHeapFree(); descriptor = uSockCreate(devHandle, U_SOCK_TYPE_DGRAM, U_SOCK_PROTOCOL_UDP); - heapXxxSockInitLoss -= uPortGetHeapFree(); U_PORT_TEST_ASSERT(descriptor >= 0); U_PORT_TEST_ASSERT(errno == 0); @@ -1561,10 +1491,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockOptionsSetGet") pLength) == 0); timeoutMs = ((int32_t) timeout.tv_sec) * 1000 + timeout.tv_usec / 1000; U_PORT_TEST_ASSERT(timeoutMs == U_SOCK_RECEIVE_TIMEOUT_DEFAULT_MS); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); U_PORT_TEST_ASSERT(uSockReceiveFrom(descriptor, NULL, pData, sizeof(pData)) < 0); - elapsedMs = uPortGetTickTimeMs() - startTimeMs; + elapsedMs = uTimeoutElapsedMs(timeoutStart); U_PORT_TEST_ASSERT(errno == U_SOCK_EWOULDBLOCK); errno = 0; U_TEST_PRINT_LINE("uSockReceiveFrom() of nothing took %d" @@ -1583,11 +1513,11 @@ U_PORT_TEST_FUNCTION("[sock]", "sockOptionsSetGet") U_SOCK_OPT_RCVTIMEO, (void *) &timeout, sizeof(timeout)) == 0); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); U_PORT_TEST_ASSERT(uSockReceiveFrom(descriptor, NULL, pData, sizeof(pData)) < 0); - elapsedMs = uPortGetTickTimeMs() - startTimeMs; + elapsedMs = uTimeoutElapsedMs(timeoutStart); U_PORT_TEST_ASSERT(errno == U_SOCK_EWOULDBLOCK); errno = 0; U_TEST_PRINT_LINE("uSockReceiveFrom() of nothing took %d" @@ -1601,15 +1531,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockOptionsSetGet") U_PORT_TEST_ASSERT(uSockClose(descriptor) == 0); uSockCleanUp(); - // Check for memory leaks - heapUsed -= uPortGetHeapFree(); - U_TEST_PRINT_LINE("during this part of the test 0 byte(s) of" - " heap were lost to the C library and %d" - " byte(s) were lost to sockets initialisation;" - " we have leaked %d byte(s).", - heapSockInitLoss + heapXxxSockInitLoss, - heapUsed - (heapSockInitLoss + heapXxxSockInitLoss)); - U_PORT_TEST_ASSERT(heapUsed <= heapSockInitLoss + heapXxxSockInitLoss); + // Check that resource usage is not increasing + resourceCount = uTestUtilGetDynamicResourceCount() - resourceCount; + U_TEST_PRINT_LINE("%d resource(s) remain outstanding.", resourceCount); + U_PORT_TEST_ASSERT(resourceCount <= U_SOCK_TEST_RESOURCE_COUNT_LIMIT); } // Remove each network type @@ -1634,14 +1559,11 @@ U_PORT_TEST_FUNCTION("[sock]", "sockLocalPort") uSockAddress_t remoteAddress; uSockDescriptor_t descriptor; bool closedCallbackCalled; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; size_t sizeBytes; size_t offset; int32_t y; - char *pDataReceived; - int32_t heapUsed; - int32_t heapSockInitLoss = 0; - int32_t heapXxxSockInitLoss = 0; + int32_t resourceCount; // Call clean up to release OS resources that may // have been left hanging by a previous failed test @@ -1654,22 +1576,16 @@ U_PORT_TEST_FUNCTION("[sock]", "sockLocalPort") // Repeat for all bearers for (uNetworkTestList_t *pTmp = pList; pTmp != NULL; pTmp = pTmp->pNext) { devHandle = *pTmp->pDevHandle; - // Get the initial-ish heap - heapUsed = uPortGetHeapFree(); + resourceCount = uTestUtilGetDynamicResourceCount(); U_TEST_PRINT_LINE("testing setting local port on %s.", gpUNetworkTestTypeName[pTmp->networkType]); U_TEST_PRINT_LINE("looking up echo server \"%s\"...", U_SOCK_TEST_ECHO_TCP_SERVER_DOMAIN_NAME); // Look up the address of the server we use for TCP echo - // The first call to a sockets API needs to - // initialise the underlying sockets layer; take - // account of that initialisation heap cost here. - heapSockInitLoss = uPortGetHeapFree(); U_PORT_TEST_ASSERT(uSockGetHostByName(devHandle, U_SOCK_TEST_ECHO_TCP_SERVER_DOMAIN_NAME, &(remoteAddress.ipAddress)) == 0); - heapSockInitLoss -= uPortGetHeapFree(); // Add the remote port number we will use remoteAddress.port = U_SOCK_TEST_ECHO_TCP_SERVER_PORT; @@ -1682,15 +1598,8 @@ U_PORT_TEST_FUNCTION("[sock]", "sockLocalPort") if (errorCode == 0) { U_TEST_PRINT_LINE("using the connection."); // Create a TCP socket - // Creating a socket may use heap in the underlying - // network layer which will be reclaimed when the - // network layer is closed but we don't do that here - // to save time so need to allow for it in the heap loss - // calculation - heapXxxSockInitLoss += uPortGetHeapFree(); descriptor = uSockCreate(devHandle, U_SOCK_TYPE_STREAM, U_SOCK_PROTOCOL_TCP); - heapXxxSockInitLoss -= uPortGetHeapFree(); U_PORT_TEST_ASSERT(descriptor >= 0); U_PORT_TEST_ASSERT(errno == 0); @@ -1736,22 +1645,23 @@ U_PORT_TEST_FUNCTION("[sock]", "sockLocalPort") sizeBytes = offset; U_TEST_PRINT_LINE("%d byte(s) sent via TCP @%d ms, now receiving...", sizeBytes, (int32_t) uPortGetTickTimeMs()); - pDataReceived = (char *) pUPortMalloc((sizeof(gSendData) - 1) + - (U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES * 2)); - U_PORT_TEST_ASSERT(pDataReceived != NULL); + uPortFree(gpDataReceived1); + gpDataReceived1 = (char *) pUPortMalloc((sizeof(gSendData) - 1) + + (U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES * 2)); + U_PORT_TEST_ASSERT(gpDataReceived1 != NULL); //lint -e(668) Suppress possible use of NULL pointer - // for pDataReceived - memset(pDataReceived, + // for gpDataReceived1 + memset(gpDataReceived1, U_SOCK_TEST_FILL_CHARACTER, (sizeof(gSendData) - 1) + (U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES * 2)); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); offset = 0; //lint -e{441} Suppress loop variable not found in // condition: we're using time instead for (y = 0; (offset < sizeof(gSendData) - 1) && - !uPortTickTimeExpiredMs(startTimeMs, 20000); y++) { + !uTimeoutExpiredSeconds(timeoutStart, 20); y++) { sizeBytes = uSockRead(descriptor, - pDataReceived + offset + + gpDataReceived1 + offset + U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES, (sizeof(gSendData) - 1) - offset); if (sizeBytes > 0) { @@ -1762,17 +1672,17 @@ U_PORT_TEST_FUNCTION("[sock]", "sockLocalPort") sizeBytes = offset; if (sizeBytes < sizeof(gSendData) - 1) { U_TEST_PRINT_LINE("only %d byte(s) received after %d ms.", sizeBytes, - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(timeoutStart)); } else { U_TEST_PRINT_LINE("all %d byte(s) received back after %d ms," " checking if they were as expected...", sizeBytes, - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(timeoutStart)); } // Check that we reassembled everything correctly U_PORT_TEST_ASSERT(checkAgainstSentData(gSendData, sizeof(gSendData) - 1, - pDataReceived, + gpDataReceived1, sizeBytes)); // Close the socket @@ -1786,7 +1696,8 @@ U_PORT_TEST_FUNCTION("[sock]", "sockLocalPort") U_PORT_TEST_ASSERT(closedCallbackCalled); uSockCleanUp(); - uPortFree(pDataReceived); + uPortFree(gpDataReceived1); + gpDataReceived1 = NULL; } else { U_TEST_PRINT_LINE("setting local port number is not supported."); U_PORT_TEST_ASSERT(errorCode == (int32_t) U_ERROR_COMMON_BSD_ERROR); @@ -1797,15 +1708,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockLocalPort") U_TEST_PRINT_LINE("clean up..."); uSockCleanUp(); - // Check for memory leaks - heapUsed -= uPortGetHeapFree(); - U_TEST_PRINT_LINE("during this part of the test 0 byte(s) of heap" - " were lost to the C library and %d byte(s) were" - " lost to sockets initialisation; we have leaked" - " %d byte(s).", - heapSockInitLoss + heapXxxSockInitLoss, - heapUsed - (heapSockInitLoss + heapXxxSockInitLoss)); - U_PORT_TEST_ASSERT(heapUsed <= heapSockInitLoss + heapXxxSockInitLoss); + // Check that resource usage is not increasing + resourceCount = uTestUtilGetDynamicResourceCount() - resourceCount; + U_TEST_PRINT_LINE("%d resource(s) remain outstanding.", resourceCount); + U_PORT_TEST_ASSERT(resourceCount <= U_SOCK_TEST_RESOURCE_COUNT_LIMIT); } // Remove each network type @@ -1833,12 +1739,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockNonBlocking") bool isBlocking; struct timeval timeout; char *pData[1]; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t timeoutMs; int32_t elapsedMs; - int32_t heapUsed; - int32_t heapSockInitLoss = 0; - int32_t heapXxxSockInitLoss = 0; + int32_t resourceCount; // Call clean up to release OS resources that may // have been left hanging by a previous failed test @@ -1851,36 +1755,23 @@ U_PORT_TEST_FUNCTION("[sock]", "sockNonBlocking") // Repeat for all bearers for (uNetworkTestList_t *pTmp = pList; pTmp != NULL; pTmp = pTmp->pNext) { devHandle = *pTmp->pDevHandle; - // Get the initial-ish heap - heapUsed = uPortGetHeapFree(); + resourceCount = uTestUtilGetDynamicResourceCount(); U_TEST_PRINT_LINE("doing non-blocking test on %s.", gpUNetworkTestTypeName[pTmp->networkType]); U_TEST_PRINT_LINE("looking up echo server \"%s\"...", U_SOCK_TEST_ECHO_TCP_SERVER_DOMAIN_NAME); // Look up the address of the server we use for TCP echo - // The first call to a sockets API needs to - // initialise the underlying sockets layer; take - // account of that initialisation heap cost here. - heapSockInitLoss = uPortGetHeapFree(); U_PORT_TEST_ASSERT(uSockGetHostByName(devHandle, U_SOCK_TEST_ECHO_TCP_SERVER_DOMAIN_NAME, &(remoteAddress.ipAddress)) == 0); - heapSockInitLoss -= uPortGetHeapFree(); // Add the port number we will use remoteAddress.port = U_SOCK_TEST_ECHO_TCP_SERVER_PORT; // Create the TCP socket - // Creating a socket may use heap in the underlying - // network layer which will be reclaimed when the - // network layer is closed but we don't do that here - // to save time so need to allow for it in the heap loss - // calculation - heapXxxSockInitLoss += uPortGetHeapFree(); descriptor = uSockCreate(devHandle, U_SOCK_TYPE_STREAM, U_SOCK_PROTOCOL_TCP); - heapXxxSockInitLoss -= uPortGetHeapFree(); U_PORT_TEST_ASSERT(descriptor >= 0); U_PORT_TEST_ASSERT(errno == 0); @@ -1923,24 +1814,24 @@ U_PORT_TEST_FUNCTION("[sock]", "sockNonBlocking") U_SOCK_OPT_RCVTIMEO, (void *) &timeout, sizeof(timeout)) == 0); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); U_PORT_TEST_ASSERT(uSockReceiveFrom(descriptor, NULL, pData, sizeof(pData)) < 0); U_PORT_TEST_ASSERT(errno == U_SOCK_EWOULDBLOCK); errno = 0; - elapsedMs = uPortGetTickTimeMs() - startTimeMs; + elapsedMs = uTimeoutElapsedMs(timeoutStart); U_TEST_PRINT_LINE("uSockReceiveFrom() of nothing took %d" " millisecond(s)...", elapsedMs); U_PORT_TEST_ASSERT(elapsedMs > timeoutMs - U_SOCK_TEST_TIME_MARGIN_MINUS_MS); U_PORT_TEST_ASSERT(elapsedMs < timeoutMs + U_SOCK_TEST_TIME_MARGIN_PLUS_MS); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); U_PORT_TEST_ASSERT(uSockRead(descriptor, pData, sizeof(pData)) < 0); U_PORT_TEST_ASSERT(errno == U_SOCK_EWOULDBLOCK); errno = 0; - elapsedMs = uPortGetTickTimeMs() - startTimeMs; + elapsedMs = uTimeoutElapsedMs(timeoutStart); U_TEST_PRINT_LINE("uSockRead() of nothing took %d millisecond(s)...", elapsedMs); U_PORT_TEST_ASSERT(elapsedMs > timeoutMs - U_SOCK_TEST_TIME_MARGIN_MINUS_MS); @@ -1959,20 +1850,20 @@ U_PORT_TEST_FUNCTION("[sock]", "sockNonBlocking") U_PORT_TEST_ASSERT(!uSockBlockingGet(descriptor)); U_TEST_PRINT_LINE("check that it has worked for receive..."); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); U_PORT_TEST_ASSERT(uSockReceiveFrom(descriptor, NULL, pData, sizeof(pData)) < 0); - elapsedMs = uPortGetTickTimeMs() - startTimeMs; + elapsedMs = uTimeoutElapsedMs(timeoutStart); U_PORT_TEST_ASSERT(errno == U_SOCK_EWOULDBLOCK); errno = 0; U_TEST_PRINT_LINE("uSockReceiveFrom() of nothing with blocking off" " took %d millisecond(s)...", elapsedMs); U_PORT_TEST_ASSERT(elapsedMs < U_SOCK_TEST_NON_BLOCKING_TIME_MS + U_SOCK_TEST_TIME_MARGIN_PLUS_MS); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); U_PORT_TEST_ASSERT(uSockRead(descriptor, pData, sizeof(pData)) < 0); - elapsedMs = uPortGetTickTimeMs() - startTimeMs; + elapsedMs = uTimeoutElapsedMs(timeoutStart); U_PORT_TEST_ASSERT(errno == U_SOCK_EWOULDBLOCK); errno = 0; U_TEST_PRINT_LINE("uSockRead() of nothing with blocking off" @@ -1985,10 +1876,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockNonBlocking") U_PORT_TEST_ASSERT(uSockBlockingGet(descriptor)); U_TEST_PRINT_LINE("check that we're blocking again..."); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); U_PORT_TEST_ASSERT(uSockReceiveFrom(descriptor, NULL, pData, sizeof(pData)) < 0); - elapsedMs = uPortGetTickTimeMs() - startTimeMs; + elapsedMs = uTimeoutElapsedMs(timeoutStart); U_PORT_TEST_ASSERT(errno == U_SOCK_EWOULDBLOCK); errno = 0; U_TEST_PRINT_LINE("uSockReceiveFrom() of nothing with blocking on" @@ -1997,10 +1888,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockNonBlocking") U_SOCK_TEST_TIME_MARGIN_MINUS_MS); U_PORT_TEST_ASSERT(elapsedMs < timeoutMs + U_SOCK_TEST_TIME_MARGIN_PLUS_MS); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); U_PORT_TEST_ASSERT(uSockRead(descriptor, pData, sizeof(pData)) < 0); - elapsedMs = uPortGetTickTimeMs() - startTimeMs; + elapsedMs = uTimeoutElapsedMs(timeoutStart); U_PORT_TEST_ASSERT(errno == U_SOCK_EWOULDBLOCK); errno = 0; U_TEST_PRINT_LINE("uSockRead() of nothing with blocking on took" @@ -2021,15 +1912,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockNonBlocking") U_PORT_TEST_ASSERT(closedCallbackCalled); uSockCleanUp(); - // Check for memory leaks - heapUsed -= uPortGetHeapFree(); - U_TEST_PRINT_LINE("during this part of the test 0 byte(s) of" - " heap were lost to the C library and %d" - " byte(s) were lost to sockets initialisation;" - " we have leaked %d byte(s).", - heapSockInitLoss + heapXxxSockInitLoss, - heapUsed - (heapSockInitLoss + heapSockInitLoss)); - U_PORT_TEST_ASSERT(heapUsed <= heapSockInitLoss + heapXxxSockInitLoss); + // Check that resource usage is not increasing + resourceCount = uTestUtilGetDynamicResourceCount() - resourceCount; + U_TEST_PRINT_LINE("%d resource(s) remain outstanding.", resourceCount); + U_PORT_TEST_ASSERT(resourceCount <= U_SOCK_TEST_RESOURCE_COUNT_LIMIT); } // Remove each network type @@ -2057,28 +1943,19 @@ U_PORT_TEST_FUNCTION("[sock]", "sockUdpEchoNonPingPong") bool allPacketsReceived = false; bool success; int32_t tries = 0; - size_t sizeBytes = 0; + size_t sizeBytes; size_t offset; //lint -esym(550, y) Suppress y not accessed ('tis true // if U_CFG_ENABLE_LOGGING is 0) int32_t y; int32_t z; - char *pDataReceived; - int32_t startTimeMs; - int32_t heapUsed; - int32_t heapSockInitLoss = 0; - int32_t heapXxxSockInitLoss = 0; + uTimeoutStart_t timeoutStart; + int32_t resourceCount; // Call clean up to release OS resources that may // have been left hanging by a previous failed test osCleanup(); - // The first time rand() is called the C library may - // allocate memory, not something we can do anything - // about, so call it once here to move that number - // out of our sums. - rand(); - // Do the standard preamble to make sure there is // a network underneath us pList = pStdPreamble(); @@ -2093,22 +1970,17 @@ U_PORT_TEST_FUNCTION("[sock]", "sockUdpEchoNonPingPong") } #endif devHandle = *pTmp->pDevHandle; - // Get the initial-ish heap - heapUsed = uPortGetHeapFree(); + sizeBytes = 0; + resourceCount = uTestUtilGetDynamicResourceCount(); U_TEST_PRINT_LINE("doing UDP non-ping-pong test on %s.", gpUNetworkTestTypeName[pTmp->networkType]); U_TEST_PRINT_LINE("looking up echo server \"%s\"...", U_SOCK_TEST_ECHO_UDP_SERVER_DOMAIN_NAME); // Look up the address of the server we use for UDP echo - // The first call to a sockets API needs to - // initialise the underlying sockets layer; take - // account of that initialisation heap cost here. - heapSockInitLoss = uPortGetHeapFree(); U_PORT_TEST_ASSERT(uSockGetHostByName(devHandle, U_SOCK_TEST_ECHO_UDP_SERVER_DOMAIN_NAME, &(remoteAddress.ipAddress)) == 0); - heapSockInitLoss -= uPortGetHeapFree(); // Add the port number we will use remoteAddress.port = U_SOCK_TEST_ECHO_UDP_SERVER_PORT; @@ -2117,15 +1989,8 @@ U_PORT_TEST_FUNCTION("[sock]", "sockUdpEchoNonPingPong") // if that is the case for (size_t retries = 2; (sizeBytes == 0) && (retries > 0); retries--) { // Create the UDP socket - // Creating a socket may use heap in the underlying - // network layer which will be reclaimed when the - // network layer is closed but we don't do that here - // to save time so need to allow for it in the heap loss - // calculation - heapXxxSockInitLoss += uPortGetHeapFree(); descriptor = uSockCreate(devHandle, U_SOCK_TYPE_DGRAM, U_SOCK_PROTOCOL_UDP); - heapXxxSockInitLoss -= uPortGetHeapFree(); U_PORT_TEST_ASSERT(descriptor >= 0); U_PORT_TEST_ASSERT(errno == 0); @@ -2174,21 +2039,22 @@ U_PORT_TEST_FUNCTION("[sock]", "sockUdpEchoNonPingPong") U_TEST_PRINT_LINE("a total of %d UDP packet(s) sent, now receiving...", y + 1); // ...and capture them all again afterwards - pDataReceived = (char *) pUPortMalloc((sizeof(gSendData) - 1) + - (U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES * 2)); - U_PORT_TEST_ASSERT(pDataReceived != NULL); + uPortFree(gpDataReceived1); + gpDataReceived1 = (char *) pUPortMalloc((sizeof(gSendData) - 1) + + (U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES * 2)); + U_PORT_TEST_ASSERT(gpDataReceived1 != NULL); //lint -e(668) Suppress possible use of NULL pointer - // for pDataReceived (it is checked above) - memset(pDataReceived, U_SOCK_TEST_FILL_CHARACTER, + // for gpDataReceived1 (it is checked above) + memset(gpDataReceived1, U_SOCK_TEST_FILL_CHARACTER, (sizeof(gSendData) - 1) + (U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES * 2)); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); offset = 0; //lint -e{441} Suppress loop variable not found in // condition: we're using time instead for (y = 0; (offset < sizeof(gSendData) - 1) && - !uPortTickTimeExpiredMs(startTimeMs, 15000); y++) { + !uTimeoutExpiredSeconds(timeoutStart, 15); y++) { z = uSockReceiveFrom(descriptor, NULL, - pDataReceived + offset + + gpDataReceived1 + offset + U_SOCK_TEST_GUARD_LENGTH_SIZE_BYTES, (sizeof(gSendData) - 1) - offset); if (z > 0) { @@ -2203,9 +2069,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockUdpEchoNonPingPong") // Check that we reassembled everything correctly allPacketsReceived = checkAgainstSentData(gSendData, sizeof(gSendData) - 1, - pDataReceived, + gpDataReceived1, sizeBytes); - uPortFree(pDataReceived); + uPortFree(gpDataReceived1); + gpDataReceived1 = NULL; tries++; } while (!allPacketsReceived && (tries < U_SOCK_TEST_UDP_RETRIES)); @@ -2216,7 +2083,7 @@ U_PORT_TEST_FUNCTION("[sock]", "sockUdpEchoNonPingPong") if (!allPacketsReceived) { // If we're going to try again, take the // network down and up again and reset errno - U_TEST_PRINT_LINE("failed to get everything, back cycling network" + U_TEST_PRINT_LINE("failed to get everything back, cycling network" " layer before trying again..."); // Give us something to search for in the log U_TEST_PRINT_LINE("*** WARNING *** RETRY UDP."); @@ -2243,14 +2110,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockUdpEchoNonPingPong") " it happens frequently it is worth checking."); } - // Check for memory leaks - heapUsed -= uPortGetHeapFree(); - U_TEST_PRINT_LINE("during this part of the test %d byte(s) were" - " lost to sockets initialisation; we have leaked" - " %d byte(s).", - heapSockInitLoss + heapXxxSockInitLoss, - heapUsed - (heapSockInitLoss + heapXxxSockInitLoss)); - U_PORT_TEST_ASSERT(heapUsed <= heapSockInitLoss + heapXxxSockInitLoss); + // Check that resource usage is not increasing + resourceCount = uTestUtilGetDynamicResourceCount() - resourceCount; + U_TEST_PRINT_LINE("%d resource(s) remain outstanding.", resourceCount); + U_PORT_TEST_ASSERT(resourceCount <= U_SOCK_TEST_RESOURCE_COUNT_LIMIT); } // Remove each network type @@ -2277,9 +2140,7 @@ U_PORT_TEST_FUNCTION("[sock]", "sockAsyncUdpEchoMayFailDueToInternetDatagramLoss size_t offset; int32_t y; int32_t stackMinFreeBytes; - int32_t heapUsed; - int32_t heapSockInitLoss = 0; - int32_t heapXxxSockInitLoss = 0; + int32_t resourceCount; // Call clean up to release OS resources that may // have been left hanging by a previous failed test @@ -2289,17 +2150,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockAsyncUdpEchoMayFailDueToInternetDatagramLoss // a network underneath us pList = pStdPreamble(); - // The first time rand() is called the C library may - // allocate memory, not something we can do anything - // about, so call it once here to move that number - // out of our sums. - rand(); - // Repeat for all bearers for (uNetworkTestList_t *pTmp = pList; pTmp != NULL; pTmp = pTmp->pNext) { devHandle = *pTmp->pDevHandle; - // Get the initial-ish heap - heapUsed = uPortGetHeapFree(); + resourceCount = uTestUtilGetDynamicResourceCount(); U_TEST_PRINT_LINE("doing UDP asynchronous receive test on %s.", gpUNetworkTestTypeName[pTmp->networkType]); @@ -2310,14 +2164,9 @@ U_PORT_TEST_FUNCTION("[sock]", "sockAsyncUdpEchoMayFailDueToInternetDatagramLoss U_SOCK_TEST_ECHO_UDP_SERVER_DOMAIN_NAME); // Look up the address of the server we use for UDP echo - // The first call to a sockets API needs to - // initialise the underlying sockets layer; take - // account of that initialisation heap cost here. - heapSockInitLoss = uPortGetHeapFree(); U_PORT_TEST_ASSERT(uSockGetHostByName(devHandle, U_SOCK_TEST_ECHO_UDP_SERVER_DOMAIN_NAME, &(remoteAddress.ipAddress)) == 0); - heapSockInitLoss -= uPortGetHeapFree(); // Add the port number we will use remoteAddress.port = U_SOCK_TEST_ECHO_UDP_SERVER_PORT; @@ -2328,16 +2177,9 @@ U_PORT_TEST_FUNCTION("[sock]", "sockAsyncUdpEchoMayFailDueToInternetDatagramLoss (retries > 0); retries--) { gTestConfig.bytesReceived = 0; // Create the UDP socket - // Creating a socket may use heap in the underlying - // network layer which will be reclaimed when the - // network layer is closed but we don't do that here - // to save time so need to allow for it in the heap loss - // calculation - heapXxxSockInitLoss += uPortGetHeapFree(); gTestConfig.descriptor = uSockCreate(devHandle, U_SOCK_TYPE_DGRAM, U_SOCK_PROTOCOL_UDP); - heapXxxSockInitLoss -= uPortGetHeapFree(); U_PORT_TEST_ASSERT(gTestConfig.descriptor >= 0); U_PORT_TEST_ASSERT(errno == 0); gTestConfig.isTcp = false; @@ -2489,14 +2331,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockAsyncUdpEchoMayFailDueToInternetDatagramLoss // Free memory from event queues uPortEventQueueCleanUp(); - // Check for memory leaks - heapUsed -= uPortGetHeapFree(); - U_TEST_PRINT_LINE("during this part of the test %d byte(s) of heap" - " were lost to the C library and %d byte(s) were" - " lost to sockets initialisation; we have leaked" - " %d byte(s).", heapSockInitLoss + heapXxxSockInitLoss, - heapUsed - (heapSockInitLoss + heapXxxSockInitLoss)); - U_PORT_TEST_ASSERT(heapUsed <= heapSockInitLoss + heapXxxSockInitLoss); + // Check that resource usage is not increasing + resourceCount = uTestUtilGetDynamicResourceCount() - resourceCount; + U_TEST_PRINT_LINE("%d resource(s) remain outstanding.", resourceCount); + U_PORT_TEST_ASSERT(resourceCount <= U_SOCK_TEST_RESOURCE_COUNT_LIMIT); } // Remove each network type @@ -2524,9 +2362,7 @@ U_PORT_TEST_FUNCTION("[sock]", "sockAsyncTcpEcho") int32_t y; int32_t z; int32_t stackMinFreeBytes; - int32_t heapUsed; - int32_t heapSockInitLoss = 0; - int32_t heapXxxSockInitLoss = 0; + int32_t resourceCount; // Call clean up to release OS resources that may // have been left hanging by a previous failed test @@ -2536,17 +2372,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockAsyncTcpEcho") // a network underneath us pList = pStdPreamble(); - // The first time rand() is called the C library may - // allocate memory, not something we can do anything - // about, so call it once here to move that number - // out of our sums. - rand(); - // Repeat for all bearers for (uNetworkTestList_t *pTmp = pList; pTmp != NULL; pTmp = pTmp->pNext) { devHandle = *pTmp->pDevHandle; - // Get the initial-ish heap - heapUsed = uPortGetHeapFree(); + resourceCount = uTestUtilGetDynamicResourceCount(); U_TEST_PRINT_LINE("doing TCP asynchronous receive test on %s.", gpUNetworkTestTypeName[pTmp->networkType]); @@ -2557,29 +2386,17 @@ U_PORT_TEST_FUNCTION("[sock]", "sockAsyncTcpEcho") U_SOCK_TEST_ECHO_TCP_SERVER_DOMAIN_NAME); // Look up the address of the server we use for TCP echo - // The first call to a sockets API needs to - // initialise the underlying sockets layer; take - // account of that initialisation heap cost here. - heapSockInitLoss = uPortGetHeapFree(); U_PORT_TEST_ASSERT(uSockGetHostByName(devHandle, U_SOCK_TEST_ECHO_TCP_SERVER_DOMAIN_NAME, &(remoteAddress.ipAddress)) == 0); - heapSockInitLoss -= uPortGetHeapFree(); // Add the port number we will use remoteAddress.port = U_SOCK_TEST_ECHO_TCP_SERVER_PORT; // Create the TCP socket - // Creating a socket may use heap in the underlying - // network layer which will be reclaimed when the - // network layer is closed but we don't do that here - // to save time so need to allow for it in the heap loss - // calculation - heapXxxSockInitLoss += uPortGetHeapFree(); gTestConfig.descriptor = uSockCreate(devHandle, U_SOCK_TYPE_STREAM, U_SOCK_PROTOCOL_TCP); - heapXxxSockInitLoss -= uPortGetHeapFree(); U_PORT_TEST_ASSERT(gTestConfig.descriptor >= 0); U_PORT_TEST_ASSERT(errno == 0); gTestConfig.isTcp = true; @@ -2703,7 +2520,7 @@ U_PORT_TEST_FUNCTION("[sock]", "sockAsyncTcpEcho") // U_SOCK_TEST_TASK_STACK_SIZE_BYTES // was big enough stackMinFreeBytes = uPortEventQueueStackMinFree(gTestConfig.eventQueueHandle); - U_TEST_PRINT_LINE("event queue task had %d byte(s)free at a minimum.", + U_TEST_PRINT_LINE("event queue task had %d byte(s) free at a minimum.", stackMinFreeBytes); U_PORT_TEST_ASSERT((stackMinFreeBytes > 0) || (stackMinFreeBytes == (int32_t) U_ERROR_COMMON_NOT_SUPPORTED)); @@ -2728,13 +2545,10 @@ U_PORT_TEST_FUNCTION("[sock]", "sockAsyncTcpEcho") // Free memory uPortFree(gTestConfig.pBuffer); - // Check for memory leaks - heapUsed -= uPortGetHeapFree(); - U_TEST_PRINT_LINE("during this part of the test %d byte(s) were lost" - " to sockets initialisation; we have leaked %d byte(s).", - heapSockInitLoss + heapXxxSockInitLoss, - heapUsed - (heapSockInitLoss + heapXxxSockInitLoss)); - U_PORT_TEST_ASSERT(heapUsed <= heapSockInitLoss + heapXxxSockInitLoss); + // Check that resource usage is not increasing + resourceCount = uTestUtilGetDynamicResourceCount() - resourceCount; + U_TEST_PRINT_LINE("%d resource(s) remain outstanding.", resourceCount); + U_PORT_TEST_ASSERT(resourceCount <= U_SOCK_TEST_RESOURCE_COUNT_LIMIT); } // Remove each network type @@ -2759,6 +2573,9 @@ U_PORT_TEST_FUNCTION("[sock]", "sockCleanUp") osCleanup(); + uPortFree(gpDataReceived1); + uPortFree(gpDataReceived2); + // The network test configuration is shared between // the network, sockets, security and location tests // so must reset the handles here in case the @@ -2771,8 +2588,12 @@ U_PORT_TEST_FUNCTION("[sock]", "sockCleanUp") uDeviceDeinit(); uPortDeinit(); - // Printed for information: asserting happens in the postamble - uTestUtilResourceCheck(U_TEST_PREFIX, NULL, true); + + // Resources should now all be cleaned up + if (!uTestUtilResourceCheck(U_TEST_PREFIX, NULL, true)) { + U_TEST_PRINT_LINE("resources not cleaned up."); + U_PORT_TEST_ASSERT(false); + } } // End of file diff --git a/common/timeout/api/u_timeout.h b/common/timeout/api/u_timeout.h new file mode 100644 index 00000000..c996aeaf --- /dev/null +++ b/common/timeout/api/u_timeout.h @@ -0,0 +1,147 @@ +/* + * Copyright 2019-2024 u-blox + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _U_TIMEOUT_H_ +#define _U_TIMEOUT_H_ + +/* Only header files representing a direct and unavoidable + * dependency between the API of this module and the API + * of another module should be included here; otherwise + * please keep #includes to your .c files. */ + +#include "u_compiler.h" // U_INLINE + +/** \addtogroup __timeout __Timeout + * @{ + */ + +/** @file + * @brief Functions to handle time-outs in a wrap-safe manner. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---------------------------------------------------------------- + * COMPILE-TIME MACROS + * -------------------------------------------------------------- */ + +/* ---------------------------------------------------------------- + * TYPES + * -------------------------------------------------------------- */ + +/** "Anonymous" structure to hold the start time, used in timeout + * calculations. The contents of this structure MUST NEVER BE + * REFERENCED except by the code here. + */ +typedef struct { + uint32_t timeMs; +} uTimeoutStart_t; + +/** It is sometimes necessary to carry around a start time and + * a duration in order to effect a "stop time". This structure + * may be used for convenience. + */ +typedef struct { + uTimeoutStart_t timeoutStart; + uint32_t durationMs; /** use a duration of 0 to main "not set". */ +} uTimeoutStop_t; + +/* ---------------------------------------------------------------- + * FUNCTIONS + * -------------------------------------------------------------- */ + +/** Initialise a time-out with the current time; the value returned + * by this function may be passed to the uTimeoutExpiredMs(), + * uTimeoutExpiredSeconds(), uTimeoutElapsedMs() or + * uTimeoutElapsedSeconds() functions, which must be used for + * wrap-safe time comparisons. + * + * The underlying source of the tick is uPortGetTickTimeMs() and the + * same restrictions apply. + * + * @return the current tick. + */ +uTimeoutStart_t uTimeoutStart(); + +/** Perform a time-out check in a way that will behave predictably + * across a tick-counter wrap. See also uTimeoutExpiredSeconds() + * and uTimeoutElapsed(). + * + * Where you might have been going to write: + * + * ``` + * int32_t startTimeMs = uPortGetTickTimeMs(); + * if (uPortGetTickTimeMs() - startTimeMs > timeoutMs) { + * // Do something because the timeout has expired + * } + * ``` + * + * ...then write this instead: + * + * ``` + * uTimeoutStart_t startTime = uTimeoutStart(); + * if (uTimeoutExpiredMs(startTime, timeoutMs)) { + * // Do something because the timeout has expired + * } + * ``` + * + * Note: this function is implemented in this header file so + * that it can be guaranteed to be in-lined by the compiler. + * + * @param startTime the start time, derived from uTimeoutStart(). + * @param durationMs the duration of the timeout in milliseconds. + * @return true if the given duration has passed + * since the start time. + */ +bool uTimeoutExpiredMs(uTimeoutStart_t startTime, uint32_t durationMs); + +/** As uTimeoutExpiredMs() but for values in seconds. + * + * @param startTime the start time, derived from uTimeoutStart(). + * @param durationSeconds the duration of the timeout in seconds. + * @return true if the given duration has passed + * since the start time. + */ +bool uTimeoutExpiredSeconds(uTimeoutStart_t startTime, + uint32_t durationSeconds); + +/** Return how much time has passed since the start of a timeout. + * + * @param startTime the start time, derived from uTimeoutStart(). + * @return the amount of time that has elapsed since + * startTime in milliseconds. + */ +uint32_t uTimeoutElapsedMs(uTimeoutStart_t startTime); + +/** As uTimeoutElapsedMs() but returning a value in seconds. + * + * @param startTime the start time, derived from uTimeoutStart(). + * @return the amount of time that has elapsed since + * startTime in seconds. + */ +uint32_t uTimeoutElapsedSeconds(uTimeoutStart_t startTime); + +#ifdef __cplusplus +} +#endif + +/** @}*/ + +#endif // _U_TIMEOUT_H_ + +// End of file diff --git a/common/timeout/src/u_timeout.c b/common/timeout/src/u_timeout.c new file mode 100644 index 00000000..5818c0c6 --- /dev/null +++ b/common/timeout/src/u_timeout.c @@ -0,0 +1,108 @@ +/* + * Copyright 2019-2024 u-blox + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** @file + * @brief Timeout functions. + */ + +#ifdef U_CFG_OVERRIDE +# include "u_cfg_override.h" // For a customer's configuration override +#endif + +/* ---------------------------------------------------------------- + * INCLUDE FILES + * -------------------------------------------------------------- */ + +#include "stddef.h" // NULL, size_t etc. +#include "stdint.h" // int32_t etc. +#include "stdbool.h" + +#include "u_timeout.h" + +#include "u_port.h" + +/* ---------------------------------------------------------------- + * COMPILE-TIME MACROS + * -------------------------------------------------------------- */ + +#ifndef U_CFG_TEST_TIMEOUT_SPEED_UP +/** Used during testing only, this allows the code here to perceive + * the underlying tick as running faster in powers of 2, meaning + * that it sees more tick timer wraps, without externally altering + * the behaviour of the code (though obviously reducing the maximum + * duration of any timeout). + */ +# define U_CFG_TEST_TIMEOUT_SPEED_UP 0 +#endif + +/* ---------------------------------------------------------------- + * TYPES + * -------------------------------------------------------------- */ + +/* ---------------------------------------------------------------- + * VARIABLES + * -------------------------------------------------------------- */ + +/* ---------------------------------------------------------------- + * STATIC FUNCTIONS + * -------------------------------------------------------------- */ + +/* ---------------------------------------------------------------- + * PUBLIC FUNCTIONS + * -------------------------------------------------------------- */ + +// Initialise a time-out with the current time. +uTimeoutStart_t uTimeoutStart() +{ + uTimeoutStart_t timeoutStart; + timeoutStart.timeMs = ((uint32_t) uPortGetTickTimeMs()) << U_CFG_TEST_TIMEOUT_SPEED_UP; + return timeoutStart; +} + +// Perform a time-out check in a wrap-safe way. +bool uTimeoutExpiredMs(uTimeoutStart_t startTime, uint32_t durationMs) +{ + uint32_t nowTimeMs = ((uint32_t) uPortGetTickTimeMs()) << U_CFG_TEST_TIMEOUT_SPEED_UP; + // Move the time-frame from the unaligned free running ticks + // to 0 by subtracting the start time + uint32_t elapsedTimeMs = nowTimeMs - startTime.timeMs; + // This will evaluate to false during the next durationMs after + // uTimeoutStart() was called + return elapsedTimeMs > (durationMs << U_CFG_TEST_TIMEOUT_SPEED_UP); +} + +// As uTimeoutExpiredMs() but for values in seconds. +bool uTimeoutExpiredSeconds(uTimeoutStart_t startTime, + uint32_t durationSeconds) +{ + return uTimeoutExpiredMs(startTime, durationSeconds * 1000); +} + +// Return how time has passed in milliseconds. +uint32_t uTimeoutElapsedMs(uTimeoutStart_t startTime) +{ + uint32_t nowTimeMs = ((uint32_t) uPortGetTickTimeMs()) << U_CFG_TEST_TIMEOUT_SPEED_UP; + uint32_t elapsedTimeMs = nowTimeMs - startTime.timeMs; + return elapsedTimeMs >> U_CFG_TEST_TIMEOUT_SPEED_UP; +} + +// As uTimeoutElapsedMs() but returning a value in seconds. +uint32_t uTimeoutElapsedSeconds(uTimeoutStart_t startTime) +{ + return uTimeoutElapsedMs(startTime) / 1000; +} + +// End of file diff --git a/common/timeout/test/u_timeout_test.c b/common/timeout/test/u_timeout_test.c new file mode 100644 index 00000000..e989fb75 --- /dev/null +++ b/common/timeout/test/u_timeout_test.c @@ -0,0 +1,167 @@ +/* + * Copyright 2019-2024 u-blox + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Only #includes of u_* and the C standard library are allowed here, + * no platform stuff and no OS stuff. Anything required from + * the platform/OS must be brought in through u_port* to maintain + * portability. + */ + +/** @file + * @brief Tests for the timeout API, should run without any HW. + * To run thie test in an acceptable time-frame (around a minute) + * please set U_CFG_TEST_TIMEOUT_SPEED_UP to 18 when compiling this code. + * The aim here is to have the tick timer wrap during testing and no + * tests to get "stuck" as a result. With a 1 ms tick, a 32-bit + * counter would wrap in 2^32 - 1 (4,294,967,295) seconds, so a + * speed-up of 18 means a wrap every 16 seconds. + */ + +#ifdef U_CFG_OVERRIDE +# include "u_cfg_override.h" // For a customer's configuration override +#endif + +#include "limits.h" +#include "stddef.h" // NULL, size_t etc. +#include "stdint.h" // int32_t etc. +#include "stdbool.h" + +#include "u_cfg_sw.h" +#include "u_cfg_app_platform_specific.h" +#include "u_cfg_test_platform_specific.h" + +#include "u_error_common.h" + +#include "u_port.h" +#include "u_port_debug.h" +#include "u_port_os.h" + +#include "u_test_util_resource_check.h" + +#include "u_timeout.h" + +/* ---------------------------------------------------------------- + * COMPILE-TIME MACROS + * -------------------------------------------------------------- */ + +/** The string to put at the start of all prints from this test. + */ +#define U_TEST_PREFIX "U_TIMEOUT_TEST: " + +/** Print a whole line, with terminator, prefixed for this test file. + */ +#define U_TEST_PRINT_LINE(format, ...) uPortLog(U_TEST_PREFIX format "\n", ##__VA_ARGS__) + +#ifndef U_TIMEOUT_NUMBER_OF_WRAPS +/** How many times we would like to go around the + * clock during testing. + */ +# define U_TIMEOUT_NUMBER_OF_WRAPS 2 +#endif + +#ifndef U_TIMEOUT_TEST_ITERATIONS +/** How many iterations we would like in total. + */ +# define U_TIMEOUT_TEST_ITERATIONS (U_TIMEOUT_NUMBER_OF_WRAPS * 5) +#endif + +#ifndef U_TIMEOUT_DURATION_MS +/** How long each timeout should be. + */ +# define U_TIMEOUT_DURATION_MS ((UINT32_MAX * U_TIMEOUT_NUMBER_OF_WRAPS) / U_TIMEOUT_TEST_ITERATIONS) +#endif + +/* ---------------------------------------------------------------- + * TYPES + * -------------------------------------------------------------- */ + +/* ---------------------------------------------------------------- + * VARIABLES + * -------------------------------------------------------------- */ + +/* ---------------------------------------------------------------- + * STATIC FUNCTIONS + * -------------------------------------------------------------- */ + +/* ---------------------------------------------------------------- + * PUBLIC FUNCTIONS: TESTS + * -------------------------------------------------------------- */ + +#if 0 +// A basic test that the timeout functions do not get stuck at a wrap. +U_PORT_TEST_FUNCTION("[timeout]", "timeoutWrap") +{ + int32_t resourceCount; + uTimeoutStart_t timeoutStart; + int32_t startTickMs; + int32_t stopTickMs; + uint32_t acceleratedElapsedTimeMs; + + // Whatever called us likely initialised the + // port so deinitialise it here to obtain the + // correct initial heap size + uPortDeinit(); + resourceCount = uTestUtilGetDynamicResourceCount(); + + uPortInit(); + + U_TEST_PRINT_LINE("testing timeout API at 2^%d real time" + ", so one day passes in %d milliseconds" + " and a 32-bit counter will wrap every" + " %d seconds; there will be %d iterations" + " each of length %d days.", + U_CFG_TEST_TIMEOUT_SPEED_UP, + 86400000 >> U_CFG_TEST_TIMEOUT_SPEED_UP, + ((UINT32_MAX >> U_CFG_TEST_TIMEOUT_SPEED_UP) + 1) / 1000, + U_TIMEOUT_TEST_ITERATIONS, + (U_TIMEOUT_DURATION_MS << U_CFG_TEST_TIMEOUT_SPEED_UP) / 86400000); + + for (uint32_t x = 0; x < U_TIMEOUT_TEST_ITERATIONS; x++) { + U_TEST_PRINT_LINE("timeout %d: %d day(s)...", x, + (U_TIMEOUT_DURATION_MS << U_CFG_TEST_TIMEOUT_SPEED_UP) / 86400000); + timeoutStart = uTimeoutStart(); + startTickMs = uPortGetTickTimeMs(); + U_PORT_TEST_ASSERT(uTimeoutElapsedMs(timeoutStart) << U_CFG_TEST_TIMEOUT_SPEED_UP < + U_TIMEOUT_DURATION_MS); + while (!uTimeoutExpiredMs(timeoutStart, U_TIMEOUT_DURATION_MS)) { + uPortTaskBlock(10); + } + U_PORT_TEST_ASSERT(uTimeoutElapsedMs(timeoutStart) << U_CFG_TEST_TIMEOUT_SPEED_UP >= + U_TIMEOUT_DURATION_MS); + stopTickMs = uPortGetTickTimeMs(); + acceleratedElapsedTimeMs = (uint32_t) (stopTickMs - startTickMs) << U_CFG_TEST_TIMEOUT_SPEED_UP; + U_TEST_PRINT_LINE("...took %d day(s) to elapse%s.", + acceleratedElapsedTimeMs / 86400000, + ((uint32_t) (stopTickMs) << U_CFG_TEST_TIMEOUT_SPEED_UP) < ((uint32_t) ( + startTickMs) << U_CFG_TEST_TIMEOUT_SPEED_UP) ? " and the underlying tick wrapped" : ""); + // If a timer has taken longer than one half of a loop around + // uPortGetTickTimeMs(), when scaled by U_CFG_TEST_TIMEOUT_SPEED_UP + // then it has got stuck + U_PORT_TEST_ASSERT(acceleratedElapsedTimeMs < UINT32_MAX / 2) + } + + uPortDeinit(); + + // Check for resource leaks + uTestUtilResourceCheck(U_TEST_PREFIX, NULL, true); + resourceCount = uTestUtilGetDynamicResourceCount() - resourceCount; + U_TEST_PRINT_LINE("we have leaked %d resources(s).", resourceCount); + U_PORT_TEST_ASSERT(resourceCount <= 0); +} + +#endif + +// End of file \ No newline at end of file diff --git a/example/mqtt_client/mqtt_main.c b/example/mqtt_client/mqtt_main.c index 88d60515..3a10710e 100644 --- a/example/mqtt_client/mqtt_main.c +++ b/example/mqtt_client/mqtt_main.c @@ -246,7 +246,7 @@ U_PORT_TEST_FUNCTION("[example]", "exampleMqttClient") char buffer[64]; size_t bufferSize; volatile bool messagesAvailable = false; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t returnCode; // Initialise the APIs we will need @@ -330,7 +330,7 @@ U_PORT_TEST_FUNCTION("[example]", "exampleMqttClient") // MQTT broker uPortLog("Publishing \"%s\" to topic \"%s\"...\n", message, topic); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); // If you were using MQTT-SN, you would call // uMqttClientSnPublish() instead and pass it // the MQTT-SN topic name returned by @@ -343,7 +343,7 @@ U_PORT_TEST_FUNCTION("[example]", "exampleMqttClient") // Wait for us to be notified that our new // message is available on the broker while (!messagesAvailable && - !uPortTickTimeExpiredMs(startTimeMs, 10000)) { + !uTimeoutExpiredSeconds(timeoutStart, 10)) { uPortTaskBlock(1000); } diff --git a/gnss/src/lib_mga/u_lib_mga.c b/gnss/src/lib_mga/u_lib_mga.c index f66895f9..df6bfaca 100644 --- a/gnss/src/lib_mga/u_lib_mga.c +++ b/gnss/src/lib_mga/u_lib_mga.c @@ -1035,7 +1035,7 @@ MGA_API_RESULT mgaSessionSendOfflineToFlash(const UBX_U1* pMgaData, UBX_I4 iSize s_pMgaFlashBlockList[i].state = MGA_MSG_WAITING_TO_SEND; s_pMgaFlashBlockList[i].sequenceNumber = (UBX_U2)i; s_pMgaFlashBlockList[i].retryCount = 0; - s_pMgaFlashBlockList[i].timeOut = 0; + memset(&s_pMgaFlashBlockList[i].timeOut, 0, sizeof(s_pMgaFlashBlockList[i].timeOut)); s_pMgaFlashBlockList[i].mgaFailedReason = MGA_FAILED_REASON_CODE_NOT_SET; if ((i == (s_mgaFlashBlockCount - 1)) && (lastBlockSize > 0)) @@ -1108,7 +1108,7 @@ MGA_API_RESULT mgaSessionSendLegacyOfflineToFlash(const UBX_U1* pAidingData, UBX s_pMgaFlashBlockList[i].state = MGA_MSG_WAITING_TO_SEND; s_pMgaFlashBlockList[i].sequenceNumber = (UBX_U2)i; s_pMgaFlashBlockList[i].retryCount = 0; - s_pMgaFlashBlockList[i].timeOut = 0; + memset(&s_pMgaFlashBlockList[i].timeOut, 0, sizeof(s_pMgaFlashBlockList[i].timeOut)); s_pMgaFlashBlockList[i].mgaFailedReason = MGA_FAILED_REASON_CODE_NOT_SET; if ((i == (s_mgaFlashBlockCount - 1)) && (lastBlockSize > 0)) @@ -1180,15 +1180,14 @@ MGA_API_RESULT mgaCheckForTimeOuts(void) MgaMsgInfo* pMsgInfo = s_pMgaMsgList; UBX_U4 i; - size_t rob = 0; for (i = 0; i < s_mgaBlockCount; i++) { if (pMsgInfo->state == MGA_MSG_WAITING_FOR_ACK) { - rob++; - int32_t now = uPortGetTickTimeMs(); - - if (now > pMsgInfo->timeOut) + // MODIFIED: use timeout API + if ((pMsgInfo->timeOut.durationMs > 0) && + uTimeoutExpiredMs(pMsgInfo->timeOut.timeoutStart, + pMsgInfo->timeOut.durationMs)) { if (pMsgInfo->retryCount < s_pFlowConfig->msgRetryCount) { @@ -1233,8 +1232,10 @@ MGA_API_RESULT mgaCheckForTimeOuts(void) if ((s_pLastFlashBlockSent->state == MGA_MSG_WAITING_FOR_ACK) || (s_pLastFlashBlockSent->state == MGA_MSG_WAITING_FOR_ACK_SECOND_CHANCE)) { - int32_t now = uPortGetTickTimeMs(); - if (now > s_pLastFlashBlockSent->timeOut) + // MODIFIED: use timeout API + if ((s_pLastFlashBlockSent->timeOut.durationMs > 0) && + uTimeoutExpiredMs(s_pLastFlashBlockSent->timeOut.timeoutStart, + s_pLastFlashBlockSent->timeOut.durationMs)) { // Timed out if (s_pLastFlashBlockSent->state == MGA_MSG_WAITING_FOR_ACK_SECOND_CHANCE) @@ -2262,7 +2263,10 @@ static void handleLegacyAidingTimeout(void) U_ASSERT((s_pLastFlashBlockSent->state == MGA_MSG_WAITING_FOR_ACK) || (s_pLastFlashBlockSent->state == MGA_MSG_WAITING_FOR_ACK_SECOND_CHANCE)); - if (now > s_pLastFlashBlockSent->timeOut) + // MODIFIED: use timeout API + if ((s_pLastFlashBlockSent->timeOut.durationMs > 0) && + uTimeoutExpiredMs(s_pLastFlashBlockSent->timeOut.timeoutStart, + s_pLastFlashBlockSent->timeOut.durationMs)) { if (s_pLastFlashBlockSent->state == MGA_MSG_WAITING_FOR_ACK) { @@ -2419,7 +2423,9 @@ static void sendMgaFlashBlock(bool next) s_pEvtInterface->evtWriteDevice(s_pCallbackContext, flashDataMsg, (UBX_I4)flashMsgTotalSize); s_pLastFlashBlockSent->state = MGA_MSG_WAITING_FOR_ACK; - s_pLastFlashBlockSent->timeOut = s_pFlowConfig->msgTimeOut + uPortGetTickTimeMs(); + // MODIFIED: use timeout API + s_pLastFlashBlockSent->timeOut.timeoutStart = uTimeoutStart(); + s_pLastFlashBlockSent->timeOut.durationMs = s_pFlowConfig->msgTimeOut; if (s_pEvtInterface->evtProgress) { @@ -2518,7 +2524,9 @@ static void sendFlashMainSeqBlock(void) s_pEvtInterface->evtWriteDevice(s_pCallbackContext, aidingFlashDataMsg, (UBX_I4)flashMsgTotalSize); s_pLastFlashBlockSent->state = MGA_MSG_WAITING_FOR_ACK; - s_pLastFlashBlockSent->timeOut = s_pFlowConfig->msgTimeOut + uPortGetTickTimeMs(); + // MODIFIED: use timeout API + s_pLastFlashBlockSent->timeOut.timeoutStart = uTimeoutStart(); + s_pLastFlashBlockSent->timeOut.durationMs = s_pFlowConfig->msgTimeOut; if (s_pEvtInterface->evtProgress) { @@ -2788,7 +2796,9 @@ static UBX_I4 sendNextMgaMessage(void) msgSize = s_pLastMsgSent->msgSize; s_pEvtInterface->evtWriteDevice(s_pCallbackContext, s_pLastMsgSent->pMsg, msgSize); s_pLastMsgSent->state = MGA_MSG_WAITING_FOR_ACK; - s_pLastMsgSent->timeOut = s_pFlowConfig->msgTimeOut + uPortGetTickTimeMs(); + // MODIFIED: use timeout API + s_pLastMsgSent->timeOut.timeoutStart = uTimeoutStart(); + s_pLastMsgSent->timeOut.durationMs = s_pFlowConfig->msgTimeOut; if (s_pEvtInterface->evtProgress) { @@ -2809,7 +2819,9 @@ static void resendMessage(MgaMsgInfo* pResendMsg) U_ASSERT(s_pEvtInterface->evtWriteDevice); s_pEvtInterface->evtWriteDevice(s_pCallbackContext, pResendMsg->pMsg, pResendMsg->msgSize); pResendMsg->state = MGA_MSG_WAITING_FOR_ACK; - pResendMsg->timeOut = s_pFlowConfig->msgTimeOut + uPortGetTickTimeMs(); + // MODIFIED: use timeout API + pResendMsg->timeOut.timeoutStart = uTimeoutStart(); + pResendMsg->timeOut.durationMs = s_pFlowConfig->msgTimeOut; if (s_pEvtInterface->evtProgress) { @@ -3014,7 +3026,8 @@ static MgaMsgInfo* buildMsgList(const UBX_U1* pMgaData, unsigned int uNumEntries pCurrentBlock->pMsg = pMgaData; pCurrentBlock->msgSize = msgSize; pCurrentBlock->state = MGA_MSG_WAITING_TO_SEND; - pCurrentBlock->timeOut = 0; // set when transfer takes place + // set when transfer takes place + memset(&pCurrentBlock->timeOut, 0, sizeof(pCurrentBlock->timeOut)); pCurrentBlock->retryCount = 0; pCurrentBlock->sequenceNumber = (UBX_U2)i; pCurrentBlock->mgaFailedReason = MGA_FAILED_REASON_CODE_NOT_SET; diff --git a/gnss/src/lib_mga/u_lib_mga.h b/gnss/src/lib_mga/u_lib_mga.h index 8e0329fe..69c4d2e8 100644 --- a/gnss/src/lib_mga/u_lib_mga.h +++ b/gnss/src/lib_mga/u_lib_mga.h @@ -29,6 +29,8 @@ #include "u_lib_mga_common_types.h" // MODIFED: quotes instead of <> for consistency with ubxlib #include "time.h" +// MODIFIED: inclusion of ubxlib timeout API +#include "u_timeout.h" /////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus @@ -233,6 +235,7 @@ extern "C" { // MODIFIED: the members of this structure have been re-ordered to put the smallest at the end, // most likely to lead to efficient structure packing + // ALSO timeOut has been changed to uTimeoutStop_t, see /common/timeout/api //! Message information structure. /*! For each UBX message that needs to be transferred to the receiver, a message info structure instance is maintained by the libMga. These are used to manage the transfer of UBX messages to the receiver. @@ -241,7 +244,7 @@ extern "C" { */ typedef struct { - time_t timeOut; //!< The time in the future when the UBX message is considered to have been lost and not made it to the receiver. + uTimeoutStop_t timeOut; //!< The time in the future when the UBX message is considered to have been lost and not made it to the receiver. const UBX_U1* pMsg; //!< Pointer to the start of the UBX message. struct //!< Fields related to MGA message transfers { diff --git a/gnss/src/u_gnss.c b/gnss/src/u_gnss.c index 92b4e408..2a8d591b 100644 --- a/gnss/src/u_gnss.c +++ b/gnss/src/u_gnss.c @@ -39,6 +39,8 @@ #include "u_ringbuffer.h" #include "u_linked_list.h" +#include "u_timeout.h" + #include "u_device_shared.h" #include "u_at_client.h" diff --git a/gnss/src/u_gnss_geofence.c b/gnss/src/u_gnss_geofence.c index 8b87ba69..6aa2b2a5 100644 --- a/gnss/src/u_gnss_geofence.c +++ b/gnss/src/u_gnss_geofence.c @@ -37,6 +37,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_linked_list.h" diff --git a/gnss/src/u_gnss_mga.c b/gnss/src/u_gnss_mga.c index ee48cfb2..b8c434ae 100644 --- a/gnss/src/u_gnss_mga.c +++ b/gnss/src/u_gnss_mga.c @@ -44,6 +44,8 @@ #include "u_port_heap.h" #include "u_port_debug.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_ubx_protocol.h" @@ -389,7 +391,7 @@ static int32_t ubxMgaSendWaitAck(uGnssPrivateInstance_t *pInstance, size_t messageBodyLengthBytes) { int32_t errorCode = (int32_t) U_ERROR_COMMON_INVALID_PARAMETER; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; // The UBX-MGA-ACK message ID uGnssPrivateMessageId_t ackMessageId = {.type = U_GNSS_PROTOCOL_UBX, .id.ubx = 0x1360 @@ -413,7 +415,7 @@ static int32_t ubxMgaSendWaitAck(uGnssPrivateInstance_t *pInstance, if (x == messageBodyLengthBytes + U_UBX_PROTOCOL_OVERHEAD_LENGTH_BYTES) { errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; // Wait for the UBX-MGA-ACK-DATA0 response for our message ID - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); do { x = uGnssPrivateReceiveStreamMessage(pInstance, &ackMessageId, pInstance->ringBufferReadHandlePrivate, @@ -431,8 +433,8 @@ static int32_t ubxMgaSendWaitAck(uGnssPrivateInstance_t *pInstance, } } } while ((ackState == 0) && - !uPortTickTimeExpiredMs(startTimeMs, - pInstance->timeoutMs)); + !uTimeoutExpiredMs(timeoutStart, + pInstance->timeoutMs)); if (ackState == 2) { errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; } else if (ackState == 1) { @@ -1058,7 +1060,7 @@ int32_t uGnssMgaGetDatabase(uDeviceHandle_t gnssHandle, uGnssPrivateInstance_t *pInstance; int32_t protocolsOut = 0; int32_t readHandle; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; // The UBX-MGA message class/ID (to capture -DBD and -ACK) uGnssPrivateMessageId_t messageId = {.type = U_GNSS_PROTOCOL_UBX, .id.ubx = 0x1300 + U_GNSS_UBX_MESSAGE_ID_ALL @@ -1100,10 +1102,10 @@ int32_t uGnssMgaGetDatabase(uDeviceHandle_t gnssHandle, if (uGnssPrivateSendOnlyStreamUbxMessage(pInstance, 0x13, 0x80, NULL, 0) == U_UBX_PROTOCOL_OVERHEAD_LENGTH_BYTES) { errorCodeOrLength = (int32_t) U_ERROR_COMMON_TIMEOUT; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while (context.keepGoing && (context.errorCodeOrLength >= 0) && - !uPortTickTimeExpiredMs(startTimeMs, - U_GNSS_MGA_DATABASE_READ_TIMEOUT_MS)) { + !uTimeoutExpiredMs(timeoutStart, + U_GNSS_MGA_DATABASE_READ_TIMEOUT_MS)) { uPortTaskBlock(250); } if (!context.keepGoing) { diff --git a/gnss/src/u_gnss_pos.c b/gnss/src/u_gnss_pos.c index 517d8877..b710537a 100644 --- a/gnss/src/u_gnss_pos.c +++ b/gnss/src/u_gnss_pos.c @@ -44,6 +44,8 @@ #include "u_port_heap.h" #include "u_port_debug.h" +#include "u_timeout.h" + #include "u_time.h" #include "u_at_client.h" @@ -290,7 +292,7 @@ static void posGetTask(void *pParameter) { int32_t errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; uGnssPosGetTaskParameters_t taskParameters; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t latitudeX1e7 = INT_MIN; int32_t longitudeX1e7 = INT_MIN; int32_t altitudeMillimetres = INT_MIN; @@ -307,13 +309,13 @@ static void posGetTask(void *pParameter) // Lock the mutex to indicate that we're running U_PORT_MUTEX_LOCK(taskParameters.pInstance->posMutex); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); taskParameters.pInstance->posTaskFlags |= U_GNSS_POS_TASK_FLAG_HAS_RUN; while ((taskParameters.pInstance->posTaskFlags & U_GNSS_POS_TASK_FLAG_KEEP_GOING) && (errorCode == (int32_t) U_ERROR_COMMON_TIMEOUT) && - !uPortTickTimeExpiredMs(startTimeMs, - U_GNSS_POS_TIMEOUT_SECONDS * 1000)) { + !uTimeoutExpiredSeconds(timeoutStart, + U_GNSS_POS_TIMEOUT_SECONDS)) { // Call posGet() to do the work errorCode = posGet(taskParameters.pInstance, &latitudeX1e7, @@ -451,7 +453,7 @@ int32_t uGnssPosGet(uDeviceHandle_t gnssHandle, #ifdef U_CFG_SARA_R5_M8_WORKAROUND uint8_t message[4]; // Room for the body of a UBX-CFG-ANT message #endif - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; if (gUGnssPrivateMutex != NULL) { @@ -477,12 +479,12 @@ int32_t uGnssPosGet(uDeviceHandle_t gnssHandle, (const char *) message, 4); } #endif - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); errorCode = (int32_t) U_ERROR_COMMON_TIMEOUT; while ((errorCode == (int32_t) U_ERROR_COMMON_TIMEOUT) && (((pKeepGoingCallback == NULL) && - !uPortTickTimeExpiredMs(startTimeMs, - U_GNSS_POS_TIMEOUT_SECONDS * 1000)) || + !uTimeoutExpiredSeconds(timeoutStart, + U_GNSS_POS_TIMEOUT_SECONDS)) || ((pKeepGoingCallback != NULL) && pKeepGoingCallback(gnssHandle)))) { // Call posGet() to do the work errorCode = posGet(pInstance, @@ -898,7 +900,7 @@ int32_t uGnssPosGetRrlp(uDeviceHandle_t gnssHandle, char *pBuffer, int32_t errorCodeOrLength = (int32_t) U_ERROR_COMMON_NOT_INITIALISED; uGnssPrivateInstance_t *pInstance; int32_t messageClass; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t svs; int32_t numBytes; int32_t z; @@ -941,12 +943,12 @@ int32_t uGnssPosGetRrlp(uDeviceHandle_t gnssHandle, char *pBuffer, } #endif messageClass = gRrlpModeToUbxRxmMessageClass[pInstance->rrlpMode]; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); errorCodeOrLength = (int32_t) U_ERROR_COMMON_TIMEOUT; while ((errorCodeOrLength == (int32_t) U_ERROR_COMMON_TIMEOUT) && (((pKeepGoingCallback == NULL) && - !uPortTickTimeExpiredMs(startTimeMs, - U_GNSS_POS_TIMEOUT_SECONDS * 1000)) || + !uTimeoutExpiredSeconds(timeoutStart, + U_GNSS_POS_TIMEOUT_SECONDS)) || ((pKeepGoingCallback != NULL) && pKeepGoingCallback(gnssHandle)))) { numBytes = uGnssPrivateSendReceiveUbxMessage(pInstance, diff --git a/gnss/src/u_gnss_private.c b/gnss/src/u_gnss_private.c index ca9b43e5..17ffa7e5 100644 --- a/gnss/src/u_gnss_private.c +++ b/gnss/src/u_gnss_private.c @@ -49,6 +49,8 @@ #include "u_port_spi.h" #include "u_port_debug.h" +#include "u_timeout.h" + #include "u_hex_bin_convert.h" #include "u_at_client.h" @@ -317,13 +319,13 @@ static int32_t streamGetFromRingBuffer(uGnssPrivateInstance_t *pInstance, size_t totalSize = 0; int32_t x; size_t leftToRead = size; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; if (pInstance != NULL) { - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); errorCodeOrLength = (int32_t) U_ERROR_COMMON_TIMEOUT; while ((leftToRead > 0) && - !uPortTickTimeExpiredMs(startTimeMs, maxTimeMs)) { + !uTimeoutExpiredMs(timeoutStart, maxTimeMs)) { if (andRemove) { receiveSize = (int32_t) uRingBufferReadHandle(&(pInstance->ringBuffer), readHandle, @@ -2134,7 +2136,7 @@ int32_t uGnssPrivateStreamFillRingBuffer(uGnssPrivateInstance_t *pInstance, int32_t timeoutMs, int32_t maxTimeMs) { int32_t errorCodeOrLength = (int32_t) U_ERROR_COMMON_INVALID_PARAMETER; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t privateStreamTypeOrError; int32_t receiveSize; int32_t totalReceiveSize = 0; @@ -2155,7 +2157,7 @@ int32_t uGnssPrivateStreamFillRingBuffer(uGnssPrivateInstance_t *pInstance, privateStreamTypeOrError = uGnssPrivateGetStreamType(pInstance->transportType); if (privateStreamTypeOrError >= 0) { errorCodeOrLength = (int32_t) U_ERROR_COMMON_TIMEOUT; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); // This is constructed as a do()/while() so that // it always has one go even with a zero timeout do { @@ -2235,10 +2237,10 @@ int32_t uGnssPrivateStreamFillRingBuffer(uGnssPrivateInstance_t *pInstance, // The first condition below is the "not yet received anything case", guarded by timeoutMs // the second condition below is when we're receiving stuff, guarded by maxTimeMs (((totalReceiveSize == 0) && - !uPortTickTimeExpiredMs(startTimeMs, timeoutMs)) || + !uTimeoutExpiredMs(timeoutStart, timeoutMs)) || ((receiveSize > 0) && ((maxTimeMs == 0) || - !uPortTickTimeExpiredMs(startTimeMs, - maxTimeMs))))); + !uTimeoutExpiredMs(timeoutStart, + maxTimeMs))))); } } @@ -2405,14 +2407,14 @@ int32_t uGnssPrivateReceiveStreamMessage(uGnssPrivateInstance_t *pInstance, int32_t receiveSize; int32_t ringBufferSize; size_t discardSize = 0; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t x = timeoutMs > 0 ? U_GNSS_RING_BUFFER_MIN_FILL_TIME_MS : 0; int32_t y; if ((pInstance != NULL) && (pPrivateMessageId != NULL) && (ppBuffer != NULL) && ((*ppBuffer == NULL) || (size > 0))) { errorCodeOrLength = (int32_t) U_ERROR_COMMON_TIMEOUT; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); // Lock our read pointer while we look for stuff uRingBufferLockReadHandle(&(pInstance->ringBuffer), readHandle); // This is constructed as a do()/while() so that it always has one go @@ -2450,7 +2452,7 @@ int32_t uGnssPrivateReceiveStreamMessage(uGnssPrivateInstance_t *pInstance, if (*ppBuffer != NULL) { // Now read the message data into the buffer, // which will move our read pointer on - y = timeoutMs - (uPortGetTickTimeMs() - startTimeMs); + y = timeoutMs - uTimeoutElapsedMs(timeoutStart); if (y < U_GNSS_RING_BUFFER_MIN_FILL_TIME_MS) { // Make sure we give ourselves time to read the messsage out y = U_GNSS_RING_BUFFER_MIN_FILL_TIME_MS; @@ -2479,7 +2481,7 @@ int32_t uGnssPrivateReceiveStreamMessage(uGnssPrivateInstance_t *pInstance, } while ((((errorCodeOrLength < 0) && (errorCodeOrLength != (int32_t) U_GNSS_ERROR_NACK) && (errorCodeOrLength != (int32_t) U_ERROR_COMMON_NO_MEMORY)) || (discardSize > 0)) && (timeoutMs > 0) && - !uPortTickTimeExpiredMs(startTimeMs, timeoutMs) && + !uTimeoutExpiredMs(timeoutStart, timeoutMs) && ((pKeepGoingCallback == NULL) || pKeepGoingCallback(pInstance->gnssHandle))); // Read pointer can be unlocked now @@ -2591,7 +2593,7 @@ int32_t uGnssPrivateSendUbxMessage(uGnssPrivateInstance_t *pInstance, int32_t errorCode = (int32_t) U_ERROR_COMMON_INVALID_PARAMETER; uGnssPrivateUbxReceiveMessage_t response = {0}; // Keep Valgrind happy int32_t timeoutMs; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; char ackBody[2] = {0}; char *pBody = &(ackBody[0]); @@ -2604,7 +2606,7 @@ int32_t uGnssPrivateSendUbxMessage(uGnssPrivateInstance_t *pInstance, response.bodySize = sizeof(ackBody); timeoutMs = pInstance->timeoutMs; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); errorCode = sendReceiveUbxMessage(pInstance, messageClass, messageId, pMessageBody, messageBodyLengthBytes, &response); @@ -2620,7 +2622,7 @@ int32_t uGnssPrivateSendUbxMessage(uGnssPrivateInstance_t *pInstance, (ackBody[1] != (char) messageId) && !((response.id == 0x01) || (response.id == 0x00)) && (uGnssPrivateGetStreamType(pInstance->transportType) >= 0) && - !uPortTickTimeExpiredMs(startTimeMs, timeoutMs)) { + !uTimeoutExpiredMs(timeoutStart, timeoutMs)) { response.cls = 0x05; response.id = -1; errorCode = receiveUbxMessageStream(pInstance, &response, diff --git a/gnss/src/u_gnss_util.c b/gnss/src/u_gnss_util.c index 8ffd0b72..4a0690e5 100644 --- a/gnss/src/u_gnss_util.c +++ b/gnss/src/u_gnss_util.c @@ -46,6 +46,8 @@ #include "u_port_i2c.h" #include "u_port_spi.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_ubx_protocol.h" @@ -96,7 +98,7 @@ int32_t uGnssUtilUbxTransparentSendReceive(uDeviceHandle_t gnssHandle, uGnssPrivateInstance_t *pInstance; int32_t privateStreamTypeOrError; uDeviceSerial_t *pDeviceSerial = NULL; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t x = 0; int32_t bytesRead = 0; char *pBuffer; @@ -173,12 +175,11 @@ int32_t uGnssUtilUbxTransparentSendReceive(uDeviceHandle_t gnssHandle, errorCodeOrResponseLength = (int32_t) U_ERROR_COMMON_SUCCESS; if (pResponse != NULL) { errorCodeOrResponseLength = (int32_t) U_GNSS_ERROR_TRANSPORT; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); // Wait for something to start coming back while ((bytesRead < (int32_t) maxResponseLengthBytes) && ((x = uGnssPrivateStreamGetReceiveSize(pInstance)) <= 0) && - !uPortTickTimeExpiredMs(startTimeMs, - pInstance->timeoutMs)) { + !uTimeoutExpiredMs(timeoutStart, pInstance->timeoutMs)) { // Relax a little uPortTaskBlock(U_GNSS_UTIL_TRANSPARENT_RECEIVE_DELAY_MS); } @@ -186,8 +187,7 @@ int32_t uGnssUtilUbxTransparentSendReceive(uDeviceHandle_t gnssHandle, // Got something; continue receiving until nothing arrives or we time out while ((bytesRead < (int32_t) maxResponseLengthBytes) && ((x = uGnssPrivateStreamGetReceiveSize(pInstance)) > 0) && - !uPortTickTimeExpiredMs(startTimeMs, - pInstance->timeoutMs)) { + !uTimeoutExpiredMs(timeoutStart, pInstance->timeoutMs)) { if (x > 0) { if (x > ((int32_t) maxResponseLengthBytes) - bytesRead) { x = maxResponseLengthBytes - bytesRead; diff --git a/gnss/test/u_gnss_geofence_test.c b/gnss/test/u_gnss_geofence_test.c index 6fdff214..d00379d5 100644 --- a/gnss/test/u_gnss_geofence_test.c +++ b/gnss/test/u_gnss_geofence_test.c @@ -50,6 +50,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_at_client.h" // Required by u_gnss_private.h #include "u_linked_list.h" @@ -169,7 +171,7 @@ static uGnssTestPrivate_t gHandles = U_GNSS_TEST_PRIVATE_DEFAULTS; /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** Variable to track the parameters received by a callback that * vary with the position being tested. @@ -202,7 +204,8 @@ static bool keepGoingCallback(uDeviceHandle_t gnssHandle) bool keepGoing = true; U_PORT_TEST_ASSERT(gnssHandle == gHandles.gnssHandle); - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -810,7 +813,6 @@ U_PORT_TEST_FUNCTION("[gnssGeofence]", "gnssGeofenceLive") uGnssTransportType_t transportTypes[U_GNSS_TRANSPORT_MAX_NUM]; int32_t y; uGnssGeofenceTestCallbackParams_t callbackParams; - int32_t startTimeMs; // In case fence A was left hanging uGnssGeofenceRemove(NULL, NULL); @@ -875,14 +877,14 @@ U_PORT_TEST_FUNCTION("[gnssGeofence]", "gnssGeofenceLive") U_GEOFENCE_POSITION_STATE_INSIDE, U_GEOFENCE_POSITION_STATE_OUTSIDE, LLONG_MIN, LLONG_MIN, INT_MIN, INT_MIN, INT_MIN); - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + U_GNSS_GEOFENCE_TEST_POS_TIMEOUT_SECONDS * 1000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_GNSS_GEOFENCE_TEST_POS_TIMEOUT_SECONDS * 1000; y = uGnssPosGet(gnssDevHandle, NULL, NULL, NULL, NULL, NULL, NULL, NULL, keepGoingCallback); U_TEST_PRINT_LINE("calling uGnssPosGet() returned %d.", y); U_PORT_TEST_ASSERT(y == 0); U_TEST_PRINT_LINE("position establishment took %d second(s).", - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(gTimeoutStop.timeoutStart)); U_PORT_TEST_ASSERT(checkCallbackResult(&callbackParams, &gCallbackParameters)); // Repeat for the asynchronous position API @@ -891,14 +893,16 @@ U_PORT_TEST_FUNCTION("[gnssGeofence]", "gnssGeofenceLive") U_GEOFENCE_POSITION_STATE_INSIDE, U_GEOFENCE_POSITION_STATE_OUTSIDE, LLONG_MIN, LLONG_MIN, INT_MIN, INT_MIN, INT_MIN); - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + U_GNSS_GEOFENCE_TEST_POS_TIMEOUT_SECONDS * 1000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_GNSS_GEOFENCE_TEST_POS_TIMEOUT_SECONDS * 1000; y = uGnssPosGetStart(gnssDevHandle, posCallback); U_TEST_PRINT_LINE("calling uGnssPosGetStart() returned %d.", y); U_PORT_TEST_ASSERT(y == 0); U_TEST_PRINT_LINE("waiting up to %d second(s) for results from asynchronous API...", U_GNSS_GEOFENCE_TEST_POS_TIMEOUT_SECONDS); - while ((gCallbackParameters.called < 2) && (uPortGetTickTimeMs() < gStopTimeMs)) { + while ((gCallbackParameters.called < 2) && + !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(1000); } U_PORT_TEST_ASSERT(checkCallbackResult(&callbackParams, &gCallbackParameters)); @@ -910,14 +914,16 @@ U_PORT_TEST_FUNCTION("[gnssGeofence]", "gnssGeofenceLive") U_GEOFENCE_POSITION_STATE_INSIDE, U_GEOFENCE_POSITION_STATE_OUTSIDE, LLONG_MIN, LLONG_MIN, INT_MIN, INT_MIN, INT_MIN); - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + U_GNSS_GEOFENCE_TEST_POS_TIMEOUT_SECONDS * 1000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_GNSS_GEOFENCE_TEST_POS_TIMEOUT_SECONDS * 1000; y = uGnssPosGetStreamedStart(gnssDevHandle, 1000, posCallback);; U_TEST_PRINT_LINE("calling uGnssPosGetStreamedStart() returned %d.", y); U_PORT_TEST_ASSERT(y == 0); U_TEST_PRINT_LINE("waiting up to %d second(s) for results from streamed API...", U_GNSS_GEOFENCE_TEST_POS_TIMEOUT_SECONDS); - while ((gCallbackParameters.called < 2) && (uPortGetTickTimeMs() < gStopTimeMs)) { + while ((gCallbackParameters.called < 2) && + !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(1000); } // Stop the stream before potentially asserting diff --git a/gnss/test/u_gnss_info_test.c b/gnss/test/u_gnss_info_test.c index 7c3cd872..2ef088db 100644 --- a/gnss/test/u_gnss_info_test.c +++ b/gnss/test/u_gnss_info_test.c @@ -47,6 +47,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_at_client.h" // Required by u_gnss_private.h #include "u_port.h" @@ -254,7 +256,7 @@ U_PORT_TEST_FUNCTION("[gnssInfo]", "gnssInfoTime") uDeviceHandle_t gnssHandle; int32_t resourceCount; int64_t y; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; size_t iterations; uGnssTransportType_t transportTypes[U_GNSS_TRANSPORT_MAX_NUM]; @@ -293,20 +295,19 @@ U_PORT_TEST_FUNCTION("[gnssInfo]", "gnssInfoTime") // has not yet found time U_TEST_PRINT_LINE("waiting up to %d second(s) to establish UTC time...", U_GNSS_TIME_TEST_TIMEOUT_SECONDS); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((y < 0) && - !uPortTickTimeExpiredMs(startTimeMs, - U_GNSS_TIME_TEST_TIMEOUT_SECONDS * 1000)) { + !uTimeoutExpiredSeconds(timeoutStart, + U_GNSS_TIME_TEST_TIMEOUT_SECONDS)) { y = uGnssInfoGetTimeUtc(gnssHandle); } if (y > 0) { U_TEST_PRINT_LINE("UTC time according to GNSS is %d (took %d second(s)" " to establish).", (int32_t) y, - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(timeoutStart)); } else { U_TEST_PRINT_LINE("could not get UTC time from GNSS after %d second(s) (%d).", - (uPortGetTickTimeMs() - startTimeMs) / 1000, - (int32_t) y); + uTimeoutElapsedSeconds(timeoutStart), (int32_t) y); } U_PORT_TEST_ASSERT(y > U_GNSS_TEST_MIN_UTC_TIME); diff --git a/gnss/test/u_gnss_mga_test.c b/gnss/test/u_gnss_mga_test.c index bd362a12..c1e8745d 100644 --- a/gnss/test/u_gnss_mga_test.c +++ b/gnss/test/u_gnss_mga_test.c @@ -71,6 +71,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_network.h" #include "u_network_test_shared_cfg.h" @@ -549,7 +551,7 @@ U_PORT_TEST_FUNCTION("[gnssMga]", "gnssMgaBasic") int32_t callbackParameter; int32_t z; uGnssCommunicationStats_t communicationStats; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; const char *pProtocolName; #endif @@ -664,7 +666,7 @@ U_PORT_TEST_FUNCTION("[gnssMga]", "gnssMgaBasic") # ifndef U_GNSS_MGA_TEST_DISABLE_DATABASE callbackParameter = 0; gDatabaseCalledCount = 0; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); if ((transportTypes[w] != U_GNSS_TRANSPORT_AT) && (intermediateHandle == NULL)) { U_TEST_PRINT_LINE("reading database from GNSS device."); gDatabaseHasQzss = false; @@ -673,7 +675,7 @@ U_PORT_TEST_FUNCTION("[gnssMga]", "gnssMgaBasic") if (callbackParameter >= 0) { U_TEST_PRINT_LINE("database callback was called %d times, with a total" " of %d byte(s) in %d milliseconds.", gDatabaseCalledCount, - callbackParameter, uPortGetTickTimeMs() - startTimeMs); + callbackParameter, uTimeoutElapsedMs(timeoutStart)); U_PORT_TEST_ASSERT(z == callbackParameter); } else { U_TEST_PRINT_LINE("database callback returned error %d.", callbackParameter); diff --git a/gnss/test/u_gnss_msg_test.c b/gnss/test/u_gnss_msg_test.c index 747460f8..866ab0d0 100644 --- a/gnss/test/u_gnss_msg_test.c +++ b/gnss/test/u_gnss_msg_test.c @@ -48,6 +48,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_at_client.h" // Required by u_gnss_private.h #include "u_port_clib_platform_specific.h" /* Integer stdio, must be included @@ -167,7 +169,7 @@ typedef struct { /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** Handles. */ @@ -198,7 +200,8 @@ static bool keepGoingCallback(uDeviceHandle_t gnssHandle) gCallbackErrorCode = 1; } - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -414,7 +417,8 @@ U_PORT_TEST_FUNCTION("[gnssMsg]", "gnssMsgReceiveBlocking") U_TEST_PRINT_LINE("receiving response without message filter and with auto-buffer."); messageId.type = U_GNSS_PROTOCOL_UBX; messageId.id.ubx = U_GNSS_UBX_MESSAGE(U_GNSS_UBX_MESSAGE_CLASS_ALL, U_GNSS_UBX_MESSAGE_ID_ALL); - gStopTimeMs = uPortGetTickTimeMs() + U_GNSS_MSG_TEST_MESSAGE_RECEIVE_TIMEOUT_MS; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_GNSS_MSG_TEST_MESSAGE_RECEIVE_TIMEOUT_MS; pBuffer3 = NULL; gCallbackErrorCode = 0; x = uGnssMsgReceive(gnssHandle, &messageId, &pBuffer3, 0, diff --git a/gnss/test/u_gnss_pos_test.c b/gnss/test/u_gnss_pos_test.c index b890103d..dff26fb2 100644 --- a/gnss/test/u_gnss_pos_test.c +++ b/gnss/test/u_gnss_pos_test.c @@ -47,6 +47,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_at_client.h" // Required by u_gnss_private.h #include "u_port.h" @@ -198,7 +200,7 @@ /** Used for keepGoingCallback() timeout. */ -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; /** Handles. */ @@ -282,7 +284,8 @@ static bool keepGoingCallback(uDeviceHandle_t gnssHandle) bool keepGoing = true; U_PORT_TEST_ASSERT(gnssHandle == gHandles.gnssHandle); - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -365,7 +368,6 @@ U_PORT_TEST_FUNCTION("[gnssPos]", "gnssPosPos") char prefix[2]; int32_t whole[2]; int32_t fraction[2]; - int64_t startTimeMs; int32_t resourceCount; size_t iterations; uGnssTransportType_t transportTypes[U_GNSS_TRANSPORT_MAX_NUM]; @@ -406,8 +408,8 @@ U_PORT_TEST_FUNCTION("[gnssPos]", "gnssPosPos") speedMillimetresPerSecond = INT_MIN; svs = 0; timeUtc = LONG_MIN; - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + (U_GNSS_POS_TEST_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_GNSS_POS_TEST_TIMEOUT_SECONDS * 1000; y = uGnssPosGet(gnssHandle, &latitudeX1e7, &longitudeX1e7, &altitudeMillimetres, @@ -419,7 +421,7 @@ U_PORT_TEST_FUNCTION("[gnssPos]", "gnssPosPos") U_PORT_TEST_ASSERT(y == 0); U_TEST_PRINT_LINE_X("position establishment took %d second(s).", z + 1, - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(gTimeoutStop.timeoutStart)); prefix[0] = latLongToBits(latitudeX1e7, &(whole[0]), &(fraction[0])); prefix[1] = latLongToBits(longitudeX1e7, &(whole[1]), &(fraction[1])); U_TEST_PRINT_LINE_X("location %c%d.%07d/%c%d.%07d (radius %d metre(s)), %d metre(s) high," @@ -452,8 +454,8 @@ U_PORT_TEST_FUNCTION("[gnssPos]", "gnssPosPos") timeUtc = LONG_MIN; gErrorCode = 0xFFFFFFFF; gGoodPosCount = 0; - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + (U_GNSS_POS_TEST_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_GNSS_POS_TEST_TIMEOUT_SECONDS * 1000; if (z == 0) { // Check that calling stop first causes no problem uGnssPosGetStop(gnssHandle); @@ -467,12 +469,13 @@ U_PORT_TEST_FUNCTION("[gnssPos]", "gnssPosPos") U_TEST_PRINT_LINE_X("calling uGnssPosGetStart() twice in rapid succession returned %d.", z + 1, y); gErrorCode = 0xFFFFFFFF; gGoodPosCount = 0; - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + (U_GNSS_POS_TEST_TIMEOUT_SECONDS * 1000); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_GNSS_POS_TEST_TIMEOUT_SECONDS * 1000; } U_TEST_PRINT_LINE_X("waiting up to %d second(s) for results from asynchronous API...", z + 1, U_GNSS_POS_TEST_TIMEOUT_SECONDS); - while ((gErrorCode == 0xFFFFFFFF) && (uPortGetTickTimeMs() < gStopTimeMs)) { + while ((gErrorCode == 0xFFFFFFFF) && !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(1000); } @@ -484,7 +487,7 @@ U_PORT_TEST_FUNCTION("[gnssPos]", "gnssPosPos") U_PORT_TEST_ASSERT(gErrorCode == 0); U_PORT_TEST_ASSERT(gGoodPosCount == 1); U_TEST_PRINT_LINE_X("position establishment took %d second(s).", z + 1, - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(gTimeoutStop.timeoutStart)); prefix[0] = latLongToBits(gLatitudeX1e7, &(whole[0]), &(fraction[0])); prefix[1] = latLongToBits(gLongitudeX1e7, &(whole[1]), &(fraction[1])); @@ -535,7 +538,6 @@ U_PORT_TEST_FUNCTION("[gnssPos]", "gnssPosRrlp") uDeviceHandle_t gnssHandle; int32_t y; char *pBuffer; - int64_t startTimeMs; int32_t resourceCount; size_t iterations; uGnssTransportType_t transportTypes[U_GNSS_TRANSPORT_MAX_NUM]; @@ -581,8 +583,8 @@ U_PORT_TEST_FUNCTION("[gnssPos]", "gnssPosRrlp") U_PORT_TEST_ASSERT(y >= 6); U_PORT_TEST_ASSERT(y <= U_GNSS_POS_RRLP_SIZE_BYTES); - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + U_GNSS_POS_TEST_TIMEOUT_SECONDS * 1000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_GNSS_POS_TEST_TIMEOUT_SECONDS * 1000; U_TEST_PRINT_LINE("asking for RRLP information with thresholds..."); y = uGnssPosGetRrlp(gnssHandle, pBuffer, U_GNSS_POS_RRLP_SIZE_BYTES, U_GNSS_POS_TEST_RRLP_SVS_THRESHOLD, @@ -591,7 +593,7 @@ U_PORT_TEST_FUNCTION("[gnssPos]", "gnssPosRrlp") U_GNSS_POS_TEST_RRLP_PSEUDORANGE_RMS_ERROR_INDEX_LIMIT, keepGoingCallback); U_TEST_PRINT_LINE("RRLP took %d second(s) to arrive.", - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(gTimeoutStop.timeoutStart)); U_TEST_PRINT_LINE("%d byte(s) of RRLP information was returned.", y); // Must contain at least 6 bytes for the header U_PORT_TEST_ASSERT(y >= 6); @@ -632,15 +634,15 @@ U_PORT_TEST_FUNCTION("[gnssPos]", "gnssPosRrlp") if (y == 0) { // Do an RRLP get of the 12C compact mode with whacky thresholds, since // they should be ignored - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + U_GNSS_POS_TEST_TIMEOUT_SECONDS * 1000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_GNSS_POS_TEST_TIMEOUT_SECONDS * 1000; U_TEST_PRINT_LINE("asking for compact RRLP information 12C..."); // length should be the UBX protocol overhead plus 12 bytes of data y = uGnssPosGetRrlp(gnssHandle, pBuffer, 8 + 12, INT_MAX, INT_MAX, INT_MAX, INT_MAX, keepGoingCallback); U_TEST_PRINT_LINE("RRLP took %d second(s) to arrive.", - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(gTimeoutStop.timeoutStart)); U_TEST_PRINT_LINE("%d byte(s) of RRLP information was returned.", y); // Must contain at least 6 bytes for the header U_PORT_TEST_ASSERT(y >= 6); @@ -679,14 +681,13 @@ U_PORT_TEST_FUNCTION("[gnssPos]", "gnssPosStreamed") char prefix[2]; int32_t whole[2]; int32_t fraction[2]; - int32_t startTimeMs; - int32_t posTimeMs = -1; int32_t resourceCount; size_t iterations; uGnssTransportType_t transportTypes[U_GNSS_TRANSPORT_MAX_NUM]; int32_t a = -1; int32_t b = -1; uGnssTimeSystem_t t = U_GNSS_TIME_SYSTEM_NONE; + uTimeoutStart_t timeoutStart; // In case a previous test failed uGnssTestPrivateCleanup(&gHandles); @@ -767,19 +768,20 @@ U_PORT_TEST_FUNCTION("[gnssPos]", "gnssPosStreamed") uGnssPosGetStreamedStop(gnssHandle); } gErrorCode = 0xFFFFFFFF; - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + U_GNSS_POS_TEST_TIMEOUT_SECONDS * 1000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_GNSS_POS_TEST_TIMEOUT_SECONDS * 1000; y = uGnssPosGetStreamedStart(gnssHandle, U_GNSS_POS_TEST_STREAMED_RATE_MS, posCallback); U_TEST_PRINT_LINE_X("uGnssPosGetStreamedStart() returned %d.", z + 1, y); U_PORT_TEST_ASSERT(y == 0); U_TEST_PRINT_LINE_X("waiting up to %d second(s) for first valid result from streamed API...", z + 1, U_GNSS_POS_TEST_TIMEOUT_SECONDS); - while ((gErrorCode != 0) && (uPortGetTickTimeMs() < gStopTimeMs)) { + while ((gErrorCode != 0) && !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(1000); } if (gErrorCode == 0) { - posTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); U_TEST_PRINT_LINE_X("waiting %d second(s) for rate change to take effect...", z + 1, U_GNSS_POS_TEST_STREAMED_WAIT_SECONDS); uPortTaskBlock(1000 * U_GNSS_POS_TEST_STREAMED_WAIT_SECONDS); @@ -796,7 +798,7 @@ U_PORT_TEST_FUNCTION("[gnssPos]", "gnssPosStreamed") U_PORT_TEST_ASSERT(gErrorCode == 0); if (gGoodPosCount > 0) { U_TEST_PRINT_LINE_X("position establishment took %d second(s).", z + 1, - (posTimeMs - startTimeMs) / 1000); + uTimeoutElapsedSeconds(timeoutStart)); U_TEST_PRINT_LINE_X("the streamed position callback was called with a good position %d time(s)" " in %d second(s), average every %d millisecond(s) (expected every" " %d milliseconds).", z + 1, diff --git a/gnss/test/u_gnss_test_private.c b/gnss/test/u_gnss_test_private.c index 51d9b47a..4bc8ca40 100644 --- a/gnss/test/u_gnss_test_private.c +++ b/gnss/test/u_gnss_test_private.c @@ -48,6 +48,8 @@ #include "u_port_i2c.h" #include "u_port_spi.h" +#include "u_timeout.h" + #include "u_at_client.h" // Required by u_gnss_private.h #include "u_cell_module_type.h" diff --git a/port/api/u_port.h b/port/api/u_port.h index c982f2ff..83c318f2 100644 --- a/port/api/u_port.h +++ b/port/api/u_port.h @@ -104,9 +104,11 @@ extern "C" { * and then calls pEntryPoint, i.e. the application, in an RTOS task. * This is used as a standard way to start the system for all of the * u-blox examples and all of the u-blox tests. + * * You may have your own mechanism for initialisating the HW and * starting an RTOS task, in which case you need not use this * function. + * * This function only returns if there is an error; * code execution ends up in pEntryPoint, which should * never return. @@ -145,98 +147,23 @@ int32_t uPortInit(); void uPortDeinit(); /** Get the current OS tick converted to a time in milliseconds. - * This is guaranteed to be unaffected by any time setting activity. - * It is NOT maintained while the processor is in deep sleep, i.e. - * with clocks stopped; port initialisation should be called on - * return from deep sleep and that will restart this time from - * zero once more. - * - * @return the current OS tick converted to milliseconds. - */ -int32_t uPortGetTickTimeMs(); - -/** Perform a tick timeout check in a way that will behave predictably - * across a tick-counter wrap. The return value of uPortGetTickTimeMs() - * is an int32_t, which will wrap in roughly 25 days. When it does so - * it will go negative, i.e. from INT32_MAX to INT32_MIN. This macro - * performs a timeout comparison with signed modulo-32 arithmetic such - * that: - * - * - if the given time has elapsed since the start time then true is - * returned, - * - if the tick counter has wrapped then true is returned, - * - else false is returned. - * - * This way no timeout comparison will ever get "stuck" if the tick - * counter wraps underneath it; it could, of course, be shorter than - * the requested timeout, but only once every 25 days. - * - * Where you would have had: - * - * ``` - * if (uPortGetTickTimeMs() - startTimeMs > timeoutMs) { - * // Do something because the timeout has expired - * } - * ``` - * - * ...then do this instead: * - * ``` - * if (uPortTickTimeExpiredMs(startTimeMs, timeoutMs)) { - * // Do something because the timeout has expired - * } - * ``` + * IMPORTANT: the value returned by this function should NOT + * be used for checking time-outs or measuring delays; please + * instead use uTickGet(), the return value of which may be + * passed to uTickExpiredMs(), uTickExpiredSeconds() + * or uTickExpired(), the time-out checking functions + * that know how to handle tick wraps. * - * If you only have a stop time, rather than a start time and a timeout, - * use uPortTickTimeBeyondStopMs() instead. + * The return value of this function is guaranteed to be + * unaffected by any time setting activity. It is NOT maintained + * while the processor is in deep sleep, i.e. with clocks stopped; + * port initialisation should be called on return from deep sleep + * and that will restart this time from zero once more. * - * Note: this function is implemented in this header file so - * that it can be guaranteed to be in-lined by the compiler. - * - * @param startTimeMs the start time in milliseconds, derived - * from uPortGetTickTimeMs(). - * @param timeoutMs the timeout in milliseconds. - * @return true if the current tick time has passed - * the timeout, or if the current tick time - * has wrapped. - */ -static U_INLINE bool uPortTickTimeExpiredMs(int32_t startTimeMs, - int32_t timeoutMs) -{ - return (uPortGetTickTimeMs() - startTimeMs > timeoutMs); -} - -/** Like uPortTickTimeExpiredMs() but for the case where - * you have a stop time rather than a start time and a timeout. - * Where you would have had: - * - * ``` - * if (uPortGetTickTimeMs() > stopTimeMs) { - * // Do something because we are beyond the stop time - * } - * ``` - * - * ...then call this macro with the stop time instead: - * - * ``` - * if (uPortTickTimeBeyondStopMs(stopTimeMs)) { - * // Do something because we are beyond the stop time - * } - * ``` - * - * Note: this function is implemented in this header file so - * that it can be guaranteed to be in-lined by the compiler. - * - * @param stopTimeMs the stop time in milliseconds, derived - * from uPortGetTickTimeMs(). - * @return true if the current tick time is greater - * than stopTimeMs or the current tick time - * has wrapped. + * @return the current OS tick converted to milliseconds. */ -static U_INLINE bool uPortTickTimeBeyondStopMs(int32_t stopTimeMs) -{ - return (uPortGetTickTimeMs() - stopTimeMs > 0); -} +int32_t uPortGetTickTimeMs(); /** Get the heap high watermark, the minimum amount of heap * free, ever. diff --git a/port/platform/arduino/include.txt b/port/platform/arduino/include.txt index ea247424..a8e944f3 100644 --- a/port/platform/arduino/include.txt +++ b/port/platform/arduino/include.txt @@ -11,6 +11,7 @@ cfg common/error/api common/assert/api +common/timeout/api common/type/api common/device/api common/device/src diff --git a/port/platform/arduino/include_test.txt b/port/platform/arduino/include_test.txt index 589266cb..a2af7f14 100644 --- a/port/platform/arduino/include_test.txt +++ b/port/platform/arduino/include_test.txt @@ -7,6 +7,7 @@ ble/test cell/test gnss/test wifi/test +common/timeout/test common/sock/test common/device/test common/network/test diff --git a/port/platform/arduino/source.txt b/port/platform/arduino/source.txt index 4965c3f8..e8f25273 100644 --- a/port/platform/arduino/source.txt +++ b/port/platform/arduino/source.txt @@ -78,6 +78,7 @@ common/network/src/u_network_private_wifi.c common/network/src/u_network_private_wifi_stub.c common/network/src/u_network_private_gnss.c common/network/src/u_network_private_gnss_stub.c +common/timeout/src/u_timeout.c common/sock/src/u_sock.c common/sock/src/u_sock_stub_cell.c common/sock/src/u_sock_stub_wifi.c diff --git a/port/platform/cell_ucpu/r5/app/test/ucpu_uart_test.c b/port/platform/cell_ucpu/r5/app/test/ucpu_uart_test.c index 712f766a..5f215031 100644 --- a/port/platform/cell_ucpu/r5/app/test/ucpu_uart_test.c +++ b/port/platform/cell_ucpu/r5/app/test/ucpu_uart_test.c @@ -213,7 +213,7 @@ static void mqttThread(void *thread_input) char pubMessage[MEG_SIZE]; char readBuffer[MEG_SIZE]; size_t readBufferSize; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; uint32_t count = 0; uint32_t result = 0; volatile bool messagesAvailable = false; @@ -265,7 +265,7 @@ static void mqttThread(void *thread_input) if (isConnectedToServer) { uPortLog("MQTT itteration count = %d\n", ++count); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); memset(pubMessage, 0, sizeof(pubMessage)); snprintf(pubMessage, sizeof(pubMessage), "%s%d", message, count); @@ -282,7 +282,7 @@ static void mqttThread(void *thread_input) // Wait for us to be notified that our new // message is available on the broker while (!messagesAvailable && - !uPortTickTimeExpiredMs(startTimeMs, 20000)) { + !uTimeoutExpiredSeconds(timeoutStart, 20)) { uPortTaskBlock(1000); } diff --git a/port/platform/cell_ucpu/r5/src/u_port_uart.c b/port/platform/cell_ucpu/r5/src/u_port_uart.c index 72c21075..7aca5ccc 100644 --- a/port/platform/cell_ucpu/r5/src/u_port_uart.c +++ b/port/platform/cell_ucpu/r5/src/u_port_uart.c @@ -25,6 +25,7 @@ #include "u_cfg_sw.h" #include "u_error_common.h" #include "u_cfg_os_platform_specific.h" // For U_CFG_OS_YIELD_MS +#include "u_timeout.h" #include "u_port_debug.h" #include "u_port.h" @@ -813,7 +814,7 @@ int32_t uPortUartEventTrySend(int32_t handle, uint32_t eventBitMap, int32_t delayMs) { int32_t errorCode = U_ERROR_COMMON_NOT_INITIALISED; - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); if ((gModemUartMutex != NULL) && (!gModemUartContext.markedForDeletion)) { @@ -831,7 +832,7 @@ int32_t uPortUartEventTrySend(int32_t handle, uint32_t eventBitMap, NULL, 0); uPortTaskBlock(U_CFG_OS_YIELD_MS); } while ((errorCode != 0) && - !uPortTickTimeExpiredMs(startTimeMs, delayMs)); + !uTimeoutExpiredMs(timeoutStart, delayMs)); } } diff --git a/port/platform/common/mutex_debug/u_mutex_debug.c b/port/platform/common/mutex_debug/u_mutex_debug.c index 3aaf85d4..a2ec426d 100644 --- a/port/platform/common/mutex_debug/u_mutex_debug.c +++ b/port/platform/common/mutex_debug/u_mutex_debug.c @@ -32,6 +32,7 @@ #include "u_cfg_sw.h" #include "u_cfg_os_platform_specific.h" #include "u_error_common.h" +#include "u_timeout.h" #include "u_assert.h" #include "u_port.h" #include "u_port_debug.h" @@ -378,7 +379,7 @@ static void watchdogTask(void *pParam) { uMutexInfo_t *pMutexInfo; uMutexFunctionInfo_t *pWaiting; - int32_t calledMs = 0; + uTimeoutStart_t called = {0}; bool callCallback = false; (void) pParam; @@ -417,8 +418,8 @@ static void watchdogTask(void *pParam) pMutexInfo = pMutexInfo->pNext; // Don't call the callback too often though - if (!uPortTickTimeExpiredMs(calledMs, - U_MUTEX_DEBUG_WATCHDOG_MAX_BARK_SECONDS * 1000)) { + if (!uTimeoutExpiredMs(called, + U_MUTEX_DEBUG_WATCHDOG_MAX_BARK_SECONDS * 1000)) { callCallback = false; } } @@ -428,7 +429,7 @@ static void watchdogTask(void *pParam) if (callCallback) { // Call the callback outside the locks so that it can have them gpWatchdogCallback(gpWatchdogCallbackParam); - calledMs = uPortGetTickTimeMs(); + called = uTimeoutStart(); } // Sleep until the next go diff --git a/port/platform/esp-idf/src/u_port_uart.c b/port/platform/esp-idf/src/u_port_uart.c index f2ec9a27..5914ef83 100644 --- a/port/platform/esp-idf/src/u_port_uart.c +++ b/port/platform/esp-idf/src/u_port_uart.c @@ -32,6 +32,7 @@ #include "u_compiler.h" // U_ATOMIC_XXX() macros #include "u_error_common.h" +#include "u_timeout.h" #include "u_port_debug.h" #include "u_port.h" #include "u_port_os.h" @@ -646,7 +647,7 @@ int32_t uPortUartEventTrySend(int32_t handle, uint32_t eventBitMap, { int32_t errorCode = (int32_t) U_ERROR_COMMON_NOT_INITIALISED; uart_event_t event; - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); if (gMutex != NULL) { @@ -672,7 +673,7 @@ int32_t uPortUartEventTrySend(int32_t handle, uint32_t eventBitMap, (void *) &event); uPortTaskBlock(U_CFG_OS_YIELD_MS); } while ((errorCode != 0) && - !uPortTickTimeExpiredMs(startTimeMs, delayMs)); + !uTimeoutExpiredMs(timeoutStart, delayMs)); } U_PORT_MUTEX_UNLOCK(gMutex); diff --git a/port/platform/esp-idf/test/u_espidf_ppp_test.c b/port/platform/esp-idf/test/u_espidf_ppp_test.c index 776bb54b..c41990bc 100644 --- a/port/platform/esp-idf/test/u_espidf_ppp_test.c +++ b/port/platform/esp-idf/test/u_espidf_ppp_test.c @@ -73,6 +73,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_network.h" // In order to provide a comms #include "u_network_test_shared_cfg.h" // path for the socket @@ -284,12 +286,12 @@ static size_t sendTcp(int32_t sock, const char *pData, size_t sizeBytes) { int32_t x; size_t sentSizeBytes = 0; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; U_TEST_PRINT_LINE("sending %d byte(s) of TCP data...", sizeBytes); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((sentSizeBytes < sizeBytes) && - !uPortTickTimeExpiredMs(startTimeMs, 10000)) { + !uTimeoutExpiredSeconds(timeoutStart, 10)) { x = send(sock, (const void *) pData, sizeBytes - sentSizeBytes, 0); if (x > 0) { sentSizeBytes += x; @@ -389,7 +391,7 @@ U_PORT_TEST_FUNCTION("[espidfSock]", "espidfSockTcp") int32_t x; size_t sizeBytes = 0; size_t offset; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; // Whatever called us likely initialised the // port so deinitialise it here to obtain the @@ -457,7 +459,7 @@ U_PORT_TEST_FUNCTION("[espidfSock]", "espidfSockTcp") // Throw random sized segments up... offset = 0; x = 0; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while (offset < gTestConfig.bytesToSend) { sizeBytes = (rand() % U_SOCK_TEST_MAX_TCP_READ_WRITE_SIZE) + 1; sizeBytes = fix(sizeBytes, U_SOCK_TEST_MAX_TCP_READ_WRITE_SIZE); @@ -487,7 +489,7 @@ U_PORT_TEST_FUNCTION("[espidfSock]", "espidfSockTcp") " process took %d milliseconds.", gTestConfig.packetsReceived, gTestConfig.bytesReceived, - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(timeoutStart)); // Check that we reassembled everything correctly U_PORT_TEST_ASSERT(checkAgainstSentData(gSendData, diff --git a/port/platform/linux/src/u_port_ppp.c b/port/platform/linux/src/u_port_ppp.c new file mode 100644 index 00000000..e7d4ca77 --- /dev/null +++ b/port/platform/linux/src/u_port_ppp.c @@ -0,0 +1,989 @@ +/* + * Copyright 2019-2024 u-blox + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** @file + * @brief This file allows a connection to be made from pppd to a + * PPP interface inside ubxlib. Such a PPP interface is provided by + * a cellular module. + * + * See port/platform/linux/README.md for a description of how it works. + * + * It is only compiled if U_CFG_PPP_ENABLE is defined. + */ + +#ifdef U_CFG_OVERRIDE +# include "u_cfg_override.h" // For a customer's configuration override +#endif +#include "stddef.h" // NULL, size_t etc. +#include "stdint.h" // int32_t etc. +#include "stdbool.h" +#include "string.h" // strlen(), memset() + +#include "pthread.h" // threadId +#include "sys/socket.h" +#include "netinet/in.h" +#include "arpa/inet.h" +#include "unistd.h" +#include "errno.h" +#include "sys/types.h" + +#include "u_cfg_os_platform_specific.h" // U_CFG_OS_PRIORITY_MAX +#include "u_cfg_sw.h" +#include "u_error_common.h" + +#include "u_timeout.h" + +#include "u_linked_list.h" + +#include "u_sock.h" + +#include "u_port.h" +#include "u_port_os.h" +#include "u_port_debug.h" +#include "u_port_heap.h" +#include "u_port_ppp.h" +#include "u_port_ppp_private.h" + +/* ---------------------------------------------------------------- + * COMPILE-TIME MACROS + * -------------------------------------------------------------- */ + +#ifndef U_PORT_PPP_LOCAL_DEVICE_NAME +/** The name of the device that is the PPP entity at the bottom + * of the IP stack on this MCU, i.e. the Linux-end of the PPP + * link that pppd will connect to. + */ +# define U_PORT_PPP_LOCAL_DEVICE_NAME "127.0.0.1:5000" +#endif + +#ifndef U_PORT_PPP_CONNECT_TIMEOUT_SECONDS +/** How long to wait for PPP to connect. + */ +# define U_PORT_PPP_CONNECT_TIMEOUT_SECONDS 15 +#endif + +#ifndef U_PORT_PPP_DISCONNECT_TIMEOUT_SECONDS +/** How long to wait for PPP to disconnect. + */ +# define U_PORT_PPP_DISCONNECT_TIMEOUT_SECONDS 10 +#endif + +#ifndef U_PORT_PPP_TX_LOOP_GUARD +/** How many times around the transmit loop to allow if stuff + * won't send. + */ +# define U_PORT_PPP_TX_LOOP_GUARD 1000 +#endif + +#ifndef U_PORT_PPP_TX_LOOP_DELAY_MS +/** How long to wait between transmit attempts in milliseconds + * when the data to transmit won't go all at once. + */ +# define U_PORT_PPP_TX_LOOP_DELAY_MS 10 +#endif + +#ifndef U_PORT_PPP_SOCKET_TASK_STACK_SIZE_BYTES +/** The stack size for the callback that is listening for + * the pppd connection locally and shipping data out from it. + */ +# define U_PORT_PPP_SOCKET_TASK_STACK_SIZE_BYTES (1024 * 5) +#endif + +#ifndef U_PORT_PPP_SOCKET_TASK_PRIORITY +/** The priority of the task that is listening for the pppd + * connection locally receiving data fro it, should + * be relatively high (e.g. U_CFG_OS_PRIORITY_MAX - 5, which is + * the same as the AT Client URC task). + */ +# define U_PORT_PPP_SOCKET_TASK_PRIORITY (U_CFG_OS_PRIORITY_MAX - 5) +#endif + +#ifndef U_PORT_PPP_BUFFER_CACHE_SIZE +/** pppd has no way to tell this code that the link is up, + * so we keep a small cache of the communications in both + * directions that we can monitor to see what's going on. + * IMPORTANT: this must be at least as big as + * gPppEncapsulatedIpcpPacketStart[], gLcpTerminateReqPacket[], + * gLcpTerminateAckPacket[] and gConnectionTerminatedString[] for + * this code to work. + */ +# define U_PORT_PPP_BUFFER_CACHE_SIZE 64 +#endif + +/* ---------------------------------------------------------------- + * TYPES + * -------------------------------------------------------------- */ + +#ifdef U_CFG_PPP_ENABLE + +/** A structure to contain a buffer, used for monitoring + * communications between the PPP entities. + */ +typedef struct { + char buffer[U_PORT_PPP_BUFFER_CACHE_SIZE]; + size_t size; +} uPortPppBufferCache_t; + +/** Define a PPP interface. + */ +typedef struct { + void *pDevHandle; + int listeningSocket; // int type since this is a native socket + int connectedSocket; + uPortTaskHandle_t socketTaskHandle; + uPortMutexHandle_t socketTaskMutex; + bool socketTaskExit; + uPortPppBufferCache_t fromModuleBufferCache; + uPortPppBufferCache_t fromPppdBufferCache; + bool dataTransferSuspended; + uPortPppConnectCallback_t *pConnectCallback; + uPortPppDisconnectCallback_t *pDisconnectCallback; + uPortPppTransmitCallback_t *pTransmitCallback; + bool pppRunning; + bool ipConnected; + bool waitingForModuleDisconnect; +} uPortPppInterface_t; + +/** Structure to hold the name of the MCU-end PPP device; + * used to ensure thread-safety between calls to + * uPortPppSetLocalDeviceName() and uPortPppAttach(). + */ +typedef struct { + char name[U_PORT_PPP_LOCAL_DEVICE_NAME_LENGTH + 1]; // +1 for terminator + pthread_t threadId; +} uPortPppLocalDevice_t; + +#endif // #ifdef U_CFG_PPP_ENABLE + +/* ---------------------------------------------------------------- + * VARIABLES + * -------------------------------------------------------------- */ + +#ifdef U_CFG_PPP_ENABLE + +/** Root of the linked list of PPP entities. + */ +static uLinkedList_t *gpPppInterfaceList = NULL; /**< A list of uPortPppInterface_t. */ + +/** Root of linked list of local device names. + */ +static uLinkedList_t *gpPppLocalDeviceNameList = NULL; /**< A list of uPortPppLocalDevice_t. */ + +/** Mutex to protect the linked list of PPP entities. + */ +static uPortMutexHandle_t gMutex = NULL; + +/** The bytes that represent the start of a PPP-encapsulated + * IPCP packet. + */ +static const char gPppEncapsulatedIpcpPacketStart[] = {0x7e, 0x80, 0x21}; + +/** The bytes that represent a normal LCP Terminate-Req. + */ +static const char gLcpTerminateReqPacket[] = {0x7e, 0xff, 0x7d, 0x23, 0xc0, 0x21, 0x7d, 0x25, + 0x7d, 0x22, 0x7d, 0x20, 0x7d, 0x30, 0x55, 0x73, + 0x65, 0x72, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x53, 0x33, 0x7e + }; + +/** The bytes that represent an LCP Terminate-Ack for + * gLcpTerminateReqPacket[]. + */ +static const char gLcpTerminateAckPacket[] = {0x7e, 0xff, 0x7d, 0x23, 0xc0, 0x21, 0x7d, 0x26, + 0x7d, 0x22, 0x7d, 0x20, 0x7d, 0x24, 0x94, 0x7d, + 0x2d, 0x7e + }; +/** The string that the cellular module sends in response + * to an gLcpTerminateReqPacket[]. + */ +static const char gConnectionTerminatedString[] = {'\r', '\n', 'N', 'O', ' ', 'C', 'A', 'R', + 'R', 'I', 'E', 'R', '\r', '\n' + }; + +#endif // #ifdef U_CFG_PPP_ENABLE + +/* ---------------------------------------------------------------- + * STATIC FUNCTIONS + * -------------------------------------------------------------- */ + +#ifdef U_CFG_PPP_ENABLE + +// Find the local device name set by the given thread. +static uPortPppLocalDevice_t *pFindLocalDeviceName(pthread_t threadId) +{ + uPortPppLocalDevice_t *pLocalDevice = NULL; + uLinkedList_t *pList = gpPppLocalDeviceNameList; + + while ((pList != NULL) && (pLocalDevice == NULL)) { + if (((uPortPppLocalDevice_t *) pList->p)->threadId == threadId) { + pLocalDevice = (uPortPppLocalDevice_t *) pList->p; + } else { + pList = pList->pNext; + } + } + + return pLocalDevice; +} + +// Find the PPP interface structure for the given handle. +static uPortPppInterface_t *pFindPppInterface(void *pDevHandle) +{ + uPortPppInterface_t *pPppInterface = NULL; + uLinkedList_t *pList = gpPppInterfaceList; + + while ((pList != NULL) && (pPppInterface == NULL)) { + if (((uPortPppInterface_t *) pList->p)->pDevHandle == pDevHandle) { + pPppInterface = (uPortPppInterface_t *) pList->p; + } else { + pList = pList->pNext; + } + } + + return pPppInterface; +} + +// Add the new pBuffer contents to pBufferCache and then determine +// if the buffer cache contains pBufferWanted. If it does not but +// there is a partial match then the contents of pBufferCache are +// moved down to remove the uninteresting bits, else pBufferCache +// is cleared. +// IMPORTANT: since this removes the cached buffer contents based +// on whether there is a match or not it will ONLY WORK if a given +// cache buffer is searched for one set of wanted stuff at a time. +static bool bufferContains(uPortPppBufferCache_t *pBufferCache, + const char *pBuffer, size_t size, + const char *pBufferWanted, size_t bufferLength) +{ + size_t count = 0; + size_t startOffset = 0; + size_t x; + + if (pBufferCache != NULL) { + if (pBuffer != NULL) { + // Copy as much of the new data as we can into the buffer cache + if (size > sizeof(pBufferCache->buffer) - pBufferCache->size) { + size = sizeof(pBufferCache->buffer) - pBufferCache->size; + } + memcpy(pBufferCache->buffer + pBufferCache->size, pBuffer, size); + pBufferCache->size += size; + } + if (pBufferWanted != NULL) { + // Check for a match + for (x = 0; (x < pBufferCache->size) && (count < bufferLength); x++) { + if (pBufferCache->buffer[x] == *(pBufferWanted + count)) { + count++; + } else { + count = 0; + if (pBufferCache->buffer[x] == *pBufferWanted) { + count = 1; + } else { + startOffset = x; + } + } + } + if ((count > 0) && (count < bufferLength)) { + // Partial match, move the contents of the cached buffer + // down to remove the uninteresting bits + x = pBufferCache->size - startOffset; + memmove(pBufferCache->buffer, pBufferCache->buffer + startOffset, x); + pBufferCache->size = x; + } else { + // Either a complete match or no match, clear the cache + pBufferCache->size = 0; + } + } + } + + return (count == bufferLength); +} + +// Do a select on a socket with a timeout in milliseconds. +static bool socketSelect(int socket, int32_t timeoutMs) +{ + fd_set set; + struct timeval timeout = {0}; + + FD_ZERO(&set); + FD_SET(socket, &set); + timeout.tv_usec = timeoutMs * 1000; + return (select(socket + 1, &set, NULL, NULL, &timeout) > 0); +} + +// Terminate a PPP link. +static void terminateLink(uPortPppInterface_t *pPppInterface) +{ + char buffer[128]; + int32_t dataSize; + int32_t sent; + const char *pData; + size_t retryCount = 0; + uTimeoutStart_t timeoutStart; + bool pppdConnected = (pPppInterface->connectedSocket >= 0); + + // First, suspend normal data transfer between the entities + pPppInterface->dataTransferSuspended = true; + + // Start by terminating the cellular side + if (pPppInterface->pTransmitCallback != NULL) { + pPppInterface->waitingForModuleDisconnect = true; + pData = gLcpTerminateReqPacket; + dataSize = sizeof(gLcpTerminateReqPacket); + while ((dataSize > 0) && (retryCount < U_PORT_PPP_TX_LOOP_GUARD)) { + sent = pPppInterface->pTransmitCallback(pPppInterface->pDevHandle, + pData, dataSize); + if (sent > 0) { + dataSize -= sent; + pData += sent; + } else { + retryCount++; + uPortTaskBlock(U_PORT_PPP_TX_LOOP_DELAY_MS); + } + } + } + + if (pPppInterface->connectedSocket >= 0) { + // While we are waiting for a response (which will be + // picked up by moduleDataCallback() by setting + // pPppInterface->waitingForModuleDisconnect to false), + // terminate pppd on the MCU-side + pData = gLcpTerminateReqPacket; + dataSize = sizeof(gLcpTerminateReqPacket); + retryCount = 0; + while ((dataSize > 0) && (retryCount < U_PORT_PPP_TX_LOOP_GUARD)) { + // Note: send() is like write() but, when passed MSG_NOSIGNAL, + // it returns an error if the far end has closed the socket, + // rather than causing Linux to throw a signal 13 (SIGPIPE) + // exception which the application would have to handle + sent = send(pPppInterface->connectedSocket, pData, dataSize, MSG_NOSIGNAL); + if (sent > 0) { + dataSize -= sent; + pData += sent; + } else { + retryCount++; + uPortTaskBlock(U_PORT_PPP_TX_LOOP_DELAY_MS); + } + } + } + + // Wait for the response from pppd on the MCU side, and + // from the cellular side (via the waitingForModuleDisconnect flag) + timeoutStart = uTimeoutStart(); + while ((pPppInterface->waitingForModuleDisconnect || pppdConnected) && + !uTimeoutExpiredSeconds(timeoutStart, + U_PORT_PPP_CONNECT_TIMEOUT_SECONDS)) { + // Wait for data to arrive on the connected socket + if (pppdConnected && + socketSelect(pPppInterface->connectedSocket, U_CFG_OS_YIELD_MS)) { + // Read the data + dataSize = read(pPppInterface->connectedSocket, buffer, sizeof(buffer)); + if ((dataSize > 0) && + bufferContains(&(pPppInterface->fromPppdBufferCache), + buffer, dataSize, + gLcpTerminateAckPacket, + sizeof(gLcpTerminateAckPacket))) { + pppdConnected = false; + } + } + uPortTaskBlock(250); + } + + if (!pppdConnected && !pPppInterface->waitingForModuleDisconnect) { + pPppInterface->ipConnected = false; + pPppInterface->pppRunning = false; + } + + // Give up waiting now whatever + pPppInterface->waitingForModuleDisconnect = false; +} + +// Callback for when data is received from the cellular side. +static void moduleDataCallback(void *pDevHandle, const char *pData, + size_t dataSize, void *pCallbackParam) +{ + uPortPppInterface_t *pPppInterface = (uPortPppInterface_t *) pCallbackParam; + int32_t x = dataSize; + const char *pTmp = pData; + int32_t written = 0; + size_t retryCount = 0; + + // Write the data to the connected socket, if there is one + while (!pPppInterface->dataTransferSuspended && (x > 0) && + (written >= 0) && (retryCount < U_PORT_PPP_TX_LOOP_GUARD) && + (pPppInterface->connectedSocket >= 0)) { + written = send(pPppInterface->connectedSocket, pTmp, x, MSG_NOSIGNAL); + if (written > 0) { + x -= written; + pTmp += written; + } else { + retryCount++; + uPortTaskBlock(U_PORT_PPP_TX_LOOP_DELAY_MS); + } + } + // Note: the check below is performed even when data transfer + // is suspended as we may still be expecting a disconnect + if ((dataSize > 0) && pPppInterface->waitingForModuleDisconnect) { + if (bufferContains(&(pPppInterface->fromModuleBufferCache), + pData, dataSize, gConnectionTerminatedString, + sizeof(gConnectionTerminatedString))) { + pPppInterface->waitingForModuleDisconnect = false; + } + } +} + +// Task to listen on a socket for a pppd connection and pull data from it. +static void socketTask(void *pParameters) +{ + uPortPppInterface_t *pPppInterface = (uPortPppInterface_t *) pParameters; + char buffer[1024]; // Can be this big because we have allowed enough room on the stack + char *pData; + int32_t x; + int32_t dataSize; + int32_t written; + size_t retryCount; + + // Lock the task mutex to indicate that we're running + U_PORT_MUTEX_LOCK(pPppInterface->socketTaskMutex); + + // "1" here for just one connection at a time + listen(pPppInterface->listeningSocket, 1); + + while (!pPppInterface->socketTaskExit) { + // Wait for a connection using select with a timeout, don't block + if (socketSelect(pPppInterface->listeningSocket, U_CFG_OS_YIELD_MS)) { + // Got some data on the listening socket, accept the connection + pPppInterface->connectedSocket = accept(pPppInterface->listeningSocket, NULL, NULL); + if (pPppInterface->connectedSocket >= 0) { + uPortLog("U_PORT_PPP: pppd has connected to socket.\n"); + while ((pPppInterface->connectedSocket >= 0) && + !pPppInterface->socketTaskExit) { + // Wait for data to arrive on the connected socket + if (socketSelect(pPppInterface->connectedSocket, U_CFG_OS_YIELD_MS) && + !pPppInterface->dataTransferSuspended) { + // Read the data + dataSize = read(pPppInterface->connectedSocket, buffer, sizeof(buffer)); + if (dataSize > 0) { + if ((pPppInterface->pTransmitCallback != NULL) && + !pPppInterface->dataTransferSuspended) { + // Write the data to the cellular module + retryCount = 0; + pData = buffer; + x = dataSize; + written = 0; + while (pPppInterface->pppRunning && + !pPppInterface->dataTransferSuspended && + (x > 0) && (written >= 0) && (retryCount < U_PORT_PPP_TX_LOOP_GUARD)) { + written = pPppInterface->pTransmitCallback(pPppInterface->pDevHandle, pData, x); + if (written > 0) { + x -= written; + pData += written; + } else { + retryCount++; + uPortTaskBlock(U_PORT_PPP_TX_LOOP_DELAY_MS); + } + } + if ((dataSize > 0) && !pPppInterface->ipConnected) { + // If the connection is not already flagged as IP-connected, + // check the buffer of data for the start of an encapsulated + // IPCP frame, which indicates that we are done with the LCP + // part, the only part that could fail: we are connected. + pPppInterface->ipConnected = bufferContains(&(pPppInterface->fromPppdBufferCache), + buffer, dataSize, + gPppEncapsulatedIpcpPacketStart, + sizeof(gPppEncapsulatedIpcpPacketStart)); + } + } + } else if (dataSize == 0) { + // If select() indicated there was data and yet + // reading the data gives us nothing then this + // is the socket telling us that the far-end has + // closed it + close(pPppInterface->connectedSocket); + pPppInterface->connectedSocket = -1; + } + } + } + if (pPppInterface->socketTaskExit) { + // If we have been told to exit then close + // the connected socket on the way out + close(pPppInterface->connectedSocket); + pPppInterface->connectedSocket = -1; + uPortLog("U_PORT_PPP: pppd has been disconnected from socket.\n"); + } else { + uPortLog("U_PORT_PPP: pppd has disconnected from socket.\n"); + } + } + } else { + uPortTaskBlock(250); + } + } + close(pPppInterface->listeningSocket); + uPortLog("U_PORT_PPP: no longer listening for pppd on socket.\n"); + + // Unlock the task mutex to indicate we're done + U_PORT_MUTEX_UNLOCK(pPppInterface->socketTaskMutex); + + uPortTaskDelete(NULL); +} + +// Start a listening task on the address given. +static int32_t startSocketTask(uPortPppInterface_t *pPppInterface, + const char *pAddressString) +{ + int32_t errorCode; + struct sockaddr_in socketAddress = {0}; + uSockAddress_t sockUbxlib; + int reuse = 1; + + errorCode = uSockStringToAddress(pAddressString, &sockUbxlib); + if (errorCode == 0) { + errorCode = (int32_t) U_ERROR_COMMON_NO_MEMORY; + // Create a listening socket and bind the given address to it + pPppInterface->connectedSocket = -1; + pPppInterface->listeningSocket = socket(AF_INET, SOCK_STREAM, 0); + if (pPppInterface->listeningSocket >= 0) { + // Set SO_REUSEADDR (and, in some cases SO_REUSEPORT) so that we + // can re-bind to the socket when we come back into here + if (setsockopt(pPppInterface->listeningSocket, SOL_SOCKET, SO_REUSEADDR, + (const char *) &reuse, sizeof(reuse)) < 0) { + // This is not fatal, it just means that the OS might prevent + // us binding to the same address again if we come back into + // here too quickly + uPortLog("U_PORT_PPP: *** WARNING *** setting socket option SO_REUSEADDR" + " returned errno %d.\n", errno); + } +#ifdef SO_REUSEPORT + if (setsockopt(pPppInterface->listeningSocket, SOL_SOCKET, SO_REUSEPORT, + (const char *) &reuse, sizeof(reuse)) < 0) { + // This is not fatal, it just means that the OS might prevent + // us binding to the same address again if we come back into + // here too quickly + uPortLog("U_PORT_PPP: *** WARNING *** setting socket option SO_REUSEPORT" + " returned errno %d.\n", errno); + } +#endif + errorCode = (int32_t) U_ERROR_COMMON_INVALID_ADDRESS; + socketAddress.sin_family = AF_INET; + if (sockUbxlib.ipAddress.type == U_SOCK_ADDRESS_TYPE_V4) { + socketAddress.sin_addr.s_addr = htonl(sockUbxlib.ipAddress.address.ipv4); + } else { + // TODO: find out how this copy should work for an IPV6 address + errorCode = (int32_t) U_ERROR_COMMON_NOT_SUPPORTED; + } + socketAddress.sin_port = htons(sockUbxlib.port); + if (bind(pPppInterface->listeningSocket, + (struct sockaddr *) &socketAddress, + sizeof(socketAddress)) == 0) { + // Now kick off a task that will listen on that socket + // and read data from anything that attaches to it + errorCode = uPortMutexCreate(&(pPppInterface->socketTaskMutex)); + if (errorCode == 0) { + errorCode = uPortTaskCreate(socketTask, + "pppSocketTask", + U_PORT_PPP_SOCKET_TASK_STACK_SIZE_BYTES, + pPppInterface, + U_PORT_PPP_SOCKET_TASK_PRIORITY, + &(pPppInterface->socketTaskHandle)); + if (errorCode == 0) { + uPortLog("U_PORT_PPP: listening for pppd on socket %s.\n", pAddressString); + } else { + uPortMutexDelete(pPppInterface->socketTaskMutex); + close(pPppInterface->listeningSocket); + } + } else { + close(pPppInterface->listeningSocket); + } + } else { + uPortLog("U_PORT_PPP: *** WARNING *** bind() to \"%s\" returned errno %d.\n", + pAddressString, errno); + } + } + } + + return errorCode; +} + +// Stop the listening task. +static void stopSocketTask(uPortPppInterface_t *pPppInterface) +{ + // Set the flag to make the socket task exit + pPppInterface->socketTaskExit = true; + // Wait for the task to exit + U_PORT_MUTEX_LOCK(pPppInterface->socketTaskMutex); + U_PORT_MUTEX_UNLOCK(pPppInterface->socketTaskMutex); + // Free the mutex + uPortMutexDelete(pPppInterface->socketTaskMutex); + pPppInterface->socketTaskMutex = NULL; +} + +// Disconnect a PPP interface. +static void pppDisconnect(uPortPppInterface_t *pPppInterface) +{ + bool wasRunning = false; + + if (pPppInterface != NULL) { + if (pPppInterface->pppRunning) { + wasRunning = true; + // We don't have control over pppd, can't tell it to + // disconnect the PPP link, which is kinda vital, + // so instead we take control of the link and terminate + // both sides ourselves + terminateLink(pPppInterface); + } + if (pPppInterface->pDisconnectCallback != NULL) { + pPppInterface->pDisconnectCallback(pPppInterface->pDevHandle, + pPppInterface->pppRunning); + } + pPppInterface->pppRunning = false; + if (wasRunning) { + uPortLog("U_PORT_PPP: socket disconnected from module (but pppd still connected to socket).\n"); + } + } +} + +#endif // #ifdef U_CFG_PPP_ENABLE + +/* ---------------------------------------------------------------- + * PUBLIC FUNCTIONS THAT ARE PRIVATE TO THIS PORT LAYER + * -------------------------------------------------------------- */ + +#ifdef U_CFG_PPP_ENABLE + +// Initialise the PPP stuff. +int32_t uPortPppPrivateInit() +{ + int32_t errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; + + if (gMutex == NULL) { + errorCode = uPortMutexCreate(&gMutex); + } + + return errorCode; +} + +// Deinitialise the PPP stuff. +void uPortPppPrivateDeinit() +{ + uLinkedList_t *pListNext; + uPortPppInterface_t *pPppInterface; + uPortPppLocalDevice_t *pLocalDevice; + + if (gMutex != NULL) { + + U_PORT_MUTEX_LOCK(gMutex); + + // Remove any local device names + while (gpPppLocalDeviceNameList != NULL) { + pLocalDevice = (uPortPppLocalDevice_t *) (gpPppLocalDeviceNameList->p); + uPortFree(pLocalDevice); + uLinkedListRemove(&gpPppLocalDeviceNameList, pLocalDevice); + } + + // Now remove all PPP interfaces + while (gpPppInterfaceList != NULL) { + pPppInterface = (uPortPppInterface_t *) gpPppInterfaceList->p; + pListNext = gpPppInterfaceList->pNext; + uLinkedListRemove(&gpPppInterfaceList, pPppInterface); + // Make sure we don't accidentally try to call the + // transmit or down callbacks since the device handle + // will have been destroyed by now + pPppInterface->pTransmitCallback = NULL; + pPppInterface->pDisconnectCallback = NULL; + pppDisconnect(pPppInterface); + stopSocketTask(pPppInterface); + uPortFree(pPppInterface); + gpPppInterfaceList = pListNext; + } + + U_PORT_MUTEX_UNLOCK(gMutex); + uPortMutexDelete(gMutex); + gMutex = NULL; + } +} + +#else + +// Initialise the PPP stuff. +int32_t uPortPppPrivateInit() +{ + return (int32_t) U_ERROR_COMMON_SUCCESS; +} + +// Deinitialise the PPP stuff. +void uPortPppPrivateDeinit() +{ +} + +#endif // #ifdef U_CFG_PPP_ENABLE + +/* ---------------------------------------------------------------- + * PUBLIC FUNCTIONS + * -------------------------------------------------------------- */ + +#ifdef U_CFG_PPP_ENABLE + +// Set the name of the device that is the MCU-end PPP entity. +int32_t uPortPppSetLocalDeviceName(const char *pDevice) +{ + int32_t errorCode = (int32_t) U_ERROR_COMMON_INVALID_PARAMETER; + uPortPppLocalDevice_t *pLocalDevice; + pthread_t threadId; + uPortPppLocalDevice_t *pTmp; + + if ((pDevice != NULL) && (strlen(pDevice) < sizeof(pLocalDevice->name))) { + errorCode = (int32_t) U_ERROR_COMMON_NO_MEMORY; + pLocalDevice = pUPortMalloc(sizeof(uPortPppLocalDevice_t)); + if (pLocalDevice != NULL) { + + U_PORT_MUTEX_LOCK(gMutex); + + // Remove any existing local device name for this + // thread ID + threadId = pthread_self(); + while ((pTmp = pFindLocalDeviceName(threadId)) != NULL) { + uPortFree(pTmp); + uLinkedListRemove(&gpPppLocalDeviceNameList, pTmp); + } + // Add the new one + strncpy(pLocalDevice->name, pDevice, sizeof(pLocalDevice->name)); + pLocalDevice->threadId = threadId; + if (uLinkedListAdd(&gpPppLocalDeviceNameList, (void *) pLocalDevice)) { + errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; + } else { + uPortFree(pLocalDevice); + } + + U_PORT_MUTEX_UNLOCK(gMutex); + } + } + + return errorCode; +} + +// Attach a PPP interface to pppd. +int32_t uPortPppAttach(void *pDevHandle, + uPortPppConnectCallback_t *pConnectCallback, + uPortPppDisconnectCallback_t *pDisconnectCallback, + uPortPppTransmitCallback_t *pTransmitCallback) +{ + int32_t errorCode = (int32_t) U_ERROR_COMMON_NOT_INITIALISED; + uPortPppInterface_t *pPppInterface; + uPortPppLocalDevice_t *pLocalDevice; + const char *pName = U_PORT_PPP_LOCAL_DEVICE_NAME; + + if (gMutex != NULL) { + + U_PORT_MUTEX_LOCK(gMutex); + + errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; + pPppInterface = pFindPppInterface(pDevHandle); + if (pPppInterface == NULL) { + errorCode = (int32_t) U_ERROR_COMMON_NO_MEMORY; + pPppInterface = (uPortPppInterface_t *) pUPortMalloc(sizeof(*pPppInterface)); + if (pPppInterface != NULL) { + memset(pPppInterface, 0, sizeof(*pPppInterface)); + // Get the pppd-end device name and start a task + // which will open a socket listening on it and + // receive data sent by it + pLocalDevice = pFindLocalDeviceName(pthread_self()); + if (pLocalDevice != NULL) { + pName = pLocalDevice->name; + } + errorCode = startSocketTask(pPppInterface, pName); + if (errorCode == 0) { + errorCode = (int32_t) U_ERROR_COMMON_NO_MEMORY; + pPppInterface->pDevHandle = pDevHandle; + pPppInterface->pConnectCallback = pConnectCallback; + pPppInterface->pDisconnectCallback = pDisconnectCallback; + pPppInterface->pTransmitCallback = pTransmitCallback; + if (uLinkedListAdd(&gpPppInterfaceList, pPppInterface)) { + // Everything else is done in uPortPppConnect() + errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; + } else { + stopSocketTask(pPppInterface); + uPortFree(pPppInterface); + } + } else { + uPortFree(pPppInterface); + } + } + } + + if (errorCode < 0) { + uPortLog("U_PORT_PPP: *** WARNING *** unable to attach PPP (%d).\n", errorCode); + } + + U_PORT_MUTEX_UNLOCK(gMutex); + } + + return errorCode; +} + +// Connect a PPP interface. +int32_t uPortPppConnect(void *pDevHandle, + uSockIpAddress_t *pIpAddress, + uSockIpAddress_t *pDnsIpAddressPrimary, + uSockIpAddress_t *pDnsIpAddressSecondary, + const char *pUsername, + const char *pPassword, + uPortPppAuthenticationMode_t authenticationMode) +{ + int32_t errorCode = (int32_t) U_ERROR_COMMON_NOT_INITIALISED; + uPortPppInterface_t *pPppInterface; + uTimeoutStart_t timeoutStart; + + // There is no way for this code to provide the authentication + // parameters back to pppd, the user has to set them when + // pppd is started + (void) pUsername; + (void) pPassword; + (void) authenticationMode; + + // PPP negotiation will set these + (void) pIpAddress; + (void) pDnsIpAddressPrimary; + (void) pDnsIpAddressSecondary; + + if (gMutex != NULL) { + + U_PORT_MUTEX_LOCK(gMutex); + + errorCode = (int32_t) U_ERROR_COMMON_NOT_FOUND; + pPppInterface = pFindPppInterface(pDevHandle); + if (pPppInterface != NULL) { + // In case we were previously connected and + // then disconnected + pPppInterface->dataTransferSuspended = false; + pPppInterface->ipConnected = false; + errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; + if (pPppInterface->pConnectCallback != NULL) { + errorCode = pPppInterface->pConnectCallback(pDevHandle, + moduleDataCallback, + pPppInterface, NULL, + U_PORT_PPP_RECEIVE_BUFFER_BYTES, + NULL); + } + if (errorCode == 0) { + pPppInterface->pppRunning = true; + // Use a nice specific error message here, most likely to point + // people at a PPP kinda problem + errorCode = (int32_t) U_ERROR_COMMON_PROTOCOL_ERROR; + // Wait for the IP connection to succeed + timeoutStart = uTimeoutStart(); + while ((!pPppInterface->ipConnected) && + !uTimeoutExpiredSeconds(timeoutStart, + U_PORT_PPP_CONNECT_TIMEOUT_SECONDS)) { + uPortTaskBlock(250); + } + if (pPppInterface->ipConnected) { + errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; + uPortLog("U_PORT_PPP: socket connected to module.\n"); + } + if ((errorCode != 0) && + (pPppInterface->pDisconnectCallback != NULL)) { + // Clean up on error + pPppInterface->pDisconnectCallback(pPppInterface->pDevHandle, false); + pPppInterface->pppRunning = false; + } + } + } + + U_PORT_MUTEX_UNLOCK(gMutex); + } + + return errorCode; +} + +// Reconnect a PPP interface. +int32_t uPortPppReconnect(void *pDevHandle, + uSockIpAddress_t *pIpAddress) +{ + int32_t errorCode = (int32_t) U_ERROR_COMMON_NOT_INITIALISED; + uPortPppInterface_t *pPppInterface; + + (void) pIpAddress; + + if (gMutex != NULL) { + + U_PORT_MUTEX_LOCK(gMutex); + + errorCode = (int32_t) U_ERROR_COMMON_NOT_FOUND; + pPppInterface = pFindPppInterface(pDevHandle); + if ((pPppInterface != NULL) && (pPppInterface->pppRunning)) { + errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; + if (pPppInterface->pConnectCallback != NULL) { + errorCode = pPppInterface->pConnectCallback(pDevHandle, + moduleDataCallback, + pPppInterface, NULL, + U_PORT_PPP_RECEIVE_BUFFER_BYTES, + NULL); + } + } + + U_PORT_MUTEX_UNLOCK(gMutex); + } + + return errorCode; +} + +// Disconnect a PPP interface. +int32_t uPortPppDisconnect(void *pDevHandle) +{ + int32_t errorCode = (int32_t) U_ERROR_COMMON_NOT_INITIALISED; + uPortPppInterface_t *pPppInterface; + + if (gMutex != NULL) { + + U_PORT_MUTEX_LOCK(gMutex); + + errorCode = (int32_t) U_ERROR_COMMON_NOT_FOUND; + pPppInterface = pFindPppInterface(pDevHandle); + if (pPppInterface != NULL) { + pppDisconnect(pPppInterface); + errorCode = (int32_t) U_ERROR_COMMON_SUCCESS; + } + + U_PORT_MUTEX_UNLOCK(gMutex); + } + + return errorCode; +} + +// Detach a PPP interface from pppd. +int32_t uPortPppDetach(void *pDevHandle) +{ + uPortPppInterface_t *pPppInterface; + + if (gMutex != NULL) { + + U_PORT_MUTEX_LOCK(gMutex); + + pPppInterface = pFindPppInterface(pDevHandle); + if (pPppInterface != NULL) { + uLinkedListRemove(&gpPppInterfaceList, pPppInterface); + pppDisconnect(pPppInterface); + stopSocketTask(pPppInterface); + uPortFree(pPppInterface); + } + + U_PORT_MUTEX_UNLOCK(gMutex); + } + + return (int32_t) U_ERROR_COMMON_SUCCESS; +} + +#endif // #ifdef U_CFG_PPP_ENABLE + +// End of file diff --git a/port/platform/linux/test/u_linux_ppp_test.c b/port/platform/linux/test/u_linux_ppp_test.c new file mode 100644 index 00000000..4df5c96e --- /dev/null +++ b/port/platform/linux/test/u_linux_ppp_test.c @@ -0,0 +1,582 @@ +/* + * Copyright 2019-2024 u-blox + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Only #includes of u_* and the C standard library are allowed here, + * no platform stuff and no OS stuff. Anything required from + * the platform/OS must be brought in through u_port* to maintain + * portability. + */ + +/** @file + * @brief Tests of Linux sockets using pppd connected to a cellular + * module via ubxlib. These tests should pass on Linux when there is a + * cellular module connected. These tests use the network API and the + * test configuration information from the network API and sockets API + & to provide the communication path. + * + * The tests are only compiled if U_CFG_PPP_ENABLE is defined. + * + * IMPORTANT: see notes in u_cfg_test_platform_specific.h for the + * naming rules that must be followed when using the U_PORT_TEST_FUNCTION() + * macro. + */ + +#ifdef U_CFG_OVERRIDE +# include "u_cfg_override.h" // For a customer's configuration override +#endif + +#ifdef U_CFG_PPP_ENABLE + +#include "stddef.h" // NULL, size_t etc. +#include "stdlib.h" // rand(), snprintf() +#include "stdint.h" // int32_t etc. +#include "stdbool.h" +#include "string.h" // strlen() +#include "unistd.h" +#include "sys/socket.h" +#include "netdb.h" // struct addrinfo +#include "arpa/inet.h" +#include "errno.h" +#include "fcntl.h" +#include "net/if.h" // struct ifreq + +#include "u_compiler.h" // U_WEAK + +#include "u_cfg_sw.h" +#include "u_cfg_app_platform_specific.h" +#include "u_cfg_test_platform_specific.h" +#include "u_cfg_os_platform_specific.h" + +#include "u_error_common.h" + +#include "u_port_clib_platform_specific.h" /* struct timeval in some cases. */ +#include "u_port.h" +#include "u_port_os.h" +#include "u_port_heap.h" +#include "u_port_debug.h" +#include "u_port_event_queue.h" + +#include "u_test_util_resource_check.h" + +#include "u_timeout.h" + +#include "u_network.h" // In order to provide a comms +#include "u_network_test_shared_cfg.h" // path for the socket + +#include "u_sock_test_shared_cfg.h" + +// These for uCellPrivateModule_t +#include "u_at_client.h" +#include "u_cell_module_type.h" +#include "u_cell.h" +#include "u_cell_file.h" +#include "u_cell_net.h" // Required by u_cell_private.h +#include "u_cell_private.h" // So that we can get at some innards + +/* ---------------------------------------------------------------- + * COMPILE-TIME MACROS + * -------------------------------------------------------------- */ + +/** The string to put at the start of all prints from this test. + */ +#define U_TEST_PREFIX "U_LINUX_SOCK_TEST: " + +/** Print a whole line, with terminator, prefixed for this test file. + */ +#define U_TEST_PRINT_LINE(format, ...) uPortLog(U_TEST_PREFIX format "\n", ##__VA_ARGS__) + +#ifndef U_LINUX_PPP_TEST_RECEIVE_TASK_STACK_SIZE_BYTES +/** The stack size to use for the asynchronous receive task. + */ +# define U_LINUX_PPP_TEST_RECEIVE_TASK_STACK_SIZE_BYTES 2560 +#endif + +#ifndef U_LINUX_PPP_TEST_RECEIVE_TASK_PRIORITY +/** The priority to use for the asynchronous receive task. + */ +# define U_LINUX_PPP_TEST_RECEIVE_TASK_PRIORITY (U_CFG_OS_PRIORITY_MIN + 5) +#endif + +#ifndef U_LINUX_PPP_TEST_RECEIVE_TASK_RELAX_MS +/** How long the receive task should relax for between receive + * attempts. + */ +# define U_LINUX_PPP_TEST_RECEIVE_TASK_RELAX_MS 10 +#endif + +#ifndef U_LINUX_PPP_TEST_RECEIVE_TASK_EXIT_MS +/** How long to allow for the the receive task to exit; + * should be quite a lot longer than + * #U_LINUX_PPP_TEST_RECEIVE_TASK_EXIT_MS. + */ +# define U_LINUX_PPP_TEST_RECEIVE_TASK_EXIT_MS 100 +#endif + +/* ---------------------------------------------------------------- + * TYPES + * -------------------------------------------------------------- */ + +/** Struct to pass to rxTask(). + */ +typedef struct { + int32_t sock; + char *pBuffer; + size_t bufferLength; + size_t bytesToSend; + size_t bytesReceived; + size_t packetsReceived; + uPortTaskHandle_t taskHandle; + bool asyncExit; +} uLinuxPppSockTestConfig_t; + +/* ---------------------------------------------------------------- + * VARIABLES + * -------------------------------------------------------------- */ + +/** Some data to exchange with an echo server. + */ +static const char gSendData[] = "_____0000:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____0100:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____0200:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____0300:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____0400:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____0500:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____0600:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____0700:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____0800:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____0900:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____1000:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____1100:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____1200:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____1300:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____1400:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____1500:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____1600:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____1700:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____1800:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____1900:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789" + "_____2000:0123456789012345678901234567890123456789" + "01234567890123456789012345678901234567890123456789"; + +/** Data structure passed around during aynchronous receive. + */ +//lint -esym(785, gTestConfig) Suppress too few initialisers +static uLinuxPppSockTestConfig_t gTestConfig = {.taskHandle = NULL}; + +/* ---------------------------------------------------------------- + * STATIC FUNCTIONS + * -------------------------------------------------------------- */ + +// Do this before every test to ensure there is a usable network. +static uNetworkTestList_t *pStdPreamble() +{ + uNetworkTestList_t *pList; + + U_PORT_TEST_ASSERT(uPortInit() == 0); + U_PORT_TEST_ASSERT(uDeviceInit() == 0); + + // Add the device for each network configuration + // if not already added + pList = pUNetworkTestListAlloc(uNetworkTestHasPpp); + if (pList == NULL) { + U_TEST_PRINT_LINE("*** WARNING *** nothing to do."); + } + // Open the devices that are not already open + for (uNetworkTestList_t *pTmp = pList; pTmp != NULL; pTmp = pTmp->pNext) { + if (*pTmp->pDevHandle == NULL) { + U_TEST_PRINT_LINE("adding device %s for network %s...", + gpUNetworkTestDeviceTypeName[pTmp->pDeviceCfg->deviceType], + gpUNetworkTestTypeName[pTmp->networkType]); + U_PORT_TEST_ASSERT(uDeviceOpen(pTmp->pDeviceCfg, pTmp->pDevHandle) == 0); + } + } + + // Bring up each network type + for (uNetworkTestList_t *pTmp = pList; pTmp != NULL; pTmp = pTmp->pNext) { + U_TEST_PRINT_LINE("bringing up %s...", + gpUNetworkTestTypeName[pTmp->networkType]); + U_PORT_TEST_ASSERT(uNetworkInterfaceUp(*pTmp->pDevHandle, + pTmp->networkType, + pTmp->pNetworkCfg) == 0); + } + + return pList; +} + +// Receive data echoed back to us over a socket. +static void rxTask(void *pParameter) +{ + int32_t sizeBytes; + uLinuxPppSockTestConfig_t *pTestConfig = (uLinuxPppSockTestConfig_t *) pParameter; + + U_TEST_PRINT_LINE("rxTask receiving on socket %d.", pTestConfig->sock); + // Read from the socket until there's nothing left to read + //lint -e{776} Suppress possible truncation of addition + do { + sizeBytes = recv(pTestConfig->sock, + pTestConfig->pBuffer + + pTestConfig->bytesReceived, + pTestConfig->bytesToSend - + pTestConfig->bytesReceived, 0); + if (sizeBytes > 0) { + U_TEST_PRINT_LINE("received %d byte(s) of data @%d ms.", + sizeBytes, (int32_t) uPortGetTickTimeMs()); + pTestConfig->bytesReceived += sizeBytes; + pTestConfig->packetsReceived++; + } else { + uPortTaskBlock(U_LINUX_PPP_TEST_RECEIVE_TASK_RELAX_MS); + } + } while ((pTestConfig->bytesReceived < pTestConfig->bytesToSend) && + !pTestConfig->asyncExit); + + U_TEST_PRINT_LINE("rxTask exiting."); + + uPortTaskDelete(NULL); +} + +// Make sure that size is greater than 0 and no more than limit. +static size_t fix(size_t size, size_t limit) +{ + if (size == 0) { + size = limit / 2; // better than 1 + } else if (size > limit) { + size = limit; + } + + return size; +} + +// Send an entire TCP data buffer until done. +static size_t sendTcp(int32_t sock, const char *pData, size_t sizeBytes) +{ + int32_t x; + size_t sentSizeBytes = 0; + uTimeoutStart_t timeoutStart; + + U_TEST_PRINT_LINE("sending %d byte(s) of TCP data...", sizeBytes); + timeoutStart = uTimeoutStart(); + while ((sentSizeBytes < sizeBytes) && + !uTimeoutExpiredSeconds(timeoutStart, 10)) { + x = send(sock, (const void *) pData, sizeBytes - sentSizeBytes, 0); + if (x > 0) { + sentSizeBytes += x; + pData += x; + U_TEST_PRINT_LINE("sent %d byte(s) of TCP data @%d ms.", + sentSizeBytes, (int32_t) uPortGetTickTimeMs()); + } + } + + return sentSizeBytes; +} + +// Check a buffer of what was sent against what was echoed back and +// print out useful info if they differ. +static bool checkAgainstSentData(const char *pDataSent, + size_t dataSentSizeBytes, + const char *pDataReceived, + size_t dataReceivedSizeBytes) +{ + bool success = true; + int32_t x; +#if U_CFG_ENABLE_LOGGING + int32_t y; + int32_t z; +#endif + + if (dataReceivedSizeBytes == dataSentSizeBytes) { + // Run through checking that the characters are the same + for (x = 0; ((*(pDataReceived + x) == *(pDataSent + x))) && + (x < (int32_t) dataSentSizeBytes); x++) { + } + if (x != (int32_t) dataSentSizeBytes) { +#if U_CFG_ENABLE_LOGGING + y = x - 5; + if (y < 0) { + y = 0; + } + z = 10; + if (y + z > (int32_t) dataSentSizeBytes) { + z = ((int32_t) dataSentSizeBytes) - y; + } + U_TEST_PRINT_LINE("difference at character %d (sent \"%*.*s\", received" + " \"%*.*s\").", x + 1, z, z, pDataSent + y, z, z, + pDataReceived + y); +#endif + success = false; + } + } else { + U_TEST_PRINT_LINE("%d byte(s) missing (%d byte(s) received when %d were" + " expected)).", dataSentSizeBytes - dataReceivedSizeBytes, + dataReceivedSizeBytes, dataSentSizeBytes); + success = false; + } + + return success; +} + +// Release OS resources that may have been left hanging +// by a failed test +static void osCleanup() +{ + if (gTestConfig.taskHandle != NULL) { + gTestConfig.asyncExit = true; + uPortTaskBlock(U_LINUX_PPP_TEST_RECEIVE_TASK_EXIT_MS); + gTestConfig.taskHandle = NULL; + } + uPortFree(gTestConfig.pBuffer); + gTestConfig.pBuffer = NULL; +} + +/* ---------------------------------------------------------------- + * PUBLIC FUNCTIONS: WEAK IMPLEMENTATION OF CELL API FUNCTION + * -------------------------------------------------------------- */ + +// This to allow the code here to at least compile if cellular is not included. +U_WEAK const uCellPrivateModule_t *pUCellPrivateGetModule(uDeviceHandle_t cellHandle) +{ + (void) cellHandle; + return NULL; +} + +/* ---------------------------------------------------------------- + * PUBLIC FUNCTIONS: TESTS + * -------------------------------------------------------------- */ + +/** Basic TCP test. + * + * Note: we used to name the tests here linuxBlah to match the + * pattern of the platform tests under ESP-IDF and Zephyr. However, + * setting U_CFG_APP_FILTER to "linux" to run just these Linux tests + * doesn't work: "linux" is implicitly defined by the toolchain to + * be 1, so any time it appears as a conditional compilation flag + * the compiler will replace it with 1. These test names begin with + * testLinux instead of just linux; setting U_CFG_APP_FILTER to + * "testLinux" _will_ work. + */ +U_PORT_TEST_FUNCTION("[testLinuxSock]", "testLinuxSockTcp") +{ + const uCellPrivateModule_t *pModule; + uNetworkTestList_t *pList; + int32_t resourceCount; + char hostIp[] = U_SOCK_TEST_ECHO_TCP_SERVER_IP_ADDRESS; + struct sockaddr_in destinationAddress; + int32_t sock; + int32_t errorCode; + int32_t x; + size_t sizeBytes = 0; + size_t offset; + uTimeoutStart_t timeoutStart; + struct ifreq interface = {0}; + + // Whatever called us likely initialised the + // port so deinitialise it here to obtain the + // correct initial resource count + uPortDeinit(); + + // Obtain the initial resource count + resourceCount = uTestUtilGetDynamicResourceCount(); + + // Do the standard preamble to make sure there is + // a network underneath us + pList = pStdPreamble(); + + // Repeat for all bearers that have a supported PPP interface + for (uNetworkTestList_t *pTmp = pList; pTmp != NULL; pTmp = pTmp->pNext) { + pModule = NULL; + if (pTmp->pDeviceCfg->deviceType == U_DEVICE_TYPE_CELL) { + pModule = pUCellPrivateGetModule(*pTmp->pDevHandle); + } + if ((pModule == NULL) || + U_CELL_PRIVATE_HAS(pModule, U_CELL_PRIVATE_FEATURE_PPP)) { + + U_TEST_PRINT_LINE("doing async TCP test on %s.", + gpUNetworkTestTypeName[pTmp->networkType]); + osCleanup(); + + inet_pton(AF_INET, hostIp, &destinationAddress.sin_addr); + destinationAddress.sin_family = AF_INET; + destinationAddress.sin_port = htons(U_SOCK_TEST_ECHO_TCP_SERVER_PORT); + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + U_TEST_PRINT_LINE("opening socket() to %s:%d returned %d (errno %d).", + hostIp, U_SOCK_TEST_ECHO_TCP_SERVER_PORT, sock, errno); + U_PORT_TEST_ASSERT(sock >= 0); + + // Set socket to be non-blocking for our asynchronous receive + x = fcntl(sock, F_GETFL, 0); + U_PORT_TEST_ASSERT(x >= 0); + x &= ~O_NONBLOCK; + U_PORT_TEST_ASSERT(fcntl(sock, F_SETFL, x) == 0); + + // Bind the socket to ppp0, the PPP interface, otherwise it will + // likely send over the Ethernet port + snprintf(interface.ifr_name, sizeof(interface.ifr_name), "ppp0"); + U_PORT_TEST_ASSERT(setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, + &interface, sizeof(interface)) == 0); + + errorCode = connect(sock, (struct sockaddr *) &destinationAddress, sizeof(destinationAddress)); + U_TEST_PRINT_LINE("connect() returned %d (errno %d).", errorCode, errno); + U_PORT_TEST_ASSERT(errorCode == 0); + + memset(&gTestConfig, 0, sizeof(gTestConfig)); + gTestConfig.sock = sock; + // We're sending all of gSendData except the + // null terminator on the end + gTestConfig.bytesToSend = sizeof(gSendData) - 1; + + // Malloc a buffer to receive TCP packets into + // and put the fill value into it + gTestConfig.bufferLength = gTestConfig.bytesToSend; + gTestConfig.pBuffer = (char *) pUPortMalloc(gTestConfig.bufferLength); + U_PORT_TEST_ASSERT(gTestConfig.pBuffer != NULL); + + // Create a task to receive data + U_PORT_TEST_ASSERT(uPortTaskCreate(rxTask, "rxTask", + U_LINUX_PPP_TEST_RECEIVE_TASK_STACK_SIZE_BYTES, + (void *) &gTestConfig, + U_LINUX_PPP_TEST_RECEIVE_TASK_PRIORITY, + &gTestConfig.taskHandle) == 0); + + // Throw random sized segments up... + offset = 0; + x = 0; + timeoutStart = uTimeoutStart(); + while (offset < gTestConfig.bytesToSend) { + sizeBytes = (rand() % U_SOCK_TEST_MAX_TCP_READ_WRITE_SIZE) + 1; + sizeBytes = fix(sizeBytes, U_SOCK_TEST_MAX_TCP_READ_WRITE_SIZE); + if (sizeBytes < U_SOCK_TEST_MIN_TCP_READ_WRITE_SIZE) { + sizeBytes = U_SOCK_TEST_MIN_TCP_READ_WRITE_SIZE; + } + if (offset + sizeBytes > gTestConfig.bytesToSend) { + sizeBytes = gTestConfig.bytesToSend - offset; + } + U_TEST_PRINT_LINE("write number %d.", x + 1); + U_PORT_TEST_ASSERT(sendTcp(gTestConfig.sock, + gSendData + offset, + sizeBytes) == sizeBytes); + offset += sizeBytes; + x++; + } + U_TEST_PRINT_LINE("a total of %d byte(s) sent in %d write(s).", offset, x); + + // Give the data time to come back + for (x = 10; (x > 0) && + (gTestConfig.bytesReceived < gTestConfig.bytesToSend); x--) { + uPortTaskBlock(1000); + } + + U_TEST_PRINT_LINE("TCP async receive task got %d segment(s)" + " totalling %d byte(s) and the send/receive" + " process took %d milliseconds.", + gTestConfig.packetsReceived, + gTestConfig.bytesReceived, + uTimeoutElapsedMs(timeoutStart)); + + // Check that we reassembled everything correctly + U_PORT_TEST_ASSERT(checkAgainstSentData(gSendData, + gTestConfig.bytesToSend, + gTestConfig.pBuffer, + gTestConfig.bytesReceived)); + + // Let the receive task close + gTestConfig.asyncExit = true; + uPortTaskBlock(U_LINUX_PPP_TEST_RECEIVE_TASK_EXIT_MS); + gTestConfig.taskHandle = NULL; + + shutdown(sock, 0); + close(sock); + + // Free memory + uPortFree(gTestConfig.pBuffer); + gTestConfig.pBuffer = NULL; + + // Free memory from event queues + uPortEventQueueCleanUp(); + + } else { + U_TEST_PRINT_LINE("*** WARNING *** not testing PPP since device does not support it."); + } + } + + // Remove each network type + for (uNetworkTestList_t *pTmp = pList; pTmp != NULL; pTmp = pTmp->pNext) { + U_TEST_PRINT_LINE("taking down %s...", + gpUNetworkTestTypeName[pTmp->networkType]); + U_PORT_TEST_ASSERT(uNetworkInterfaceDown(*pTmp->pDevHandle, + pTmp->networkType) == 0); + } + // Remove each device + for (uNetworkTestList_t *pTmp = pList; pTmp != NULL; pTmp = pTmp->pNext) { + if (*pTmp->pDevHandle != NULL) { + U_TEST_PRINT_LINE("closing device %s...", + gpUNetworkTestDeviceTypeName[pTmp->pDeviceCfg->deviceType]); + U_PORT_TEST_ASSERT(uDeviceClose(*pTmp->pDevHandle, false) == 0); + *pTmp->pDevHandle = NULL; + } + } + uNetworkTestListFree(); + + uDeviceDeinit(); + uPortDeinit(); + + // Check for resource leaks + uTestUtilResourceCheck(U_TEST_PREFIX, NULL, true); + resourceCount = uTestUtilGetDynamicResourceCount() - resourceCount; + U_TEST_PRINT_LINE("we have leaked %d resources(s).", resourceCount); + U_PORT_TEST_ASSERT(resourceCount <= 0); +} + +/** Clean-up to be run at the end of this round of tests, just + * in case there were test failures which would have resulted + * in the deinitialisation being skipped. + */ +U_PORT_TEST_FUNCTION("[testLinuxSock]", "testLinuxSockCleanUp") +{ + osCleanup(); + // The network test configuration is shared between + // the network, sockets, security and location tests + // so must reset the handles here in case the + // tests of one of the other APIs are coming next. + uNetworkTestCleanUp(); + uDeviceDeinit(); + uPortDeinit(); + // Printed for information: asserting happens in the postamble + uTestUtilResourceCheck(U_TEST_PREFIX, NULL, true); +} + +#endif // #ifdef U_CFG_PPP_ENABLE + +// End of file diff --git a/port/platform/nrf5sdk/src/u_port_uart.c b/port/platform/nrf5sdk/src/u_port_uart.c index 2aa29e1f..6201411d 100644 --- a/port/platform/nrf5sdk/src/u_port_uart.c +++ b/port/platform/nrf5sdk/src/u_port_uart.c @@ -47,6 +47,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_port_clib_platform_specific.h" /* Integer stdio, must be included before the other port files if any print or scan function is used. */ @@ -968,7 +970,7 @@ int32_t uPortUartEventTrySend(int32_t handle, uint32_t eventBitMap, { uErrorCode_t errorCode = U_ERROR_COMMON_NOT_INITIALISED; uPortUartEvent_t event; - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); if (gMutex != NULL) { @@ -988,7 +990,7 @@ int32_t uPortUartEventTrySend(int32_t handle, uint32_t eventBitMap, &event, sizeof(event)); uPortTaskBlock(U_CFG_OS_YIELD_MS); } while ((errorCode != 0) && - !uPortTickTimeExpiredMs(startTimeMs, delayMs)); + !uTimeoutExpiredMs(timeoutStart, delayMs)); } U_PORT_MUTEX_UNLOCK(gMutex); diff --git a/port/platform/platformio/example/position.c b/port/platform/platformio/example/position.c index b5e18c15..0c778486 100644 --- a/port/platform/platformio/example/position.c +++ b/port/platform/platformio/example/position.c @@ -80,13 +80,13 @@ void main() printf("Waiting for position."); uLocation_t location; int tries = 0; - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); do { printf("."); errorCode = uLocationGet(deviceHandle, U_LOCATION_TYPE_GNSS, NULL, NULL, &location, NULL); } while (errorCode == U_ERROR_COMMON_TIMEOUT && tries++ < 4); - printf("\nWaited: %lld s\n", (uPortGetTickTimeMs() - startTimeMs) / 1000); + printf("\nWaited: %lld s\n", uTimeoutElapsedSeconds(timeoutStart)); if (errorCode == 0) { printf("Position: https://maps.google.com/?q=%d.%07d,%d.%07d\n", location.latitudeX1e7 / 10000000, location.latitudeX1e7 % 10000000, diff --git a/port/platform/platformio/inc_src.txt b/port/platform/platformio/inc_src.txt index c3db3fdd..4d549c18 100644 --- a/port/platform/platformio/inc_src.txt +++ b/port/platform/platformio/inc_src.txt @@ -24,6 +24,7 @@ common/at_client common/error common/assert +common/timeout common/location common/mqtt_client common/http_client diff --git a/port/platform/stm32cube/src/u_port_i2c.c b/port/platform/stm32cube/src/u_port_i2c.c index 711bf20a..58158fe7 100644 --- a/port/platform/stm32cube/src/u_port_i2c.c +++ b/port/platform/stm32cube/src/u_port_i2c.c @@ -26,6 +26,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_port.h" #include "u_port_os.h" #include "u_port_gpio.h" // For unblocking @@ -239,11 +241,11 @@ static int32_t configureHw(I2C_TypeDef *pReg, int32_t clockHertz) static bool waitFlagOk(I2C_TypeDef *pReg, uint32_t flag, FlagStatus status, int32_t timeoutMs) { - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); bool wait; while ((wait = (U_PORT_HAL_I2C_GET_FLAG(pReg, flag) != status)) && - !uPortTickTimeExpiredMs(startTimeMs, timeoutMs)) { + !uTimeoutExpiredMs(timeoutStart, timeoutMs)) { } return !wait; @@ -256,12 +258,12 @@ static bool waitFlagOk(I2C_TypeDef *pReg, uint32_t flag, static bool waitTransmitOk(I2C_TypeDef *pReg, uint32_t flag, int32_t timeoutMs) { - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); bool wait; bool ackFailed = false; while ((wait = (U_PORT_HAL_I2C_GET_FLAG(pReg, flag) == RESET)) && - !uPortTickTimeExpiredMs(startTimeMs, timeoutMs) && + !uTimeoutExpiredMs(timeoutStart, timeoutMs) && !ackFailed) { if (U_PORT_HAL_I2C_GET_FLAG(pReg, I2C_FLAG_AF) == SET) { // If there's been an acknowledgement failure, diff --git a/port/platform/stm32cube/src/u_port_uart.c b/port/platform/stm32cube/src/u_port_uart.c index c3fcfb25..eab0b11b 100644 --- a/port/platform/stm32cube/src/u_port_uart.c +++ b/port/platform/stm32cube/src/u_port_uart.c @@ -34,6 +34,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_port_clib_platform_specific.h" /* Integer stdio, must be included before the other port files if any print or scan function is used. */ @@ -1313,7 +1315,7 @@ int32_t uPortUartWrite(int32_t handle, uPortUartData_t *pUartData; USART_TypeDef *pReg; bool txOk = true; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; if (gMutex != NULL) { @@ -1325,7 +1327,7 @@ int32_t uPortUartWrite(int32_t handle, pReg = gUartCfg[pUartData->uart].pReg; // Do the blocking send sizeOrErrorCode = (int32_t) sizeBytes; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((sizeBytes > 0) && (txOk)) { LL_USART_TransmitData8(pReg, *pDataPtr); // Hint when debugging: if your code stops dead here @@ -1337,8 +1339,8 @@ int32_t uPortUartWrite(int32_t handle, // was wrong and it's not connected to the right // thing. while (!(txOk = LL_USART_IsActiveFlag_TXE(pReg)) && - !uPortTickTimeExpiredMs(startTimeMs, - U_PORT_UART_WRITE_TIMEOUT_MS)) {} + !uTimeoutExpiredMs(timeoutStart, + U_PORT_UART_WRITE_TIMEOUT_MS)) {} if (txOk) { pDataPtr++; sizeBytes--; @@ -1347,8 +1349,8 @@ int32_t uPortUartWrite(int32_t handle, // Wait for transmission to complete so that we don't // write over stuff the next time while (!LL_USART_IsActiveFlag_TC(pReg) && - !uPortTickTimeExpiredMs(startTimeMs, - U_PORT_UART_WRITE_TIMEOUT_MS)) {} + !uTimeoutExpiredMs(timeoutStart, + U_PORT_UART_WRITE_TIMEOUT_MS)) {} sizeOrErrorCode -= (int32_t) sizeBytes; } @@ -1523,7 +1525,7 @@ int32_t uPortUartEventTrySend(int32_t handle, uint32_t eventBitMap, uErrorCode_t errorCode = U_ERROR_COMMON_NOT_INITIALISED; uPortUartData_t *pUartData; uPortUartEvent_t event; - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); if (gMutex != NULL) { @@ -1543,7 +1545,7 @@ int32_t uPortUartEventTrySend(int32_t handle, uint32_t eventBitMap, &event, sizeof(event)); uPortTaskBlock(U_CFG_OS_YIELD_MS); } while ((errorCode != 0) && - !uPortTickTimeExpiredMs(startTimeMs, delayMs)); + !uTimeoutExpiredMs(timeoutStart, delayMs)); } U_PORT_MUTEX_UNLOCK(gMutex); diff --git a/port/platform/zephyr/src/u_port_ppp.c b/port/platform/zephyr/src/u_port_ppp.c index 02dc6786..b8b1d452 100644 --- a/port/platform/zephyr/src/u_port_ppp.c +++ b/port/platform/zephyr/src/u_port_ppp.c @@ -49,6 +49,8 @@ #include "u_cfg_sw.h" #include "u_error_common.h" +#include "u_timeout.h" + #include "u_sock.h" // uSockStringToAddress() #include "u_port.h" @@ -645,7 +647,7 @@ static void netIfEventCallback(struct net_mgmt_event_callback *pCb, // Detach the Zephyr PPP interface. static void pppDetach(uPortPppInterface_t *pPppInterface) { - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; if ((pPppInterface != NULL) && (pPppInterface->pNetIf != NULL)) { // START: HACK HACK HACK HACK HACK HACK HACK @@ -671,10 +673,10 @@ static void pppDetach(uPortPppInterface_t *pPppInterface) // Wait for netIfEventCallback to be called-back // with the event NET_EVENT_IF_DOWN; it // will set gpPppInterface->ipConnected - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((gpPppInterface->ipConnected) && - !uPortTickTimeExpiredMs(startTimeMs, - U_PORT_PPP_DISCONNECT_TIMEOUT_SECONDS * 1000)) { + !uTimeoutExpiredSeconds(timeoutStart, + U_PORT_PPP_DISCONNECT_TIMEOUT_SECONDS)) { uPortTaskBlock(250); } pPppInterface->ipConnected = false; @@ -846,7 +848,7 @@ int32_t uPortPppConnect(void *pDevHandle, { int32_t errorCode = (int32_t) U_ERROR_COMMON_NOT_INITIALISED; struct net_if *pNetIf; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; // Note: Zephyr does not (as of version 3.5 at least) support // entering a user name and password, and probably doesn't @@ -900,10 +902,10 @@ int32_t uPortPppConnect(void *pDevHandle, // Wait for netIfEventCallback to be called back // with the event NET_EVENT_IPV4_ADDR_ADD; it // will set gpPppInterface->ipConnected - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((!gpPppInterface->ipConnected) && - !uPortTickTimeExpiredMs(startTimeMs, - U_PORT_PPP_CONNECT_TIMEOUT_SECONDS * 1000)) { + !uTimeoutExpiredSeconds(timeoutStart, + U_PORT_PPP_CONNECT_TIMEOUT_SECONDS)) { uPortTaskBlock(250); } if (gpPppInterface->ipConnected) { diff --git a/port/platform/zephyr/src/u_port_uart.c b/port/platform/zephyr/src/u_port_uart.c index 4219c932..a120b6f8 100644 --- a/port/platform/zephyr/src/u_port_uart.c +++ b/port/platform/zephyr/src/u_port_uart.c @@ -54,6 +54,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_linked_list.h" #include "u_port_debug.h" @@ -839,7 +841,7 @@ int32_t uPortUartEventTrySend(int32_t handle, uint32_t eventBitMap, uErrorCode_t errorCode = U_ERROR_COMMON_NOT_INITIALISED; uPortUartData_t *pUartData; uPortUartEvent_t event; - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); if (gMutex != NULL) { @@ -858,7 +860,7 @@ int32_t uPortUartEventTrySend(int32_t handle, uint32_t eventBitMap, &event, sizeof(event)); uPortTaskBlock(U_CFG_OS_YIELD_MS); } while ((errorCode != 0) && - !uPortTickTimeExpiredMs(startTimeMs, delayMs)); + !uTimeoutExpiredMs(timeoutStart, delayMs)); } U_PORT_MUTEX_UNLOCK(gMutex); diff --git a/port/platform/zephyr/test/u_zephyr_ppp_test.c b/port/platform/zephyr/test/u_zephyr_ppp_test.c index c633a4d8..84d6a83d 100644 --- a/port/platform/zephyr/test/u_zephyr_ppp_test.c +++ b/port/platform/zephyr/test/u_zephyr_ppp_test.c @@ -59,6 +59,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_network.h" // In order to provide a comms path #include "u_network_test_shared_cfg.h" @@ -285,12 +287,12 @@ static size_t sendTcp(int32_t sock, const char *pData, size_t sizeBytes) { int32_t x; size_t sentSizeBytes = 0; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; U_TEST_PRINT_LINE("sending %d byte(s) of TCP data...", sizeBytes); - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((sentSizeBytes < sizeBytes) && - !uPortTickTimeExpiredMs(startTimeMs, 10000)) { + !uTimeoutExpiredSeconds(timeoutStart, 10)) { x = zsock_send(sock, (const void *) pData, sizeBytes - sentSizeBytes, 0); if (x > 0) { sentSizeBytes += x; @@ -390,7 +392,7 @@ U_PORT_TEST_FUNCTION("[zephyrSock]", "zephyrSockTcp") int32_t x; size_t sizeBytes = 0; size_t offset; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; // Whatever called us likely initialised the // port so deinitialise it here to obtain the @@ -460,7 +462,7 @@ U_PORT_TEST_FUNCTION("[zephyrSock]", "zephyrSockTcp") // Throw random sized segments up... offset = 0; x = 0; - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while (offset < gTestConfig.bytesToSend) { sizeBytes = (rand() % U_SOCK_TEST_MAX_TCP_READ_WRITE_SIZE) + 1; sizeBytes = fix(sizeBytes, U_SOCK_TEST_MAX_TCP_READ_WRITE_SIZE); @@ -490,7 +492,7 @@ U_PORT_TEST_FUNCTION("[zephyrSock]", "zephyrSockTcp") " process took %d milliseconds.", gTestConfig.packetsReceived, gTestConfig.bytesReceived, - uPortGetTickTimeMs() - startTimeMs); + uTimeoutElapsedMs(timeoutStart)); // Check that we reassembled everything correctly U_PORT_TEST_ASSERT(checkAgainstSentData(gSendData, diff --git a/port/test/u_port_test.c b/port/test/u_port_test.c index e15fc6f0..1c566019 100644 --- a/port/test/u_port_test.c +++ b/port/test/u_port_test.c @@ -38,6 +38,7 @@ #include "string.h" // strlen() and strcmp() #include "stdio.h" // snprintf() #include "time.h" // time_t and struct tm + #include "u_compiler.h" #include "u_cfg_sw.h" @@ -70,6 +71,8 @@ #include "u_port_event_queue.h" #include "u_error_common.h" +#include "u_timeout.h" + #include "u_assert.h" #include "u_test_util_resource_check.h" @@ -3043,7 +3046,7 @@ U_PORT_TEST_FUNCTION("[port]", "portTimers") { int32_t resourceCount; int32_t y; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; // Whatever called us likely initialised the // port so deinitialise it here to obtain the @@ -3102,9 +3105,9 @@ U_PORT_TEST_FUNCTION("[port]", "portTimers") // one-shot timer expires // Note: this test deliberately allows for slop in the actual timer // values however their relative values should still be correct - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((gTimerParameterValue[2] == 0) && - !uPortTickTimeExpiredMs(startTimeMs, 10000)) { + !uTimeoutExpiredSeconds(timeoutStart, 10)) { uPortTaskBlock(100); } U_PORT_TEST_ASSERT((gTimerParameterValue[2] == 1) && (gTimerParameterValue[3] == 3)); @@ -3120,9 +3123,9 @@ U_PORT_TEST_FUNCTION("[port]", "portTimers") U_PORT_TEST_ASSERT(uPortTimerStart(gTimerHandle[3]) == 0); U_PORT_TEST_ASSERT(uPortTimerStart(gTimerHandle[3]) == 0); // Wait for the periodic timer to expire one more time - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((gTimerParameterValue[3] < 4) && - !uPortTickTimeExpiredMs(startTimeMs, 5000)) { + !uTimeoutExpiredSeconds(timeoutStart, 5)) { uPortTaskBlock(100); } U_PORT_TEST_ASSERT(gTimerParameterValue[3] == 4); @@ -3174,7 +3177,7 @@ U_PORT_TEST_FUNCTION("[port]", "portCriticalSection") int32_t errorCode; int32_t resourceCount; uint32_t y; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; int32_t errorFlag = 0x00; // Whatever called us likely initialised the @@ -3210,8 +3213,8 @@ U_PORT_TEST_FUNCTION("[port]", "portCriticalSection") U_PORT_TEST_ASSERT(gVariable > 0); // Start the critical section - startTimeMs = uPortGetTickTimeMs(); - (void)startTimeMs; // Suppress value not being read (it is for Windows) + timeoutStart = uTimeoutStart(); + (void) timeoutStart; // Suppress value not being read (it is for Windows) errorCode = uPortEnterCritical(); // Note: don't assert inside here as we don't want to leave this test // with the critical section active, instead just set errorFlag to indicate @@ -3231,8 +3234,8 @@ U_PORT_TEST_FUNCTION("[port]", "portCriticalSection") // long time to _prove_ that the critical section has worked //lint -e{441, 550} Suppress loop variable not used in 2nd part of for() for (size_t x = 0; (gVariable == y) && - !uPortTickTimeExpiredMs(startTimeMs, - U_PORT_TEST_CRITICAL_SECTION_TEST_WAIT_TIME_MS); x++) { + !uTimeoutExpiredMs(timeoutStart, + U_PORT_TEST_CRITICAL_SECTION_TEST_WAIT_TIME_MS); x++) { uPortTaskBlock(100); } #endif @@ -3248,11 +3251,11 @@ U_PORT_TEST_FUNCTION("[port]", "portCriticalSection") U_PORT_TEST_ASSERT(errorFlag == 0); // gVariable should start changing again - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); //lint -e{441, 550} Suppress loop variable not used in 2nd part of for() for (size_t x = 0; (gVariable == y) && - !uPortTickTimeExpiredMs(startTimeMs, - U_PORT_TEST_CRITICAL_SECTION_TEST_WAIT_TIME_MS); x++) { + !uTimeoutExpiredMs(timeoutStart, + U_PORT_TEST_CRITICAL_SECTION_TEST_WAIT_TIME_MS); x++) { uPortTaskBlock(10); } U_PORT_TEST_ASSERT(gVariable != y); diff --git a/port/ubxlib.cmake b/port/ubxlib.cmake index 27db0693..c547ded0 100644 --- a/port/ubxlib.cmake +++ b/port/ubxlib.cmake @@ -99,6 +99,7 @@ endfunction() u_add_module_dir(base ${UBXLIB_BASE}/common/at_client) u_add_module_dir(base ${UBXLIB_BASE}/common/error) u_add_module_dir(base ${UBXLIB_BASE}/common/assert) +u_add_module_dir(base ${UBXLIB_BASE}/common/timeout) u_add_module_dir(base ${UBXLIB_BASE}/common/location) u_add_module_dir(base ${UBXLIB_BASE}/common/mqtt_client) u_add_module_dir(base ${UBXLIB_BASE}/common/http_client) diff --git a/port/ubxlib.mk b/port/ubxlib.mk index 161fe105..361f2c6b 100644 --- a/port/ubxlib.mk +++ b/port/ubxlib.mk @@ -10,6 +10,7 @@ UBXLIB_MODULE_DIRS = \ ${UBXLIB_BASE}/common/at_client \ ${UBXLIB_BASE}/common/error \ ${UBXLIB_BASE}/common/assert \ + ${UBXLIB_BASE}/common/timeout \ ${UBXLIB_BASE}/common/location \ ${UBXLIB_BASE}/common/mqtt_client \ ${UBXLIB_BASE}/common/http_client \ diff --git a/ubxlib.h b/ubxlib.h index 98ee3954..6e2eeb92 100644 --- a/ubxlib.h +++ b/ubxlib.h @@ -71,6 +71,7 @@ #include // Other common APIs +#include #include #include #include diff --git a/wifi/src/gen2/u_wifi.c b/wifi/src/gen2/u_wifi.c index 78dd0276..1519d976 100644 --- a/wifi/src/gen2/u_wifi.c +++ b/wifi/src/gen2/u_wifi.c @@ -42,6 +42,7 @@ #include "u_port_debug.h" #include "u_cfg_os_platform_specific.h" +#include "u_timeout.h" #include "u_at_client.h" #include "u_short_range_module_type.h" #include "u_short_range.h" diff --git a/wifi/src/gen2/u_wifi_cfg.c b/wifi/src/gen2/u_wifi_cfg.c index 09866bb8..bf21357b 100644 --- a/wifi/src/gen2/u_wifi_cfg.c +++ b/wifi/src/gen2/u_wifi_cfg.c @@ -37,6 +37,8 @@ #include "u_port_os.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_short_range_module_type.h" diff --git a/wifi/src/gen2/u_wifi_http.c b/wifi/src/gen2/u_wifi_http.c index 4859b732..03861a1b 100644 --- a/wifi/src/gen2/u_wifi_http.c +++ b/wifi/src/gen2/u_wifi_http.c @@ -40,6 +40,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_assert.h" #include "u_port_clib_platform_specific.h" /* Integer stdio, must be included diff --git a/wifi/src/gen2/u_wifi_loc.c b/wifi/src/gen2/u_wifi_loc.c index 7f2e900c..deb3d526 100644 --- a/wifi/src/gen2/u_wifi_loc.c +++ b/wifi/src/gen2/u_wifi_loc.c @@ -48,6 +48,8 @@ #include "u_port_heap.h" #include "u_port_debug.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_location.h" diff --git a/wifi/src/gen2/u_wifi_mqtt.c b/wifi/src/gen2/u_wifi_mqtt.c index 6d2e672e..fddcdbb8 100644 --- a/wifi/src/gen2/u_wifi_mqtt.c +++ b/wifi/src/gen2/u_wifi_mqtt.c @@ -50,6 +50,8 @@ #include "u_port_debug.h" #include "u_port_event_queue.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_mqtt_common.h" diff --git a/wifi/src/gen2/u_wifi_sock.c b/wifi/src/gen2/u_wifi_sock.c index 3776fc06..e6e44b08 100644 --- a/wifi/src/gen2/u_wifi_sock.c +++ b/wifi/src/gen2/u_wifi_sock.c @@ -37,6 +37,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_assert.h" #include "u_port.h" @@ -534,8 +536,8 @@ int32_t uWifiSockReceiveFrom(uDeviceHandle_t devHandle, *pRemoteAddress = pUWiFiSocket->remoteAddress; } } - int32_t startTimeMs = uPortGetTickTimeMs(); - while (!uPortTickTimeExpiredMs(startTimeMs, 5000) && + uTimeoutStart_t timeoutStart = uTimeoutStart(); + while (!uTimeoutExpiredSeconds(timeoutStart, 5) && (dataSizeBytes > 0) && ((res = uWifiSockRead(devHandle, sockHandle, pData, dataSizeBytes)) >= 0)) { tot += res; diff --git a/wifi/src/u_wifi.c b/wifi/src/u_wifi.c index 81fa6184..abc46014 100644 --- a/wifi/src/u_wifi.c +++ b/wifi/src/u_wifi.c @@ -42,6 +42,7 @@ #include "u_port_debug.h" #include "u_cfg_os_platform_specific.h" +#include "u_timeout.h" #include "u_at_client.h" #include "u_short_range_module_type.h" #include "u_short_range.h" diff --git a/wifi/src/u_wifi_cfg.c b/wifi/src/u_wifi_cfg.c index 530ac3e2..20fe680b 100644 --- a/wifi/src/u_wifi_cfg.c +++ b/wifi/src/u_wifi_cfg.c @@ -37,6 +37,8 @@ #include "u_port_os.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_short_range_module_type.h" diff --git a/wifi/src/u_wifi_geofence.c b/wifi/src/u_wifi_geofence.c index 442bc741..aa202b66 100644 --- a/wifi/src/u_wifi_geofence.c +++ b/wifi/src/u_wifi_geofence.c @@ -35,6 +35,8 @@ #include "u_error_common.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_linked_list.h" diff --git a/wifi/src/u_wifi_http.c b/wifi/src/u_wifi_http.c index 51784a6e..7ad8a882 100644 --- a/wifi/src/u_wifi_http.c +++ b/wifi/src/u_wifi_http.c @@ -51,6 +51,8 @@ #include "u_port_debug.h" #include "u_port_event_queue.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_sock.h" diff --git a/wifi/src/u_wifi_loc.c b/wifi/src/u_wifi_loc.c index 0bff4965..bf2a9518 100644 --- a/wifi/src/u_wifi_loc.c +++ b/wifi/src/u_wifi_loc.c @@ -48,6 +48,8 @@ #include "u_port_heap.h" #include "u_port_debug.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_location.h" @@ -611,7 +613,7 @@ int32_t uWifiLocGet(uDeviceHandle_t wifiHandle, uShortRangePrivateInstance_t *pInstance; volatile uWifiLocContext_t *pContext; uAtClientHandle_t atHandle; - int32_t startTimeMs; + uTimeoutStart_t timeoutStart; uLocation_t location; if (gUShortRangePrivateMutex != NULL) { @@ -647,11 +649,11 @@ int32_t uWifiLocGet(uDeviceHandle_t wifiHandle, uWifiPrivateUudhttpUrc, pInstance); if (errorCode == 0) { - startTimeMs = uPortGetTickTimeMs(); + timeoutStart = uTimeoutStart(); while ((pContext->errorCode == (int32_t) U_ERROR_COMMON_TIMEOUT) && (((pKeepGoingCallback == NULL) && - !uPortTickTimeExpiredMs(startTimeMs, - U_WIFI_LOC_ANSWER_TIMEOUT_SECONDS * 1000)) || + !uTimeoutExpiredSeconds(timeoutStart, + U_WIFI_LOC_ANSWER_TIMEOUT_SECONDS)) || ((pKeepGoingCallback != NULL) && pKeepGoingCallback(wifiHandle)))) { uPortTaskBlock(250); } diff --git a/wifi/src/u_wifi_mqtt.c b/wifi/src/u_wifi_mqtt.c index 33182114..de86a17e 100644 --- a/wifi/src/u_wifi_mqtt.c +++ b/wifi/src/u_wifi_mqtt.c @@ -50,6 +50,8 @@ #include "u_port_debug.h" #include "u_port_event_queue.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_mqtt_common.h" diff --git a/wifi/src/u_wifi_sock.c b/wifi/src/u_wifi_sock.c index 6b2875ed..a8b6b99f 100644 --- a/wifi/src/u_wifi_sock.c +++ b/wifi/src/u_wifi_sock.c @@ -45,6 +45,8 @@ #include "u_port_debug.h" #include "u_cfg_os_platform_specific.h" +#include "u_timeout.h" + #include "u_at_client.h" #include "u_sock_errno.h" @@ -1756,7 +1758,7 @@ int32_t uWifiSockAccept(uDeviceHandle_t devHandle, return -U_SOCK_EBADFD; } uWifiSockSocket_t *pServerSock = &(gSockets[sockHandle]); - int32_t startTimeMs = uPortGetTickTimeMs(); + uTimeoutStart_t timeoutStart = uTimeoutStart(); while (true) { uShortRangeLock(); uWifiSockSocket_t *pClientSock = pFindClientSocketByPort(devHandle, pServerSock->localPort); @@ -1765,8 +1767,8 @@ int32_t uWifiSockAccept(uDeviceHandle_t devHandle, *pRemoteAddress = pClientSock->remoteAddress; return pClientSock->sockHandle; } else if (gUWifiSocketAcceptTimeoutS >= 0) { - if (uPortTickTimeExpiredMs(startTimeMs, - gUWifiSocketAcceptTimeoutS * 1000)) { + if (uTimeoutExpiredSeconds(timeoutStart, + gUWifiSocketAcceptTimeoutS)) { return U_ERROR_COMMON_TIMEOUT; } } diff --git a/wifi/test/u_wifi_captive_portal_test.c b/wifi/test/u_wifi_captive_portal_test.c index 3676ccf1..1d995f61 100644 --- a/wifi/test/u_wifi_captive_portal_test.c +++ b/wifi/test/u_wifi_captive_portal_test.c @@ -62,6 +62,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_sock.h" #include "u_at_client.h" @@ -128,7 +130,7 @@ static uDeviceCfg_t gDeviceCfg = { } }; -static int32_t gStartTimeMs = -1; +static uTimeoutStop_t gTimeoutStop = {0}; /* ---------------------------------------------------------------- * STATIC FUNCTIONS @@ -140,9 +142,9 @@ static bool keepGoingCallback(uDeviceHandle_t devHandle) U_PORT_TEST_ASSERT(devHandle == gDeviceHandle); - if ((gStartTimeMs >= 0) && - !uPortTickTimeExpiredMs(gStartTimeMs, - U_WIFI_CAPTIVE_PORTAL_TEST_TIMEOUT_SECONDS * 1000)) { + if ((gTimeoutStop.durationMs > 0) && + uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -182,7 +184,8 @@ U_PORT_TEST_FUNCTION("[wifiCaptivePortal]", "wifiCaptivePortal") uNetworkInterfaceDown(gDeviceHandle, U_NETWORK_TYPE_WIFI); // Now do the actual test - gStartTimeMs = uPortGetTickTimeMs(); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_WIFI_CAPTIVE_PORTAL_TEST_TIMEOUT_SECONDS * 1000; int32_t returnCode = uWifiCaptivePortal(gDeviceHandle, "UBXLIB_TEST_PORTAL", NULL, keepGoingCallback); U_TEST_PRINT_LINE("uWifiCaptivePortal() returned %d.", returnCode); diff --git a/wifi/test/u_wifi_geofence_test.c b/wifi/test/u_wifi_geofence_test.c index 5f6a3307..78edf351 100644 --- a/wifi/test/u_wifi_geofence_test.c +++ b/wifi/test/u_wifi_geofence_test.c @@ -62,6 +62,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_location.h" #include "u_linked_list.h" @@ -142,7 +144,7 @@ static uShortRangeUartConfig_t gUart = { .uartPort = U_CFG_APP_SHORT_RANGE_UART, static uWifiTestPrivate_t gHandles = { -1, -1, NULL, NULL }; -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; static int32_t gErrorCode; static uGeofence_t *gpFenceA = NULL; @@ -164,7 +166,8 @@ static bool keepGoingCallback(uDeviceHandle_t param) (void) param; - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -236,7 +239,6 @@ U_PORT_TEST_FUNCTION("[wifiGeofence]", "wifiGeofenceBasic") { int32_t resourceCount; uLocation_t location; - int32_t startTimeMs; int32_t x; resourceCount = uTestUtilGetDynamicResourceCount(); @@ -282,8 +284,8 @@ U_PORT_TEST_FUNCTION("[wifiGeofence]", "wifiGeofenceBasic") U_PORT_TEST_ASSERT(uWifiGeofenceApply(gHandles.devHandle, gpFenceB) == 0); U_TEST_PRINT_LINE("testing geofence with blocking Wifi location."); - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + U_WIFI_GEOFENCE_TEST_TIMEOUT_SECONDS * 1000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_WIFI_GEOFENCE_TEST_TIMEOUT_SECONDS * 1000; // Choose Google to do this with as it seems generally the most reliable x = uWifiLocGet(gHandles.devHandle, U_LOCATION_TYPE_CLOUD_GOOGLE, U_PORT_STRINGIFY_QUOTED(U_CFG_APP_GOOGLE_MAPS_API_KEY), @@ -291,7 +293,7 @@ U_PORT_TEST_FUNCTION("[wifiGeofence]", "wifiGeofenceBasic") U_WIFI_GEOFENCE_TEST_RSSI_FILTER_DBM, &location, keepGoingCallback); U_TEST_PRINT_LINE("uWifiLocGet() returned %d in %d ms.", - x, uPortGetTickTimeMs() - startTimeMs); + x, uTimeoutElapsedMs(gTimeoutStop.timeoutStart)); U_TEST_PRINT_LINE("%s fence A, %s fence B.", gpPositionStateString[gPositionStateA], gpPositionStateString[gPositionStateB]); @@ -305,7 +307,8 @@ U_PORT_TEST_FUNCTION("[wifiGeofence]", "wifiGeofenceBasic") gErrorCode = 0; gPositionStateA = U_GEOFENCE_POSITION_STATE_NONE; gPositionStateB = U_GEOFENCE_POSITION_STATE_NONE; - startTimeMs = uPortGetTickTimeMs(); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_WIFI_GEOFENCE_TEST_TIMEOUT_SECONDS * 1000; x = uWifiLocGetStart(gHandles.devHandle, U_LOCATION_TYPE_CLOUD_GOOGLE, U_PORT_STRINGIFY_QUOTED(U_CFG_APP_GOOGLE_MAPS_API_KEY), U_WIFI_GEOFENCE_TEST_AP_FILTER, @@ -315,8 +318,8 @@ U_PORT_TEST_FUNCTION("[wifiGeofence]", "wifiGeofenceBasic") U_PORT_TEST_ASSERT(x == 0); U_TEST_PRINT_LINE("waiting %d second(s) for result...", U_WIFI_GEOFENCE_TEST_TIMEOUT_SECONDS); while ((gErrorCode >= 0) && (gErrorCode < 2) && - !uPortTickTimeExpiredMs(startTimeMs, - U_WIFI_GEOFENCE_TEST_TIMEOUT_SECONDS * 1000)) { + !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(250); } // On really fast systems (e.g. Linux machines) it is possible @@ -325,7 +328,7 @@ U_PORT_TEST_FUNCTION("[wifiGeofence]", "wifiGeofenceBasic") uPortTaskBlock(250); uWifiLocGetStop(gHandles.devHandle); U_TEST_PRINT_LINE("gErrorCode was %d after %d second(s).", gErrorCode, - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(gTimeoutStop.timeoutStart)); U_TEST_PRINT_LINE("%s fence A, %s fence B.", gpPositionStateString[gPositionStateA], gpPositionStateString[gPositionStateB]); diff --git a/wifi/test/u_wifi_loc_test.c b/wifi/test/u_wifi_loc_test.c index 349ec9dc..0e9d9d9a 100644 --- a/wifi/test/u_wifi_loc_test.c +++ b/wifi/test/u_wifi_loc_test.c @@ -60,6 +60,8 @@ #include "u_test_util_resource_check.h" +#include "u_timeout.h" + #include "u_location.h" #include "u_at_client.h" @@ -151,7 +153,7 @@ static uWifiLocTestLocType_t gLocType[] = { static size_t gIteration; // Stop time, global so that keepGoingCallback() can find it. -static int32_t gStopTimeMs; +static uTimeoutStop_t gTimeoutStop; // Global used for callback() to indicate what it received. static int32_t gCallback; @@ -167,7 +169,8 @@ static bool keepGoingCallback(uDeviceHandle_t param) (void) param; - if (uPortTickTimeBeyondStopMs(gStopTimeMs)) { + if (uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { keepGoing = false; } @@ -292,7 +295,6 @@ U_PORT_TEST_FUNCTION("[wifiLoc]", "wifiLocBasic") { int32_t z; int32_t resourceCount; - int32_t startTimeMs = 0; uLocation_t location; resourceCount = uTestUtilGetDynamicResourceCount(); @@ -306,8 +308,8 @@ U_PORT_TEST_FUNCTION("[wifiLoc]", "wifiLocBasic") U_TEST_PRINT_LINE("testing blocking Wifi location with %s.", gLocType[gIteration].pName); // It is possible for these cloud services to fail, so give them a few goes for (size_t y = 0; (y < U_WIFI_LOC_TEST_TRIES) && (z != 0); y++) { - startTimeMs = uPortGetTickTimeMs(); - gStopTimeMs = startTimeMs + U_WIFI_LOC_TEST_TIMEOUT_SECONDS * 1000; + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_WIFI_LOC_TEST_TIMEOUT_SECONDS * 1000; locationSetDefaults(&location); z = uWifiLocGet(gHandles.devHandle, gLocType[gIteration].type, gLocType[gIteration].pApiKey, @@ -315,7 +317,8 @@ U_PORT_TEST_FUNCTION("[wifiLoc]", "wifiLocBasic") U_WIFI_LOC_TEST_RSSI_FILTER_DBM, &location, keepGoingCallback); U_TEST_PRINT_LINE("uWifiLocGet() for %s returned %d in %d ms.", - gLocType[gIteration].pName, z, uPortGetTickTimeMs() - startTimeMs); + gLocType[gIteration].pName, z, + uTimeoutElapsedMs(gTimeoutStop.timeoutStart)); } // Success or allow error code 206 on HERE since it often isn't able to establish position in our lab U_PORT_TEST_ASSERT((z == 0) || ((z == 206) && @@ -342,7 +345,8 @@ U_PORT_TEST_FUNCTION("[wifiLoc]", "wifiLocBasic") // It is possible for these cloud services to fail, so give them a few goes gCallback = INT_MIN; for (size_t y = 0; (y < U_WIFI_LOC_TEST_TRIES) && (gCallback != 0); y++) { - startTimeMs = uPortGetTickTimeMs(); + gTimeoutStop.timeoutStart = uTimeoutStart(); + gTimeoutStop.durationMs = U_WIFI_LOC_TEST_TIMEOUT_SECONDS * 1000; gCallback = INT_MIN; locationSetDefaults(&location); z = uWifiLocGetStart(gHandles.devHandle, gLocType[gIteration].type, @@ -352,10 +356,10 @@ U_PORT_TEST_FUNCTION("[wifiLoc]", "wifiLocBasic") callback); U_TEST_PRINT_LINE("uWifiLocGetStart() for %s returned %d.", gLocType[gIteration].pName, z); U_PORT_TEST_ASSERT(z == 0); - U_TEST_PRINT_LINE("waiting %d second(s) for result...", U_WIFI_LOC_TEST_TIMEOUT_SECONDS); + U_TEST_PRINT_LINE("waiting %d second(s) for result...", gTimeoutStop.durationMs / 1000); while ((gCallback == INT_MIN) && - !uPortTickTimeExpiredMs(startTimeMs, - U_WIFI_LOC_TEST_TIMEOUT_SECONDS * 1000)) { + !uTimeoutExpiredMs(gTimeoutStop.timeoutStart, + gTimeoutStop.durationMs)) { uPortTaskBlock(250); } if (gCallback != 0) { @@ -365,7 +369,7 @@ U_PORT_TEST_FUNCTION("[wifiLoc]", "wifiLocBasic") } uWifiLocGetStop(gHandles.devHandle); U_TEST_PRINT_LINE("gCallback was %d after %d second(s).", gCallback, - (uPortGetTickTimeMs() - startTimeMs) / 1000); + uTimeoutElapsedSeconds(gTimeoutStop.timeoutStart)); U_PORT_TEST_ASSERT(gCallback >= 0); if (gCallback != 0) { // Sometimes the cloud service (e.g. Here does this on occasion) is