diff --git a/inc/ifc_struct_defs.h b/inc/ifc_struct_defs.h index 7861faf..88428b4 100644 --- a/inc/ifc_struct_defs.h +++ b/inc/ifc_struct_defs.h @@ -3,10 +3,16 @@ #include -#define NET_INFO_BUFF_SIZE (30) +#define NET_INFO_BUFF_SIZE (31) #define DL_BAND_CFG_SIZE (3 * 4 + 2) #define STATS_SIZE (10 * 4) #define TIME_INFO_SIZE (6 * 2 + 1) +#define GW_SCAN_INFO_SIZE (13) +#define MAX_GW_SCAN_RESULTS (16) +#define NUM_GW_SCANS_TO_KEEP (8) // sort through the list and find the best +#define MAX_GW_KEY_LIST (16) // number of gateways to keep keys in gw_list + +#define GW_SCAN_INFO_BUFF_SIZE (MAX_GW_SCAN_RESULTS * GW_SCAN_INFO_SIZE + 1) #ifndef PACKED #if defined ( __CC_ARM ) @@ -56,6 +62,7 @@ typedef struct PACKED llabs_network_info_t llabs_connect_status_t connection_status; uint8_t is_scanning_gateways; uint64_t gateway_id; + uint8_t is_repeater; } llabs_network_info_t; // Defines the band-specific frequency parameters (FCC 902-928, etc...) @@ -82,6 +89,30 @@ typedef struct llabs_stats uint32_t num_rx_errors; ///< Number of times we received a Rx error from the back end } llabs_stats_t; +typedef struct PACKED llabs_gateway_scan_results +{ + uint64_t id; + int16_t rssi; + int8_t snr; + int8_t channel; + uint8_t is_repeater; +} llabs_gateway_scan_results_t; + +typedef struct PACKED llabs_gateway_scan_results_alt +{ + uint64_t id; + int16_t rssi; + int8_t error_count; + int8_t channel; + uint8_t is_active; +} llabs_gateway_scan_results_alt_t; + +typedef union llabs_gateway_list_data +{ + llabs_gateway_scan_results_t gw_results; + llabs_gateway_scan_results_alt_t gw_data; +}llabs_gateway_list_data_t; + typedef struct PACKED llabs_time { uint32_t seconds; ///< Seconds since UNIX epoch 00:00:00 UTC on 1 January 1970 @@ -95,16 +126,22 @@ typedef struct PACKED llabs_time_info llabs_time_t last_sync; } llabs_time_info_t; -void ll_net_info_deserialize(const uint8_t buff[NET_INFO_BUFF_SIZE], llabs_network_info_t * net_info); -uint16_t ll_net_info_serialize(const llabs_network_info_t * net_info, uint8_t buff[NET_INFO_BUFF_SIZE]); -void ll_dl_band_cfg_deserialize(const uint8_t buff[DL_BAND_CFG_SIZE], llabs_dl_band_cfg_t * dl_cfg); -uint16_t ll_dl_band_cfg_serialize(const llabs_dl_band_cfg_t * dl_cfg, uint8_t buff[DL_BAND_CFG_SIZE]); -void ll_stats_deserialize(const uint8_t buff[STATS_SIZE], llabs_stats_t * stats); -uint16_t ll_stats_serialize(const llabs_stats_t * stats, uint8_t buff[STATS_SIZE]); +void ll_net_info_deserialize(const uint8_t buff[NET_INFO_BUFF_SIZE], + llabs_network_info_t *net_info); +uint16_t ll_net_info_serialize(const llabs_network_info_t *net_info, + uint8_t buff[NET_INFO_BUFF_SIZE]); +void ll_gw_scan_result_deserialize(const uint8_t buff[GW_SCAN_INFO_BUFF_SIZE], + llabs_gateway_scan_results_t *scan_result, uint8_t *num_gw); +uint16_t ll_gw_scan_result_serialize(llabs_gateway_scan_results_t scan_result, + uint8_t num_gw, uint8_t buff[GW_SCAN_INFO_BUFF_SIZE]); +void ll_dl_band_cfg_deserialize(const uint8_t buff[DL_BAND_CFG_SIZE], llabs_dl_band_cfg_t *dl_cfg); +uint16_t ll_dl_band_cfg_serialize(const llabs_dl_band_cfg_t *dl_cfg, + uint8_t buff[DL_BAND_CFG_SIZE]); +void ll_stats_deserialize(const uint8_t buff[STATS_SIZE], llabs_stats_t *stats); +uint16_t ll_stats_serialize(const llabs_stats_t *stats, uint8_t buff[STATS_SIZE]); void ll_time_deserialize(const uint8_t buff[TIME_INFO_SIZE], llabs_time_info_t *time_info); uint16_t ll_time_serialize(const llabs_time_info_t *time_info, uint8_t buff[TIME_INFO_SIZE]); - /** @} (end addtogroup Module_Interface) */ /* @@ -118,14 +155,14 @@ uint16_t ll_time_serialize(const llabs_time_info_t *time_info, uint8_t buff[TIME * messages over the host interface. The write_* functions serialize an * integer into a byte stream , and the read_* functions deserialize an * integer from a byte stream. - * + * * See * serialization on Wikipedia for more details about why these functions * exist. */ - /** - * @{ - */ +/** +* @{ +*/ /** * @brief diff --git a/inc/ll_ifc.h b/inc/ll_ifc.h index fd38e18..14be5e6 100644 --- a/inc/ll_ifc.h +++ b/inc/ll_ifc.h @@ -1,6 +1,6 @@ #ifndef __LL_IFC_H #define __LL_IFC_H - +#include #include "ll_ifc_utils.h" #ifdef __cplusplus @@ -513,19 +513,67 @@ extern "C" { #endif /** - * @brief - * Reset the host-side state maintained by the interface. - * - * @details - * The host implementation maintains a very small amount of state - * including the current message identifier. This function resets - * this internal state and is intended to allow for controlled - * testing. This function is not normally used in production code. - * - * @return - * 0 - success, negative otherwise. - */ + * @brief + * Reset the host-side state maintained by the interface. + * + * @details + * The host implementation maintains a very small amount of state + * including the current message identifier. This function resets + * this internal state and is intended to allow for controlled + * testing. This function is not normally used in production code. + * + * @return + * 0 - success, negative otherwise. + */ + int32_t ll_reset_state( void ); + /** + * @brief + * Grabs a recursive mutex used to protect hal_read_write() in ll_ifc and + * to make multi-operation ll_ifc calls work atomically. + * + * @details + * None. + * + * @return + * 0 - success, negative otherwise. + */ + bool transport_mutex_grab(void); + /** + * @brief + * Releases the mutex grabbed with transport_mutex_grab(). + * + * @details + * None. + * + * @return + * 1 - success, zero otherwise + */ + void transport_mutex_release(void); + /** + * @brief + * Implement a critical section if the communication could be interrupted for + * extended periods. + * + * @details + * None. + * + * @return + * 1 - success, zero otherwise + */ + bool transport_enter_critical(void); + /** + * @brief + * Implement a critical section if the communication could be interrupted for + * extended periods. + * + * @details + * None. + * + * @return + * 1 - success, zero otherwise. + */ + bool transport_exit_critical(void); /** @} (end defgroup Module_Interface) */ diff --git a/inc/ll_ifc_consts.h b/inc/ll_ifc_consts.h index 637c95a..c2f4986 100644 --- a/inc/ll_ifc_consts.h +++ b/inc/ll_ifc_consts.h @@ -15,10 +15,11 @@ */ #define IFC_VERSION_MAJOR (0) -#define IFC_VERSION_MINOR (6) +#define IFC_VERSION_MINOR (8) #define IFC_VERSION_TAG (0) -#define APP_TOKEN_LEN (10) +#define APP_TOKEN_LEN (10) +#define UNIQUE_ID_LEN (8) #define MAX_RX_MSG_LEN (128) extern const uint32_t OPEN_NET_TOKEN; ///< Open network token (0x4f50454e) @@ -64,7 +65,7 @@ typedef enum OP_CONN_FILT_SET = 93, ///< 0x5D OP_CONN_FILT_GET = 94, ///< 0x5E //STRIPTHIS!START - OP_RESERVED0 = 96, ///< 0x60 + OP_RESERVED0 = 96, ///< 0x5F OP_RESERVED1 = 97, ///< 0x60 //STRIPTHIS!STOP OP_TX_CW = 98, ///< 0x61 @@ -94,7 +95,25 @@ typedef enum OP_TIMESTAMP = 131, ///< 0x83 reserved, not fully implemented OP_SEND_TIMESTAMP = 132, ///< 0x84 reserved, not fully implemented //STRIPTHIS!STOP - + OP_GET_SCAN_INFO = 133, ///< 0x85 + OP_CONN_TO_GW_CH = 134, ///< 0x86 + OP_DISCONNECT = 135, ///< 0x87 + OP_SCAN_MODE_GET = 136, ///< 0x88 + OP_SCAN_MODE_SET = 137, ///< 0x89 + OP_SCAN_THRESHOLD_GET = 138, ///< 0x8A + OP_SCAN_THRESHOLD_SET = 139, ///< 0x8B + OP_SCAN_ATTEMPTS_GET = 140, ///< 0x8C + OP_SCAN_ATTEMPTS_SET = 141, ///< 0x8D + OP_SCAN_ATTEMPTS_LEFT = 142, ///< 0x8E + OP_RSSI_OFFSET_GET = 143, ///< 0x8F + OP_RSSI_OFFSET_SET = 144, ///< 0x90 + OP_CTRL_MSG_ENABLED_SET = 145, ///< 0x91 + OP_CTRL_MSG_ENABLED_GET = 146, ///< 0x92 + OP_GPIO_ENABLE_PIN = 147, ///< 0x93 + OP_GPIO_DISABLE_PIN = 148, ///< 0x94 + OP_GPIO_PIN_STATUS = 149, ///< 0x95 + OP_GPIO_SET_HIGH = 150, ///< 0x96 + OP_GPIO_SET_LOW = 151, ///< 0x97 //STRIPTHIS!START OP_FCC_TEST = 245, ///< 0xF5 OP_PER_TEST_TX = 246, ///< 0xF6 @@ -277,6 +296,9 @@ typedef enum ll_ifc_error_codes_e { #define IRQ_FLAGS_TX_ERROR (0x00000020UL) ///< Set every time there is a Tx Error #define IRQ_FLAGS_RX_DONE (0x00000100UL) ///< Set every time a new packet is received #define IRQ_FLAGS_MAILBOX_EMPTY (0x00000200UL) ///< Set when a GW reports an empty mailbox + +#define IRQ_FLAGS_SYNC_FAILED (0x00000400UL) ///< Set when syncing to a channel fails + #define IRQ_FLAGS_CONNECTED (0x00001000UL) ///< Set every time we transition from the disconnected -> connected state #define IRQ_FLAGS_DISCONNECTED (0x00002000UL) ///< Set every time we transition from the connected -> disconnected state //STRIPTHIS!START @@ -289,12 +311,16 @@ typedef enum ll_ifc_error_codes_e { #define IRQ_FLAGS_INITIALIZATION_COMPLETE (0x00080000UL) ///< Set every time the MAC has completed initialization #define IRQ_FLAGS_CRYPTO_ERROR (0x00100000UL) ///< Set when a crypto exchange attempt fails #define IRQ_FLAGS_APP_TOKEN_ERROR (0x00200000UL) ///< Set when an application token registration fails +#define IRQ_FLAGS_DOWNLINK_ERROR (0x00400000UL) ///< Set when a downlink registration fails +#define IRQ_CLOUD_GPIO_2_INTERRUPT (0x01000000UL) ///< Set when the cloud GPIO input is triggered +#define IRQ_CLOUD_GPIO_3_INTERRUPT (0x02000000UL) ///< Set when the cloud GPIO input is triggered +#define IRQ_FLAGS_ASSERT (0x80000000UL) ///< Set every time we transition from the connected->disconnected state //STRIPTHIS!START // LifeRaft IRQ flags -#define IRQ_FLAGS_STATUS_REQ (0x00400000UL) ///< Set when we want to request the status of the host controller -#define IRQ_FLAGS_FIRMWARE_REQ (0x00800000UL) ///< Set when we want to request the firmware data of the host controller +//#define IRQ_FLAGS_STATUS_REQ (0x00400000UL) ///< Set when we want to request the status of the host controller +//#define IRQ_FLAGS_FIRMWARE_REQ (0x00800000UL) ///< Set when we want to request the firmware data of the host controller //STRIPTHIS!STOP -#define IRQ_FLAGS_ASSERT (0x80000000UL) ///< Set every time we transition from the connected->disconnected state + /** * @brief diff --git a/inc/ll_ifc_ftp.h b/inc/ll_ifc_ftp.h index 1899016..e8a61d2 100644 --- a/inc/ll_ifc_ftp.h +++ b/inc/ll_ifc_ftp.h @@ -61,12 +61,14 @@ extern "C" { * @{ */ -#define MAX_NUM_SEGMENTS (2400) +#define MAX_NUM_SEGMENTS (9800) // Can support a 1MB image #define MAX_FILE_SEGMENT_BYTES (107) -#define NUM_RX_SEGS_BITMASK (MAX_NUM_SEGMENTS / 32) +//#define NUM_RX_SEGS_BITMASK (MAX_NUM_SEGMENTS / 32) +#define NUM_RX_SEGS_BITMASK (((MAX_NUM_SEGMENTS % 32) == 0) ? (MAX_NUM_SEGMENTS >> 5) : ((MAX_NUM_SEGMENTS >> 5) + 1)) #define BASE_UL_MSG_LEN (14) -#define MAX_NUM_RETRY_SEGS (16) -#define LL_FTP_TX_BUF_SIZE (BASE_UL_MSG_LEN + MAX_NUM_RETRY_SEGS * 2) +#define MAX_NUM_RETRY_SEGS (1024) +//#define LL_FTP_TX_BUF_SIZE (BASE_UL_MSG_LEN + MAX_NUM_RETRY_SEGS * 2) +#define LL_FTP_TX_BUF_SIZE (256) // Can fit 121 segment requests per payload // The file header contains the crc, file size, file id, and file version @@ -76,6 +78,8 @@ extern "C" { #define LL_FTP_HDR_OFFSET_ID (8) #define LL_FTP_HDR_OFFSET_VERSION (12) #define LL_FTP_HDR_LEN (16) +#define LL_FTP_HDR_OFFSET_DAT_LEN (16) +#define LL_FTP_HDR_OFFSET_DAT (17) /** * @brief @@ -221,7 +225,7 @@ typedef ll_ftp_return_code_t (*ll_ftp_apply_t)(uint32_t file_id, uint32_t file_v * @return * LL_FTP_OK - success, see ::ll_ftp_return_code. */ -typedef ll_ftp_return_code_t (*ll_ftp_send_uplink_t)(const uint8_t* buf, uint8_t len, bool acked, uint8_t port); +typedef ll_ftp_return_code_t (*ll_ftp_send_uplink_t)(const uint8_t* buf, uint16_t len, bool acked, uint8_t port); /** * @brief diff --git a/inc/ll_ifc_symphony.h b/inc/ll_ifc_symphony.h index 73ba78d..f46b85c 100644 --- a/inc/ll_ifc_symphony.h +++ b/inc/ll_ifc_symphony.h @@ -26,6 +26,40 @@ extern "C" { * @{ */ +/** + * @brief These are the different scanning modes for Link Labs Symphony + * Modules. + * + * A Quick Scan will attempt to connect to the first gateway or repeater it sees. The + * intent behind this scan is to keep the scanning process as quick and + * simple as possible resulting in less power consumption of the scanning + * features. + * + * A Normal Scan is the default scan that Link Labs Symphony Modules have + * always used. This scan looks for a balance between power consumption, + * results and performance. The normal scan will look at every gateway within + * it's range and assess which gateway has the best connection credentials. + * Once all of the channels have been scanned, it will connect to the gateway or + * repeater with the best RSSI and SNR. + * + * An Info Scan can be use to gather a list of scan results. This scan mode + * gathers much more data about each gateway and repeater on the air; then + * saves all of that information into an array of scan_results that the user + * can use. The intent behind this scan was to provide the users with a "WiFi-like" + * connection system with symphony. So once you have your scan results and you + * find the gateway you want to connect to, you can specify that to the module + * and it will directly connect you to it. You can also re-purpose this scan in + * many ways to see what gateways your module can see for RSSI analysis and much more. + * This scan will not attempt to connect to any gateway, but will wait for the user + * to either manually connect to a gateway, or set the scan_config in order to scan + * regularly. + */ +enum ll_scan_mode { + LLABS_QUICK_SCAN_AND_CONNECT, ///< Quick Scan resulting in a connection attempt. + LLABS_NORMAL_SCAN_AND_CONNECT, ///< Normal Scan resulting in a connection attempt. + LLABS_INFO_SCAN ///< Full Scan resulting in a list of local gateways. +}; + enum ll_downlink_mode { LL_DL_OFF = 0, ///< 0x00 LL_DL_ALWAYS_ON = 1, ///< 0x01 @@ -62,7 +96,22 @@ extern const llabs_dl_band_cfg_t DL_BAN_BRA; ///< Brazil DL Band Configuration extern const llabs_dl_band_cfg_t DL_BAN_AUS; ///< Australia DL Band Configuration extern const llabs_dl_band_cfg_t DL_BAN_NZL; ///< New Zealand DL Band Configuration extern const llabs_dl_band_cfg_t DL_BAN_ETSI; ///< Europe (ETSI) DL Band Configuration - +/** + * @brief + * Set the scan attemps on the module + * + * @details + * Sets the number of times a scan will restart upon a + * failed scan before going to disconnect idle state. + * + * @param[in] scan_attempts + * The number of times the scan will restart upon a failed scan. + * 0 = Infinite Scan Attempts; Range (1, 65535) + * + * @return + * 0 - success, negative otherwise. + */ +int32_t ll_scan_attempts_set(uint16_t scan_attempts); /** * @brief @@ -129,6 +178,400 @@ int32_t ll_config_set(uint32_t net_token, const uint8_t app_token[APP_TOKEN_LEN] int32_t ll_config_get(uint32_t *net_token, uint8_t app_token[APP_TOKEN_LEN], enum ll_downlink_mode * dl_mode, uint8_t *qos); +/** + * @brief + * Set the current scan configuration of the module. + * + * @details + * Sets the scan configuration values for the module. + * Calling this function will put the module in scanning mode + * automatically. + * + * @param[in] scan_mode + * The type of scan that should be done. + * + * @param[in] threshold + * The minimum RSSI threshold for the module to accept a gateway or repeater connection. + * 0 = No RSSI threshold; + * + * @param[in] scan_attempts + * The number of times the scan will restart upon a failed scan. + * 0 = Infinite Scan Attempts; Range (1, 65535) + * + * @return + * 0, on success, negative otherwise + */ +int32_t ll_scan_config_set(enum ll_scan_mode scan_mode, int16_t threshold, uint16_t scan_attempts); + +/** + * @brief + * Get the current scan configuration of the module. + * + * @details + * Returns the configuration of the module set by the user + * (or the defualts if the user didn't get the scan config + * yet). + * + * @param[out] scan_type + * Pointer to the scan type of the module. + * + * @param[out] threshold + * Pointer to the minimum RSSI threshold to connect to a gateway. + * 0 = No RSSI threshold; + * + * @param[out] scan_attempts + * Pointer to the number of times the scan will restart upon a failed scan. + * 0 = Infinite Scan Attempts; Range (1, 65535) + * + * @param[out] scans_left + * Pointer to how many scan attempts the module still has to do before becoming idle. + * + * @return + * 0, on success, negative otherwise + */ +int32_t ll_scan_config_get(enum ll_scan_mode *scan_mode, int16_t *threshold, uint16_t *scan_attempts, uint16_t *scans_left); +/** + * @brief + * Get the current scan mode of the module. + * + * @details + * Returns the scan mode (NORMAL, INFO, QUICK) of the module set by the user + * (or the defualts if the user didn't get the scan mode + * yet). + * + * @param[out] scan_mode + * Pointer to the scan mode of the module. + * + * @return + * 0, on success, negative otherwise + */ +int32_t ll_scan_mode_get(enum ll_scan_mode *scan_mode); + +/** + * @brief + * Set the current scan mode of the module. + * + * @details + * Set the scan mode (NORMAL, INFO, QUICK) of the module + * + * @param[out] scan_mode + * scan mode of the module. + * + * @return + * 0, on success, negative otherwise + */ +int32_t ll_scan_mode_set(enum ll_scan_mode scan_mode); + + +/** + * @brief + * Provides the user with a list of available access points and allows the user to decide + * which one to connect to. + * + * @details + * You can only retrieve a scan list when the gateway is in a "INFO SCAN" mode, this can be + * set in the scan_config, and setting the new values will trigger a new scan. + * This method should be constantly polled at any interval during and after the scan, while + * the scan is executing, you will receive a nack - "busy try again" until the results are given. + * + * @param[out] scan_results + * This is an array of network information that contains the results of the scan. + * + * @param[out] num_gw + * The number of gateways scanned. + * + * @return + * 0, on success; NACK_BUSY_TRY_AGAIN, While scan is still going, negative otherwise + */ +int32_t ll_get_gateway_scan_results(llabs_gateway_scan_results_t (*scan_results)[MAX_GW_SCAN_RESULTS], uint8_t* num_gw); + +/** + * @brief + * Provides an extensible way to get gateway scan results, when you call this function + * (given the module has scan results stored), you will receive a scan result and the + * number of scan results left for you to poll. + * + * @details + * You can only retrieve a scan list when the gateway is in a "INFO SCAN" mode, this can be + * set in the scan_config, and setting the new values will trigger a new scan. + * This method should be constantly polled at any interval during and after the scan, while + * the scan is executing, you will receive a nack - "busy try again" until the results are given. + * + * @param[out] scan_results + * The scan results of the given gateway. + * + * @param[out] num_gw + * The current gateway number as well as how many gateways are left to poll. + * + * @return + * 0, on success; NACK_BUSY_TRY_AGAIN, While scan is still going, negative otherwise + */ +int32_t ll_poll_scan_result(llabs_gateway_scan_results_t *scan_result, uint8_t *num_gw); + +/** + * @brief + * Connect to a gateway based on the Channel it is on. + * + * @details + * This function will set the modules downlink channel to that of the + * requested channel and attempt to sync with any gateway on that channel. + * This function call does not require any scan results to be effective. + * Will only take effect when in IDLE_NO_GW mode. + * + * @param[in] channel + * The channel of the gateway that should be connected to. Must be between + * 0 and 45. + * + * @return + * 0, on success, negative otherwise + */ +int32_t ll_connect_to_gw_channel(uint8_t channel); + +/** + * @brief + * Disconnects the module from any current gateway. + * + * @details + * The state that the module is left in depends on the scan_config, + * since this call could either put the gateway in IDLE_NO_GW or can + * just start a new scan. Will only take effect when in IDLE_GW mode. + * + * @return + * 0, on success, negative otherwise + */ +int32_t ll_disconnect(void); + +/** + * @brief + * Enable or Disable the Control Message Feature. + * + * @details + * The control message feature allows the module to receive the following + * messages from conductor and bypass the host application completely. + * * Module Reset + * * Module Info Scan & Report + * * Connect to Gateway Channel + * * Get Module Stats + * * Cloud GPIO Functions + * + * These functions are good for recovering modules that have a locked up host + * and are also good for deployment operations with site analysis. Using the + * info scan and report function with the connect to gateway channel commands + * can give a server operator a lot of control over their deployment and fix + * any possible connectivity issues. The module stats command can also give + * a server administrator an idea of how the module is doing on a system level. + * Cloud GPIO functions have an infinite number of possibilities that can be used + * and configured how ever the host application sees fit. + * + * When the control message feature is enabled the module will automatically send + * out a message very similar to the mailbox request message. This message will be + * sent at a constant 15 minute interval to request any control messages that might + * be pending. In Downlink Always On mode the module will still send out this message + * in order to give the server a "heartbeat" or a constant ping to keep updating both + * the server's and the module's idea of connectivity between them. When the module is + * set for Downlink Always On mode the gateway will not hold the control message for the + * control message request, but instead will send it down ASAP because the module should + * be listening for it at that point. + * + * @param[in] enable + * If you want to enable the control message feature or not. + * + * @return + * 0, on success, negative otherwise + */ +int32_t ll_control_messages_enabled_set(bool enable); + +/** + * @brief + * Get if the Control Message Feature is Enabled or Disabled. + * + * @param[out] enabled + * If the control message feature is enabled or not. + * + * @return + * 0, on success, negative otherwise + */ +int32_t ll_control_messages_enabled_get(bool *enabled); + +/** + * @brief + * This function will activate the specified GPIO pin, by default all pins are disabled but + * as soon as a pin is enabled, that setting is persisted through module resets / reboots. + * + * Activating disabled pins will increase battery usage considerably. + * + * @details + * These GPIO pins are accessible from the cloud via control messages that enable the following + * commands to interface with the GPIO... + * * Activate Pin ( This Function ) + * * Deactivate Pin + * * Get Status + * * Write to Pin + * + * The module will also send a notification to the cloud when the GPIO input pin is triggered + * to enable external callbacks from the cloud. If you want to use the GPIO feature by itself + * and not send out the triggered read control message notification, then you can completely + * disable the control message feature with `ll_control_messages_enabled_set(false);`. + * + * @param[in] pin + * Corresponds to the Virtual GPIO pin layout... + * + * -------------------------------------------------------------------------------------------- + * | Virtual Pin # | Module Pin # | Function | + * |---------------|--------------|-----------------------------------------------------------| + * | Pin 0 | Pin 12 | Output Pin | + * | Pin 1 | Pin 23 | Output Pin | + * | Pin 2 | Pin 29 | Input Pin [ Triggers Callback on Falling Edge ] | + * | Pin 3 | Pin 31 | Input Pin [ Triggers Callback on Rising Edge ] | + * -------------------------------------------------------------------------------------------- + * + * @return + * 0, on success, negative otherwise + */ +int32_t ll_cloud_gpio_activate_pin(uint8_t pin); + +/** + * @brief + * This function will deactivate the specified GPIO pin, by default all pins are disabled but + * as soon as a pin is enabled, that setting is persisted through module resets / reboots. + * + * Disabling active pins will decrease battery usage considerably. + * + * @details + * These GPIO pins are accessible from the cloud via control messages that enable the following + * commands to interface with the GPIO... + * * Activate Pin + * * Deactivate Pin ( This Function ) + * * Get Status + * * Write to Pin + * + * The module will also send a notification to the cloud when the GPIO input pin is triggered + * to enable external callbacks from the cloud. If you want to use the GPIO feature by itself + * and not send out the triggered read control message notification, then you can completely + * disable the control message feature with `ll_control_messages_enabled_set(false);`. + * + * @param[in] pin + * Corresponds to the Virtual GPIO pin layout... + * + * -------------------------------------------------------------------------------------------- + * | Virtual Pin # | Module Pin # | Function | + * |---------------|--------------|-----------------------------------------------------------| + * | Pin 0 | Pin 12 | Output Pin | + * | Pin 1 | Pin 23 | Output Pin | + * | Pin 2 | Pin 29 | Input Pin [ Triggers Callback on Falling Edge ] | + * | Pin 3 | Pin 31 | Input Pin [ Triggers Callback on Rising Edge ] | + * -------------------------------------------------------------------------------------------- + * + * @return + * 0, on success, negative otherwise + */ +int32_t ll_cloud_gpio_deactivate_pin(uint8_t pin); + +/** + * @brief + * Get the status of the requested GPIO pin to see if it is activated or not. + * + * @details + * These GPIO pins are accessible from the cloud via control messages that enable the following + * commands to interface with the GPIO... + * * Activate Pin + * * Deactivate Pin + * * Get Status ( This Function ) + * * Write to Pin + * + * The module will also send a notification to the cloud when the GPIO input pin is triggered + * to enable external callbacks from the cloud. If you want to use the GPIO feature by itself + * and not send out the triggered read control message notification, then you can completely + * disable the control message feature with `ll_control_messages_enabled_set(false);`. + * + * @param[in] pin + * Corresponds to the Virtual GPIO pin layout... + * + * -------------------------------------------------------------------------------------------- + * | Virtual Pin # | Module Pin # | Function | + * |---------------|--------------|-----------------------------------------------------------| + * | Pin 0 | Pin 12 | Output Pin | + * | Pin 1 | Pin 23 | Output Pin | + * | Pin 2 | Pin 29 | Input Pin [ Triggers Callback on Falling Edge ] | + * | Pin 3 | Pin 31 | Input Pin [ Triggers Callback on Rising Edge ] | + * -------------------------------------------------------------------------------------------- + * + * @param[out] active + * Whether or not the pin is active or not. + * + * @return + * 0, on success, negative otherwise + */ +int32_t ll_cloud_gpio_get_pin_status(uint8_t pin, bool *active); + +/** + * @brief + * Sets the requested GPIO pin to output HIGH. This function only works for output pins. + * + * @details + * These GPIO pins are accessible from the cloud via control messages that enable the following + * commands to interface with the GPIO... + * * Activate Pin + * * Deactivate Pin + * * Get Status + * * Write to Pin ( This Function ) + * + * The module will also send a notification to the cloud when the GPIO input pin is triggered + * to enable external callbacks from the cloud. If you want to use the GPIO feature by itself + * and not send out the triggered read control message notification, then you can completely + * disable the control message feature with `ll_control_messages_enabled_set(false);`. + * + * @param[in] pin + * Corresponds to the Virtual GPIO pin layout... + * + * -------------------------------------------------------------------------------------------- + * | Virtual Pin # | Module Pin # | Function | + * |---------------|--------------|-----------------------------------------------------------| + * | Pin 0 | Pin 12 | Output Pin | + * | Pin 1 | Pin 23 | Output Pin | + * | Pin 2 | Pin 29 | Input Pin [ Triggers Callback on Falling Edge ] | + * | Pin 3 | Pin 31 | Input Pin [ Triggers Callback on Rising Edge ] | + * -------------------------------------------------------------------------------------------- + * + * @return + * 0, on success, negative otherwise + */ +int32_t ll_cloud_gpio_set_pin_high(uint8_t pin); + +/** + * @brief + * Sets the requested GPIO pin to output LOW. This function only works for output pins. + * + * @details + * These GPIO pins are accessible from the cloud via control messages that enable the following + * commands to interface with the GPIO... + * * Activate Pin + * * Deactivate Pin + * * Get Status + * * Write to Pin ( This Function ) + * + * The module will also send a notification to the cloud when the GPIO input pin is triggered + * to enable external callbacks from the cloud. If you want to use the GPIO feature by itself + * and not send out the triggered read control message notification, then you can completely + * disable the control message feature with `ll_control_messages_enabled_set(false);`. + * + * @param[in] pin + * Corresponds to the Virtual GPIO pin layout... + * + * -------------------------------------------------------------------------------------------- + * | Virtual Pin # | Module Pin # | Function | + * |---------------|--------------|-----------------------------------------------------------| + * | Pin 0 | Pin 12 | Output Pin | + * | Pin 1 | Pin 23 | Output Pin | + * | Pin 2 | Pin 29 | Input Pin [ Triggers Callback on Falling Edge ] | + * | Pin 3 | Pin 31 | Input Pin [ Triggers Callback on Rising Edge ] | + * -------------------------------------------------------------------------------------------- + * + * @return + * 0, on success, negative otherwise + */ +int32_t ll_cloud_gpio_set_pin_low(uint8_t pin); + /** * @brief * Gets the state of the module. @@ -245,6 +688,33 @@ int32_t ll_dl_band_cfg_get(llabs_dl_band_cfg_t *p_dl_band_cfg); */ int32_t ll_dl_band_cfg_set(const llabs_dl_band_cfg_t *p_dl_band_cfg); +/** + * @brief + * Get what the RSSI offset calibration is. + * + * @param[out] rssi_offset + * the rssi offset value. + * + * @ return + * 0 - success, negative otherwise. + */ +int32_t ll_rssi_offset_get(int8_t *rssi_offset); + +/** + * @brief + * Calibrate the module's rssi value with an offset. + * + * @note + * The range for an RSSI offset is (-15, 15). + * + * @param[out] rssi_offset + * the rssi offset value. + * + * @ return + * 0 - success, negative otherwise. + */ +int32_t ll_rssi_offset_set(int8_t rssi_offset); + /** * @brief * Get the Connection Filter value. diff --git a/inc/ll_ifc_xmodem.h b/inc/ll_ifc_xmodem.h index 79cf2fe..850ffd5 100644 --- a/inc/ll_ifc_xmodem.h +++ b/inc/ll_ifc_xmodem.h @@ -102,6 +102,10 @@ int32_t ll_xmodem_prepare_module(bool is_host_ifc_active); */ int32_t ll_xmodem_send(ll_xmodem_callbacks_t *cb, uint8_t* payload, size_t len); +int32_t ll_xmodem_send_part(ll_xmodem_callbacks_t *cb, uint8_t* payload, size_t payload_len); +int32_t ll_xmodem_send_start_xfer(void); +int32_t ll_xmodem_send_EOF_validate(void); + /** @} (end defgroup XMODEM_Interface) */ /** @} (end addtogroup Link_Labs_Interface_Library) */ diff --git a/src/ifc_struct_defs.c b/src/ifc_struct_defs.c index 22cb5c1..cee73c2 100644 --- a/src/ifc_struct_defs.c +++ b/src/ifc_struct_defs.c @@ -53,6 +53,7 @@ void ll_net_info_deserialize(const uint8_t buff[NET_INFO_BUFF_SIZE], llabs_netwo net_info->connection_status = (llabs_connect_status_t) read_uint8(&b); net_info->is_scanning_gateways = read_uint8(&b); net_info->gateway_id = read_uint64(&b); + net_info->is_repeater = read_uint8(&b); } // Serializes an llabs_network_info_t struct into a buffer to be sent over the host interface. @@ -70,6 +71,32 @@ uint16_t ll_net_info_serialize(const llabs_network_info_t *net_info, uint8_t buf write_uint8(net_info->connection_status, &buff_cpy); write_uint8(net_info->is_scanning_gateways, &buff_cpy); write_uint64(net_info->gateway_id, &buff_cpy); + write_uint8(net_info->is_repeater, &buff_cpy); + return buff_cpy - buff; +} + +void ll_gw_scan_result_deserialize(const uint8_t buff[GW_SCAN_INFO_BUFF_SIZE], + llabs_gateway_scan_results_t *scan_result, uint8_t *num_gw) +{ + uint8_t const *b = buff; + *num_gw = read_uint8(&b); + (*scan_result).id = read_uint64(&b); + (*scan_result).rssi = read_uint16(&b); + (*scan_result).snr = read_uint8(&b); + (*scan_result).channel = read_uint8(&b); + (*scan_result).is_repeater = read_uint8(&b); +} + +uint16_t ll_gw_scan_result_serialize(llabs_gateway_scan_results_t scan_result, const uint8_t num_gw, + uint8_t buff[GW_SCAN_INFO_BUFF_SIZE]) +{ + uint8_t *buff_cpy = buff; + write_uint8(num_gw, &buff_cpy); + write_uint64(scan_result.id, &buff_cpy); + write_uint16(scan_result.rssi, &buff_cpy); + write_uint8(scan_result.snr, &buff_cpy); + write_uint8(scan_result.channel, &buff_cpy); + write_uint8(scan_result.is_repeater, &buff_cpy); return buff_cpy - buff; } diff --git a/src/ll_ifc.c b/src/ll_ifc.c index 0a9bc76..8434dc0 100644 --- a/src/ll_ifc.c +++ b/src/ll_ifc.c @@ -1,20 +1,32 @@ +#include +#include +#include + +#include "ifc_struct_defs.h" #include "ll_ifc.h" #include "ll_ifc_consts.h" -#include "ifc_struct_defs.h" #include "ll_ifc_symphony.h" #include "ll_ifc_no_mac.h" -#include -#include -#include #ifndef NULL // defines NULL on *some* platforms #define NULL (0) #endif #define CMD_HEADER_LEN (5) #define RESP_HEADER_LEN (6) + + +#define WAKEUP_BYTE (0xFF) + +#define LL_IFC_MSG_BUFF_SIZE 258 +#define LL_IFC_MSG_BUFF_IN_SIZE 126 + +static uint8_t _ll_ifc_msg_buff[LL_IFC_MSG_BUFF_SIZE]; +static uint8_t _ll_ifc_msg_in_buff[LL_IFC_MSG_BUFF_IN_SIZE]; + static uint16_t compute_checksum(uint8_t *hdr, uint16_t hdr_len, uint8_t *payload, uint16_t payload_len); static void send_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint16_t len); static int32_t recv_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint16_t len); +static int32_t recv_packet2(opcode_t op, uint8_t message_num, uint8_t *buf, uint16_t len); const uint32_t OPEN_NET_TOKEN = 0x4f50454e; @@ -22,10 +34,6 @@ static int32_t message_num = 0; int32_t hal_read_write(opcode_t op, uint8_t buf_in[], uint16_t in_len, uint8_t buf_out[], uint16_t out_len) { - // int i; - // int curr_byte; - // int num_bytes; - int32_t ret; // Error checking: @@ -40,12 +48,12 @@ int32_t hal_read_write(opcode_t op, uint8_t buf_in[], uint16_t in_len, uint8_t b { return(LL_IFC_ERROR_INCORRECT_PARAMETER); } - + transport_enter_critical(); // OK, inputs have been sanitized. Carry on... send_packet(op, message_num, buf_in, in_len); - ret = recv_packet(op, message_num, buf_out, out_len); + transport_exit_critical(); message_num++; return(ret); @@ -53,15 +61,26 @@ int32_t hal_read_write(opcode_t op, uint8_t buf_in[], uint16_t in_len, uint8_t b int32_t hal_read_write_exact(opcode_t op, uint8_t buf_in[], uint16_t in_len, uint8_t buf_out[], uint16_t out_len) { + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + int32_t ret = hal_read_write(op, buf_in, in_len, buf_out, out_len); if (ret >= 0) { if (ret != out_len) { - return LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + ret = LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + else + { + ret = 0; } - ret = 0; } + + transport_mutex_release(); + return ret; } @@ -105,7 +124,7 @@ char const * ll_return_code_description(int32_t return_code) { switch (return_code) { - case -LL_IFC_ACK: return "success"; + case -LL_IFC_ACK: return "Success"; case -LL_IFC_NACK_CMD_NOT_SUPPORTED: return "Command not supported"; case -LL_IFC_NACK_INCORRECT_CHKSUM: return "Incorrect Checksum"; case -LL_IFC_NACK_PAYLOAD_LEN_OOR: return "Length of payload sent in command was out of range"; @@ -139,35 +158,69 @@ char const * ll_return_code_description(int32_t return_code) int32_t ll_firmware_type_get(ll_firmware_type_t *t) { - uint8_t buf[FIRMWARE_TYPE_LEN]; + int32_t ret; - if(t == NULL) + if(NULL == t) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - ret = hal_read_write(OP_FIRMWARE_TYPE, NULL, 0, buf, FIRMWARE_TYPE_LEN); - if (ret == FIRMWARE_TYPE_LEN) + + if (!(transport_mutex_grab())) { - t->cpu_code = buf[0] << 8 | buf[1]; - t->functionality_code = buf[2] << 8 | buf[3]; + return LL_IFC_ERROR_HAL_CALL_FAILED; } - return ret; + + ret = hal_read_write(OP_FIRMWARE_TYPE, NULL, 0, &_ll_ifc_msg_buff[0], FIRMWARE_TYPE_LEN); + transport_mutex_release(); + + if (ret == 0) + { + //return ret; + } + else if(FIRMWARE_TYPE_LEN != ret) + { + ret = LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + else + { + t->cpu_code = _ll_ifc_msg_buff[0] << 8 | _ll_ifc_msg_buff[1]; + t->functionality_code = _ll_ifc_msg_buff[2] << 8 | _ll_ifc_msg_buff[3]; + } + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_hardware_type_get(ll_hardware_type_t *t) { - uint8_t type; + int32_t ret; - if(t == NULL) + if(NULL == t) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - ret = hal_read_write(OP_HARDWARE_TYPE, NULL, 0, &type, sizeof(type)); - if (ret == sizeof(type)) + + if (!(transport_mutex_grab())) { - *t = (ll_hardware_type_t) type; + return LL_IFC_ERROR_HAL_CALL_FAILED; } - return ret; + + ret = hal_read_write(OP_HARDWARE_TYPE, NULL, 0, &_ll_ifc_msg_buff[0], sizeof(uint8_t)); + + if(ret < 0) + { + //return ret; + } + else if(sizeof(uint8_t) != ret) + { + ret = LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + else + { + *t = (ll_hardware_type_t) _ll_ifc_msg_buff[0]; + } + + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; } const char * ll_hardware_type_string(ll_hardware_type_t t) @@ -185,48 +238,102 @@ const char * ll_hardware_type_string(ll_hardware_type_t t) int32_t ll_interface_version_get(ll_version_t *version) { - uint8_t buf[VERSION_LEN]; int32_t ret; - if(version == NULL) + if(NULL == version) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - ret = hal_read_write(OP_IFC_VERSION, NULL, 0, buf, VERSION_LEN); - if (ret == VERSION_LEN) + + if (!(transport_mutex_grab())) { - version->major = buf[0]; - version->minor = buf[1]; - version->tag = buf[2] << 8 | buf[3]; + return LL_IFC_ERROR_HAL_CALL_FAILED; } - return ret; + + ret = hal_read_write(OP_IFC_VERSION, NULL, 0, &_ll_ifc_msg_buff[0], VERSION_LEN); + + if(ret < 0) + { + //return ret; + } + else if (VERSION_LEN != ret) + { + ret = LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + else + { + version->major = _ll_ifc_msg_buff[0]; + version->minor = _ll_ifc_msg_buff[1]; + version->tag = _ll_ifc_msg_buff[2] << 8 | _ll_ifc_msg_buff[3]; + } + + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_version_get(ll_version_t *version) { uint8_t buf[VERSION_LEN]; int32_t ret; - if(version == NULL) + if(NULL == version) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - ret = hal_read_write(OP_VERSION, NULL, 0, buf, VERSION_LEN); - if (ret == VERSION_LEN) + + if (!(transport_mutex_grab())) { - version->major = buf[0]; - version->minor = buf[1]; - version->tag = buf[2] << 8 | buf[3]; + return LL_IFC_ERROR_HAL_CALL_FAILED; } - return ret; + + ret = hal_read_write(OP_VERSION, NULL, 0, &_ll_ifc_msg_buff[0], VERSION_LEN); + + if(ret < 0) + { + //return ret; + } + else if (VERSION_LEN != ret) + { + ret = LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + else + { + version->major = _ll_ifc_msg_buff[0]; + version->minor = _ll_ifc_msg_buff[1]; + version->tag = _ll_ifc_msg_buff[2] << 8 | _ll_ifc_msg_buff[3]; + } + + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_sleep_block(void) { - return hal_read_write(OP_SLEEP_BLOCK, (uint8_t*) "1", 1, NULL, 0); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + _ll_ifc_msg_buff[0] = '1'; + _ll_ifc_msg_buff[1] = 0; + int32_t ret = hal_read_write(OP_SLEEP_BLOCK, &_ll_ifc_msg_buff[0], 1, NULL, 0); + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_sleep_unblock(void) { - return hal_read_write(OP_SLEEP_BLOCK, (uint8_t*) "0", 1, NULL, 0); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + _ll_ifc_msg_buff[0] = '0'; + _ll_ifc_msg_buff[1] = 0; + int32_t ret = hal_read_write(OP_SLEEP_BLOCK, &_ll_ifc_msg_buff[0], 1, NULL, 0); + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_mac_mode_set(ll_mac_type_t mac_mode) @@ -235,8 +342,18 @@ int32_t ll_mac_mode_set(ll_mac_type_t mac_mode) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - uint8_t u8_mac_mode = (uint8_t)mac_mode; - return hal_read_write(OP_MAC_MODE_SET, &u8_mac_mode, 1, NULL, 0); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + _ll_ifc_msg_buff[0] = (uint8_t)mac_mode; + int32_t ret = hal_read_write(OP_MAC_MODE_SET, &_ll_ifc_msg_buff[0], 1, NULL, 0); + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_mac_mode_get(ll_mac_type_t *mac_mode) @@ -246,17 +363,37 @@ int32_t ll_mac_mode_get(ll_mac_type_t *mac_mode) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - uint8_t u8_mac_mode; - ret = hal_read_write(OP_MAC_MODE_GET, NULL, 0, &u8_mac_mode, sizeof(uint8_t)); - *mac_mode = (ll_mac_type_t)u8_mac_mode; - return ret; + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + + ret = hal_read_write(OP_MAC_MODE_GET, NULL, 0, &_ll_ifc_msg_buff[0], sizeof(uint8_t)); + *mac_mode = _ll_ifc_msg_buff[0]; + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_antenna_set(uint8_t ant) { if((ant == 1) || (ant == 2)) { - return hal_read_write(OP_ANTENNA_SET, &ant, 1, NULL, 0); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + _ll_ifc_msg_buff[0] = ant; + + int32_t ret = hal_read_write(OP_ANTENNA_SET, &_ll_ifc_msg_buff[0], 1, NULL, 0); + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } else { @@ -270,57 +407,131 @@ int32_t ll_antenna_get(uint8_t *ant) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - return hal_read_write(OP_ANTENNA_GET, NULL, 0, ant, 1); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_ANTENNA_GET, NULL, 0, &_ll_ifc_msg_buff[0], 1); + *ant = _ll_ifc_msg_buff[0]; + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_unique_id_get(uint64_t *unique_id) { - uint8_t buff[8]; int32_t ret; - int i; + uint8_t i; + if (unique_id == NULL) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - ret = hal_read_write(OP_MODULE_ID, NULL, 0, buff, 8); - *unique_id = 0; - for (i = 0; i < 8; i++) + + if (!(transport_mutex_grab())) { - *unique_id |= ((uint64_t) buff[i]) << (8 * (7 - i)); + return LL_IFC_ERROR_HAL_CALL_FAILED; } - return ret; + ret = hal_read_write(OP_MODULE_ID, NULL, 0, &_ll_ifc_msg_buff[0], UNIQUE_ID_LEN); + + if(ret < 0) + { + //return ret; + } + else if (UNIQUE_ID_LEN != ret) + { + ret = LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + else + { + *unique_id = 0; + for (i = 0; i < UNIQUE_ID_LEN; i++) + { + *unique_id |= ((uint64_t) _ll_ifc_msg_buff[i]) << (8 * (7 - i)); + } + } + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_settings_store(void) { - return hal_read_write(OP_STORE_SETTINGS, NULL, 0, NULL, 0); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_STORE_SETTINGS, NULL, 0, NULL, 0); + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_settings_delete(void) { - return hal_read_write(OP_DELETE_SETTINGS, NULL, 0, NULL, 0); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_DELETE_SETTINGS, NULL, 0, NULL, 0); + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_restore_defaults(void) { - return hal_read_write(OP_RESET_SETTINGS, NULL, 0, NULL, 0); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_RESET_SETTINGS, NULL, 0, NULL, 0); + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_sleep(void) { - return hal_read_write(OP_SLEEP, NULL, 0, NULL, 0); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_SLEEP, NULL, 0, NULL, 0); + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_reset_mcu(void) { - return hal_read_write(OP_RESET_MCU, NULL, 0, NULL, 0); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_RESET_MCU, NULL, 0, NULL, 0); + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_bootloader_mode(void) { send_packet(OP_TRIGGER_BOOTLOADER, message_num, NULL, 0); - return 0; + return LL_IFC_ACK; } /** @@ -330,29 +541,44 @@ int32_t ll_bootloader_mode(void) */ int32_t ll_irq_flags(uint32_t flags_to_clear, uint32_t *flags) { - // Assuming big endian convention over the interface + if(NULL == flags) + { + return LL_IFC_ERROR_INCORRECT_PARAMETER; + } - uint8_t in_buf[4]; - uint8_t out_buf[4] = {0,0,0,0}; + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } - in_buf[0] = (uint8_t)((flags_to_clear >> 24) & 0xFF); - in_buf[1] = (uint8_t)((flags_to_clear >> 16) & 0xFF); - in_buf[2] = (uint8_t)((flags_to_clear >> 8) & 0xFF); - in_buf[3] = (uint8_t)((flags_to_clear ) & 0xFF); + // Assuming big endian convention over the interface + _ll_ifc_msg_buff[0] = (uint8_t)((flags_to_clear >> 24) & 0xFF); + _ll_ifc_msg_buff[1] = (uint8_t)((flags_to_clear >> 16) & 0xFF); + _ll_ifc_msg_buff[2] = (uint8_t)((flags_to_clear >> 8) & 0xFF); + _ll_ifc_msg_buff[3] = (uint8_t)((flags_to_clear ) & 0xFF); - int32_t rw_response = hal_read_write(OP_IRQ_FLAGS, in_buf, 4, out_buf, 4); + int32_t ret = hal_read_write(OP_IRQ_FLAGS, &_ll_ifc_msg_buff[0], 4, &_ll_ifc_msg_in_buff[0], 4); - if(rw_response > 0) + if(ret < 0) + { + //return ret; + } + else if(4 != ret) + { + ret = LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + else { uint32_t flags_temp = 0; - flags_temp |= (((uint32_t)out_buf[0]) << 24); - flags_temp |= (((uint32_t)out_buf[1]) << 16); - flags_temp |= (((uint32_t)out_buf[2]) << 8); - flags_temp |= (((uint32_t)out_buf[3])); + flags_temp |= (((uint32_t)_ll_ifc_msg_in_buff[0]) << 24); + flags_temp |= (((uint32_t)_ll_ifc_msg_in_buff[1]) << 16); + flags_temp |= (((uint32_t)_ll_ifc_msg_in_buff[2]) << 8); + flags_temp |= (((uint32_t)_ll_ifc_msg_in_buff[3])); *flags = flags_temp; } - - return(rw_response); + + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; } //STRIPTHIS!START @@ -363,57 +589,90 @@ int32_t ll_timestamp_get(uint32_t * timestamp_us) int32_t ll_timestamp_set(ll_timestamp_operation_t operation, uint32_t timestamp_us, uint32_t * actual_timestamp_us) { - uint8_t in_buf[5]; - uint8_t * b_in = in_buf; - uint8_t out_buf[4] = {0,0,0,0}; + uint8_t * b_out = &_ll_ifc_msg_buff[0]; if (actual_timestamp_us == NULL) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - write_uint8((uint8_t) operation, &b_in); - write_uint32(timestamp_us, &b_in); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + write_uint8((uint8_t) operation, &b_out); + write_uint32(timestamp_us, &b_out); - int32_t rw_response = hal_read_write_exact(OP_TIMESTAMP, in_buf, sizeof(in_buf), out_buf, sizeof(out_buf)); - if (rw_response >= 0) + int32_t ret = hal_read_write_exact(OP_TIMESTAMP, &_ll_ifc_msg_buff[0], 5, &_ll_ifc_msg_in_buff[0], 4); + + if (ret >= 0) { - uint8_t const * b_out = out_buf; - *actual_timestamp_us = read_uint32(&b_out); - rw_response = 0; + uint8_t const * b_in = &_ll_ifc_msg_in_buff[0]; + *actual_timestamp_us = read_uint32(&b_in); + ret = LL_IFC_ACK; } - return rw_response; + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_trigger_watchdog(void) { uint8_t cmd_buf[2]; - cmd_buf[0] = 0x00; - cmd_buf[1] = 0x01; - return hal_read_write(OP_RESERVED1, cmd_buf, 2, NULL, 0); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + _ll_ifc_msg_buff[0] = 0x00; + _ll_ifc_msg_buff[1] = 0x01; + + int32_t ret = hal_read_write(OP_RESERVED1, &_ll_ifc_msg_buff[0], 2, NULL, 0); + + transport_mutex_release(); + + return ret; } int32_t ll_get_assert_info(char *filename, uint16_t filename_len, uint32_t *line) { - uint8_t tmp_arr[4 + 20]; - int32_t ret = hal_read_write(OP_GET_ASSERT, NULL, 0, tmp_arr, 4 + 20); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_GET_ASSERT, NULL, 0, &_ll_ifc_msg_in_buff[0], 4 + 20); + if (ret > 0) { *line = 0; - *line += (uint32_t)(tmp_arr[0]) << 24; - *line += (uint32_t)(tmp_arr[1]) << 16; - *line += (uint32_t)(tmp_arr[2]) << 8; - *line += (uint32_t)(tmp_arr[3]) << 0; + *line += (uint32_t)(_ll_ifc_msg_in_buff[0]) << 24; + *line += (uint32_t)(_ll_ifc_msg_in_buff[1]) << 16; + *line += (uint32_t)(_ll_ifc_msg_in_buff[2]) << 8; + *line += (uint32_t)(_ll_ifc_msg_in_buff[3]) << 0; uint16_t cpy_len = filename_len < 20 ? filename_len : 20; - memcpy(filename, tmp_arr + 4, cpy_len); + memcpy(filename, &_ll_ifc_msg_in_buff[4], cpy_len); } + + transport_mutex_release(); return ret; } + int32_t ll_trigger_assert(void) { - return hal_read_write(OP_SET_ASSERT, NULL, 0, NULL, 0); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_SET_ASSERT, NULL, 0, NULL, 0); + transport_mutex_release(); + return ret; } //STRIPTHIS!STOP @@ -444,21 +703,29 @@ int32_t ll_reset_state( void ) * @return * none */ +#define SP_NUM_WAKEUP_BYTES (5) +#define SP_NUM_ZEROS (3) +#define SP_NUM_CKSUM_BYTES (2) +#define SP_HEADER_SIZE (CMD_HEADER_LEN + SP_NUM_ZEROS) +uint8_t wakeup_buf[SP_NUM_WAKEUP_BYTES]; +uint8_t header_buf[(SP_HEADER_SIZE>RESP_HEADER_LEN)?SP_HEADER_SIZE:RESP_HEADER_LEN]; +uint8_t checksum_buff[SP_NUM_CKSUM_BYTES]; +uint16_t header_idx; + static void send_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint16_t len) { - #define SP_NUM_ZEROS (4) - #define SP_HEADER_SIZE (CMD_HEADER_LEN + SP_NUM_ZEROS) - uint8_t header_buf[SP_HEADER_SIZE]; - uint8_t checksum_buff[2]; uint16_t computed_checksum; - uint16_t header_idx = 0; uint16_t i; - // Send a couple wakeup bytes, just-in-case - for (i = 0; i < SP_NUM_ZEROS; i++) - { - header_buf[header_idx ++] = 0xff; - } + header_idx = 0; + // Send the wakeup bytes + memset((uint8_t *) wakeup_buf, WAKEUP_BYTE, (size_t) SP_NUM_WAKEUP_BYTES); + + transport_write(wakeup_buf, SP_NUM_WAKEUP_BYTES); + + memset((uint8_t *) header_buf, 0xFF, (size_t) SP_NUM_ZEROS); + + header_idx = SP_NUM_ZEROS; header_buf[header_idx++] = FRAME_START; header_buf[header_idx++] = op; @@ -466,7 +733,7 @@ static void send_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint16_t header_buf[header_idx++] = (uint8_t)(0xFF & (len >> 8)); header_buf[header_idx++] = (uint8_t)(0xFF & (len >> 0)); - computed_checksum = compute_checksum(header_buf + SP_NUM_ZEROS, CMD_HEADER_LEN, buf, len); + computed_checksum = compute_checksum(&header_buf[SP_NUM_ZEROS], CMD_HEADER_LEN, buf, len); transport_write(header_buf, SP_HEADER_SIZE); @@ -478,7 +745,6 @@ static void send_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint16_t checksum_buff[0] = (computed_checksum >> 8); checksum_buff[1] = (computed_checksum >> 0); transport_write(checksum_buff, 2); - } /** @@ -518,13 +784,11 @@ static void send_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint16_t * -108 transport_read failed getting FRAME_START * -109 transport_read failed getting header */ +static uint8_t _ll_ifc_start_byte = 0; +static uint8_t _ll_ifc_temp_byte; + static int32_t recv_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint16_t len) { - uint8_t header_buf[RESP_HEADER_LEN]; - uint16_t header_idx; - - uint8_t curr_byte = 0; - uint8_t checksum_buff[2]; uint16_t computed_checksum; int32_t ret_value = 0; int32_t ret; @@ -532,6 +796,7 @@ static int32_t recv_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint1 memset(header_buf, 0, sizeof(header_buf)); struct time time_start, time_now; + if (gettime(&time_start) < 0) { return LL_IFC_ERROR_HAL_CALL_FAILED; @@ -539,12 +804,14 @@ static int32_t recv_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint1 do { + /* Timeout of infinite Rx loop if responses never show up*/ - ret = transport_read(&curr_byte, 1); + ret = transport_read(&_ll_ifc_start_byte, 1); if (gettime(&time_now) < 0) { return LL_IFC_ERROR_HAL_CALL_FAILED; + } if(time_now.tv_sec - time_start.tv_sec > 2) @@ -552,7 +819,7 @@ static int32_t recv_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint1 len = 0; return LL_IFC_ERROR_HOST_INTERFACE_TIMEOUT; } - } while(curr_byte != FRAME_START); + } while(_ll_ifc_start_byte != FRAME_START); if (ret < 0) { @@ -563,7 +830,7 @@ static int32_t recv_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint1 header_idx = 0; header_buf[header_idx++] = FRAME_START; - ret = transport_read(header_buf + 1, RESP_HEADER_LEN - 1); + ret = transport_read(&header_buf[header_idx], RESP_HEADER_LEN - 1); if (ret < 0) { /* transport_read failed - return an error */ @@ -595,10 +862,11 @@ static int32_t recv_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint1 int32_t ret; do { - uint8_t temp_byte; - ret = transport_read(&temp_byte, 1); + + ret = transport_read(&_ll_ifc_temp_byte, 1); } while (ret == 0); + return LL_IFC_ERROR_BUFFER_TOO_SMALL; } else if (len_from_header < len) @@ -609,7 +877,6 @@ static int32_t recv_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint1 if (ret_value == 0) { - // If we got here, then we: // 1) Received the FRAME_START in the response // 2) The message number matched @@ -620,18 +887,27 @@ static int32_t recv_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint1 // Grab the payload if there is supposed to be one if ((buf != NULL) && (len > 0)) { - transport_read(buf, len); + ret = transport_read(buf, len); + if (ret < 0) + { + return -2; + } } - } - // Finally, make sure the checksum matches - transport_read(checksum_buff, 2); + // Finally, make sure the checksum matches + ret = transport_read(checksum_buff, 2); + if (ret < 0) + { + return -2; + } - computed_checksum = compute_checksum(header_buf, RESP_HEADER_LEN, buf, len); - uint16_t rx_checksum = ((uint16_t)checksum_buff[0] << 8) + checksum_buff[1]; - if (rx_checksum != computed_checksum) - { - return LL_IFC_ERROR_CHECKSUM_MISMATCH; + computed_checksum = compute_checksum(header_buf, RESP_HEADER_LEN, buf, len); + uint16_t rx_checksum = ((uint16_t)checksum_buff[0] << 8) + checksum_buff[1]; + if (rx_checksum != computed_checksum) + { + return LL_IFC_ERROR_CHECKSUM_MISMATCH; + + } } if (ret_value == 0) @@ -646,6 +922,7 @@ static int32_t recv_packet(opcode_t op, uint8_t message_num, uint8_t *buf, uint1 } } + /** * @brief * compute_checksum diff --git a/src/ll_ifc_ftp.c b/src/ll_ifc_ftp.c index 6491aae..3ddd085 100644 --- a/src/ll_ifc_ftp.c +++ b/src/ll_ifc_ftp.c @@ -73,7 +73,7 @@ static ll_ftp_return_code_t ll_ftp_send_uplink(ll_ftp_t* f, size_t len) { uint8_t old_max_port = ll_ul_max_port; ll_ul_max_port = LL_FTP_PORT; - ll_ftp_return_code_t ret = f->cb.uplink(f->tx_buf, len, true, LL_FTP_PORT); + ll_ftp_return_code_t ret = f->cb.uplink(f->tx_buf, (uint16_t) len, true, LL_FTP_PORT); ll_ul_max_port = old_max_port; gettime(&f->time_last_msg); return ret; @@ -194,6 +194,7 @@ static uint16_t ll_ftp_get_missing_segs(ll_ftp_t* f, bool fill_buf) uint16_t seg_num; uint8_t num_segs_base; uint8_t idx; + uint16_t total_payload = fill_buf ? BASE_UL_MSG_LEN : 0; uint16_t base_max = f->num_segs >> 5; // divide by 32 for(i = 0; i <= base_max; i++) @@ -209,15 +210,21 @@ static uint16_t ll_ftp_get_missing_segs(ll_ftp_t* f, bool fill_buf) // request complete retransmission return 0xFFFF; } + seg_num = (i << 5) + j; // i * 32 + j - + idx = num_missing_segs * 2; - if(fill_buf) + + // Only fill the buffer up to the maximum number of segments we can request in + // a single payload + if ((fill_buf) && ((total_payload + sizeof(seg_num)) <= LL_FTP_TX_BUF_SIZE)) { f->tx_buf[LL_FTP_NAK_FILE_SEGS_INDEX + idx] = seg_num & 0x00FF; f->tx_buf[LL_FTP_NAK_FILE_SEGS_INDEX + idx + 1] = (seg_num >> 8) & 0x00FF; + + total_payload += sizeof(seg_num); + num_missing_segs++; } - num_missing_segs++; } } } @@ -225,7 +232,7 @@ static uint16_t ll_ftp_get_missing_segs(ll_ftp_t* f, bool fill_buf) return num_missing_segs; } -static uint8_t ll_ftp_ack_init_generate(ll_ftp_t* f, bool ack) +static uint16_t ll_ftp_ack_init_generate(ll_ftp_t* f, bool ack) { f->tx_buf[LL_FTP_MSG_PACKET_TYPE_INDEX] = ACK_INIT; if (ack) @@ -246,7 +253,7 @@ static uint8_t ll_ftp_ack_init_generate(ll_ftp_t* f, bool ack) return BASE_UL_MSG_LEN; } -static uint8_t ll_ftp_ack_segs_complete_generate(ll_ftp_t* f) +static uint16_t ll_ftp_ack_segs_complete_generate(ll_ftp_t* f) { f->tx_buf[LL_FTP_MSG_PACKET_TYPE_INDEX] = ACK_SEGMENT; f->tx_buf[LL_FTP_ACK_ACK_TYPE_INDEX] = ACK_ACK; @@ -259,7 +266,7 @@ static uint8_t ll_ftp_ack_segs_complete_generate(ll_ftp_t* f) return BASE_UL_MSG_LEN; } -static uint8_t ll_ftp_ack_segs_request_generate(ll_ftp_t* f) +static uint16_t ll_ftp_ack_segs_request_generate(ll_ftp_t* f) { f->tx_buf[LL_FTP_MSG_PACKET_TYPE_INDEX] = ACK_SEGMENT; f->tx_buf[LL_FTP_ACK_ACK_TYPE_INDEX] = ACK_NAK_SEGMENT; @@ -268,7 +275,7 @@ static uint8_t ll_ftp_ack_segs_request_generate(ll_ftp_t* f) // check max length number of retry segments uint16_t num_missing_segs = ll_ftp_get_missing_segs(f, true); - uint8_t return_len = BASE_UL_MSG_LEN; + uint16_t return_len = BASE_UL_MSG_LEN; if(MAX_NUM_RETRY_SEGS <= num_missing_segs) { f->tx_buf[LL_FTP_ACK_ACK_TYPE_INDEX] = ACK_NAK; @@ -278,16 +285,16 @@ static uint8_t ll_ftp_ack_segs_request_generate(ll_ftp_t* f) return_len += num_missing_segs * sizeof(uint16_t); } - uint32_t crc = crc32(0, &f->tx_buf[LL_FTP_ACK_ACK_TYPE_INDEX], return_len - LL_FTP_ACK_ACK_TYPE_INDEX); + uint32_t crc = crc32(0, &f->tx_buf[LL_FTP_ACK_ACK_TYPE_INDEX], (size_t) return_len - LL_FTP_ACK_ACK_TYPE_INDEX); UINT32_TO_BYTESTREAM((&f->tx_buf[LL_FTP_MSG_CRC_INDEX]), crc); return return_len; } -static uint8_t ll_ftp_ack_apply_generate(ll_ftp_t* f) +static uint16_t ll_ftp_ack_apply_generate(ll_ftp_t* f, bool success) { f->tx_buf[LL_FTP_MSG_PACKET_TYPE_INDEX] = ACK_APPLY; - f->tx_buf[LL_FTP_ACK_ACK_TYPE_INDEX] = ACK_ACK; + f->tx_buf[LL_FTP_ACK_ACK_TYPE_INDEX] = (success ? ACK_ACK : ACK_NAK); UINT32_TO_BYTESTREAM((&f->tx_buf[LL_FTP_ACK_FILE_ID_INDEX]), f->file_id); UINT32_TO_BYTESTREAM((&f->tx_buf[LL_FTP_ACK_FILE_VERSION_INDEX]), f->file_version); @@ -307,7 +314,7 @@ static void ll_ftp_new_file_initialize(ll_ftp_t* f, ll_ftp_msg_t* msg) memset(f->rx_segs, 0, sizeof(f->rx_segs[0]) * NUM_RX_SEGS_BITMASK); // send ACK_INIT - uint8_t len = ll_ftp_ack_init_generate(f, true); + uint16_t len = ll_ftp_ack_init_generate(f, true); ll_ftp_send_uplink(f, len); } @@ -332,6 +339,7 @@ static int32_t ll_ftp_idle_start(ll_ftp_t* f) static int32_t ll_ftp_segment_start(ll_ftp_t* f, ll_ftp_msg_t* msg) { + ll_ftp_return_code_t msg_ret; int32_t ret = LL_FTP_NO_ACTION; int32_t cb_ret = f->cb.open(msg->file_id, msg->file_version, msg->file_size); @@ -344,8 +352,12 @@ static int32_t ll_ftp_segment_start(ll_ftp_t* f, ll_ftp_msg_t* msg) else if (TX_INIT == msg->msg_type || TX_SEGMENT == msg->msg_type) { // send ACK_INIT - uint8_t len = ll_ftp_ack_init_generate(f, false); - ll_ftp_send_uplink(f, len); + uint16_t len = ll_ftp_ack_init_generate(f, false); + msg_ret = ll_ftp_send_uplink(f, len); + if (msg_ret != LL_FTP_OK) + { + ret = LL_FTP_ERROR; + } } return ret; @@ -353,14 +365,20 @@ static int32_t ll_ftp_segment_start(ll_ftp_t* f, ll_ftp_msg_t* msg) static int32_t ll_ftp_apply_start(ll_ftp_t* f) { + ll_ftp_return_code_t msg_ret; int32_t ret = LL_FTP_ERROR; int32_t cb_ret = f->cb.close(f->file_id, f->file_version); if(LL_FTP_OK == cb_ret) { - uint8_t len = ll_ftp_ack_segs_complete_generate(f); - ll_ftp_send_uplink(f, len); + uint16_t len = ll_ftp_ack_segs_complete_generate(f); + ret = LL_FTP_OK; + msg_ret = ll_ftp_send_uplink(f, len); + if (msg_ret != LL_FTP_OK) + { + ret = LL_FTP_ERROR; + } } return ret; @@ -542,6 +560,7 @@ static int32_t ll_ftp_transition_out_of_segment(ll_ftp_t* f, ll_ftp_msg_t* msg, } break; default: + ret = LL_FTP_ERROR; break; } @@ -550,6 +569,7 @@ static int32_t ll_ftp_transition_out_of_segment(ll_ftp_t* f, ll_ftp_msg_t* msg, static int32_t ll_ftp_segment_process_msg(ll_ftp_t* f, uint8_t* buf, uint8_t len) { + ll_ftp_return_code_t msg_ret; ll_ftp_msg_t ftp_msg; int32_t ret = ll_ftp_parse_rx_msg(buf, len, &ftp_msg); if(LL_FTP_OK != ret) @@ -605,13 +625,19 @@ static int32_t ll_ftp_segment_process_msg(ll_ftp_t* f, uint8_t* buf, uint8_t len { // Only able to apply in APPLY state // send NAK with retry segs - uint8_t len = ll_ftp_ack_segs_request_generate(f); - ll_ftp_send_uplink(f, len); + uint16_t len = ll_ftp_ack_segs_request_generate(f); + ret = LL_FTP_OK; + msg_ret = ll_ftp_send_uplink(f, len); + if (msg_ret != LL_FTP_OK) + { + ret = LL_FTP_ERROR; + } } else if(TICK == ftp_msg.msg_type) { struct time time_now; + ret = LL_FTP_OK; // Rely on a periodic 1 Hz tick to request segments if necessary gettime(&time_now); @@ -619,8 +645,13 @@ static int32_t ll_ftp_segment_process_msg(ll_ftp_t* f, uint8_t* buf, uint8_t len { if(f->retry_count < LL_FTP_MAX_NUM_RETRIES) { - uint8_t len = ll_ftp_ack_segs_request_generate(f); - ll_ftp_send_uplink(f, len); + uint16_t len = ll_ftp_ack_segs_request_generate(f); + msg_ret = ll_ftp_send_uplink(f, len); + if (msg_ret != LL_FTP_OK) + { + ret = LL_FTP_ERROR; + } + f->retry_count++; } else @@ -628,7 +659,6 @@ static int32_t ll_ftp_segment_process_msg(ll_ftp_t* f, uint8_t* buf, uint8_t len next_state = IDLE; } } - ret = LL_FTP_OK; } // Do state transitions out of SEGMENT @@ -686,6 +716,7 @@ static int32_t ll_ftp_transition_out_of_apply(ll_ftp_t* f, ll_ftp_msg_t* msg, ll static int32_t ll_ftp_apply_process_msg(ll_ftp_t* f, uint8_t* buf, uint8_t len) { ll_ftp_msg_t ftp_msg; + ll_ftp_return_code_t msg_ret; int32_t ret = ll_ftp_parse_rx_msg(buf, len, &ftp_msg); if(LL_FTP_OK != ret) @@ -718,23 +749,31 @@ static int32_t ll_ftp_apply_process_msg(ll_ftp_t* f, uint8_t* buf, uint8_t len) } else if ((TX_APPLY == ftp_msg.msg_type) && (IS_MY_FILE)) { + uint16_t len; int32_t cb_ret = f->cb.apply(f->file_id, f->file_version, f->file_size); if(LL_FTP_OK == cb_ret) { - uint8_t len = ll_ftp_ack_apply_generate(f); - ll_ftp_send_uplink(f, len); - next_state = IDLE; + len = ll_ftp_ack_apply_generate(f, true); } else { - // Apply rejected. Forget File. + // Apply rejected. Send NAK and forget file. + len = ll_ftp_ack_apply_generate(f, false); + ret = LL_FTP_ERROR; + } + + next_state = IDLE; + msg_ret = ll_ftp_send_uplink(f, len); + if (msg_ret != LL_FTP_OK) + { ret = LL_FTP_ERROR; - next_state = IDLE; } } else if(TICK == ftp_msg.msg_type) { struct time time_now; + + ret = LL_FTP_OK; // Rely on a periodic 1 Hz tick to request segments if necessary gettime(&time_now); @@ -742,8 +781,13 @@ static int32_t ll_ftp_apply_process_msg(ll_ftp_t* f, uint8_t* buf, uint8_t len) { if(f->retry_count < LL_FTP_MAX_NUM_RETRIES) { - uint8_t len = ll_ftp_ack_segs_complete_generate(f); - ll_ftp_send_uplink(f, len); + uint16_t len = ll_ftp_ack_segs_complete_generate(f); + msg_ret = ll_ftp_send_uplink(f, len); + if (msg_ret != LL_FTP_OK) + { + ret = LL_FTP_ERROR; + } + f->retry_count++; } else @@ -751,7 +795,6 @@ static int32_t ll_ftp_apply_process_msg(ll_ftp_t* f, uint8_t* buf, uint8_t len) next_state = IDLE; } } - ret = LL_FTP_OK; } // Do state transitions out of APPLY diff --git a/src/ll_ifc_no_mac.c b/src/ll_ifc_no_mac.c index d3ce57a..c90e098 100644 --- a/src/ll_ifc_no_mac.c +++ b/src/ll_ifc_no_mac.c @@ -30,7 +30,8 @@ int32_t ll_rssi_scan_set(uint32_t u1, uint32_t u2, uint32_t u3, uint32_t u4) buf[14] = (u4 >> 8) & 0xFF; buf[15] = (u4 ) & 0xFF; - return hal_read_write(OP_RSSI_SET, buf, 16, NULL, 0); + int32_t ret = hal_read_write(OP_RSSI_SET, buf, 16, NULL, 0); + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_rssi_scan_get(uint8_t buf[], uint16_t len, uint8_t *bytes_received) @@ -47,22 +48,35 @@ int32_t ll_rssi_scan_get(uint8_t buf[], uint16_t len, uint8_t *bytes_received) if (rw_response < 0) { *bytes_received = 0; - return(-1); - } - else - { - *bytes_received = (uint8_t) (rw_response & 0xFF); - return(0); + return rw_response; } + + *bytes_received = (uint8_t) (rw_response & 0xFF); + return (rw_response >= 0) ? LL_IFC_ACK : rw_response; } int32_t ll_radio_params_get(uint8_t *sf, uint8_t *cr, uint8_t *bw, uint32_t *freq, uint16_t *preamble_syms, uint8_t *header_enabled, uint8_t *crc_enabled, uint8_t *iq_inverted) { + if((NULL == sf) || (NULL == cr) || (NULL == bw) || (NULL == freq) || + (NULL == preamble_syms) || (NULL == header_enabled) || (NULL == crc_enabled) || (NULL == iq_inverted)) + { + return LL_IFC_ERROR_INCORRECT_PARAMETER; + } + int32_t ret; uint8_t buff[8]; ret = hal_read_write(OP_GET_RADIO_PARAMS, NULL, 0, buff, 8); + if (ret < 0) + { + return ret; + } + if (ret != 8) + { + return LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + *sf = (buff[0] >> 4) + 6; *cr = ((buff[0] >> 2) & 0x03) + 1; @@ -79,7 +93,7 @@ int32_t ll_radio_params_get(uint8_t *sf, uint8_t *cr, uint8_t *bw, uint32_t *fre *freq |= (uint32_t)(buff[6] << 8); *freq |= (uint32_t)(buff[7] ); - return ret; + return LL_IFC_ACK; } int32_t ll_radio_params_set(uint8_t flags, uint8_t sf, uint8_t cr, uint8_t bw, uint32_t freq, @@ -179,7 +193,8 @@ int32_t ll_tx_power_get(int8_t *pwr) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - return hal_read_write(OP_TX_POWER_GET, NULL, 0, (uint8_t *)pwr, 1); + int32_t ret = hal_read_write(OP_TX_POWER_GET, NULL, 0, (uint8_t *)pwr, 1); + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_frequency_set(uint32_t freq) @@ -218,7 +233,8 @@ int32_t ll_sync_word_get(uint8_t *sync_word) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - return hal_read_write(OP_SYNC_WORD_GET, NULL, 0, sync_word, 1); + int32_t ret = hal_read_write(OP_SYNC_WORD_GET, NULL, 0, sync_word, 1); + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_echo_mode(void) @@ -322,7 +338,7 @@ int32_t ll_packet_recv(uint16_t num_timeout_symbols, uint8_t buf[], uint16_t len if (rw_response < 0) { *bytes_received = 0; - return(-1); + return rw_response; } else { @@ -358,7 +374,7 @@ int32_t ll_packet_recv_with_rssi(uint16_t num_timeout_symbols, uint8_t buf[], ui if (rw_response < 0) { *bytes_received = 0; - return(-1); + return rw_response; } else { diff --git a/src/ll_ifc_symphony.c b/src/ll_ifc_symphony.c index f6a58fc..3956816 100644 --- a/src/ll_ifc_symphony.c +++ b/src/ll_ifc_symphony.c @@ -1,9 +1,18 @@ #include "ll_ifc_symphony.h" #include "ll_ifc_private.h" -#include // memmove +#include "ifc_struct_defs.h" +#include // memmove + +//uint8_t _uplink_message_buff[256 + 2]; +//uint8_t *uplink_message_buff = _uplink_message_buff + 2; + +static uint8_t _ll_ifc_message_buff[256 + 2]; +static uint8_t isMsgBuffInUse; + +//uint8_t *uplink_message_buff = _uplink_message_buff + 2; + +#define UPLINK_DATA_INDEX 2 -uint8_t _uplink_message_buff[256 + 2]; -uint8_t *uplink_message_buff = _uplink_message_buff + 2; uint8_t ll_ul_max_port = 127; const llabs_dl_band_cfg_t DL_BAN_FCC = {902000000, 928000000, 386703, 3, 0}; // USA / Mexico @@ -12,32 +21,58 @@ const llabs_dl_band_cfg_t DL_BAN_AUS = {918000000, 926000000, 386703, 3, 0}; // const llabs_dl_band_cfg_t DL_BAN_NZL = {921000000, 928000000, 386703, 3, 0}; // New Zealand const llabs_dl_band_cfg_t DL_BAN_ETSI = {869100000, 871000000, 386703, 1, 0}; // Europe + int32_t ll_net_token_get(uint32_t *p_net_token) { - uint8_t buff[4]; if (p_net_token == NULL) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - int32_t ret = hal_read_write(OP_NET_TOKEN_GET, NULL, 0, buff, 4); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_NET_TOKEN_GET, NULL, 0, &_ll_ifc_message_buff[0], 4); + transport_mutex_release(); + + if (ret < 0) + { + return ret; + } + + if (4 != ret) + { + return LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + *p_net_token = 0; - *p_net_token |= (uint32_t)buff[0] << 24; - *p_net_token |= (uint32_t)buff[1] << 16; - *p_net_token |= (uint32_t)buff[2] << 8; - *p_net_token |= (uint32_t)buff[3]; - return ret; + *p_net_token |= (uint32_t) _ll_ifc_message_buff[0] << 24; + *p_net_token |= (uint32_t) _ll_ifc_message_buff[1] << 16; + *p_net_token |= (uint32_t) _ll_ifc_message_buff[2] << 8; + *p_net_token |= (uint32_t) _ll_ifc_message_buff[3]; + return LL_IFC_ACK; } int32_t ll_net_token_set(uint32_t net_token) { - if(net_token != 0xFFFFFFFF) + if (net_token != 0xFFFFFFFF) { - uint8_t buff[4]; - buff[0] = (net_token >> 24) & 0xFF; - buff[1] = (net_token >> 16) & 0xFF; - buff[2] = (net_token >> 8) & 0xFF; - buff[3] = (net_token) & 0xFF; - return hal_read_write(OP_NET_TOKEN_SET, buff, 4, NULL, 0); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + _ll_ifc_message_buff[0] = (net_token >> 24) & 0xFF; + _ll_ifc_message_buff[1] = (net_token >> 16) & 0xFF; + _ll_ifc_message_buff[2] = (net_token >> 8) & 0xFF; + _ll_ifc_message_buff[3] = (net_token) &0xFF; + + + int32_t ret = hal_read_write(OP_NET_TOKEN_SET, &_ll_ifc_message_buff[0], 4, NULL, 0); + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; } else { @@ -51,11 +86,23 @@ static int32_t ll_app_token_set(const uint8_t *app_token, uint8_t len) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - if(10 != len) + + if (10 != len) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - return hal_read_write(OP_APP_TOKEN_SET, (uint8_t*) app_token, 10, NULL, 0); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + memcpy(&_ll_ifc_message_buff[0], app_token, len); + + int32_t ret = hal_read_write(OP_APP_TOKEN_SET, &_ll_ifc_message_buff[0], 10, NULL, 0); + + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; } static int32_t ll_app_token_get(uint8_t *app_token) @@ -64,7 +111,28 @@ static int32_t ll_app_token_get(uint8_t *app_token) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - return hal_read_write(OP_APP_TOKEN_GET, NULL, 0, app_token, 10); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_APP_TOKEN_GET, NULL, 0, &_ll_ifc_message_buff[0], 10); + + memcpy(app_token, &_ll_ifc_message_buff[0], 10); + + transport_mutex_release(); + + if (ret < 0) + { + return ret; + } + if (10 != ret) + { + return LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + + return LL_IFC_ACK; } static int32_t ll_receive_mode_set(uint8_t rx_mode) @@ -73,7 +141,17 @@ static int32_t ll_receive_mode_set(uint8_t rx_mode) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - return hal_read_write(OP_RX_MODE_SET, &rx_mode, 1, NULL, 0); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + _ll_ifc_message_buff[0] = rx_mode; + + int32_t ret = hal_read_write(OP_RX_MODE_SET, &_ll_ifc_message_buff[0], 1, NULL, 0); + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; } static int32_t ll_receive_mode_get(uint8_t *rx_mode) @@ -82,7 +160,18 @@ static int32_t ll_receive_mode_get(uint8_t *rx_mode) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - return hal_read_write(OP_RX_MODE_GET, NULL, 0, rx_mode, sizeof(*rx_mode)); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_RX_MODE_GET, NULL, 0, &_ll_ifc_message_buff[0], sizeof(*rx_mode)); + + *rx_mode = _ll_ifc_message_buff[0]; + + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; } static int32_t ll_qos_request(uint8_t qos) @@ -91,7 +180,18 @@ static int32_t ll_qos_request(uint8_t qos) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - return hal_read_write(OP_QOS_REQUEST, &qos, 1, NULL, 0); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + _ll_ifc_message_buff[0] = qos; + + int32_t ret = hal_read_write(OP_QOS_REQUEST, &_ll_ifc_message_buff[0], 1, NULL, 0); + + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; } static int32_t ll_qos_get(uint8_t *qos) @@ -100,9 +200,129 @@ static int32_t ll_qos_get(uint8_t *qos) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - return hal_read_write(OP_QOS_GET, NULL, 0, qos, sizeof(*qos)); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_QOS_GET, NULL, 0, &_ll_ifc_message_buff[0], sizeof(*qos)); + + *qos = _ll_ifc_message_buff[0]; + + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_scan_mode_set(enum ll_scan_mode scan_mode) +{ + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + _ll_ifc_message_buff[0] = (uint8_t) scan_mode; + + int32_t ret = hal_read_write(OP_SCAN_MODE_SET, &_ll_ifc_message_buff[0], 1, NULL, 0); + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_scan_mode_get(enum ll_scan_mode *scan_mode) +{ + uint8_t u8_scan_mode; + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_SCAN_MODE_GET, NULL, 0, &_ll_ifc_message_buff[0], 1); + + *scan_mode = _ll_ifc_message_buff[0]; + + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +static int32_t ll_threshold_set(int16_t threshold) +{ + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + _ll_ifc_message_buff[0] = threshold & 0xff; + _ll_ifc_message_buff[1] = threshold >> 8; + + int32_t ret = hal_read_write(OP_SCAN_THRESHOLD_SET, &_ll_ifc_message_buff[0], 2, NULL, 0); + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +static int32_t ll_threshold_get(int16_t *threshold) +{ + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_SCAN_THRESHOLD_GET, NULL, 0, &_ll_ifc_message_buff[0], 2); + + *threshold = ((uint16_t) _ll_ifc_message_buff[1] << 8) | _ll_ifc_message_buff[0]; + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; +} + + +static int32_t ll_scan_attempts_get(uint16_t *scan_attempts) +{ + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_SCAN_ATTEMPTS_GET, NULL, 0, &_ll_ifc_message_buff[0], 2); + + *scan_attempts = ((uint16_t) _ll_ifc_message_buff[1] << 8) | _ll_ifc_message_buff[0]; + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } +static int32_t ll_scan_attempts_left_get(uint16_t *scan_attempts) +{ + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_SCAN_ATTEMPTS_LEFT, NULL, 0, &_ll_ifc_message_buff[0], 2); + *scan_attempts = ((uint16_t) _ll_ifc_message_buff[1] << 8) | _ll_ifc_message_buff[0]; + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; +} + + +int32_t ll_scan_attempts_set(uint16_t scan_attempts) +{ + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + _ll_ifc_message_buff[0] = scan_attempts & 0xff; + _ll_ifc_message_buff[1] = scan_attempts >> 8; + + int32_t ret = hal_read_write(OP_SCAN_ATTEMPTS_SET, &_ll_ifc_message_buff[0], 2, NULL, 0); + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; +} int32_t ll_config_set(uint32_t net_token, const uint8_t app_token[APP_TOKEN_LEN], enum ll_downlink_mode dl_mode, uint8_t qos) @@ -110,30 +330,30 @@ int32_t ll_config_set(uint32_t net_token, const uint8_t app_token[APP_TOKEN_LEN] int32_t ret; ret = ll_net_token_set(net_token); - if (LL_IFC_ACK > ret) + if (LL_IFC_ACK != ret) { return ret; } ret = ll_app_token_set(app_token, APP_TOKEN_LEN); - if (LL_IFC_ACK > ret) + if (LL_IFC_ACK != ret) { return ret; } ret = ll_receive_mode_set(dl_mode); - if (LL_IFC_ACK > ret) + if (LL_IFC_ACK != ret) { return ret; } ret = ll_qos_request(qos); - if (LL_IFC_ACK > ret) + if (LL_IFC_ACK != ret) { return ret; } - return ret; + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_config_get(uint32_t *net_token, uint8_t app_token[APP_TOKEN_LEN], @@ -142,75 +362,335 @@ int32_t ll_config_get(uint32_t *net_token, uint8_t app_token[APP_TOKEN_LEN], int32_t ret; ret = ll_net_token_get(net_token); - if (LL_IFC_ACK > ret) + if (LL_IFC_ACK != ret) { return ret; } ret = ll_app_token_get(app_token); - if (LL_IFC_ACK > ret) + if (LL_IFC_ACK != ret) { return ret; } - ret = ll_receive_mode_get((uint8_t *)dl_mode); - if (LL_IFC_ACK > ret) + ret = ll_receive_mode_get((uint8_t *) dl_mode); + if (LL_IFC_ACK != ret) { return ret; } ret = ll_qos_get(qos); - if (LL_IFC_ACK > ret) + if (LL_IFC_ACK != ret) { return ret; } - return ret; + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_scan_config_set(enum ll_scan_mode scan_mode, int16_t threshold, uint16_t scan_attempts) +{ + if (scan_mode > LLABS_INFO_SCAN) + { + return LL_IFC_ERROR_INCORRECT_PARAMETER; + } + + int32_t ret = ll_scan_mode_set(scan_mode); + if (ret < LL_IFC_ACK) + { + return ret; + } + + ret = ll_threshold_set(threshold); + if (ret < LL_IFC_ACK) + { + return ret; + } + + ret = ll_scan_attempts_set(scan_attempts); + if (ret < LL_IFC_ACK) + { + return ret; + } + + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_scan_config_get(enum ll_scan_mode *scan_mode, int16_t *threshold, + uint16_t *scan_attempts, uint16_t *scans_left) +{ + int32_t ret = ll_scan_mode_get(scan_mode); + if (ret < LL_IFC_ACK) + { + return ret; + } + + ret = ll_threshold_get(threshold); + if (ret < LL_IFC_ACK) + { + return ret; + } + + ret = ll_scan_attempts_get(scan_attempts); + if (ret < LL_IFC_ACK) + { + return ret; + } + + ret = ll_scan_attempts_left_get(scans_left); + if (ret < LL_IFC_ACK) + { + return ret; + } + + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_connect_to_gw_channel(uint8_t channel) +{ + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + _ll_ifc_message_buff[0] = channel; + + int32_t ret = hal_read_write(OP_CONN_TO_GW_CH, &_ll_ifc_message_buff[0], 1, NULL, 0); + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_control_messages_enabled_set(bool enable) +{ + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + _ll_ifc_message_buff[0] = enable; + int32_t ret = hal_read_write(OP_CTRL_MSG_ENABLED_SET, &_ll_ifc_message_buff[0], 1, NULL, 0); + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_control_messages_enabled_get(bool *enabled) +{ + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + int32_t ret = hal_read_write(OP_CTRL_MSG_ENABLED_GET, NULL, 0, &_ll_ifc_message_buff[0], 1); + *enabled = _ll_ifc_message_buff[0]; + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_cloud_gpio_activate_pin(uint8_t pin) +{ + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + _ll_ifc_message_buff[0] = pin; + int32_t ret = hal_read_write(OP_GPIO_ENABLE_PIN, &_ll_ifc_message_buff[0], 1, NULL, 0); + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_cloud_gpio_deactivate_pin(uint8_t pin) +{ + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + _ll_ifc_message_buff[0] = pin; + int32_t ret = hal_read_write(OP_GPIO_DISABLE_PIN, &_ll_ifc_message_buff[0], 1, NULL, 0); + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_cloud_gpio_get_pin_status(uint8_t pin, bool *active) +{ + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + _ll_ifc_message_buff[0] = pin; + int32_t ret = hal_read_write(OP_GPIO_PIN_STATUS, &_ll_ifc_message_buff[0], 1, NULL, 0); + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_cloud_gpio_set_pin_high(uint8_t pin) +{ + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + _ll_ifc_message_buff[0] = pin; + int32_t ret = hal_read_write(OP_GPIO_SET_HIGH, &_ll_ifc_message_buff[0], 1, NULL, 0); + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_cloud_gpio_set_pin_low(uint8_t pin) +{ + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + _ll_ifc_message_buff[0] = pin; + int32_t ret = hal_read_write(OP_GPIO_SET_LOW, &_ll_ifc_message_buff[0], 1, NULL, 0); + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_disconnect() +{ + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + int32_t ret = hal_read_write(OP_DISCONNECT, NULL, 0, NULL, 0); + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_poll_scan_result(llabs_gateway_scan_results_t *scan_result, uint8_t *num_gw) +{ + if (scan_result == NULL || num_gw == NULL) + { + return LL_IFC_ERROR_INCORRECT_PARAMETER; + } + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + uint8_t buff[GW_SCAN_INFO_BUFF_SIZE]; + + int32_t ret = hal_read_write(OP_GET_SCAN_INFO, NULL, 0, &_ll_ifc_message_buff[0], GW_SCAN_INFO_BUFF_SIZE); + + if (ret < LL_IFC_ACK) + { + goto LL_POLL_SCAN_ERROR; + } + + ll_gw_scan_result_deserialize(&_ll_ifc_message_buff[0], scan_result, num_gw); + +LL_POLL_SCAN_ERROR: + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_get_gateway_scan_results(llabs_gateway_scan_results_t (*scan_results)[MAX_GW_SCAN_RESULTS], + uint8_t *num_gw) +{ + uint8_t gw=0; + *num_gw = 0; + + do + { + llabs_gateway_scan_results_t scan_result; + + int32_t ret = ll_poll_scan_result(&scan_result, &gw); + // if scanning will return a NACK_BUSY (6) + // if done scanning, but no gateways will return NACK_NO_DATA but no paylaod + // if done scanning, and gateway, will return LL_IFC_ACK and gw will be an index (0-?) + // and decrement each time called until gw is zero. Zero is a valid gateway index and last + // one in the list. + // + if (ret != LL_IFC_ACK) + { + return ret; + } + + // When num_gw is uninitialized, we need to set it with the total + // amount of gateways. The interface decrements num_gw to use as an index prior to + // sending so we need to add one for number. + // + if (*num_gw == 0) + { + *num_gw = gw + 1; + } + + memcpy(&(*scan_results)[gw], &scan_result, sizeof(scan_result)); + + } while (gw > 0); + + return LL_IFC_ACK; } int32_t ll_get_state(enum ll_state *state, enum ll_tx_state *tx_state, enum ll_rx_state *rx_state) { int32_t ret = LL_IFC_ACK; + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + if (NULL != state) { uint8_t u8_state; - ret = hal_read_write(OP_STATE, NULL, 0, &u8_state, 1); + ret = hal_read_write(OP_STATE, NULL, 0, &_ll_ifc_message_buff[0], 1); if (LL_IFC_ACK > ret) { - return ret; + goto GET_STATE_ERROR; } - *state = (enum ll_state)(int8_t)u8_state; + *state = (enum ll_state)(int8_t)_ll_ifc_message_buff[0]; } if (NULL != tx_state) { uint8_t u8_tx_state; - ret = hal_read_write(OP_TX_STATE, NULL, 0, &u8_tx_state, 1); + ret = hal_read_write(OP_TX_STATE, NULL, 0, &_ll_ifc_message_buff[0], 1); if (LL_IFC_ACK > ret) { - return ret; + goto GET_STATE_ERROR; } - *tx_state = (enum ll_tx_state)(int8_t)u8_tx_state; + *tx_state = (enum ll_tx_state)(int8_t)_ll_ifc_message_buff[0]; } if (NULL != rx_state) { uint8_t u8_rx_state; - ret = hal_read_write(OP_RX_STATE, NULL, 0, &u8_rx_state, 1); + ret = hal_read_write(OP_RX_STATE, NULL, 0, &_ll_ifc_message_buff[0], 1); if (LL_IFC_ACK > ret) { - return ret; + goto GET_STATE_ERROR; } - *rx_state = (enum ll_rx_state)(int8_t)u8_rx_state; + *rx_state = (enum ll_rx_state)(int8_t)_ll_ifc_message_buff[0]; } - return ret; +GET_STATE_ERROR: + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_mailbox_request(void) { - return hal_read_write(OP_MAILBOX_REQUEST, NULL, 0, NULL, 0); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_MAILBOX_REQUEST, NULL, 0, NULL, 0); + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_app_reg_get(uint8_t *is_registered) @@ -219,131 +699,314 @@ int32_t ll_app_reg_get(uint8_t *is_registered) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - return hal_read_write(OP_APP_TOKEN_REG_GET, NULL, 0, is_registered, 1); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_APP_TOKEN_REG_GET, NULL, 0, &_ll_ifc_message_buff[0], 1); + *is_registered = _ll_ifc_message_buff[0]; + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_encryption_key_exchange_request(void) { - return hal_read_write(OP_CRYPTO_KEY_XCHG_REQ, NULL, 0, NULL, 0); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_CRYPTO_KEY_XCHG_REQ, NULL, 0, NULL, 0); + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_net_info_get(llabs_network_info_t *p_net_info) { - uint8_t buff[NET_INFO_BUFF_SIZE]; if (p_net_info == NULL) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - int32_t ret = hal_read_write(OP_NET_INFO_GET, NULL, 0, buff, NET_INFO_BUFF_SIZE); - ll_net_info_deserialize(buff, p_net_info); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_NET_INFO_GET, NULL, 0, &_ll_ifc_message_buff[0], NET_INFO_BUFF_SIZE); + + if (LL_IFC_ACK > ret) + { + // release mutex and return + } + else if (NET_INFO_BUFF_SIZE != ret) + { + ret = LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + else + { + ll_net_info_deserialize(&_ll_ifc_message_buff[0], p_net_info); + ret = LL_IFC_ACK; + } + + transport_mutex_release(); + return ret; } int32_t ll_stats_get(llabs_stats_t *s) { - uint8_t buff[STATS_SIZE]; if (s == NULL) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - int32_t ret = hal_read_write(OP_STATS_GET, NULL, 0, buff, STATS_SIZE); - ll_stats_deserialize(buff, s); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_STATS_GET, NULL, 0, &_ll_ifc_message_buff[0], STATS_SIZE); + transport_mutex_release(); + + if (LL_IFC_ACK > ret) + { + // do nothing and return + } + else if (STATS_SIZE != ret) + { + ret = LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + else + { + ll_stats_deserialize(&_ll_ifc_message_buff[0], s); + ret = LL_IFC_ACK; + } return ret; } -int32_t ll_retrieve_message(uint8_t *buf, uint16_t *size, uint8_t *port, int16_t *rssi, uint8_t *snr) +int32_t ll_retrieve_message(uint8_t *buf, uint16_t *size, uint8_t *port, int16_t *rssi, + uint8_t *snr) { - int32_t rw_response; - if (buf == NULL || size == NULL) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - rw_response = hal_read_write(OP_MSG_RECV, NULL, 0, buf, *size); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } - if (rw_response < LL_IFC_ACK) + int32_t ret = hal_read_write(OP_MSG_RECV, NULL, 0, &_ll_ifc_message_buff[0], *size); + + if (ret < LL_IFC_ACK) + { + *size = 0; + } + else if ((ret & 0xff) <= 4)// Size is required { *size = 0; - return rw_response; + ret = LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; } + else + { + *size = (uint8_t)(ret & 0xFF) - 4; - // Size is required - *size = (uint8_t)(rw_response & 0xFF) - 4; + // Optional RSSI + if (NULL != rssi) + { + *rssi = 0; + *rssi = _ll_ifc_message_buff[0] + ((uint16_t) _ll_ifc_message_buff[1] << 8); + } - // Optional RSSI - if(NULL != rssi) - { - *rssi = 0; - *rssi = buf[0] + ((uint16_t)buf[1] << 8); + // Optional RSSI + if (NULL != snr) + { + *snr = _ll_ifc_message_buff[2]; + } + + if (NULL != port) + { + *port = _ll_ifc_message_buff[3]; + } + + // get rid of snr and rssi in buffer + memmove(buf, _ll_ifc_message_buff + 4, *size); + + ret = LL_IFC_ACK; } - // Optional RSSI - if(NULL != snr) + transport_mutex_release(); + return ret; +} + +int32_t ll_dl_band_cfg_get(llabs_dl_band_cfg_t *p) +{ + if (p == NULL) { - *snr = buf[2]; + return LL_IFC_ERROR_INCORRECT_PARAMETER; } - if (NULL != port) + if (!(transport_mutex_grab())) { - *port = buf[3]; + return LL_IFC_ERROR_HAL_CALL_FAILED; } - //get rid of snr and rssi in buffer - memmove(buf, buf + 4, *size); + int32_t ret = hal_read_write(OP_DL_BAND_CFG_GET, NULL, 0, &_ll_ifc_message_buff[0], DL_BAND_CFG_SIZE); + - return 0; + if (LL_IFC_ACK > ret) + { + } + else if (DL_BAND_CFG_SIZE != ret) + { + ret = LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + else + { + ll_dl_band_cfg_deserialize(&_ll_ifc_message_buff[0], p); + ret = LL_IFC_ACK; + } + + transport_mutex_release(); + return ret; } -int32_t ll_dl_band_cfg_get(llabs_dl_band_cfg_t *p) +int32_t ll_dl_band_cfg_set(const llabs_dl_band_cfg_t *p) { - uint8_t buff[DL_BAND_CFG_SIZE]; if (p == NULL) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - int32_t ret = hal_read_write(OP_DL_BAND_CFG_GET, NULL, 0, buff, DL_BAND_CFG_SIZE); - ll_dl_band_cfg_deserialize(buff, p); - return ret; + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + ll_dl_band_cfg_serialize(p, &_ll_ifc_message_buff[0]); + + int32_t ret = hal_read_write(OP_DL_BAND_CFG_SET, &_ll_ifc_message_buff[0], DL_BAND_CFG_SIZE, NULL, 0); + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } -int32_t ll_dl_band_cfg_set(const llabs_dl_band_cfg_t *p) +int32_t ll_rssi_offset_get(int8_t *rssi_offset) { - uint8_t buff[DL_BAND_CFG_SIZE]; - if (p == NULL) + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_RSSI_OFFSET_GET, NULL, 0, &_ll_ifc_message_buff[0], 1); + *rssi_offset = (int8_t)_ll_ifc_message_buff[0]; + + transport_mutex_release(); + + + return (ret >= 0) ? LL_IFC_ACK : ret; +} + +int32_t ll_rssi_offset_set(int8_t rssi_offset) +{ + if (rssi_offset > 15 || rssi_offset < -15) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - ll_dl_band_cfg_serialize(p, buff); - return hal_read_write(OP_DL_BAND_CFG_SET, buff, DL_BAND_CFG_SIZE, NULL, 0); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + _ll_ifc_message_buff[0] = rssi_offset; + + int32_t ret = hal_read_write(OP_RSSI_OFFSET_SET, &_ll_ifc_message_buff[0], 1, NULL, 0); + + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } -int32_t ll_connection_filter_get(uint8_t* p_f) +int32_t ll_connection_filter_get(uint8_t *p_f) { if (NULL == p_f) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - uint8_t f; - int32_t ret = hal_read_write(OP_CONN_FILT_GET, NULL, 0, &f, 1); - *p_f = f; - return ret; + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_CONN_FILT_GET, NULL, 0, &_ll_ifc_message_buff[0], 1); + + + if (LL_IFC_ACK > ret) + { + + } + else if (sizeof(uint8_t) != ret) + { + ret = LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + else + { + *p_f = _ll_ifc_message_buff[0]; + } + + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_connection_filter_set(uint8_t f) { - return hal_read_write(OP_CONN_FILT_SET, &f, 1, NULL, 0); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + _ll_ifc_message_buff[0] = f; + int32_t ret = hal_read_write(OP_CONN_FILT_SET, &_ll_ifc_message_buff[0], 1, NULL, 0); + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_system_time_get(llabs_time_info_t *time_info) { - uint8_t buff[TIME_INFO_SIZE]; if (time_info == NULL) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - int32_t ret = hal_read_write(OP_SYSTEM_TIME_GET, NULL, 0, buff, TIME_INFO_SIZE); - ll_time_deserialize(buff, time_info); + + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + int32_t ret = hal_read_write(OP_SYSTEM_TIME_GET, NULL, 0, &_ll_ifc_message_buff[0], STATS_SIZE); + transport_mutex_release(); + + if (LL_IFC_ACK > ret) + { + } + else if (TIME_INFO_SIZE != ret) + { + ret = LL_IFC_ERROR_INCORRECT_RESPONSE_LENGTH; + } + else + { + ll_time_deserialize(_ll_ifc_message_buff, time_info); + ret = LL_IFC_ACK; + } return ret; } @@ -353,7 +1016,15 @@ int32_t ll_system_time_sync(uint8_t sync_mode) { return LL_IFC_ERROR_INCORRECT_PARAMETER; } - return hal_read_write(OP_SYSTEM_TIME_SYNC, &sync_mode, sizeof(sync_mode), NULL, 0); + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + _ll_ifc_message_buff[0] = sync_mode; + + int32_t ret = hal_read_write(OP_SYSTEM_TIME_SYNC, &_ll_ifc_message_buff[0], sizeof(sync_mode), NULL, 0); + transport_mutex_release(); + return (ret >= 0) ? LL_IFC_ACK : ret; } int32_t ll_message_send(uint8_t buf[], uint16_t len, bool ack, uint8_t port) @@ -368,9 +1039,18 @@ int32_t ll_message_send(uint8_t buf[], uint16_t len, bool ack, uint8_t port) return LL_IFC_ERROR_INCORRECT_PARAMETER; } - memmove(uplink_message_buff, buf, len); - _uplink_message_buff[0] = (uint8_t)ack; - _uplink_message_buff[1] = port; - return hal_read_write(OP_MSG_SEND, _uplink_message_buff, len + 2, NULL, 0); -} + if (!(transport_mutex_grab())) + { + return LL_IFC_ERROR_HAL_CALL_FAILED; + } + + memmove(&_ll_ifc_message_buff[2], buf, len); + _ll_ifc_message_buff[0] = (uint8_t) ack; + _ll_ifc_message_buff[1] = port; + + int32_t ret = hal_read_write(OP_MSG_SEND, &_ll_ifc_message_buff[0], len + 2, NULL, 0); + transport_mutex_release(); + + return (ret >= 0) ? LL_IFC_ACK : ret; +} diff --git a/src/ll_ifc_transport_pc.c b/src/ll_ifc_transport_pc.c index 1b7c45b..9eb9f98 100644 --- a/src/ll_ifc_transport_pc.c +++ b/src/ll_ifc_transport_pc.c @@ -321,6 +321,69 @@ int32_t transport_write(uint8_t *buff, uint16_t len) return ret; } +/** +* @brief +* Grabs a recursive mutex used to protect hal_read_write() in ll_ifc and +* to make multi-operation ll_ifc calls work atomically. +* +* @details +* None. +* +* @return +* 0 - success, negative otherwise. +*/ +bool transport_mutex_grab(void) +{ + return true; +} + +/** +* @brief +* Releases the mutex grabbed with transport_mutex_grab(). +* +* @details +* None. +* +* @return +* 1 - success, zero otherwise +*/ +void transport_mutex_release(void) +{ + return; +} + +/** +* @brief +* Implement a critical section if the communication could be interrupted for +* extended periods. +* +* @details +* None. +* +* @return +* 1 - success, zero otherwise +*/ +bool transport_enter_critical(void) +{ + return true; +} + +/** +* @brief +* Implement a critical section if the communication could be interrupted for +* extended periods. +* +* @details +* None. +* +* @return +* 1 - success, zero otherwise. +*/ +bool transport_exit_critical(void) +{ + return true; +} + static ssize_t read_with_timeout(int fd, void *bf, size_t len, time_t sec) { fd_set set; diff --git a/src/ll_ifc_xmodem.c b/src/ll_ifc_xmodem.c index 02c9d6a..bd09564 100644 --- a/src/ll_ifc_xmodem.c +++ b/src/ll_ifc_xmodem.c @@ -11,6 +11,16 @@ #define CAN (0x18) ///< Cancel #define CCC (0x43) ///< ASCII ā€œCā€ +uint16_t s_packet_number; + +uint8_t xmodem_rx_buff[30]; +uint8_t xmodem_tx_buff[133]; + + + + + + // returns the response of the client // only if the responce is... // * ACK @@ -18,14 +28,16 @@ // * CAN // * CCC // * \n -static int32_t ll_xmodem_get_client_response(uint8_t* response) +static int32_t ll_xmodem_get_client_response(void) { struct time time_start; gettime(&time_start); + memset(xmodem_rx_buff,0,30); + do { - int32_t ret = transport_read(response, 1); + int32_t ret = transport_read(xmodem_rx_buff, 1); if (ret < -1) { return ret; @@ -36,7 +48,8 @@ static int32_t ll_xmodem_get_client_response(uint8_t* response) return -2; } } - while((ACK != *response) && (NAK != *response) && (CAN != *response) && (CCC != *response) && ('\n' != *response)); + while((ACK != xmodem_rx_buff[0]) && (NAK != xmodem_rx_buff[0]) && + (CAN != xmodem_rx_buff[0]) && (CCC != xmodem_rx_buff[0]) && ('\n' != xmodem_rx_buff[0])); return 0; } @@ -50,56 +63,58 @@ static int32_t ll_xmodem_send_packet(uint8_t* payload, uint16_t payload_len, uin } // Build XModem Packet - uint8_t packet[133] = {0x1A}, response = 0; - uint16_t crc = 0; + uint16_t crc = 0; // Initalize Packet with - memset(packet, 0x1A, 133 * sizeof(uint8_t)); + memset(xmodem_tx_buff, 0x1A, 133 * sizeof(uint8_t)); // Start of Header - packet[0] = SOH; + xmodem_tx_buff[0] = SOH; // Packet Number - packet[1] = packet_number & 0xff; - packet[2] = 0xff - packet_number; + xmodem_tx_buff[1] = packet_number & 0xff; + xmodem_tx_buff[2] = 0xff - packet_number; // Payload - memcpy(packet + 3 * sizeof(uint8_t), payload, payload_len * sizeof(uint8_t)); + memcpy(xmodem_tx_buff + 3 * sizeof(uint8_t), payload, payload_len * sizeof(uint8_t)); // CRC - crc = crc16((char *)packet + 3 * sizeof(uint8_t), 128); - packet[132] = crc & 0xff; - packet[131] = crc >> 8; + crc = crc16((char *)xmodem_tx_buff + 3 * sizeof(uint8_t), 128); + xmodem_tx_buff[132] = crc & 0xff; + xmodem_tx_buff[131] = crc >> 8; // Send XModem Packet - int32_t ret = transport_write(packet, 133); + int32_t ret = transport_write(xmodem_tx_buff, 133); if (ret < 0) { return ret; } // returns the client response - ret = ll_xmodem_get_client_response(&response); + ret = ll_xmodem_get_client_response(); if (ret < 0) { return ret; } - return response; + return xmodem_rx_buff[0]; } // send a single byte through xmodem static int32_t ll_xmodem_send_byte(uint8_t byte) { - uint8_t response = 0; struct time time_start; gettime(&time_start); + // memset(xmodem_tx_buff, 0, 133 * sizeof(uint8_t)); + + xmodem_tx_buff[0] = byte; + do { - int32_t ret = transport_write(&byte, 1); + int32_t ret = transport_write(&xmodem_tx_buff[0], 1); if (ret < 0) { return ret; } - ret = ll_xmodem_get_client_response(&response); + ret = ll_xmodem_get_client_response(); if (ret < 0) { return ret; @@ -110,33 +125,36 @@ static int32_t ll_xmodem_send_byte(uint8_t byte) return -2; } } - while (ACK != response); + while (ACK != xmodem_rx_buff[0]); - return response; + return xmodem_rx_buff[0]; } // returns 0 when the requested response is recieved, negative otherwise -static int32_t ll_xmodem_wait_for(uint8_t response) +static int32_t ll_xmodem_wait_for(uint8_t char_expected) { struct time time_start; - uint8_t res = 0; + gettime(&time_start); + // memset(xmodem_rx_buff,0,30); + do { - int32_t ret = ll_xmodem_get_client_response(&res); - if (ret < 0) + int32_t ret = transport_read(&xmodem_rx_buff[0], 1); + if (ret < -1) { return ret; } + if (ll_difftime_from_now(&time_start) >= TIMEOUT) { return -2; } } - while(response != res); + while(char_expected != xmodem_rx_buff[0]); return 0; } @@ -145,23 +163,23 @@ static int32_t ll_xmodem_wait_for(uint8_t response) // // data - location of the data // len - length of the allocated string -static int32_t ll_xmodem_parse_module_output(char* data, uint8_t len) +static int32_t ll_xmodem_parse_module_output(char* data, uint8_t len, uint16_t timeout_s) { struct time time_start; gettime(&time_start); - uint8_t buf; uint8_t i = 0; + memset(xmodem_rx_buff,0,30); do { - int32_t ret = transport_read(&buf, 1); - if (ret >= 0 && buf != 0x0 && buf != 0xff && buf != '\n' && buf != '\r') + int32_t ret = transport_read(&xmodem_rx_buff[0], 1); + if (ret >= 0 && xmodem_rx_buff[0] != 0x0 && xmodem_rx_buff[0] != 0xff && xmodem_rx_buff[0] != '\n' && xmodem_rx_buff[0] != '\r') { - data[i++] = (char) buf; + data[i++] = (char) xmodem_rx_buff[0]; } - if (ll_difftime_from_now(&time_start) >= TIMEOUT) + if (ll_difftime_from_now(&time_start) >= timeout_s) // returns seconds { return -2; } @@ -181,9 +199,11 @@ int32_t ll_xmodem_prepare_module(bool is_host_ifc_active) sleep_ms(2000); } + // memset(xmodem_tx_buff, 0, 133 * sizeof(uint8_t)); + + xmodem_tx_buff[0] = 'u'; // Send upload request to the module - uint8_t buf = 'u'; - int32_t ret = transport_write(&buf, 1); + int32_t ret = transport_write(xmodem_tx_buff, 1); if (ret < 0) { return ret; @@ -200,6 +220,110 @@ int32_t ll_xmodem_prepare_module(bool is_host_ifc_active) return 0; } +int32_t ll_xmodem_send_start_xfer(void) +{ + int32_t ret; + // Wait for the reciever to send us the start signal. + s_packet_number = 1; + ret = ll_xmodem_wait_for('C'); + return ret; +} + +//use this to send 128 bytes at a time +int32_t ll_xmodem_send_part(ll_xmodem_callbacks_t *cb, uint8_t* payload, size_t payload_len) +{ + int32_t ret; + + if (payload == NULL || payload_len < 1 || payload_len > 128) + { + return LL_IFC_ERROR_INCORRECT_PARAMETER; + } + + if (cb->progress == NULL) + { + return -5; + } + + // Send Data Payload + ret = ll_xmodem_send_packet(payload, payload_len, s_packet_number); + switch (ret) + { + case ACK: + s_packet_number++; + cb->progress(s_packet_number, payload_len); + return 0; + break; + case NAK: + return -4; + break; + case CAN: + return -3; + case CCC: // ignore start byte + return -2; + break; + default: + if (ret < 0) + { + return ret; // something broke... + } + } + +} + +int32_t ll_xmodem_send_EOF_validate(void) +{ + int32_t ret; + // Finish Transfer + ret = ll_xmodem_send_byte(EOT); + if (ret < 0) + { + return ret; + } + + // Don't sent ETB. + // Firmware download happen immediately + // verifying... happens immediately + // OK\r\n took 8 seconds + // activating was immediate after ok + + char fw_downloaded[20] = { '\0' }; + ll_xmodem_parse_module_output(fw_downloaded, 19, 3); + + + char fw_verify[15] = { '\0' }; + ll_xmodem_parse_module_output(fw_verify, 14, 12); + + char fw_activate[18] = { '\0' }; + ll_xmodem_parse_module_output(fw_activate, 17, 3); + + if (strcmp(fw_downloaded, "Firmware downloaded") != 0) + { + return -6; + } + + if (strcmp(fw_verify, "Verifying...OK") != 0) + { + // TODO: may use strstr to look for OK in what was + // returned. + return -7; + } + + if (strcmp(fw_activate, "Activating...DONE") != 0) + { + return -8; + } + + // Reboot the Module + xmodem_tx_buff[0] = 'r'; + ret = transport_write(&xmodem_tx_buff[0], 1); + if (ret < 0) + { + return ret; + } + + return 0; +} + int32_t ll_xmodem_send(ll_xmodem_callbacks_t *cb, uint8_t* payload, size_t payload_len) { if (payload == NULL || payload_len < 1) @@ -275,13 +399,13 @@ int32_t ll_xmodem_send(ll_xmodem_callbacks_t *cb, uint8_t* payload, size_t paylo } char fw_downloaded[20] = { '\0' }; - ll_xmodem_parse_module_output(fw_downloaded, 19); + ll_xmodem_parse_module_output(fw_downloaded, 19, 3); char fw_verify[15] = { '\0' }; - ll_xmodem_parse_module_output(fw_verify, 14); + ll_xmodem_parse_module_output(fw_verify, 14, 3); char fw_activate[18] = { '\0' }; - ll_xmodem_parse_module_output(fw_activate, 17); + ll_xmodem_parse_module_output(fw_activate, 17, 3); if (strcmp(fw_downloaded, "Firmware downloaded") != 0) {