diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100755 index bb9905f..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "files.associations": { - "*.unknown": "platformio-debug.asm", - "anedya_err.h": "c", - "anedya.h": "c", - "time.h": "c", - "config.h": "c", - "anedya_commons.h": "c", - "anedya_config.h": "c", - "anedya_client.h": "c" - } -} \ No newline at end of file diff --git a/include/anedya_client.h b/include/anedya_client.h index 259dabf..8a5704c 100755 --- a/include/anedya_client.h +++ b/include/anedya_client.h @@ -1,126 +1,180 @@ #pragma once -#include -#include "anedya_err.h" #include "anedya_commons.h" #include "anedya_config.h" +#include "anedya_err.h" #include "anedya_sdk_config.h" #include "anedya_txn.h" +#include #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif - struct anedya_txn_store_t - { - anedya_txn_t *txns[ANEDYA_MAX_CONCURRENT_TXN]; - bool txn_slot_free[ANEDYA_MAX_CONCURRENT_TXN]; - int64_t aquired_time[ANEDYA_MAX_CONCURRENT_TXN]; - bool _lock; - }; - - typedef struct anedya_txn_store_t anedya_txn_store_t; - - typedef void (*anedya_on_connect_handler_t)(anedya_client_t *client); - typedef void (*anedya_on_disconnect_handler_t)(anedya_client_t *client); - typedef void (*anedya_message_handler_t)(anedya_client_t *cl, char *topic, int topic_len, char *payload, int payload_len); - struct anedya_client_t - { - anedya_config_t *config; +struct anedya_txn_store_t { + anedya_txn_t *txns[ANEDYA_MAX_CONCURRENT_TXN]; + bool txn_slot_free[ANEDYA_MAX_CONCURRENT_TXN]; + int64_t aquired_time[ANEDYA_MAX_CONCURRENT_TXN]; + bool _lock; +}; + +typedef struct anedya_txn_store_t anedya_txn_store_t; + +typedef void (*anedya_on_connect_handler_t)(anedya_client_t *client); +typedef void (*anedya_on_disconnect_handler_t)(anedya_client_t *client); +typedef void (*anedya_message_handler_t)(anedya_client_t *cl, char *topic, + int topic_len, char *payload, + int payload_len); +struct anedya_client_t { + anedya_config_t *config; #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char log_buffer[ANEDYA_LOG_BUFFER * ANEDYA_MAX_LOG_BATCH]; - char _message_topics[4][100]; + char log_buffer[ANEDYA_LOG_BUFFER * ANEDYA_MAX_LOG_BATCH]; + char _message_topics[4][100]; #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION + char *tx_buffer; + char *rx_buffer; #ifdef ANEDYA_ENABLE_DEVICE_LOGS - char *log_buffer; + char *log_buffer; #endif - char *_message_topics[3]; + char *_message_topics[3]; #endif #ifdef ANEDYA_CONNECTION_METHOD_MQTT - anedya_mqtt_client_handle_t mqtt_client; - anedya_message_handler_t _message_handler; - anedya_on_connect_handler_t _anedya_on_connect_handler; - anedya_on_disconnect_handler_t _anedya_on_disconnect_handler; - uint8_t is_connected; - char broker_url[100]; + anedya_mqtt_client_handle_t mqtt_client; + anedya_message_handler_t _message_handler; + anedya_on_connect_handler_t _anedya_on_connect_handler; + anedya_on_disconnect_handler_t _anedya_on_disconnect_handler; + char broker_url[100]; + anedya_event_handler_t _event_handler; +#endif +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char http_base_url[100]; // e.g. "device.ap-in-1.anedya.io" +#endif + uint8_t is_connected; + anedya_txn_store_t txn_store; +}; + +/** + * @brief Initialize the Anedya client with the provided configuration. + * + * This function initializes an Anedya client instance using the specified + * configuration parameters. It allocates required buffers and sets up MQTT + * connection if `ANEDYA_CONNECTION_METHOD_MQTT` is defined. + * + * @param[in] config Pointer to the `anedya_config_t` structure containing + * configuration parameters. + * @param[out] client Pointer to the `anedya_client_t` structure to initialize. + * + * @retval - `ANEDYA_OK` if the client initialization is successful. + * @retval - `ANEDYA_ERR_NO_MEMORY` if memory allocation for any buffer fails. + * @retval Other error codes based on initialization failures. + * + * @warning Ensure that the configuration is properly populated before calling + * this function. + */ +anedya_err_t anedya_client_init(anedya_config_t *config, + anedya_client_t *client); + +anedya_err_t _anedya_txn_store_init(anedya_txn_store_t *store); +anedya_err_t _anedya_txn_store_aquire_slot(anedya_txn_store_t *store, + anedya_txn_t *txn); +anedya_err_t _anedya_txn_store_release_slot(anedya_txn_store_t *store, + anedya_txn_t *txn); +#ifdef ANEDYA_CONNECTION_METHOD_HTTP +void _anedya_handle_http_txn_response(anedya_client_t *cl, char *payload, + int payload_len, anedya_txn_t *txn); #endif - anedya_event_handler_t _event_handler; - anedya_txn_store_t txn_store; - }; - - /** - * @brief Initialize the Anedya client with the provided configuration. - * - * This function initializes an Anedya client instance using the specified configuration parameters. - * It allocates required buffers and sets up MQTT connection if `ANEDYA_CONNECTION_METHOD_MQTT` is defined. - * - * @param[in] config Pointer to the `anedya_config_t` structure containing configuration parameters. - * @param[out] client Pointer to the `anedya_client_t` structure to initialize. - * - * @retval - `ANEDYA_OK` if the client initialization is successful. - * @retval - `ANEDYA_ERR_NO_MEMORY` if memory allocation for any buffer fails. - * @retval Other error codes based on initialization failures. - * - * @warning Ensure that the configuration is properly populated before calling this function. - */ - anedya_err_t anedya_client_init(anedya_config_t *config, anedya_client_t *client); - - anedya_err_t _anedya_txn_store_init(anedya_txn_store_t *store); - anedya_err_t _anedya_txn_store_aquire_slot(anedya_txn_store_t *store, anedya_txn_t *txn); - anedya_err_t _anedya_txn_store_release_slot(anedya_txn_store_t *store, anedya_txn_t *txn); - void _anedya_handle_txn_response(anedya_client_t *cl, char *payload, int payload_len, uint8_t topic); - void _anedya_handle_event(anedya_client_t *cl, char *payload, int payload_len, uint8_t topic); + +void _anedya_handle_txn_response(anedya_client_t *cl, char *payload, + int payload_len, uint8_t topic); + +void _anedya_handle_event(anedya_client_t *cl, char *payload, int payload_len, + uint8_t topic); #ifdef ANEDYA_CONNECTION_METHOD_MQTT - /** - * @brief Connect the Anedya client to the server. - * - * This function establishes a connection to the server using the client's MQTT client instance. - * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client to connect. - * - * @retval - `ANEDYA_OK` if the connection is successful. - * @retval Error code if the connection fails, as returned by `_anedya_interface_mqtt_connect`. - * - * @note Ensure that the client is properly initialized before attempting to connect. - * @warning This function should be called only after initializing the client. - */ - anedya_err_t anedya_client_connect(anedya_client_t *client); - - /** - * @brief Disconnect the Anedya client from the server. - * - * This function disconnects the Anedya client from the server. - * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client to disconnect. - * - * @retval - `ANEDYA_OK` if the disconnection is successful. - * @retval - Error code if the disconnection fails, as returned by `_anedya_interface_mqtt_disconnect`. - * - * @note Ensure that the client is connected before calling this function. - */ - anedya_err_t anedya_client_disconnect(anedya_client_t *client); - - /** - * @brief Destroy the Anedya client instance. - * - * This function releases resources associated with the Anedya client's MQTT client instance. - * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client to destroy. - * - * @retval - `ANEDYA_OK` if the client instance is successfully destroyed. - * @retval - Error code if destruction fails, as returned by `_anedya_interface_mqtt_destroy`. - * - * @note Ensure that the client is disconnected before calling this function. - */ - anedya_err_t anedya_client_destroy(anedya_client_t *client); - - void _anedya_message_handler(anedya_client_t *cl, char *topic, int topic_len, char *payload, int payload_len); - void _anedya_on_connect_handler(anedya_client_t *client); - void _anedya_on_disconnect_handler(anedya_client_t *client); +/** + * @brief Connect the Anedya client to the server. + * + * This function establishes a connection to the server using the client's MQTT + * client instance. + * + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client to connect. + * + * @retval - `ANEDYA_OK` if the connection is successful. + * @retval Error code if the connection fails, as returned by + * `_anedya_interface_mqtt_connect`. + * + * @note Ensure that the client is properly initialized before attempting to + * connect. + * @warning This function should be called only after initializing the client. + */ +anedya_err_t anedya_client_connect(anedya_client_t *client); + +/** + * @brief Disconnect the Anedya client from the server. + * + * This function disconnects the Anedya client from the server. + * + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client to disconnect. + * + * @retval - `ANEDYA_OK` if the disconnection is successful. + * @retval - Error code if the disconnection fails, as returned by + * `_anedya_interface_mqtt_disconnect`. + * + * @note Ensure that the client is connected before calling this function. + */ +anedya_err_t anedya_client_disconnect(anedya_client_t *client); + +/** + * @brief Destroy the Anedya client instance. + * + * This function releases resources associated with the Anedya client's MQTT + * client instance. + * + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client to destroy. + * + * @retval - `ANEDYA_OK` if the client instance is successfully destroyed. + * @retval - Error code if destruction fails, as returned by + * `_anedya_interface_mqtt_destroy`. + * + * @note Ensure that the client is disconnected before calling this function. + */ +anedya_err_t anedya_client_destroy(anedya_client_t *client); + +void _anedya_message_handler(anedya_client_t *cl, char *topic, int topic_len, + char *payload, int payload_len); +void _anedya_on_connect_handler(anedya_client_t *client); +void _anedya_on_disconnect_handler(anedya_client_t *client); + +#endif + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP +/** + * @brief Initialize HTTP mode client as "connected" (stateless — no persistent + * TCP). + * + * In HTTP mode there is no long-lived connection to establish. This function + * simply validates the configuration, builds the base URL, and marks + * is_connected = 1 so that all operation functions can proceed. + * + * @param[in] client Pointer to the anedya_client_t to operate on. + * @retval ANEDYA_OK always. + */ +anedya_err_t anedya_client_connect(anedya_client_t *client); +/** + * @brief Mark HTTP mode client as disconnected. + * + * Sets is_connected = 0. Subsequent operation calls will return + * ANEDYA_ERR_NOT_CONNECTED. + * + * @param[in] client Pointer to the anedya_client_t to operate on. + * @retval ANEDYA_OK always. + */ +anedya_err_t anedya_client_disconnect(anedya_client_t *client); #endif #ifdef __cplusplus diff --git a/include/anedya_interface.h b/include/anedya_interface.h index 66934f6..e8f34f6 100755 --- a/include/anedya_interface.h +++ b/include/anedya_interface.h @@ -105,6 +105,60 @@ extern "C" #endif +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + + /** + * @brief Perform a synchronous HTTP POST request to the Anedya server. + * + * This interface function must be implemented by the platform layer. It is responsible + * for performing a TLS-secured HTTP POST request to the Anedya REST API. + * + * Authentication headers (`Auth-mode: key` and `Authorization: `) must + * be set by the implementation using client->config->connection_key. + * + * @param[in] client Pointer to the anedya_client_t (used to access config/region/key). + * @param[in] path The HTTP path to POST to, e.g. "/v1/submitData". + * @param[in] payload JSON payload string (null-terminated). + * @param[in] payload_len Length of payload. + * @param[out] resp_buf Pre-allocated buffer where the response body will be written. + * @param[in] resp_buf_size Size of resp_buf. + * @param[out] resp_len Actual number of bytes written into resp_buf. + * + * @retval ANEDYA_OK on HTTP 200 success. + * @retval ANEDYA_ERR on any transport/TLS/HTTP error. + */ + anedya_err_t _anedya_interface_http_post( + anedya_client_t *client, + const char *path, + const char *payload, + int payload_len, + char *resp_buf, + int resp_buf_size, + int *resp_len); + + /** + * @brief Perform a synchronous HTTP GET request to the Anedya server. + * + * Identical contract to _anedya_interface_http_post but uses GET method and sends no body. + * Reserved for future use; currently all Anedya endpoints use POST. + * + * @param[in] client Pointer to the anedya_client_t. + * @param[in] path The HTTP path to GET. + * @param[out] resp_buf Pre-allocated response buffer. + * @param[in] resp_buf_size Size of resp_buf. + * @param[out] resp_len Actual bytes written. + * + * @retval ANEDYA_OK on success, ANEDYA_ERR on failure. + */ + anedya_err_t _anedya_interface_http_get( + anedya_client_t *client, + const char *path, + char *resp_buf, + int resp_buf_size, + int *resp_len); + +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/include/anedya_op_commands.h b/include/anedya_op_commands.h index c00affd..21a0057 100644 --- a/include/anedya_op_commands.h +++ b/include/anedya_op_commands.h @@ -10,63 +10,62 @@ typedef const char *anedya_cmd_status_t; -typedef struct -{ - anedya_uuid_t cmdId; - char command[50]; - unsigned int command_len; - char data[1000]; - unsigned int data_len; - unsigned int cmd_data_type; - unsigned long long exp; - char status[20]; - unsigned long long issued_at; - unsigned long long updated; +typedef struct { + anedya_uuid_t cmdId; + char command[50]; + unsigned int command_len; + char data[1000]; + unsigned int data_len; + unsigned int cmd_data_type; + unsigned long long exp; + char status[20]; + unsigned long long issued_at; + unsigned long long updated; } anedya_command_obj_t; -typedef struct -{ - anedya_uuid_t cmdId; - anedya_cmd_status_t status; - unsigned char *data; - unsigned int data_len; - unsigned int data_type; +typedef struct { + anedya_uuid_t cmdId; + anedya_cmd_status_t status; + unsigned char *data; + unsigned int data_len; + unsigned int data_type; } anedya_req_cmd_status_update_t; -anedya_err_t _anedya_parse_inbound_command(char *payload, unsigned int payload_len, anedya_command_obj_t *obj); +anedya_err_t _anedya_parse_inbound_command(char *payload, + unsigned int payload_len, + anedya_command_obj_t *obj); // ============= Command List ================ -typedef struct -{ - unsigned short limit; - unsigned short offset; +typedef struct { + unsigned short limit; + unsigned short offset; } anedya_req_cmd_list_t; -typedef struct -{ - bool is_available; - anedya_command_obj_t *commands; - unsigned short int totalcount; - unsigned short int count; - unsigned short int next; +typedef struct { + uint8_t is_available; + anedya_command_obj_t *commands; + unsigned short int totalcount; + unsigned short int count; + unsigned short int next; } anedya_op_cmd_list_resp_t; -void _anedya_op_command_handle_list_resp(anedya_client_t *client, anedya_txn_t *txn); +void _anedya_op_command_handle_list_resp(anedya_client_t *client, + anedya_txn_t *txn); // ============== Next Command ================== -typedef struct -{ - bool is_available; - anedya_uuid_t cmdId; - char command[50]; - unsigned int command_len; - char status[20]; - unsigned char *data; - unsigned int data_len; - unsigned int data_type; - unsigned long long issued_at; - unsigned long long updated; - bool nextavailable; +typedef struct { + uint8_t is_available; + anedya_uuid_t cmdId; + char command[50]; + unsigned int command_len; + char status[20]; + unsigned char *data; + unsigned int data_len; + unsigned int data_type; + unsigned long long issued_at; + unsigned long long updated; + uint8_t nextavailable; } anedya_op_cmd_next_resp_t; -void _anedya_op_cmd_handle_next_resp(anedya_client_t *client, anedya_txn_t *txn); \ No newline at end of file +void _anedya_op_cmd_handle_next_resp(anedya_client_t *client, + anedya_txn_t *txn); \ No newline at end of file diff --git a/include/anedya_operations.h b/include/anedya_operations.h index be27afa..b95f41d 100755 --- a/include/anedya_operations.h +++ b/include/anedya_operations.h @@ -3,16 +3,16 @@ #ifndef _ANEDYA_OPERATIONS_H_ #define _ANEDYA_OPERATIONS_H_ -#include #include "anedya.h" #include "anedya_json_builder.h" #include "anedya_json_parse.h" -#include "anedya_ota.h" -#include "anedya_op_vs.h" -#include "anedya_op_submitevent.h" -#include "anedya_op_submitdata.h" #include "anedya_op_commands.h" +#include "anedya_op_submitdata.h" +#include "anedya_op_submitevent.h" +#include "anedya_op_vs.h" +#include "anedya_ota.h" #include "string.h" +#include // Anedya Operation codes @@ -30,6 +30,7 @@ #define ANEDYA_OP_VALUESTORE_DELETE 12 #define ANEDYA_OP_CMD_GET_LIST 13 #define ANEDYA_OP_CMD_NEXT 14 +#define ANEDYA_OP_ONGOING_OTA 15 // Anedya Events #define ANEDYA_EVENT_VS_UPDATE_FLOAT 1 @@ -41,393 +42,539 @@ // Anedya Operations Error Codes #define ANEDYA_OP_ERR_RESP_BUFFER_OVERFLOW -1 -typedef struct -{ - bool success; - char *error_msg; - size_t error; +typedef struct { + bool success; + char *error_msg; + size_t error; } anedya_generic_resp_t; -// =========================== Anedya Operations and Requests ========================= +// =========================== Anedya Operations and Requests +// ========================= /** * @brief Send a device bind request to the server. * - * This function initiates a binding request for the device, creating a transaction and generating - * the required JSON payload for binding. The request is published to the MQTT server if the client - * is connected. + * This function initiates a binding request for the device, creating a + * transaction and generating the required JSON payload for binding. The request + * is published to the MQTT server if the client is connected. * * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the bind request transaction. - * @param[in] req_config Pointer to the `anedya_req_bind_device_t` structure containing binding configuration details. + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the bind request + * transaction. + * @param[in] req_config Pointer to the `anedya_req_bind_device_t` structure + * containing binding configuration details. * * @retval - `ANEDYA_OK` if the bind request is successfully sent. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_device_bind_req(anedya_client_t *client, anedya_txn_t *txn, anedya_req_bind_device_t *req_config); +anedya_err_t anedya_device_bind_req(anedya_client_t *client, anedya_txn_t *txn, + anedya_req_bind_device_t *req_config); /** * @brief Send a heartbeat signal to the server. * - * This function sends a heartbeat signal from the device to the server to maintain an active - * connection status. + * This function sends a heartbeat signal from the device to the server to + * maintain an active connection status. * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the heartbeat transaction. + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the heartbeat + * transaction. * * @retval - `ANEDYA_OK` if the heartbeat request is successfully sent. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_device_send_heartbeat(anedya_client_t *client, anedya_txn_t *txn); +anedya_err_t anedya_device_send_heartbeat(anedya_client_t *client, + anedya_txn_t *txn); /** - * @brief Request the next OTA (Over-the-Air) deployment details from the server. + * @brief Request the next OTA (Over-the-Air) deployment details from the + * server. * - * This function sends a request for the next available OTA deployment. It initializes the - * response structure to indicate no deployment available initially and creates a transaction - * with the required JSON payload if the client is connected. + * This function sends a request for the next available OTA deployment. It + * initializes the response structure to indicate no deployment available + * initially and creates a transaction with the required JSON payload if the + * client is connected. * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the OTA request transaction. - * The response (`txn->response`) will be populated with OTA deployment details. + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the OTA request + * transaction. The response (`txn->response`) will be populated with OTA + * deployment details. * * @retval - `ANEDYA_OK` if the OTA request is successfully sent. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ anedya_err_t anedya_op_ota_next_req(anedya_client_t *client, anedya_txn_t *txn); +/** + * @brief List ongoing OTA deployments, for which device has specified status at + * least once. + * + * This function lists ongoing OTA deployments, for which the device has + * specified status at least once. This does not list deployments with status: + * skipped, aborted, success and failure. Apart from that any status is + * considered as "in Progress". + * + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the OTA list + * transaction. The response (`txn->response`) will be populated with OTA + * deployment details. + * + * @retval - `ANEDYA_OK` if the OTA list request is successfully sent. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. + * @retval - Error code if transaction registration or message publishing fails. + * + * @note Ensure the client is connected before calling this function. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. + */ +anedya_err_t anedya_op_ongoing_ota_req(anedya_client_t *client, + anedya_txn_t *txn, + anedya_req_ongoing_ota_obj_t obj); + /** * @brief Send an OTA update status to the server. * - * This function sends the status of an OTA update for a specific deployment to the server. It - * creates a transaction, generates the JSON payload with deployment details, and publishes it - * to the server if the client is connected. + * This function sends the status of an OTA update for a specific deployment to + * the server. It creates a transaction, generates the JSON payload with + * deployment details, and publishes it to the server if the client is + * connected. * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the OTA update status transaction. - * @param[in] req Pointer to the `anedya_req_ota_update_status_t` structure containing the deployment - * ID and status to be sent. + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the OTA update + * status transaction. + * @param[in] req Pointer to the `anedya_req_ota_update_status_t` structure + * containing the deployment ID and status to be sent. * * @retval - `ANEDYA_OK` if the OTA update status is successfully sent. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_ota_update_status_req(anedya_client_t *client, anedya_txn_t *txn, anedya_req_ota_update_status_t *req); +anedya_err_t +anedya_op_ota_update_status_req(anedya_client_t *client, anedya_txn_t *txn, + anedya_req_ota_update_status_t *req); /** * @brief Submit a floating-point data value to the server. * - * This function sends a floating-point value with a specific variable identifier and timestamp - * to the server. It initializes a transaction, generates a JSON payload for the data submission, - * and publishes it to the server if the client is connected. - * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the data submission transaction. - * @param[in] variable_identifier A string representing the unique identifier for the variable. + * This function sends a floating-point value with a specific variable + * identifier and timestamp to the server. It initializes a transaction, + * generates a JSON payload for the data submission, and publishes it to the + * server if the client is connected. + * + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the data + * submission transaction. + * @param[in] variable_identifier A string representing the unique identifier + * for the variable. * @param[in] value Floating-point value to be submitted. * @param[in] timestamp_ms Timestamp of the data point in milliseconds. * * @retval - `ANEDYA_OK` if the data is successfully submitted. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_submit_float_req(anedya_client_t *client, anedya_txn_t *txn, const char *variable_identifier, float value, uint64_t timestamp_ms); +anedya_err_t anedya_op_submit_float_req(anedya_client_t *client, + anedya_txn_t *txn, + const char *variable_identifier, + float value, uint64_t timestamp_ms); /** * @brief Submit a string data value to the server. * - * This function sends a string value with a specific variable identifier and timestamp - * to the server. It initializes a transaction, generates a JSON payload for the data submission, - * and publishes it to the server if the client is connected. + * This function sends a string value with a specific variable identifier and + * timestamp to the server. It initializes a transaction, generates a JSON + * payload for the data submission, and publishes it to the server if the client + * is connected. * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the data submission transaction. - * @param[in] variable_identifier A string representing the unique identifier for the variable. + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the data + * submission transaction. + * @param[in] variable_identifier A string representing the unique identifier + * for the variable. * @param[in] value String value to be submitted. * @param[in] timestamp_ms Timestamp of the data point in milliseconds. * * @retval - `ANEDYA_OK` if the data is successfully submitted. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_submit_status_req(anedya_client_t *client, anedya_txn_t *txn, const char *variable_identifier, const char *value, uint64_t timestamp_ms); +anedya_err_t anedya_op_submit_status_req(anedya_client_t *client, + anedya_txn_t *txn, + const char *variable_identifier, + const char *value, + uint64_t timestamp_ms); /** * @brief Submit a geo-coordinate data value to the server. * - * This function sends a floating-point value with a specific variable identifier and timestamp - * to the server. It initializes a transaction, generates a JSON payload for the data submission, - * and publishes it to the server if the client is connected. - * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the data submission transaction. - * @param[in] variable_identifier A string representing the unique identifier for the variable. + * This function sends a floating-point value with a specific variable + * identifier and timestamp to the server. It initializes a transaction, + * generates a JSON payload for the data submission, and publishes it to the + * server if the client is connected. + * + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the data + * submission transaction. + * @param[in] variable_identifier A string representing the unique identifier + * for the variable. * @param[in] value Geo-coordinate value to be submited * @param[in] timestamp_ms Timestamp of the data point in milliseconds. * * @retval - `ANEDYA_OK` if the data is successfully submitted. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_submit_geo_req(anedya_client_t *client, anedya_txn_t *txn, const char *variable_identifier, anedya_geo_data_t *value, uint64_t timestamp_ms); +anedya_err_t anedya_op_submit_geo_req(anedya_client_t *client, + anedya_txn_t *txn, + const char *variable_identifier, + anedya_geo_data_t *value, + uint64_t timestamp_ms); /** * @brief Set a string value in the valuestore at anedya. * - * This function allows setting a string value associated with a specific key in the - * device's valuestore. It initializes a transaction, creates a JSON payload with the provided - * key and value, and publishes it to the server if the client is connected. + * This function allows setting a string value associated with a specific key in + * the device's valuestore. It initializes a transaction, creates a JSON payload + * with the provided key and value, and publishes it to the server if the client + * is connected. * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the valuestore transaction. - * @param[in] key A string representing the unique identifier (key) for the value in the valuestore. + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the valuestore + * transaction. + * @param[in] key A string representing the unique identifier (key) for the + * value in the valuestore. * @param[in] value The string value to be stored in the valuestore. * @param[in] value_len The length of the string value. * * @retval - `ANEDYA_OK` if the valuestore entry is successfully set. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. - * @retval - `ANEDYA_ERR_VALUE_TOO_LONG` if the string value is longer than 1000 bytes. - * @retval - `ANEDYA_ERR_VALUE_MISMATCH_LEN` if the string value length does not match the provided length. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. + * @retval - `ANEDYA_ERR_VALUE_TOO_LONG` if the string value is longer than 1000 + * bytes. + * @retval - `ANEDYA_ERR_VALUE_MISMATCH_LEN` if the string value length does not + * match the provided length. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_valuestore_set_string(anedya_client_t *client, anedya_txn_t *txn, const char *key, const char *value, size_t value_len); +anedya_err_t anedya_op_valuestore_set_string(anedya_client_t *client, + anedya_txn_t *txn, const char *key, + const char *value, + size_t value_len); /** * @brief Set a floating-point value in the valuestore at anedya. * - * This function allows setting a floating-point value associated with a specific key in the - * device's valuestore. It initializes a transaction, creates a JSON payload with the provided - * key and value, and publishes it to the server if the client is connected. - * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the valuestore transaction. - * @param[in] key A string representing the unique identifier (key) for the value in the valuestore. + * This function allows setting a floating-point value associated with a + * specific key in the device's valuestore. It initializes a transaction, + * creates a JSON payload with the provided key and value, and publishes it to + * the server if the client is connected. + * + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the valuestore + * transaction. + * @param[in] key A string representing the unique identifier (key) for the + * value in the valuestore. * @param[in] value The floating-point value to be stored in the valuestore. * * @retval - `ANEDYA_OK` if the valuestore entry is successfully set. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_valuestore_set_float(anedya_client_t *client, anedya_txn_t *txn, const char *key, float value); +anedya_err_t anedya_op_valuestore_set_float(anedya_client_t *client, + anedya_txn_t *txn, const char *key, + float value); /** * @brief Set a boolean-point value in the valuestore at anedya. * - * This function allows setting a boolean-point value associated with a specific key in the - * device's valuestore. It initializes a transaction, creates a JSON payload with the provided - * key and value, and publishes it to the server if the client is connected. - * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the valuestore transaction. - * @param[in] key A string representing the unique identifier (key) for the value in the valuestore. + * This function allows setting a boolean-point value associated with a specific + * key in the device's valuestore. It initializes a transaction, creates a JSON + * payload with the provided key and value, and publishes it to the server if + * the client is connected. + * + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the valuestore + * transaction. + * @param[in] key A string representing the unique identifier (key) for the + * value in the valuestore. * @param[in] value The floating-point value to be stored in the valuestore. * * @retval - `ANEDYA_OK` if the valuestore entry is successfully set. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_valuestore_set_bool(anedya_client_t *client, anedya_txn_t *txn, const char *key, bool value); +anedya_err_t anedya_op_valuestore_set_bool(anedya_client_t *client, + anedya_txn_t *txn, const char *key, + bool value); /** * @brief Set a binary value in the valuestore at anedya. * - * This function allows setting a binary value encoded in Base64 associated with a specific key - * in the device's valuestore. It initializes a transaction, creates a JSON payload with the - * provided key and value, and publishes it to the server if the client is connected. - * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the valuestore transaction. - * @param[in] key A string representing the unique identifier (key) for the value in the valuestore. - * @param[in] base64_value The binary value, encoded in Base64, to be stored in the valuestore. + * This function allows setting a binary value encoded in Base64 associated with + * a specific key in the device's valuestore. It initializes a transaction, + * creates a JSON payload with the provided key and value, and publishes it to + * the server if the client is connected. + * + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the valuestore + * transaction. + * @param[in] key A string representing the unique identifier (key) for the + * value in the valuestore. + * @param[in] base64_value The binary value, encoded in Base64, to be stored in + * the valuestore. * @param[in] base64_value_len The length of the Base64 encoded value. * * @retval - `ANEDYA_OK` if the valuestore entry is successfully set. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. - * @retval - `ANEDYA_ERR_VALUE_TOO_LONG` if the Base64 encoded value is longer than 1000 bytes. - * @retval - `ANEDYA_ERR_VALUE_MISMATCH_LEN` if the length of the Base64 encoded value does not match the provided length. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. + * @retval - `ANEDYA_ERR_VALUE_TOO_LONG` if the Base64 encoded value is longer + * than 1000 bytes. + * @retval - `ANEDYA_ERR_VALUE_MISMATCH_LEN` if the length of the Base64 encoded + * value does not match the provided length. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_valuestore_set_bin(anedya_client_t *client, anedya_txn_t *txn, const char *key, const char *base64_value, size_t base64_value_len); +anedya_err_t anedya_op_valuestore_set_bin(anedya_client_t *client, + anedya_txn_t *txn, const char *key, + const char *base64_value, + size_t base64_value_len); /** * @brief Get the value associated with a key from the valuestore at anedya. * - * This function retrieves a value associated with a specific key from the valuestore. - * It initializes a transaction, creates a JSON payload with the provided key, and publishes it - * to the server if the client is connected. + * This function retrieves a value associated with a specific key from the + * valuestore. It initializes a transaction, creates a JSON payload with the + * provided key, and publishes it to the server if the client is connected. * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the valuestore transaction. - * @param[in] obj Pointer to an `anedya_valuestore_get_key_t` structure containing the key to retrieve. + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the valuestore + * transaction. + * @param[in] obj Pointer to an `anedya_valuestore_get_key_t` structure + * containing the key to retrieve. * * @retval - `ANEDYA_OK` if the valuestore entry is successfully retrieved. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_valuestore_get_key(anedya_client_t *client, anedya_txn_t *txn, anedya_req_valuestore_get_key_t obj); +anedya_err_t anedya_op_valuestore_get_key(anedya_client_t *client, + anedya_txn_t *txn, + anedya_req_valuestore_get_key_t obj); /** * @brief Get the list of the keys from the valuestore at anedya. * - * This function retrieves a list of keys-value associated with a list of keys from the valuestore. + * This function retrieves a list of keys-value associated with a list of keys + * from the valuestore. * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the valuestore transaction. - * @param[in] obj Pointer to an `anedya_req_valuestore_list_obj_t` structure containing the list of keys to retrieve. + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the valuestore + * transaction. + * @param[in] obj Pointer to an `anedya_req_valuestore_list_obj_t` structure + * containing the list of keys to retrieve. * * @retval - `ANEDYA_OK` if the valuestore entry is successfully retrieved. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_valuestore_list_obj(anedya_client_t *client, anedya_txn_t *txn, anedya_req_valuestore_list_obj_t obj); +anedya_err_t +anedya_op_valuestore_list_obj(anedya_client_t *client, anedya_txn_t *txn, + anedya_req_valuestore_list_obj_t obj); /** * @brief Delete a value from the valuestore at anedya. * - * This function deletes a value associated with a specific key from the valuestore. + * This function deletes a value associated with a specific key from the + * valuestore. * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the valuestore transaction. - * @param[in] key A string representing the unique identifier (key) for the value in the valuestore. + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the valuestore + * transaction. + * @param[in] key A string representing the unique identifier (key) for the + * value in the valuestore. * * @retval - `ANEDYA_OK` if the valuestore entry is successfully deleted. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_valuestore_delete(anedya_client_t *client, anedya_txn_t *txn, const char *key); +anedya_err_t anedya_op_valuestore_delete(anedya_client_t *client, + anedya_txn_t *txn, const char *key); /** * @brief Send an event to Anedya * * This function sends an event to Anedya. * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[inout] txn Pointer to an `anedya_txn_t` structure for the valuestore transaction. + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[inout] txn Pointer to an `anedya_txn_t` structure for the valuestore + * transaction. * @param[in] req_config Pointer to the request config * * @retval - `ANEDYA_OK` if the valuestore entry is successfully set. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_submit_event(anedya_client_t *client, anedya_txn_t *txn, anedya_req_submit_event_t *req_config); +anedya_err_t anedya_op_submit_event(anedya_client_t *client, anedya_txn_t *txn, + anedya_req_submit_event_t *req_config); /** * @brief Update command status * * This function updates status of a received command to Anedya. * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[inout] txn Pointer to an `anedya_txn_t` structure for the valuestore transaction. + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[inout] txn Pointer to an `anedya_txn_t` structure for the valuestore + * transaction. * @param[in] req_config Pointer to the request config * * @retval - `ANEDYA_OK` if the valuestore entry is successfully set. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_cmd_status_update(anedya_client_t *client, anedya_txn_t *txn, anedya_req_cmd_status_update_t *req_config); +anedya_err_t +anedya_op_cmd_status_update(anedya_client_t *client, anedya_txn_t *txn, + anedya_req_cmd_status_update_t *req_config); /** * @brief List commands * * This function lists queued commands of a specific device * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[inout] txn Pointer to an `anedya_txn_t` structure for the valuestore transaction. - * @param[in] obj Pointer to an `anedya_req_cmd_list_t` structure containing the list of commands to retrieve. + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[inout] txn Pointer to an `anedya_txn_t` structure for the valuestore + * transaction. + * @param[in] obj Pointer to an `anedya_req_cmd_list_t` structure containing the + * list of commands to retrieve. * * @retval - `ANEDYA_OK` if the valuestore entry is successfully retrieved. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_cmd_get_list(anedya_client_t *client, anedya_txn_t *txn, anedya_req_cmd_list_t obj); +anedya_err_t anedya_op_cmd_get_list(anedya_client_t *client, anedya_txn_t *txn, + anedya_req_cmd_list_t obj); /** * @brief Retrieve the next command for execution from Anedya. * - * This function retrieves the next available command for execution from the server. + * This function retrieves the next available command for execution from the + * server. * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[out] txn Pointer to an `anedya_txn_t` structure for the command transaction. + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[out] txn Pointer to an `anedya_txn_t` structure for the command + * transaction. * * @retval - `ANEDYA_OK` if the next command is successfully retrieved. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ anedya_err_t anedya_op_cmd_next(anedya_client_t *client, anedya_txn_t *txn); @@ -436,24 +583,32 @@ anedya_err_t anedya_op_cmd_next(anedya_client_t *client, anedya_txn_t *txn); * * This function sends a log to Anedya. * - * @param[in] client Pointer to the `anedya_client_t` structure representing the client. - * @param[inout] txn Pointer to an `anedya_txn_t` structure for the valuestore transaction. + * @param[in] client Pointer to the `anedya_client_t` structure representing the + * client. + * @param[inout] txn Pointer to an `anedya_txn_t` structure for the valuestore + * transaction. * @param[in] log Pointer to the log * @param[in] log_len Length of the log * @param[in] timestamp_ms Timestamp of the log * * @retval - `ANEDYA_OK` if the valuestore entry is successfully set. - * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the server. + * @retval - `ANEDYA_ERR_NOT_CONNECTED` if the client is not connected to the + * server. * @retval - Error code if transaction registration or message publishing fails. * * @note Ensure the client is connected before calling this function. - * @warning This function uses static or dynamic allocation based on configuration macros. - * Ensure the appropriate allocation macros are defined. + * @warning This function uses static or dynamic allocation based on + * configuration macros. Ensure the appropriate allocation macros are defined. */ -anedya_err_t anedya_op_submit_log(anedya_client_t *client, anedya_txn_t *txn, char *log, unsigned int log_len, unsigned long long timestamp_ms); +anedya_err_t anedya_op_submit_log(anedya_client_t *client, anedya_txn_t *txn, + char *log, unsigned int log_len, + unsigned long long timestamp_ms); -//========================== Reponse handlers =================================== -void _anedya_device_handle_generic_resp(anedya_client_t *client, anedya_txn_t *txn); +//========================== Reponse handlers +//=================================== +void _anedya_device_handle_generic_resp(anedya_client_t *client, + anedya_txn_t *txn); void _anedya_op_ota_next_resp(anedya_client_t *client, anedya_txn_t *txn); +void _anedya_op_ongoing_ota_resp(anedya_client_t *client, anedya_txn_t *txn); #endif \ No newline at end of file diff --git a/include/anedya_ota.h b/include/anedya_ota.h index 9c9f9e4..7764eee 100644 --- a/include/anedya_ota.h +++ b/include/anedya_ota.h @@ -1,32 +1,52 @@ #pragma once #include "anedya_commons.h" +#include "anedya_json_parse.h" #include "anedya_models.h" #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif - typedef struct - { - bool deployment_available; - anedya_uuid_t deployment_id; - anedya_asset_t asset; - } anedya_op_next_ota_resp_t; +typedef struct { + bool deployment_available; + anedya_uuid_t deployment_id; + anedya_asset_t asset; +} anedya_op_next_ota_resp_t; - typedef struct - { - const char *status; - anedya_uuid_t *deployment_id; - } anedya_req_ota_update_status_t; +// ------ongoing OTA ------ + +typedef struct { + unsigned short limit; + unsigned short offset; +} anedya_req_ongoing_ota_obj_t; + +typedef struct { + anedya_uuid_t deployment_id; + anedya_asset_t *asset; + char status[15]; +} anedya_op_ongoing_asset_list_t; + +typedef struct { + int count; + anedya_op_ongoing_asset_list_t *assets; +} anedya_op_ongoing_ota_resp_t; + +// ------update OTA status ------ +typedef struct { + const char *status; + anedya_uuid_t *deployment_id; +} anedya_req_ota_update_status_t; #define ANEDYA_OTA_STATUS_START "start" #define ANEDYA_OTA_STATUS_SUCCESS "success" #define ANEDYA_OTA_STATUS_FAILURE "failure" #define ANEDYA_OTA_STATUS_SKIPPED "skipped" - anedya_err_t _anedya_op_ota_next_parser(json_t *json, anedya_op_next_ota_resp_t *resp); +anedya_err_t _anedya_op_ota_next_parser(json_t *json, + anedya_op_next_ota_resp_t *resp); +anedya_err_t _anedya_op_ongoing_ota_parser(json_t *json, + anedya_op_ongoing_ota_resp_t *resp); #ifdef __cplusplus } diff --git a/include/anedya_sdk_config.h b/include/anedya_sdk_config.h index 60f060d..7758f89 100755 --- a/include/anedya_sdk_config.h +++ b/include/anedya_sdk_config.h @@ -4,6 +4,11 @@ */ #pragma once +#ifdef __has_include +#if __has_include("sdkconfig.h") +#include "sdkconfig.h" +#endif +#endif // Feature management #define ANEDYA_ENABLE_DEVICE_LOGS @@ -20,14 +25,16 @@ /*======================================*/ #if defined(ANEDYA_EMBED_PEM) && defined(ANEDYA_EMBED_DER) -#warning "Embedding certifciates in both PEM and DER format can increase binary size" +#warning \ + "Embedding certifciates in both PEM and DER format can increase binary size" #endif #if !defined(ANEDYA_EMBED_PEM) && !defined(ANEDYA_EMBED_DER) #error "Please define either ANEDYA_EMBED_PEM or ANEDYA_EMBED_DER" #endif -#define ANEDYA_TLS_ENABLE_ECC // Using ECC can save roughly 400 bytes of static storage +#define ANEDYA_TLS_ENABLE_ECC // Using ECC can save roughly 400 bytes of static + // storage // #define ANEDYA_TLS_ENABLE_RSA /* @@ -37,51 +44,78 @@ Supported methods are: - HTTP Defining both of the methods will result in compilation error. -Depending on the method selected, corresponding implementation of APIs will be implemented. +Depending on the method selected, corresponding implementation of APIs will be +implemented. */ +/* Connection method is now driven by Kconfig (menuconfig). + * Select "Anedya SDK Settings" -> "Connection Method" to choose MQTTS or HTTPS. + * Do NOT define these manually here; set them in sdkconfig via idf.py + * menuconfig. + */ +#if defined(CONFIG_CONN_ANEDYA_MQTT) #define ANEDYA_CONNECTION_METHOD_MQTT -// #define ANEDYA_CONNECTION_METHOD_HTTP +#elif defined(CONFIG_CONN_ANEDYA_HTTPS) +#define ANEDYA_CONNECTION_METHOD_HTTP +#else +/* Fallback for non-ESP-IDF platforms: define one of the macros in your build + * system. */ +#endif -// Include error definitions, omit these definitions reduces binary size by a small margin +// Include error definitions, omit these definitions reduces binary size by a +// small margin #define ANEDYA_INCLUDE_ERR_NAMES -// Depending on your platform, anedya-core library can be tailored to use all statically assigned memory or to use dynamic memory allocation. -// If you are using static memory allocation, please define ANEDYA_ENABLE_STATIC_ALLOCATION. -// If you are using dynamic memory allocation, please define ANEDYA_ENABLE_DYNAMIC_ALLOCATION. +// Depending on your platform, anedya-core library can be tailored to use all +// statically assigned memory or to use dynamic memory allocation. If you are +// using static memory allocation, please define +// ANEDYA_ENABLE_STATIC_ALLOCATION. If you are using dynamic memory allocation, +// please define ANEDYA_ENABLE_DYNAMIC_ALLOCATION. // -// For static allocation of memory, additional values are required to be defined. +// For static allocation of memory, additional values are required to be +// defined. #define ANEDYA_ENABLE_STATIC_ALLOCATION // #define ANEDYA_ENABLE_DYNAMIC_ALLOCATION -#if defined(ANEDYA_CONNECTION_METHOD_MQTT) && defined(ANEDYA_CONNECTION_METHOD_HTTP) -#error "ANEDYA_CONNECTION_METHOD_MQTT and ANEDYA_CONNECTION_METHOD_HTTP cannot be defined at the same time" +#if defined(ANEDYA_CONNECTION_METHOD_MQTT) && \ + defined(ANEDYA_CONNECTION_METHOD_HTTP) +#error \ + "ANEDYA_CONNECTION_METHOD_MQTT and ANEDYA_CONNECTION_METHOD_HTTP cannot be defined at the same time" #endif -#if !defined(ANEDYA_CONNECTION_METHOD_MQTT) && !defined(ANEDYA_CONNECTION_METHOD_HTTP) +#if !defined(ANEDYA_CONNECTION_METHOD_MQTT) && \ + !defined(ANEDYA_CONNECTION_METHOD_HTTP) #error "ANEDYA CONFIG: Connection methods needs to be specified" #endif -#if defined(ANEDYA_ENABLE_STATIC_ALLOCATION) && defined(ANEDYA_ENABLE_DYNAMIC_ALLOCATION) -#error "ANEDYA_ENABLE_STATIC_ALLOCATION and ANEDYA_ENABLE_DYNAMIC_ALLOCATION cannot be defined at the same time" +#if defined(ANEDYA_ENABLE_STATIC_ALLOCATION) && \ + defined(ANEDYA_ENABLE_DYNAMIC_ALLOCATION) +#error \ + "ANEDYA_ENABLE_STATIC_ALLOCATION and ANEDYA_ENABLE_DYNAMIC_ALLOCATION cannot be defined at the same time" #endif #if defined(ANEDYA_TLS_ENABLE_ECC) && defined(ANEDYA_TLS_ENABLE_RSA) -#error "ANEDYA_TLS_ENABLE_ECC and ANEDYA_TLS_ENABLE_RSA cannot be defined at the same time" +#error \ + "ANEDYA_TLS_ENABLE_ECC and ANEDYA_TLS_ENABLE_RSA cannot be defined at the same time" #endif -// Define different buffer sizes(in bytes) to preallocate memeory to carry out different transactions -// Please provide sufficient buffer according to your requirement. -// Lower buffer will not be able to include multiple datapoint submission in single request -// Higher buffer will be able to include multiple datapoint submission in single request but will occupy higher SRAM -// Default buffer size is 1024 bytes +// Define different buffer sizes(in bytes) to preallocate memeory to carry out +// different transactions Please provide sufficient buffer according to your +// requirement. Lower buffer will not be able to include multiple datapoint +// submission in single request Higher buffer will be able to include multiple +// datapoint submission in single request but will occupy higher SRAM Default +// buffer size is 1024 bytes #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION #define ANEDYA_TX_BUFFER_SIZE CONFIG_AN_TX_BUFFER #define ANEDYA_RX_BUFFER_SIZE CONFIG_AN_RX_BUFFER #ifdef ANEDYA_ENABLE_DEVICE_LOGS -#define ANEDYA_LOG_BUFFER 1024 // Anedya max size of the log -#define ANEDYA_MAX_LOG_BATCH 10 // Maximum Number of logs that can be submitted in a single request +#define ANEDYA_LOG_BUFFER 1024 // Anedya max size of the log +#define ANEDYA_MAX_LOG_BATCH \ + 10 // Maximum Number of logs that can be submitted in a single request #endif #endif -#define ANEDYA_MAX_CONCURRENT_TXN CONFIG_AN_MAX_CONCURRENT_TXN // Number of maximum under process concurrent requests to Anedya. Please note that each concurrent transaction will consume \ No newline at end of file +#define ANEDYA_MAX_CONCURRENT_TXN \ + CONFIG_AN_MAX_CONCURRENT_TXN // Number of maximum under process concurrent + // requests to Anedya. Please note that each + // concurrent transaction will consume \ No newline at end of file diff --git a/interfaces/esp32-quectel/anedya_esp_quectelEC200_interface.c b/interfaces/esp32-quectel/anedya_esp_quectelEC200_interface.c deleted file mode 100644 index 1697870..0000000 --- a/interfaces/esp32-quectel/anedya_esp_quectelEC200_interface.c +++ /dev/null @@ -1,1477 +0,0 @@ -#include "sdkconfig.h" - -#ifdef CONFIG_AN_INTERFACE_ESP32_QUETEL -#include "anedya_interface.h" - -// Network Interface is Sim Network Quectel - -#include "anedya_esp_quectelEC200_interface.h" -#include "anedya_certs.h" -#include "anedya_client.h" -#include "anedya_commons.h" -#include "time.h" -#include -#include - -static const char *TAG = "Anedya"; -static short debug_level = 1; - -static esp_mqtt_client_config_t mqtt_cfg; - -static short UART_PORT_NUMBER = -1; -static SemaphoreHandle_t uart_port_mutex; - -#define UNKONWN_CMD -1 -#define MODEM_CMD_EX_ASAP 0 -#define MODEM_RESP_WAIT 1 -static unsigned int CMD_TYPE = MODEM_CMD_EX_ASAP; - -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION -static uint8_t response_topic[150]; -static uint8_t modem_response[ANEDYA_RX_BUFFER_SIZE]; -static uint8_t dtmp[200] = {0}; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - -static unsigned int modem_response_len = 0; -static bool more_data_available = false; - -anedya_ext_mqtt_event_t mqtt_event; -#define MQTT_EVENT_RECEIVE_DATA (BIT0) - -static EventGroupHandle_t ModemEvents; -static EventGroupHandle_t MqttEvents; - -#define MODEM_EVENT_RECEIVE_DATA (BIT0) -#define MODEM_EVENT_OTA_NOT_IN_PROGRESS (BIT1) - -#define PATTERN_CHR_NUM (3) /*!< Set the number of consecutive and identical characters received by receiver which defines a UART pattern*/ -static uint8_t pat[PATTERN_CHR_NUM + 1]; - -static void _uart_event_task(void *pvParameters); -static anedya_err_t _anedya_ext_clear_uart_buffer(anedya_client_t *anedya_client); -static void _anedya_ext_mqtt_event_task(void *pvParameters); -static void _mqtt_message_parser(anedya_client_t *anedya_client, uart_event_t event); -static anedya_err_t _anedya_ext_send_AT_command(char *cmd, unsigned int cmd_type, char *resp, char *expected_resp, size_t timeout); - -void _anedya_interface_sleep_ms(size_t ms) -{ - vTaskDelay(ms / portTICK_PERIOD_MS); -} - -uint64_t _anedya_interface_get_time_ms() -{ - struct timeval ts; - gettimeofday(&ts, NULL); - return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_usec / 1000; -} - -void _anedya_interface_std_out(const char *str) -{ - ESP_LOGI("ANEDYA", "%s", str); -} - -static void _anedya_ext_mqtt_event_task(void *pvParameters) -{ - anedya_client_t *anedya_client = (anedya_client_t *)pvParameters; - - xEventGroupClearBits(MqttEvents, MQTT_EVENT_RECEIVE_DATA); - while (1) - { - xEventGroupWaitBits(MqttEvents, MQTT_EVENT_RECEIVE_DATA, pdFALSE, pdFALSE, portMAX_DELAY); - xEventGroupClearBits(MqttEvents, MQTT_EVENT_RECEIVE_DATA); - - switch (mqtt_event.event_id) - { - case EXT_MQTT_EVENT_CONNECTED: - if (anedya_client->_anedya_on_connect_handler != NULL) - { - anedya_client->_anedya_on_connect_handler(anedya_client); - } - continue; - case EXT_MQTT_EVENT_DISCONNECTED: - if (anedya_client->_anedya_on_disconnect_handler != NULL) - { - anedya_client->_anedya_on_disconnect_handler(anedya_client); - } - continue; - case EXT_MQTT_EVENT_DATA: - if (anedya_client->_message_handler != NULL) - { - anedya_client->_message_handler(anedya_client, mqtt_event.topic, mqtt_event.topic_len, mqtt_event.data, mqtt_event.data_len); - } - continue; - default: - continue; - } - - vTaskDelay(1 / portTICK_PERIOD_MS); - } -} - -static void _mqtt_message_parser(anedya_client_t *anedya_client, uart_event_t event) -{ - int dummy1, dummy2; - // check for mqtt connect URC - char *conn_ptr = strstr((char *)dtmp, "+QMTCONN:"); - if (conn_ptr != NULL) - { - int ret_code = 5; - int matched = sscanf((char *)conn_ptr, "+QMTCONN: %*d,%*d,%d", &ret_code); - if (matched) - { - if (ret_code == 0) - { - mqtt_event.event_id = EXT_MQTT_EVENT_CONNECTED; - xEventGroupSetBits(MqttEvents, MQTT_EVENT_RECEIVE_DATA); - } - else - { - ESP_LOGE(TAG, "Invalid uart response!"); - } - } - } - // check for mqtt disconnect URC - char *stat_ptr = strstr((char *)dtmp, "+QMTSTAT:"); - if (stat_ptr != NULL) - { - ESP_LOGE(TAG, "Mqtt Disconnected!"); - mqtt_event.event_id = EXT_MQTT_EVENT_DISCONNECTED; - xEventGroupSetBits(MqttEvents, MQTT_EVENT_RECEIVE_DATA); - } - - // check for the mqtt message URC - char *recv_ptr = strstr((char *)dtmp, "+QMTRECV:"); - if (recv_ptr != NULL) - { - modem_response_len = 0; - int matched = sscanf(recv_ptr, "+QMTRECV: %d,%d,\"%[^\"]\",%d", &dummy1, &dummy2, response_topic, &modem_response_len); - if (matched) - { - if (modem_response_len > 9) - { - char *start_ptr = strchr((char *)dtmp, '{'); - if (start_ptr) - { - strncpy((char *)modem_response, (char *)start_ptr, modem_response_len); - } - } - more_data_available = true; - } - else - { - ESP_LOGE("UART EVENT HANDLER", "Invalid uart response"); - } - } - else if (more_data_available) - { - if (modem_response_len < 10) - { - int a = modem_response_len; - int b; - - int matched = sscanf((char *)dtmp, "%d,\"{", &b); - if (matched != 1) - { - ESP_LOGE(TAG, "Failed to extract b from response"); - more_data_available = false; - return; - } - // Find number of digits in b - int temp = b, digits = 0; - while (temp != 0) - { - temp /= 10; - digits++; - } - - // Concatenate - modem_response_len = a * pow(10, digits) + b; - char *start_ptr = strchr((char *)dtmp, '{'); - if (start_ptr) - { - strncpy((char *)modem_response, (char *)start_ptr, modem_response_len); - } - if (strlen((char *)modem_response) == modem_response_len) - { - if (debug_level > 1) - ESP_LOGW("Anedya Response", "%s", (char *)modem_response); - - if (strlen((char *)response_topic) == 0) - { - ESP_LOGE(TAG, "No topic found in response!"); - more_data_available = false; - return; - } - - if (modem_response[modem_response_len - 1] == '}') - { - mqtt_event.event_id = EXT_MQTT_EVENT_DATA; - mqtt_event.data = (char *)modem_response; - mqtt_event.topic = (char *)response_topic; - mqtt_event.data_len = strlen((char *)modem_response); - mqtt_event.topic_len = strlen((char *)response_topic); - xEventGroupSetBits(MqttEvents, MQTT_EVENT_RECEIVE_DATA); - xEventGroupSetBits(ModemEvents, MODEM_EVENT_RECEIVE_DATA); - } - more_data_available = false; - return; - } - } - else if (strlen((char *)modem_response) < modem_response_len) - { - int i = 0; - while (event.size != i) - { - strncat((char *)modem_response, (char *)dtmp + i, 1); - if (strlen((char *)modem_response) == modem_response_len) - { - if (debug_level > 1) - ESP_LOGW("Anedya Response", "%s", (char *)modem_response); - - if (strlen((char *)response_topic) == 0) - { - ESP_LOGE(TAG, "No topic found in response!"); - more_data_available = false; - break; - } - - if (modem_response[modem_response_len - 1] == '}') - { - mqtt_event.event_id = EXT_MQTT_EVENT_DATA; - mqtt_event.data = (char *)modem_response; - mqtt_event.topic = (char *)response_topic; - mqtt_event.data_len = strlen((char *)modem_response); - mqtt_event.topic_len = strlen((char *)response_topic); - xEventGroupSetBits(MqttEvents, MQTT_EVENT_RECEIVE_DATA); - xEventGroupSetBits(ModemEvents, MODEM_EVENT_RECEIVE_DATA); - } - more_data_available = false; - break; - } - i++; - } - } - else - { - if (debug_level > 1) - ESP_LOGW("Anedya Response", "%s", (char *)modem_response); - - if (strlen((char *)response_topic) == 0) - { - ESP_LOGE(TAG, "No topic found in response!"); - more_data_available = false; - return; - } - - if (modem_response[modem_response_len - 1] == '}') - { - mqtt_event.event_id = EXT_MQTT_EVENT_DATA; - mqtt_event.data = (char *)modem_response; - mqtt_event.topic = (char *)response_topic; - mqtt_event.data_len = strlen((char *)modem_response); - mqtt_event.topic_len = strlen((char *)response_topic); - xEventGroupSetBits(MqttEvents, MQTT_EVENT_RECEIVE_DATA); - xEventGroupSetBits(ModemEvents, MODEM_EVENT_RECEIVE_DATA); - } - more_data_available = false; - } - } - else - { - if (debug_level > 1) - ESP_LOGI(TAG, "Modem response: %s", (char *)dtmp); - xEventGroupSetBits(ModemEvents, MODEM_EVENT_RECEIVE_DATA); - } - return; -} - -static void _uart_event_task(void *pvParameters) -{ - anedya_client_t *anedya_client = (anedya_client_t *)pvParameters; - QueueHandle_t uart_queue = ((anedya_ext_config_t *)anedya_client->config->interface_config)->uart_queue_handle; - - uart_event_t event; - size_t buffered_size; - _anedya_ext_clear_uart_buffer(anedya_client); // Clear the UART buffer - - for (;;) - { - xEventGroupWaitBits(ModemEvents, MODEM_EVENT_OTA_NOT_IN_PROGRESS, pdFALSE, pdFALSE, portMAX_DELAY); - - // Waiting for UART event - if (xQueueReceive(uart_queue, (void *)&event, (TickType_t)portMAX_DELAY)) - { - switch (event.type) - { - case UART_DATA: - // ESP_LOGI("UART EVENT HANDLER", "[UART DATA]: %d", event.size); - for (int i = 0; i < 200; ++i) - dtmp[i] = 0; - - if (!more_data_available) - { - // empty the buffers - for (int i = 0; i < ANEDYA_RX_BUFFER_SIZE; ++i) - modem_response[i] = 0; - for (int j = 0; j < 150; ++j) - response_topic[j] = 0; - } - // Remove unwanted characters - int len = uart_read_bytes(UART_PORT_NUMBER, dtmp, event.size, pdMS_TO_TICKS(2000)); - if (len <= 0) - break; - int j = 0; - for (int i = 0; i < len; ++i) - { - if (dtmp[i] != '\r' && dtmp[i] != '\n') - dtmp[j++] = dtmp[i]; - } - dtmp[j] = '\0'; - - // ESP_LOGI("UartEventHandler", "%s", dtmp); - _mqtt_message_parser(anedya_client, event); - break; - - case UART_FIFO_OVF: - ESP_LOGI("UART EVENT HANDLER", "hw fifo overflow"); - uart_flush_input(UART_PORT_NUMBER); - xQueueReset(uart_queue); - break; - - case UART_BUFFER_FULL: - ESP_LOGI("UART EVENT HANDLER", "ring buffer full"); - uart_flush_input(UART_PORT_NUMBER); - xQueueReset(uart_queue); - break; - - case UART_BREAK: - ESP_LOGI("UART EVENT HANDLER", "uart rx break"); - break; - - case UART_PARITY_ERR: - ESP_LOGI("UART EVENT HANDLER", "uart parity error"); - break; - - case UART_FRAME_ERR: - ESP_LOGI("UART EVENT HANDLER", "uart frame error"); - break; - - case UART_PATTERN_DET: - uart_get_buffered_data_len(UART_PORT_NUMBER, &buffered_size); - int pos = uart_pattern_pop_pos(UART_PORT_NUMBER); - ESP_LOGI("UART EVENT HANDLER", "[UART PATTERN DETECTED] pos: %d, buffered size: %d", pos, buffered_size); - if (pos == -1) - { - uart_flush_input(UART_PORT_NUMBER); - } - else - { - uart_read_bytes(UART_PORT_NUMBER, dtmp, pos, 100 / portTICK_PERIOD_MS); - - // Clear pat manually - for (int i = 0; i < (PATTERN_CHR_NUM + 1); ++i) - pat[i] = 0; - - uart_read_bytes(UART_PORT_NUMBER, pat, PATTERN_CHR_NUM, 100 / portTICK_PERIOD_MS); - - ESP_LOGI("UART EVENT HANDLER", "read data: %s", dtmp); - ESP_LOGI("UART EVENT HANDLER", "read pat : %s", pat); - } - break; - - default: - ESP_LOGI("UART EVENT HANDLER", "uart event type: %d", event.type); - break; - } - } - - vTaskDelay(5 / portTICK_PERIOD_MS); - } -} - -static anedya_err_t _anedya_ext_send_AT_command(char *cmd, unsigned int cmd_type, char *resp, char *expected_resp, size_t timeout) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - CMD_TYPE = cmd_type; - if (debug_level > 1) - ESP_LOGI(TAG, "TX Commnad: %s", cmd); - uart_write_bytes(UART_PORT_NUMBER, cmd, strlen(cmd)); - - if (cmd_type == MODEM_RESP_WAIT) - { - int start_time = xTaskGetTickCount(); - if (expected_resp != NULL) - { - while (xTaskGetTickCount() - start_time < timeout / portTICK_PERIOD_MS) - { - if (!xEventGroupWaitBits(ModemEvents, MODEM_EVENT_RECEIVE_DATA, pdFALSE, pdFALSE, timeout / portTICK_PERIOD_MS)) - { - ESP_LOGW(TAG, "Timed out waiting for response from modem"); - return ANEDYA_ERR_EXT_TIMEOUT; - } - char *check_ptr = strstr((char *)dtmp, expected_resp); - // if (strncmp((char *)dtmp, expected_resp, strlen((char *)expected_resp)) == 0) - if (check_ptr != NULL) - { - // ESP_LOGI("RX Commnad:", "%s", dtmp); - if (resp != NULL) - { - strcpy((char *)resp, (char *)dtmp); - } - CMD_TYPE = UNKONWN_CMD; - xEventGroupClearBits(ModemEvents, MODEM_EVENT_RECEIVE_DATA); - return ANEDYA_OK; - } - xEventGroupClearBits(ModemEvents, MODEM_EVENT_RECEIVE_DATA); - } - return ANEDYA_ERR_EXT_TIMEOUT; - } - else - { - // ESP_LOGI(TAG, "Waiting for response from modem with timeout: %d ms", timeout); - vTaskDelay(timeout / portTICK_PERIOD_MS); - if (strlen((char *)dtmp) == 0) - return ANEDYA_ERR_EXT_TIMEOUT; - } - } - else - { - if (!xEventGroupWaitBits(ModemEvents, MODEM_EVENT_RECEIVE_DATA, pdFALSE, pdFALSE, timeout / portTICK_PERIOD_MS)) - { - ESP_LOGW(TAG, "Timed out waiting for response from modem"); - return ANEDYA_ERR_EXT_TIMEOUT; - } - } - // ESP_LOGI("RX Commnad:", "%s", dtmp); - if (resp != NULL) - { - strcpy((char *)resp, (char *)dtmp); - } - for (int i = 0; i < strlen((char *)dtmp); i++) - dtmp[i] = 0; - CMD_TYPE = UNKONWN_CMD; - xEventGroupClearBits(ModemEvents, MODEM_EVENT_RECEIVE_DATA); - return ANEDYA_OK; -} - -anedya_err_t _anedya_interface_init(anedya_client_t *client) -{ - anedya_ext_config_t *ext_config = (anedya_ext_config_t *)client->config->interface_config; - UART_PORT_NUMBER = ext_config->uart_port_num; - - if (ext_config->uart_port_num == -1) - { - ESP_LOGE(TAG, "Invalid port number passed to uart init"); - return ANEDYA_EXT_ERR; - } - if(debug_level > 0) - ESP_LOGI(TAG, "Initializing the Anedya Quectel EC200 interface"); - ModemEvents = xEventGroupCreate(); - MqttEvents = xEventGroupCreate(); - uart_port_mutex = xSemaphoreCreateMutex(); - - // Install UART driver, and get the queue. - uart_driver_install(ext_config->uart_port_num, ANEDYA_RX_BUFFER_SIZE, ANEDYA_TX_BUFFER_SIZE, 20, &ext_config->uart_queue_handle, 0); - uart_param_config(ext_config->uart_port_num, &ext_config->uart_config); - - // Set UART pins (using UART0 default pins ie no changes.) - uart_set_pin(ext_config->uart_port_num, ext_config->tx_pin, ext_config->rx_pin, ext_config->rts_pin, ext_config->cts_pin); // Mcu RTS PIN, Mcu CTS PIN - - // Enable pattern detection - if (uart_enable_pattern_det_baud_intr(ext_config->uart_port_num, '+', PATTERN_CHR_NUM, 9, 0, 0) != ESP_OK) - { - ESP_LOGE(TAG, "Could not enable pattern detection"); - return ANEDYA_EXT_ERR; - } - - if (uart_pattern_queue_reset(ext_config->uart_port_num, 20) != ESP_OK) - { - ESP_LOGE(TAG, "Could not reset pattern queue"); - return ANEDYA_EXT_ERR; - } - - // Create the task - if (xTaskCreate(_uart_event_task, "uart_event_task", 8192, client, 1, NULL) != pdPASS) - { - ESP_LOGE(TAG, "Could not create uart event task"); - return ANEDYA_EXT_ERR; - } - - xEventGroupSetBits(ModemEvents, MODEM_EVENT_OTA_NOT_IN_PROGRESS); - anedya_err_t err; - - err = _anedya_ext_send_AT_command("ATE0\r\n", MODEM_CMD_EX_ASAP, NULL, "OK", 2000); // disable echo - - if (xTaskCreate(_anedya_ext_mqtt_event_task, "MQTT_EVENT_TASK", 8192, client, 2, NULL) != pdPASS) - { - ESP_LOGE(TAG, "Failed to create MQTT Event task"); - } - err = _anedya_ext_send_AT_command("AT+QMTDISC=0\r\n", MODEM_CMD_EX_ASAP, NULL, NULL, 2000); // disconnect from MQTT broker - err = _anedya_ext_send_AT_command("AT\r\n", MODEM_RESP_WAIT, NULL, "OK", 2000); - if (err == ANEDYA_OK) - { - if (ext_config->apn_count > 0) - { - int check = 0; - while (1) - { - if (debug_level > 0) - ESP_LOGI(TAG, "Checking Modem Internet Connectivity..."); - int status = -1, rssi = 0, mode = -1; - err = anedya_ext_network_reg_status(client, &status, 2000); - err = anedya_ext_network_operator(client, &mode, 2000); - err = anedya_ext_signal_quality(client, &rssi, NULL, 2000); - if (debug_level > 0) - ESP_LOGI(TAG, "Status: %d, Mode: %d, RSSI: %d", status, mode, rssi); - char ping_url[100] = {0}; - snprintf(ping_url, 100, "https://device.%s.anedya.io/v1/check", client->config->region); - err = anedya_ext_net_check(client, ping_url, strlen(ping_url), 30000); - if (err == ANEDYA_OK) - { - if (debug_level > 0) - { - ESP_LOGI(TAG, "Modem is connected to internet."); - } - return ANEDYA_OK; - } - else - { - if (debug_level > 0) - ESP_LOGI(TAG, "Setting APN..."); - - err = anedya_ext_deactivate_pdp_context(client, 1, 2000); - anedya_ext_apn_config_t *apn_config = (anedya_ext_apn_config_t *)ext_config->apn_configs; - for (int i = 0; i < ext_config->apn_count; i++) - { - if (apn_config[i].apn == NULL) - { - ESP_LOGE(TAG, "APN is NULL, plz check the config"); - return ANEDYA_EXT_ERR; - } - anedya_ext_set_apn(client, apn_config[i].cid, apn_config[i].ip_ver, apn_config[i].apn, apn_config[i].username, apn_config[i].password); - vTaskDelay(50 / portTICK_PERIOD_MS); - } - err = anedya_ext_set_fun_mode(client, 0, NULL, 2000); - err = anedya_ext_set_fun_mode(client, 1, NULL, 10000); - } - check++; - if (check > 4) - return ANEDYA_EXT_ERR; - vTaskDelay(10000 / portTICK_PERIOD_MS); - } - } - } - return err; -} - -anedya_err_t anedya_ext_restore_settings_to_factory_defaults(anedya_client_t *client, int timeout) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - // if (value < 0) - // return ANEDYA_EXT_ERR; - xSemaphoreTake(uart_port_mutex, (timeout + 5000) / portTICK_PERIOD_MS); -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char AT_cmd[20]; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - - sprintf(AT_cmd, "AT&F\r\n"); - anedya_err_t err = _anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, NULL, "OK", timeout); - xSemaphoreGive(uart_port_mutex); - return err; -} -anedya_err_t anedya_ext_set_fun_mode(anedya_client_t *client, int fun, int rst, int timeout) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - if (fun < 0 || rst < 0) - { - ESP_LOGE(TAG, "Invalid fun or rst value!"); - return ANEDYA_EXT_ERR; - } - xSemaphoreTake(uart_port_mutex, (timeout + 5000) / portTICK_PERIOD_MS); -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char AT_cmd[30]; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - if (fun >= 0 && rst >= 0) - { - sprintf(AT_cmd, "AT+CFUN=%d,%d\r\n", (short)fun, (short)rst); - } - else if (rst < 0) - { - sprintf(AT_cmd, "AT+CFUN=%d\r\n", fun); - } - anedya_err_t err = ANEDYA_EXT_ERR; - if (rst == 1) - { - err = _anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, NULL, "RDY", timeout); - _anedya_ext_send_AT_command("ATE0\r\n", MODEM_CMD_EX_ASAP, NULL, NULL, 2000); - } - else - { - err = _anedya_ext_send_AT_command(AT_cmd, MODEM_CMD_EX_ASAP, NULL, NULL, timeout); - } - xSemaphoreGive(uart_port_mutex); - return err; -} - -anedya_err_t anedya_ext_connectivity_check(anedya_client_t *client, int timeout) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - xSemaphoreTake(uart_port_mutex, portMAX_DELAY); - anedya_err_t err = _anedya_ext_send_AT_command("AT\r\n", MODEM_RESP_WAIT, NULL, "OK", timeout); - xSemaphoreGive(uart_port_mutex); - return err; -} - -anedya_err_t anedya_ext_network_reg_status(anedya_client_t *client, int *stat, int timeout) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - if (stat == NULL) - { - ESP_LOGE(TAG, "stat is null!"); - return ANEDYA_EXT_ERR; - } -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char s_response[20] = {0}; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - - xSemaphoreTake(uart_port_mutex, (timeout + 5000) / portTICK_PERIOD_MS); - anedya_err_t err = ANEDYA_EXT_ERR; - err = _anedya_ext_send_AT_command("AT+CEREG?\r\n", MODEM_RESP_WAIT, s_response, "+CEREG:", timeout); - xSemaphoreGive(uart_port_mutex); - - int check = sscanf(s_response, "+CEREG: %*d,%d", stat); - if (check != 1) - { - return ANEDYA_EXT_ERR; - } - - return err; -} -anedya_err_t anedya_ext_network_operator(anedya_client_t *client, int *mode, int timeout) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - if (mode == NULL) - { - ESP_LOGE(TAG, "mode is null!"); - return ANEDYA_EXT_ERR; - } -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char s_response[20] = {0}; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - - xSemaphoreTake(uart_port_mutex, (timeout + 5000) / portTICK_PERIOD_MS); - anedya_err_t err = ANEDYA_EXT_ERR; - err = _anedya_ext_send_AT_command("AT+COPS?\r\n", MODEM_RESP_WAIT, s_response, "+COPS:", timeout); - xSemaphoreGive(uart_port_mutex); - - int check = sscanf(s_response, "+COPS: %d", mode); - if (check != 1) - { - return ANEDYA_EXT_ERR; - } - - return err; -} -anedya_err_t anedya_ext_signal_quality(anedya_client_t *client, int *rssi, int *ber, int timeout) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char s_response[20] = {0}; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - - if (rssi == NULL) - { - ESP_LOGE(TAG, "rssi is null"); - return ANEDYA_EXT_ERR; - } - xSemaphoreTake(uart_port_mutex, (timeout + 5000) / portTICK_PERIOD_MS); - anedya_err_t err = ANEDYA_EXT_ERR; - err = _anedya_ext_send_AT_command("AT+CSQ\r\n", MODEM_RESP_WAIT, s_response, "+CSQ:", timeout); - xSemaphoreGive(uart_port_mutex); - if (ber != NULL) - { - int check = sscanf(s_response, "+CSQ: %d,%d", rssi, ber); - if (check != 2) - { - return ANEDYA_EXT_ERR; - } - } - else - { - int check = sscanf(s_response, "+CSQ: %d,", rssi); - if (check != 1) - { - return ANEDYA_EXT_ERR; - } - } - return err; -} - -anedya_err_t anedya_ext_pdp_context_status(anedya_client_t *client, char *pdp_context_out, int timeout) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - xSemaphoreTake(uart_port_mutex, (timeout + 5000) / portTICK_PERIOD_MS); - anedya_err_t err = ANEDYA_EXT_ERR; - err = _anedya_ext_send_AT_command("AT+CGDCONT?\r\n", MODEM_RESP_WAIT, pdp_context_out, "+CGDCONT:", timeout); - xSemaphoreGive(uart_port_mutex); - return err; -} -anedya_err_t anedya_ext_activate_pdp_context(anedya_client_t *client, int cid, int timeout) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - if (cid < 0) - { - ESP_LOGE(TAG, "cid is invalid!"); - return ANEDYA_EXT_ERR; - } - xSemaphoreTake(uart_port_mutex, (timeout + 5000) / portTICK_PERIOD_MS); - anedya_err_t err = ANEDYA_EXT_ERR; -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char AT_cmd[30] = {0}; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - - sprintf(AT_cmd, "AT+QIACT=%d\r\n", cid); - err = _anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, NULL, "OK", timeout); - xSemaphoreGive(uart_port_mutex); - return err; -} -anedya_err_t anedya_ext_deactivate_pdp_context(anedya_client_t *client, int cid, int timeout) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - if (cid == NULL || cid < 0) - { - ESP_LOGE(TAG, "cid is invalid!"); - return ANEDYA_EXT_ERR; - } - xSemaphoreTake(uart_port_mutex, (timeout + 5000) / portTICK_PERIOD_MS); - anedya_err_t err = ANEDYA_EXT_ERR; -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char AT_cmd[30] = {0}; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - - sprintf(AT_cmd, "AT+QIDEACT=%d\r\n", cid); - err = _anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, NULL, "OK", timeout); - xSemaphoreGive(uart_port_mutex); - return err; -} - -anedya_err_t anedya_ext_read_pdp_context(anedya_client_t *client, char *pdp_context_out, int timeout) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - xSemaphoreTake(uart_port_mutex, (timeout + 5000) / portTICK_PERIOD_MS); - anedya_err_t err = ANEDYA_EXT_ERR; - err = _anedya_ext_send_AT_command("AT+QIACT?\r\n", MODEM_RESP_WAIT, pdp_context_out, "+QIACT:", timeout); - xSemaphoreGive(uart_port_mutex); - return err; -} - -anedya_err_t anedya_ext_net_check(anedya_client_t *client, char *url, int url_len, int timeout) -{ - if (url_len > 100) - { - ESP_LOGE(TAG, "URL too long, exceeds 100 characters"); - return ANEDYA_EXT_ERR; - } - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - - xSemaphoreTake(uart_port_mutex, portMAX_DELAY); - - // Configure HTTP and SSL - _anedya_ext_send_AT_command("AT+QHTTPCFG=\"contextid\",1\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); - _anedya_ext_send_AT_command("AT+QHTTPCFG=\"responseheader\",1\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); - _anedya_ext_send_AT_command("AT+QHTTPCFG=\"requestheader\",0\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); - _anedya_ext_send_AT_command("AT+QHTTPCFG=\"sslctxid\",3\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); - _anedya_ext_send_AT_command("AT+QSSLCFG=\"sslversion\",3,3\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); - _anedya_ext_send_AT_command("AT+QSSLCFG=\"seclevel\",3,0\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); - _anedya_ext_send_AT_command("AT+QSSLCFG=\"sni\",3,1\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); - _anedya_ext_send_AT_command("AT+QSSLCFG=\"cacert\",3,\"UFS:anedya_tls_root_ca.pem\"\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char AT_cmd[100] = {0}; - char cmd_response[20] = {0}; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - - snprintf(AT_cmd, sizeof(AT_cmd), "AT+QHTTPURL=%d,80\r\n", url_len); - if (_anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, NULL, "CONNECT", 80000) != ANEDYA_OK) - { - xSemaphoreGive(uart_port_mutex); - return ANEDYA_EXT_ERR; - } - - uart_write_bytes(UART_PORT_NUMBER, (const char *)url, url_len); - vTaskDelay(pdMS_TO_TICKS(1000)); - - snprintf(AT_cmd, sizeof(AT_cmd), "AT+QHTTPGET=%d\r\n", timeout / 1000); - if (_anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, cmd_response, "+QHTTPGET:", timeout + 1000) != ANEDYA_OK) - { - xSemaphoreGive(uart_port_mutex); - return ANEDYA_EXT_ERR; - } - xSemaphoreGive(uart_port_mutex); - if (strlen(cmd_response) > 0) - { - if (debug_level > 2) - ESP_LOGI(TAG, "Ping response: %s", cmd_response); - int err = 0; - short check = sscanf(cmd_response, "+QHTTPGET: %d", &err); - if (check == 1) - { - if (err == 0) - { - if (debug_level > 2) - ESP_LOGI(TAG, "Ping success: %d", err); - return ANEDYA_OK; - } - else if (err == 702) - { - ESP_LOGI(TAG, "Ping failed: %d", err); - return ANEDYA_EXT_ERR; - } - } - else - { - ESP_LOGW(TAG, "Invalid Ping Response: %s", cmd_response); - } - } - else - { - ESP_LOGE(TAG, "Ping failed: %s", cmd_response); - return ANEDYA_EXT_ERR; - } - return ANEDYA_OK; -} - -anedya_err_t anedya_ext_set_apn(anedya_client_t *client, int cid, char *ip_ver, char *apn, char *user, char *pass) -{ - xSemaphoreTake(uart_port_mutex, portMAX_DELAY); -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char at_cmd[100] = {0}; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - - sprintf(at_cmd, "AT+CGDCONT=%d,\"%s\",\"%s\"\r\n", cid, ip_ver, apn); - anedya_err_t err = _anedya_ext_send_AT_command(at_cmd, MODEM_RESP_WAIT, NULL, "OK", 2000); - xSemaphoreGive(uart_port_mutex); - return err; -} - -static anedya_err_t _anedya_ext_clear_uart_buffer(anedya_client_t *anedya_client) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - size_t buffered_len = 0; - QueueHandle_t uart_queue = ((anedya_ext_config_t *)anedya_client->config->interface_config)->uart_queue_handle; - ESP_ERROR_CHECK(uart_get_buffered_data_len(UART_PORT_NUMBER, &buffered_len)); - for (int i = 0; i < buffered_len; i++) - { - uint8_t data; - uart_read_bytes(UART_PORT_NUMBER, &data, 1, pdMS_TO_TICKS(500)); - } - xQueueReset(uart_queue); - return ANEDYA_OK; -} - -anedya_err_t anedya_ext_get_modem_time(anedya_client_t *client, int mode, char *output_dateTime) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - xSemaphoreTake(uart_port_mutex, portMAX_DELAY); -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char temp[50]; - char AT_cmd[20]; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - - sprintf(AT_cmd, "AT+QLTS=%d\r\n", mode); - anedya_err_t err = _anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, temp, "+QLTS:", 10000); - if (err == ANEDYA_OK) - { - sscanf(temp, "+QLTS: \"%[^\"]\"", output_dateTime); - // ESP_LOGI(TAG, "Modem Time: %s", output_dateTime); - } - xSemaphoreGive(uart_port_mutex); - return err; -} - -#ifdef ANEDYA_CONNECTION_METHOD_MQTT - -anedya_mqtt_client_handle_t _anedya_interface_mqtt_init(anedya_client_t *parent, char *broker, const char *devid, const char *secret) -{ - mqtt_cfg = (esp_mqtt_client_config_t){ - .network.disable_auto_reconnect = false, - .outbox.limit = 1024, - .broker = { - .address.port = 8883, - .address.hostname = broker, - .address.transport = MQTT_TRANSPORT_OVER_SSL, - // .verification.certificate = (const char *)anedya_tls_root_ca, - // .verification.certificate_len = anedya_tls_root_ca_len, - }, - .credentials = { - .username = devid, - .authentication.password = secret, - .client_id = devid, - }, - }; -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char AT_cmd[300]; - char response[20] = {0}; -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - - anedya_err_t err = ANEDYA_EXT_ERR; - xSemaphoreTake(uart_port_mutex, portMAX_DELAY); - err = _anedya_ext_send_AT_command("AT+IFC=2,2\r\n", MODEM_RESP_WAIT, NULL, "OK", 2000); // Enable RTS/CTS flow control - err = _anedya_ext_send_AT_command("AT+IFC?\r\n", MODEM_RESP_WAIT, NULL, "OK", 2000); - - // uploade tls root ca - err = _anedya_ext_send_AT_command("AT+QFOPEN=\"anedya_tls_root_ca.pem\",1\r\n", MODEM_RESP_WAIT, response, "+QFOPEN:", 2000); - if (err != ANEDYA_OK) - { - ESP_LOGE(TAG, "Failed to open `anedya_tls_root_ca.pem` file"); - xSemaphoreGive(uart_port_mutex); - return NULL; - } - int f_handle; - int matched = sscanf((char *)response, "+QFOPEN: %d", &f_handle); - if (matched != 1) - { - ESP_LOGE(TAG, "Failed to get file handle"); - xSemaphoreGive(uart_port_mutex); - return NULL; - } - // ESP_LOGI(TAG, "File handle: %d", f_handle); - - snprintf(AT_cmd, sizeof(AT_cmd), "AT+QFWRITE=%d,%d,20\r\n", (int)f_handle, anedya_tls_root_ca_len); - // Send QFWRITE command to modem - err = _anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, response, "CONNECT", 10000); - if (err != ANEDYA_OK) - { - ESP_LOGE(TAG, "Failed to initiate QFWRITE"); - xSemaphoreGive(uart_port_mutex); - return (void *)NULL; - } - for (int i = 0; i < anedya_tls_root_ca_len; i++) - { - char data[2]; - data[0] = anedya_tls_root_ca[i]; - data[1] = '\0'; - int bytes_written = uart_write_bytes(UART_PORT_NUMBER, data, strlen(data)); - if (bytes_written != strlen(data)) - { - ESP_LOGE(TAG, "Failed to write %d bytes to UART. Only %d bytes were written.", strlen(data), bytes_written); - xSemaphoreGive(uart_port_mutex); - return NULL; - } - } - if (!xEventGroupWaitBits(ModemEvents, MODEM_EVENT_RECEIVE_DATA, pdFALSE, pdFALSE, 10000 / portTICK_PERIOD_MS)) - { - ESP_LOGE(TAG, "Failed to upload anedya tls root ca!"); - xSemaphoreGive(uart_port_mutex); - return NULL; - } - if (strncmp((char *)dtmp, "+QFWRITE: 769,769", strlen("+QFWRITE: 769,769")) == 0) - { - if (debug_level > 2) - ESP_LOGI(TAG, "set anedya tls root ca success!"); - } - else - { - ESP_LOGE(TAG, "Failed to upload anedya tls root ca!"); - xSemaphoreGive(uart_port_mutex); - return NULL; - } - xEventGroupClearBits(ModemEvents, MODEM_EVENT_RECEIVE_DATA); - - snprintf(AT_cmd, sizeof(AT_cmd), "AT+QFCLOSE=%d\r\n", f_handle); - err = _anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, NULL, "OK", 5000); - - // Config broker credentials - // NOTE: ssl context id is 2 for the mqtt client, will set it 3 for the http client - err = _anedya_ext_send_AT_command("AT+QMTCFG=\"recv/mode\",0,0,1\r\n", MODEM_RESP_WAIT, NULL, "OK", 2000); - err = _anedya_ext_send_AT_command("AT+QMTCFG=\"SSL\",0,1,2\r\n", MODEM_RESP_WAIT, NULL, "OK", 2000); - err = _anedya_ext_send_AT_command("AT+QSSLCFG=\"cacert\",2,\"UFS:anedya_tls_root_ca.pem\"\r\n", MODEM_RESP_WAIT, NULL, "OK", 2000); - err = _anedya_ext_send_AT_command("AT+QSSLCFG=\"seclevel\",2,1\r\n", MODEM_RESP_WAIT, NULL, "OK", 2000); - err = _anedya_ext_send_AT_command("AT+QSSLCFG=\"sni\",2,1\r\n", MODEM_RESP_WAIT, NULL, "OK", 2000); - err = _anedya_ext_send_AT_command("AT+QSSLCFG=\"sslversion\",2,4\r\n", MODEM_RESP_WAIT, NULL, "OK", 2000); - err = _anedya_ext_send_AT_command("AT+QSSLCFG=\"ciphersuite\",2,0xFFFF\r\n", MODEM_RESP_WAIT, NULL, "OK", 2000); - err = _anedya_ext_send_AT_command("AT+QSSLCFG=\"ignorelocaltime\",2,1\r\n", MODEM_RESP_WAIT, NULL, "OK", 2000); - xSemaphoreGive(uart_port_mutex); - return (void *)&mqtt_cfg; -} - -anedya_err_t anedya_interface_mqtt_connect(anedya_mqtt_client_handle_t anclient) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - // xSemaphoreTake(uart_port_mutex, portMAX_DELAY); -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char AT_cmd[300]; - char response[20] = {0}; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - - anedya_err_t err = ANEDYA_EXT_ERR; - xSemaphoreTake(uart_port_mutex, portMAX_DELAY); - sprintf(AT_cmd, "AT+QMTOPEN=0,\"%s\",8883\r\n", mqtt_cfg.broker.address.hostname); - err = _anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, response, "+QMTOPEN:", 40000); - if (err != ANEDYA_OK) - { - ESP_LOGE(TAG, "Failed to open MQTT connection"); - xSemaphoreGive(uart_port_mutex); - return ANEDYA_EXT_ERR; - } - if (debug_level > 3) - ESP_LOGI(TAG, "OPEN RESPONSE: %s", (char *)response); - int result_code = -1; - int matched = sscanf((char *)response, "+QMTOPEN: %*d,%d", &result_code); - if (matched) - { - if (result_code == 0) - { - if (debug_level > 0) - ESP_LOGI(TAG, "MQTT connection opened!"); - } - else - { - ESP_LOGE(TAG, "Failed to open MQTT connection, response: %s", (char *)response); - xSemaphoreGive(uart_port_mutex); - return ANEDYA_EXT_ERR; - } - } - else - { - ESP_LOGE(TAG, "Failed to open MQTT connection, modem err"); - } - - snprintf(AT_cmd, sizeof(AT_cmd), "AT+QMTCONN=0,\"%s\",\"%s\",\"%s\"\r\n", mqtt_cfg.credentials.client_id, mqtt_cfg.credentials.username, mqtt_cfg.credentials.authentication.password); - err = _anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, response, "+QMTCONN:", 30000); - if (err == ANEDYA_OK) - { - int ret_code = 5; - int matched = sscanf((char *)response, "+QMTCONN: %*d,%*d,%d", &ret_code); - if (matched) - { - if (ret_code == 0) - { - if (debug_level > 0) - ESP_LOGI(TAG, "MQTT connection established!"); - xSemaphoreGive(uart_port_mutex); - return ANEDYA_OK; - } - else - { - switch (ret_code) - { - case 1: - ESP_LOGE(TAG, " Connection Refused: Unacceptable Protocol Version "); - break; - case 2: - ESP_LOGE(TAG, "Connection Refused: Identifier Rejected "); - break; - case 3: - ESP_LOGE(TAG, "Connection Refused: Server Unavailable "); - break; - case 4: - ESP_LOGE(TAG, "Connection Refused: Bad User Name or Password "); - break; - case 5: - ESP_LOGE(TAG, "Connection Refused: Not Authorized "); - break; - default: - ESP_LOGE(TAG, "Connection Refused! "); - ESP_LOGE(TAG, "Modem Response: %s", (char *)response); - break; - } - xSemaphoreGive(uart_port_mutex); - return ANEDYA_EXT_ERR; - } - } - else - { - ESP_LOGE(TAG, "Invalid uart response!"); - } - } - xSemaphoreGive(uart_port_mutex); - return err; -} - -anedya_err_t anedya_interface_mqtt_disconnect(anedya_mqtt_client_handle_t anclient) -{ - - return ANEDYA_OK; -} - -anedya_err_t anedya_interface_mqtt_destroy(anedya_mqtt_client_handle_t anclient) -{ - - return ANEDYA_OK; -} - -size_t anedya_interface_mqtt_status(anedya_mqtt_client_handle_t anclient) -{ - - return 0; -} - -anedya_err_t anedya_interface_mqtt_subscribe(anedya_mqtt_client_handle_t anclient, char *topic, int topilc_len, int qos) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char AT_cmd[300]; - char response[20] = {0}; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - if (debug_level > 2) - ESP_LOGI(TAG, "Subscribing to topic: %s", (char *)topic); - snprintf(AT_cmd, sizeof(AT_cmd), "AT+QMTSUB=0,1,\"%s\",%d\r\n", (char *)topic, qos); - xSemaphoreTake(uart_port_mutex, portMAX_DELAY); - anedya_err_t err = _anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, response, "+QMTSUB:", 5000); - if (err == ANEDYA_OK) - { - if (debug_level > 3) - ESP_LOGI(TAG, "MQTT subscribed! %s", (char *)response); - int result = 2; - int matched = sscanf((char *)response, "+QMTSUB: %*d,%*d,%d", &result); - if (matched) - { - if (result == 0) - { - xSemaphoreGive(uart_port_mutex); - return ANEDYA_OK; - } - else - { - ESP_LOGE(TAG, "MQTT subscribe failed!"); - switch (result) - { - case 1: - ESP_LOGE(TAG, "Packet retransmission "); - break; - case 2: - ESP_LOGE(TAG, "Failed to send packet"); - break; - default: - ESP_LOGE(TAG, "Unknown error | res: %s", (char *)response); - break; - } - ESP_LOGE(TAG, "MQTT subscribe failed! %s", (char *)response); - xSemaphoreGive(uart_port_mutex); - return ANEDYA_EXT_ERR; - } - } - else - { - ESP_LOGE(TAG, "MQTT subscribe failed! %s", (char *)response); - xSemaphoreGive(uart_port_mutex); - return ANEDYA_EXT_ERR; - } - } - xSemaphoreGive(uart_port_mutex); - return err; -} - -anedya_err_t anedya_interface_mqtt_unsubscribe(anedya_mqtt_client_handle_t anclient, char *topic, int topic_len) -{ - - return ANEDYA_OK; -} - -anedya_err_t anedya_interface_mqtt_publish(anedya_mqtt_client_handle_t anclient, char *topic, int topic_len, char *payload, int payload_len, int qos, int retain) -{ - - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - if (xSemaphoreTake(uart_port_mutex, 60000 / portTICK_PERIOD_MS) == pdTRUE) - { - char AT_cmd[topic_len + 40]; - snprintf(AT_cmd, sizeof(AT_cmd), "AT+QMTPUBEX=0,1,%d,%d,\"%s\",%d\r\n", qos, retain, (char *)topic, payload_len); - anedya_err_t err = _anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, NULL, ">", 10000); - if (err == ANEDYA_OK) - { - - err = _anedya_ext_send_AT_command((char *)payload, MODEM_RESP_WAIT, NULL, "}", 5000); - } - - xSemaphoreGive(uart_port_mutex); - return err; - } - else - { - ESP_LOGE(TAG, "Failed to take semaphore in publish."); - return ANEDYA_EXT_ERR; - } -} - -anedya_err_t anedya_set_message_callback(anedya_mqtt_client_handle_t anclient, anedya_client_t *client) -{ - return ANEDYA_OK; -} -#endif // end of ANEDYA_CONNECTION_METHOD_MQTT - -anedya_err_t anedya_ext_http_get_range_request(anedya_client_t *client, anedya_ext_net_reader_t *reader, char *url, int url_len, int starting_position, int readlen, int timeout) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - - xSemaphoreTake(uart_port_mutex, portMAX_DELAY); - - // Configure HTTP and SSL - _anedya_ext_send_AT_command("AT+QHTTPCFG=\"contextid\",1\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); - _anedya_ext_send_AT_command("AT+QHTTPCFG=\"responseheader\",1\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); - _anedya_ext_send_AT_command("AT+QHTTPCFG=\"requestheader\",0\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); - _anedya_ext_send_AT_command("AT+QHTTPCFG=\"sslctxid\",3\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); - _anedya_ext_send_AT_command("AT+QSSLCFG=\"sslversion\",3,3\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); - _anedya_ext_send_AT_command("AT+QSSLCFG=\"seclevel\",3,0\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); - _anedya_ext_send_AT_command("AT+QSSLCFG=\"sni\",3,1\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); - _anedya_ext_send_AT_command("AT+QSSLCFG=\"cacert\",3,\"UFS:anedya_tls_root_ca.pem\"\r\n", MODEM_RESP_WAIT, NULL, "OK", 5000); -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char AT_cmd[100] = {0}; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - - snprintf(AT_cmd, sizeof(AT_cmd), "AT+QHTTPURL=%d,80\r\n", url_len); - if (_anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, NULL, "CONNECT", 80000) != ANEDYA_OK) - return ANEDYA_EXT_ERR; - - uart_write_bytes(UART_PORT_NUMBER, (const char *)url, url_len); - vTaskDelay(pdMS_TO_TICKS(1000)); - - snprintf(AT_cmd, sizeof(AT_cmd), "AT+QHTTPGETEX=80,%d,%d\r\n", starting_position, readlen); - if (_anedya_ext_send_AT_command(AT_cmd, MODEM_RESP_WAIT, NULL, "+QHTTPGET:", 80000) != ANEDYA_OK) - return ANEDYA_EXT_ERR; - - xEventGroupClearBits(ModemEvents, MODEM_EVENT_OTA_NOT_IN_PROGRESS); - _anedya_ext_clear_uart_buffer(client); // Clear the UART buffer - - ESP_LOGI("TX Command", "AT+QHTTPREAD=300\r\n"); - uart_write_bytes(UART_PORT_NUMBER, "AT+QHTTPREAD=300\r\n", strlen("AT+QHTTPREAD=300\r\n")); - -// --- Header Parsing Section --- -#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char header_buf[2048] = {0}; - -#endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - - int header_pos = 0; - bool headers_done = false; - bool content_length_found = false; - int content_length = -1; - uint8_t byte; - - TickType_t start = xTaskGetTickCount(); - while (!headers_done && (xTaskGetTickCount() - start < pdMS_TO_TICKS(timeout))) - { - int read = uart_read_bytes(UART_PORT_NUMBER, &byte, 1, pdMS_TO_TICKS(500)); - if (read == 1) - { - if (header_pos < sizeof(header_buf) - 1) - { - header_buf[header_pos++] = byte; - header_buf[header_pos] = '\0'; - } - - // Detect end of headers - if (strstr(header_buf, "\r\n\r\n") != NULL) - { - headers_done = true; - break; - } - } - else - { - vTaskDelay(pdMS_TO_TICKS(10)); - } - } - - if (!headers_done) - { - ESP_LOGE(TAG, "Failed to read HTTP headers"); - return ANEDYA_EXT_ERR; - } - - // --- Parse Content-Length --- - char *line = strtok(header_buf, "\r\n"); - while (line != NULL) - { - if (strstr(line, "Content-Length:") != NULL && !content_length_found) - { - int parsed_len = -1; - if (sscanf(line, "Content-Length: %d", &parsed_len) == 1) - { - content_length = parsed_len; - content_length_found = true; - reader->content_length = content_length; - ESP_LOGI(TAG, "Parsed Content-Length: %d", content_length); - } - } - line = strtok(NULL, "\r\n"); - } - - if (!content_length_found) - { - ESP_LOGE(TAG, "Content-Length header not found"); - return ANEDYA_EXT_ERR; - } - - // You can now read binary asset content from UART here if needed - - return ANEDYA_OK; -} - -size_t anedya_ext_ota_read_next(anedya_client_t *client, anedya_ext_net_reader_t *reader, int read_len, char *output, int timeout) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return 0; - } - - size_t read = uart_read_bytes(UART_PORT_NUMBER, output, read_len, pdMS_TO_TICKS(timeout)); - if (read == 0) - { - ESP_LOGI(TAG, "Read error %d", read); - return read; - } - // ESP_LOGI(TAG, "Read %d bytes from uARt", read); - reader->bytes_read += read; - return read; -} - -anedya_err_t anedya_ext_ota_reader_close(anedya_client_t *client, anedya_ext_net_reader_t *reader) -{ - if (UART_PORT_NUMBER == -1) - { - ESP_LOGE(TAG, "Invalid port number"); - return ANEDYA_EXT_ERR; - } - _anedya_ext_clear_uart_buffer(client); // Clear the UART buffer - xEventGroupSetBits(ModemEvents, MODEM_EVENT_OTA_NOT_IN_PROGRESS); - xSemaphoreGive(uart_port_mutex); - // ESP_LOGI(TAG, "Reset the queue"); - return ANEDYA_OK; -} - -#endif // AN_INTERFACE_ESP32_QUETEL \ No newline at end of file diff --git a/interfaces/esp32-wifi/anedya_esp_wifi_interface.c b/interfaces/esp32-wifi/anedya_esp_wifi_interface.c deleted file mode 100644 index 990ac70..0000000 --- a/interfaces/esp32-wifi/anedya_esp_wifi_interface.c +++ /dev/null @@ -1,228 +0,0 @@ -#include "sdkconfig.h" - -#ifdef CONFIG_AN_INTERFACE_ESP32_WIFI - -#include "anedya_interface.h" - -#include "anedya_esp_wifi_interface.h" -#include "anedya_certs.h" -#include "anedya_client.h" -#include "anedya_commons.h" -#include "time.h" -#include - -static const char *TAG = "ANEDYA_ESPI"; - -#define MAX_HTTP_RECV_BUFFER 512 -#define MAX_HTTP_OUTPUT_BUFFER 2048 - -esp_mqtt_client_handle_t client; -bool anedya_espi_mqtt_connected = false; - -anedya_err_t _anedya_interface_init(anedya_client_t *client) -{ - return ANEDYA_OK; -} - -void _anedya_interface_sleep_ms(size_t ms) -{ - vTaskDelay(ms / portTICK_PERIOD_MS); -} - -uint64_t _anedya_interface_get_time_ms() -{ - struct timeval ts; - gettimeofday(&ts, NULL); - return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_usec / 1000; -} - -static void anedya_espi_mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) -{ - // ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32, base, event_id); - esp_mqtt_event_handle_t event = event_data; - // esp_mqtt_client_handle_t client = event->client; - anedya_client_t *cl = (anedya_client_t *)handler_args; - // int msg_id; - switch ((esp_mqtt_event_id_t)event_id) - { - case MQTT_EVENT_CONNECTED: - // ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); - // Issue callback - if (cl->_anedya_on_connect_handler != NULL) - { - cl->_anedya_on_connect_handler(cl); - } - break; - case MQTT_EVENT_DISCONNECTED: - // ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); - if (cl->_anedya_on_disconnect_handler != NULL) - { - cl->_anedya_on_disconnect_handler(cl); - } - break; - - case MQTT_EVENT_SUBSCRIBED: - // ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); - break; - case MQTT_EVENT_UNSUBSCRIBED: - // ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); - break; - case MQTT_EVENT_PUBLISHED: - // ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); - break; - case MQTT_EVENT_DATA: - // ESP_LOGI(TAG, "MQTT_EVENT_DATA"); - // printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); - // printf("DATA=%.*s\r\n", event->data_len, event->data); - cl->_message_handler(cl, event->topic, event->topic_len, event->data, event->data_len); - break; - case MQTT_EVENT_ERROR: - ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); - if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) - { - ESP_LOGI(TAG, "Last error code reported from esp-tls: 0x%x", event->error_handle->esp_tls_last_esp_err); - ESP_LOGI(TAG, "Last tls stack error number: 0x%x", event->error_handle->esp_tls_stack_err); - ESP_LOGI(TAG, "Last captured errno : %d (%s)", event->error_handle->esp_transport_sock_errno, - strerror(event->error_handle->esp_transport_sock_errno)); - } - else if (event->error_handle->error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) - { - ESP_LOGI(TAG, "Connection refused error: 0x%x", event->error_handle->connect_return_code); - } - else - { - ESP_LOGW(TAG, "Unknown error type: 0x%x", event->error_handle->error_type); - } - break; - default: - ESP_LOGI(TAG, "Other event id:%d", event->event_id); - break; - } -} - -#ifdef ANEDYA_CONNECTION_METHOD_MQTT - -anedya_mqtt_client_handle_t _anedya_interface_mqtt_init(anedya_client_t *parent, char *broker, const char *devid, const char *secret) -{ - esp_mqtt_client_config_t mqtt_cfg = { - .network.disable_auto_reconnect = false, - .outbox.limit = 1024, - .broker = { - .address.port = 8883, - .address.hostname = broker, - .address.transport = MQTT_TRANSPORT_OVER_SSL, - .verification.certificate = (const char *)anedya_tls_root_ca, - .verification.certificate_len = anedya_tls_root_ca_len, - }, - .credentials = { - .username = devid, - .authentication.password = secret, - .client_id = devid, - }, - }; - // ESP_LOGI("ANEDYA_ESPI", "Connecting to MQTT secret: %s Length:%d", secret, parent->config->connection_key_len); - client = esp_mqtt_client_init(&mqtt_cfg); - esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, anedya_espi_mqtt_event_handler, (void *)parent); - vTaskDelay(2 / portTICK_PERIOD_MS); - return (void *)&client; -} - -anedya_err_t anedya_interface_mqtt_connect(anedya_mqtt_client_handle_t anclient) -{ - esp_mqtt_client_handle_t *c = (esp_mqtt_client_handle_t *)anclient; - esp_err_t err = esp_mqtt_client_start(*c); - if (err != ESP_OK) - { - return ANEDYA_ERR; - } - return ANEDYA_OK; -} - -anedya_err_t anedya_interface_mqtt_disconnect(anedya_mqtt_client_handle_t anclient) -{ - esp_mqtt_client_handle_t *c = (esp_mqtt_client_handle_t *)anclient; - esp_err_t err = esp_mqtt_client_stop(*c); - if (err != ESP_OK) - { - return ANEDYA_ERR; - } - return ANEDYA_OK; -} - -anedya_err_t anedya_interface_mqtt_destroy(anedya_mqtt_client_handle_t anclient) -{ - esp_mqtt_client_handle_t *c = (esp_mqtt_client_handle_t *)anclient; - esp_err_t err = esp_mqtt_client_destroy(*c); - if (err != ESP_OK) - { - return ANEDYA_ERR; - } - return ANEDYA_OK; -} - -size_t anedya_interface_mqtt_status(anedya_mqtt_client_handle_t anclient) -{ - if (anedya_espi_mqtt_connected) - { - return 0; - } - else - { - return -1; - } -} - -anedya_err_t anedya_interface_mqtt_subscribe(anedya_mqtt_client_handle_t anclient, char *topic, int topilc_len, int qos) -{ - esp_mqtt_client_handle_t *c = (esp_mqtt_client_handle_t *)anclient; - int id = esp_mqtt_client_subscribe_single(*c, topic, qos); - if (id == -1) - { - return ANEDYA_ERR; - } - if (id == -2) - { - return ANEDYA_INTERFACE_BUSY; - } - return ANEDYA_OK; -} - -anedya_err_t anedya_interface_mqtt_unsubscribe(anedya_mqtt_client_handle_t anclient, char *topic, int topic_len) -{ - esp_mqtt_client_handle_t *c = (esp_mqtt_client_handle_t *)anclient; - int id = esp_mqtt_client_unsubscribe(*c, topic); - if (id == -1) - { - return ANEDYA_ERR; - } - return ANEDYA_OK; -} - -anedya_err_t anedya_interface_mqtt_publish(anedya_mqtt_client_handle_t anclient, char *topic, int topic_len, char *payload, int payload_len, int qos, int retain) -{ - esp_mqtt_client_handle_t *c = (esp_mqtt_client_handle_t *)anclient; - int id = esp_mqtt_client_publish(*c, topic, payload, payload_len, qos, retain); - if (id == -1) - { - return ANEDYA_ERR; - } - if (id == -2) - { - return ANEDYA_INTERFACE_BUSY; - } - return ANEDYA_OK; -} - -anedya_err_t anedya_set_message_callback(anedya_mqtt_client_handle_t anclient, anedya_client_t *client) -{ - return ANEDYA_OK; -} - -void _anedya_interface_std_out(const char *str) -{ - ESP_LOGI("ANEDYA_ESPI", "%s", str); -} - -#endif - -#endif // AN_INTERFACE_ESP32_WIFI \ No newline at end of file diff --git a/interfaces/include/anedya_esp_quectelEC200_interface.h b/interfaces/include/anedya_esp_quectelEC200_interface.h deleted file mode 100644 index 4c76852..0000000 --- a/interfaces/include/anedya_esp_quectelEC200_interface.h +++ /dev/null @@ -1,368 +0,0 @@ -#pragma once - -#include "sdkconfig.h" - -#ifdef CONFIG_AN_INTERFACE_ESP32_QUETEL - -#include "anedya_sdk_config.h" - -#ifdef ___cplusplus -extern "C" -{ -#endif - -#include "esp_err.h" -#include "anedya_commons.h" -#include "anedya_config.h" -#include "freertos/FreeRTOS.h" -#include "freertos/event_groups.h" -#include "esp_log.h" -#include "esp_event.h" -#include "esp_netif.h" -#include "esp_system.h" -#include -#include "mqtt_client.h" -#include "esp_tls.h" -#include -#include "driver/gpio.h" -#include "driver/uart.h" - - - typedef struct - { - int cid; - const char *ip_ver; - const char *apn; - const char *username; - const char *password; - } anedya_ext_apn_config_t; - - typedef struct - { - unsigned int uart_port_num; - unsigned int tx_pin; - unsigned int rx_pin; - unsigned int rts_pin; - unsigned int cts_pin; - uart_config_t uart_config; - QueueHandle_t uart_queue_handle; - anedya_ext_apn_config_t *apn_configs; - int apn_count; - } anedya_ext_config_t; - -#define EXT_MQTT_EVENT_CONNECTED 1 -#define EXT_MQTT_EVENT_DISCONNECTED 2 -#define EXT_MQTT_EVENT_DATA 3 - - typedef struct - { - int event_id; - char *data; - int data_len; - char *topic; - int topic_len; - } anedya_ext_mqtt_event_t; - - typedef struct - { - int content_length; - int bytes_read; - } anedya_ext_net_reader_t; - - /** - * @brief Checks if the modem is connected via UART - * - * - * @param[in] client Pointer to the Anedya client structure containing configuration - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the modem is connected - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the modem is not connected - * - * @warning Must uart initialized before calling this function. - */ - anedya_err_t anedya_ext_connectivity_check(anedya_client_t *client, int timeout); - - /** - * @brief Restores the modem settings to factory defaults - * - * @param client Pointer to the Anedya client structure containing configuration - * @param timeout The maximum time to wait for the operation to complete - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the operation is successful - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the operation times out - * @retval - `ANEDYA_EXT_ERR` if fail to set - * - * @warning Must uart initialized before calling this function. - */ - anedya_err_t anedya_ext_restore_settings_to_factory_defaults(anedya_client_t *client, int timeout); - - /** - * @brief Sets the modem's functionality mode - * - * @param[in] client Pointer to the Anedya client structure containing configuration - * @param[in] fun The new functionality mode - * @param[in] rst The new reset mode - * @param[in] wait_for_rdy Whether to wait for the RDY response after setting the mode - * @param[in] timeout The maximum time to wait for the operation to complete - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the operation is successful - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the operation times out - * @retval - `ANEDYA_EXT_ERR` if fail to set - * - * @warning Must uart initialized before calling this function. - */ - anedya_err_t anedya_ext_set_fun_mode(anedya_client_t *client, int fun, int rst, int timeout); - - /** - * @brief Gets the current network registration status - * - * @param client[in] Pointer to the Anedya client structure containing configuration - * @param stat[out] Pointer to an integer to store the current network registration status - * @param timeout[in] The maximum time to wait for the operation to complete - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the operation is successful - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the operation times out - * @retval - `ANEDYA_EXT_ERR` if fail to get - * - * @warning Must uart initialized before calling this function. - */ - anedya_err_t anedya_ext_network_reg_status(anedya_client_t *client, int *stat, int timeout); - - /** - * @brief Retrieves the current network operator mode - * - * - * @param[in] client Pointer to the Anedya client structure containing configuration - * @param[out] mode Pointer to an integer to store the current network operator mode - * @param[in] timeout The maximum time to wait for the operation to complete - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the operation is successful - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the operation times out - * @retval - `ANEDYA_EXT_ERR` if there is an error in communication or invalid parameters - * - * @warning The UART must be initialized before calling this function. - * @note Ensure that the `mode` pointer is not NULL. - */ - anedya_err_t anedya_ext_network_operator(anedya_client_t *client, int *mode, int timeout); - - /** - * @brief Retrieves the current signal quality - * - * @param[in] client Pointer to the Anedya client structure containing configuration - * @param[out] rssi Pointer to an integer to store the signal strength in dBm - * @param[out] ber Pointer to an integer to store the signal quality in error rate - * @param[in] timeout The maximum time to wait for the operation to complete - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the operation is successful - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the operation times out - * @retval - `ANEDYA_EXT_ERR` if there is an error in communication or invalid parameters - * - * @warning The UART must be initialized before calling this function. - * @note Ensure that the `rssi` pointer is not NULL. - * @note If `ber` is NULL, only the signal strength is retrieved. - */ - anedya_err_t anedya_ext_signal_quality(anedya_client_t *client, int *rssi, int *ber, int timeout); - - /** - * @brief Retrieves the current PDP context status - * - * @param[in] client Pointer to the Anedya client structure containing configuration - * @param[out] pdp_context_out Buffer to store the PDP context information - * @param[in] timeout The maximum time to wait for the operation to complete - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the operation is successful - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the operation times out - * @retval - `ANEDYA_EXT_ERR` if there is an error in communication or invalid parameters - * - * @warning The UART must be initialized before calling this function. - * @note Ensure that the `pdp_context_out` buffer is adequately sized to hold the response. - */ - anedya_err_t anedya_ext_pdp_context_status(anedya_client_t *client, char *pdp_context_out, int timeout); - - /** - * @brief Activates the specified PDP context - * - * @param[in] client Pointer to the Anedya client structure containing configuration - * @param[in] cid The identifier of the PDP context to activate - * @param[in] timeout The maximum time to wait for the operation to complete - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the operation is successful - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the operation times out - * @retval - `ANEDYA_EXT_ERR` if there is an error in communication or invalid parameters - * - * @warning The UART must be initialized before calling this function. - * @note Ensure that the `cid` is a valid PDP context identifier. - */ - anedya_err_t anedya_ext_activate_pdp_context(anedya_client_t *client, int cid, int timeout); - - /** - * @brief Deactivates the specified PDP context - * - * @param[in] client Pointer to the Anedya client structure containing configuration - * @param[in] cid The identifier of the PDP context to deactivate - * @param[in] timeout The maximum time to wait for the operation to complete - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the operation is successful - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the operation times out - * @retval - `ANEDYA_EXT_ERR` if there is an error in communication or invalid parameters - * - * @warning The UART must be initialized before calling this function. - * @note Ensure that the `cid` is a valid PDP context identifier. - */ - anedya_err_t anedya_ext_deactivate_pdp_context(anedya_client_t *client, int cid, int timeout); - - /** - * @brief Reads the PDP context from the modem - * - * This function retrieves the current PDP context from the modem and stores it in the provided buffer. - * - * @param[in] client Pointer to the Anedya client structure containing configuration - * @param[out] pdp_context_out Buffer to store the PDP context response - * @param[in] timeout The maximum time to wait for the operation to complete - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the operation is successful - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the operation times out - * @retval - `ANEDYA_EXT_ERR` if there is an error in communication or invalid parameters - * - * @warning The UART must be initialized before calling this function. - * @note Ensure that the `pdp_context_out` buffer is adequately sized to hold the response. - */ - anedya_err_t anedya_ext_read_pdp_context(anedya_client_t *client, char *pdp_context_out, int timeout); - - /** - * @brief Checks network connectivity - * - * This function attempts to ping the specified URL to check if it is reachable. - * - * @param[in] client Pointer to the Anedya client structure containing configuration - * @param[in] url The URL to ping (e.g., www.google.com) - * @param[in] timeout The maximum time to wait for the operation to complete - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the operation is successful - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the operation times out - * @retval - `ANEDYA_EXT_ERR` if there is an error in communication or invalid parameters - * - * @warning The UART must be initialized before calling this function. - * @note Ensure that the `url` is a valid URL. - */ - anedya_err_t anedya_ext_net_check(anedya_client_t *client, char *url, int url_len, int timeout); - - /** - * @brief Sets the Access Point Name (APN) for a specified PDP context - * - * This function configures the APN settings for a given PDP context using the provided parameters. - * - * @param[in] client Pointer to the Anedya client structure containing configuration - * @param[in] cid The identifier of the PDP context to configure - * @param[in] ip_ver The IP version to use (e.g., "IP", "IPV6", or "IPV4V6") - * @param[in] apn The Access Point Name to set for the PDP context - * @param[in] user Optional username for APN authentication (can be NULL if not required) - * @param[in] pass Optional password for APN authentication (can be NULL if not required) - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the operation is successful - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the operation times out - * @retval - `ANEDYA_EXT_ERR` if there is an error in communication or invalid parameters - * - * @warning The UART must be initialized before calling this function. - * @note Ensure that the `apn` pointer is not NULL. - */ - anedya_err_t anedya_ext_set_apn(anedya_client_t *client, int cid, char *ip_ver, char *apn, char *user, char *pass); - - /** - * @brief Gets the current date and time from the modem - * - * This function sends an AT command to the modem to retrieve the current date and time. - * - * @param[in] client Pointer to the Anedya client structure containing configuration - * @param[in] mode The AT command mode to use (e.g., 0 for current time, 1 for local time) - * @param[out] output_dateTime The retrieved date and time in the format "YYYY-MM-DD HH:MM:SS" - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the operation is successful - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the operation times out - * @retval - `ANEDYA_EXT_ERR` if there is an error in communication or invalid parameters - * - * @warning The UART must be initialized before calling this function. - * @note Ensure that the `output_dateTime` pointer is not NULL. - */ - anedya_err_t anedya_ext_get_modem_time(anedya_client_t *client, int mode, char *output_dateTime); - - // OTA related functions - /** - * @brief Function to send a partial HTTP GET request - * - * This function sends a partial HTTP GET request to the specified URL. - * - * @param[in] client Pointer to the Anedya client structure containing configuration - * @param[in] reader Pointer to the Anedya HTTP reader structure - * @param[in] url The URL to download from - * @param[in] url_len The length of the URL - * @param[in] starting_position The starting byte position to read from - * @param[in] readlen The number of bytes to read - * @param[in] timeout The maximum time to wait for the operation to complete - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the operation is successful - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the operation times out - * @retval - `ANEDYA_EXT_ERR` if there is an error in communication or invalid parameters - * - * @warning The UART must be initialized before calling this function. - * @note Ensure that the `url` is a valid URL and that the `starting_position` and `readlen` parameters are valid. - */ - anedya_err_t anedya_ext_http_get_range_request(anedya_client_t *client, anedya_ext_net_reader_t *reader, char *url, int url_len, int starting_position, int readlen, int timeout); - - /** - * @brief Reads from the UART interface for the specified number of bytes - * - * This function reads from the UART interface for the specified number of bytes. - * - * @param[in] client Pointer to the Anedya client structure containing configuration - * @param[in] reader Pointer to the Anedya HTTP reader structure - * @param[in] read_len The number of bytes to read - * @param[out] output The buffer to store the read data - * @param[in] timeout The maximum time to wait for the operation to complete - * - * @return size_t - * @retval - The number of bytes read - * @retval - 0 if there is an error in communication or invalid parameters - * - * @warning The UART must be initialized before calling this function. - * @note Ensure that the `read_len` parameter is valid and that the `output` pointer is not NULL. - */ - size_t anedya_ext_ota_read_next(anedya_client_t *client, anedya_ext_net_reader_t *reader, int read_len, char *output, int timeout); - - /** - * @brief Closes the OTA reader - * - * This function closes the OTA reader and releases the UART lock. - * - * @param[in] client Pointer to the Anedya client structure containing configuration - * @param[in] reader Pointer to the Anedya HTTP reader structure - * - * @return anedya_err_t - * @retval - `ANEDYA_OK` if the operation is successful - * @retval - `ANEDYA_ERR_EXT_TIMEOUT` if the operation times out - * @retval - `ANEDYA_EXT_ERR` if there is an error in communication or invalid parameters - * - * @warning The UART must be initialized before calling this function. - * @note Ensure that the `reader` pointer is not NULL. - */ - anedya_err_t anedya_ext_ota_reader_close(anedya_client_t *client, anedya_ext_net_reader_t *reader); - -#ifdef __cplusplus -} -#endif - -#endif // AN_INTERFACE_ESP32_QUETEL \ No newline at end of file diff --git a/interfaces/include/anedya_esp_wifi_interface.h b/interfaces/include/anedya_esp_wifi_interface.h deleted file mode 100644 index e7538ec..0000000 --- a/interfaces/include/anedya_esp_wifi_interface.h +++ /dev/null @@ -1,21 +0,0 @@ -#include "sdkconfig.h" - -#ifdef CONFIG_AN_INTERFACE_ESP32_WIFI - -#include "anedya_sdk_config.h" - -#ifndef _ANEDYA_ESP_INTERFACE_WIFIH_ -#define _ANEDYA_ESP_INTERFACE_WIFI_H_ - -#include "esp_err.h" -#include "esp_log.h" -#include "esp_event.h" -#include "esp_netif.h" -#include "esp_system.h" -#include -#include "mqtt_client.h" -#include "esp_tls.h" - -#endif - -#endif // AN_INTERFACE_ESP32_WIFI diff --git a/src/anedya_certs.c b/src/anedya_certs.c index 532d526..80db6e9 100644 --- a/src/anedya_certs.c +++ b/src/anedya_certs.c @@ -275,7 +275,7 @@ const char anedya_tls_root_ca[] = { 0x73, 0x70, 0x69, 0x52, 0x5a, 0x37, 0x47, 0x74, 0x44, 0x44, 0x72, 0x39, 0x78, 0x46, 0x39, 0x31, 0x57, 0x62, 0x73, 0x4b, 0x30, 0x50, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x0a}; + 0x0a,0x00}; const unsigned int anedya_tls_root_ca_len = 769; #endif diff --git a/src/anedya_client.c b/src/anedya_client.c index bd6b9b4..0bd32fd 100755 --- a/src/anedya_client.c +++ b/src/anedya_client.c @@ -1,439 +1,499 @@ -#include #include "anedya.h" #include "anedya_certs.h" #include "anedya_json_parse.h" -#include "anedya_operations.h" #include "anedya_op_commands.h" +#include "anedya_operations.h" #include "string.h" #include "sys/time.h" // TODO: Remove time header dependency +#include -anedya_err_t anedya_client_init(anedya_config_t *config, anedya_client_t *client) -{ - client->config = config; +anedya_err_t anedya_client_init(anedya_config_t *config, + anedya_client_t *client) { + client->config = config; - // Initialize the interface - anedya_err_t err = _anedya_interface_init(client); - if (err != ANEDYA_OK) - { - return err; - } + // Initialize the interface + anedya_err_t err = _anedya_interface_init(client); + if (err != ANEDYA_OK) { + return err; + } #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION - client->tx_buffer = anedya_interface_allocate_memory(config->tx_buffer_size); - if (client->tx_buffer == NULL) - { - return ANEDYA_ERR_NO_MEMORY; - } - client->rx_buffer = anedya_interface_allocate_memory(config->rx_buffer_size); - if (client->rx_buffer == NULL) - { - return ANEDYA_ERR_NO_MEMORY; - } + client->tx_buffer = anedya_interface_allocate_memory(config->tx_buffer_size); + if (client->tx_buffer == NULL) { + return ANEDYA_ERR_NO_MEMORY; + } + client->rx_buffer = anedya_interface_allocate_memory(config->rx_buffer_size); + if (client->rx_buffer == NULL) { + return ANEDYA_ERR_NO_MEMORY; + } #ifdef ANEDYA_ENABLE_DEVICE_LOGS - client->log_buffer = anedya_interface_allocate_memory(config->log_buffer_size * config->log_batch_size); - if (client->log_buffer == NULL) - { - return ANEDYA_ERR_NO_MEMORY; - } + client->log_buffer = anedya_interface_allocate_memory( + config->log_buffer_size * config->log_batch_size); + if (client->log_buffer == NULL) { + return ANEDYA_ERR_NO_MEMORY; + } #endif #endif // Compute the broker url #ifdef ANEDYA_CONNECTION_METHOD_MQTT - char url[100]; - sprintf(url, "mqtt.%s.anedya.io", config->region); - strcpy(client->broker_url, url); - anedya_mqtt_client_handle_t handle = _anedya_interface_mqtt_init(client, client->broker_url, client->config->_device_id_str, client->config->connection_key); - client->mqtt_client = handle; - client->_message_handler = _anedya_message_handler; - client->_anedya_on_connect_handler = _anedya_on_connect_handler; - client->_anedya_on_disconnect_handler = _anedya_on_disconnect_handler; - // Initialize txn store - err = _anedya_txn_store_init(&client->txn_store); - if (err != ANEDYA_OK) - { - return err; - } + char url[100]; + sprintf(url, "mqtt.%s.anedya.io", config->region); + strcpy(client->broker_url, url); + anedya_mqtt_client_handle_t handle = _anedya_interface_mqtt_init( + client, client->broker_url, client->config->_device_id_str, + client->config->connection_key); + client->mqtt_client = handle; + client->_message_handler = _anedya_message_handler; + client->_anedya_on_connect_handler = _anedya_on_connect_handler; + client->_anedya_on_disconnect_handler = _anedya_on_disconnect_handler; + // Initialize txn store + err = _anedya_txn_store_init(&client->txn_store); + if (err != ANEDYA_OK) { + return err; + } #endif - char topic_prefix[100]; - strcpy(topic_prefix, "$anedya/device/"); - strcat(topic_prefix, config->_device_id_str); - strcat(topic_prefix, "/"); +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + // Build REST base URL: device..anedya.io + char http_url[100]; + sprintf(http_url, "device.%s.anedya.io", config->region); + strcpy(client->http_base_url, http_url); + // HTTP is stateless - mark as connected immediately + client->is_connected = 1; + // Initialize txn store (still used to track in-flight requests) + err = _anedya_txn_store_init(&client->txn_store); + if (err != ANEDYA_OK) { + return err; + } +#endif + +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + char topic_prefix[100]; + strcpy(topic_prefix, "$anedya/device/"); + strcat(topic_prefix, config->_device_id_str); + strcat(topic_prefix, "/"); - strcpy(client->_message_topics[0], topic_prefix); - strcat(client->_message_topics[0], "response"); + strcpy(client->_message_topics[0], topic_prefix); + strcat(client->_message_topics[0], "response"); - strcpy(client->_message_topics[1], topic_prefix); - strcat(client->_message_topics[1], "errors"); + strcpy(client->_message_topics[1], topic_prefix); + strcat(client->_message_topics[1], "errors"); - strcpy(client->_message_topics[2], topic_prefix); - strcat(client->_message_topics[2], "commands"); + strcpy(client->_message_topics[2], topic_prefix); + strcat(client->_message_topics[2], "commands"); - strcpy(client->_message_topics[3], topic_prefix); - strcat(client->_message_topics[3], "valuestore/updates/json"); + strcpy(client->_message_topics[3], topic_prefix); + strcat(client->_message_topics[3], "valuestore/updates/json"); +#endif - return ANEDYA_OK; + return ANEDYA_OK; } #ifdef ANEDYA_CONNECTION_METHOD_MQTT -anedya_err_t anedya_client_connect(anedya_client_t *client) -{ - anedya_err_t err; - err = anedya_interface_mqtt_connect(client->mqtt_client); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; +anedya_err_t anedya_client_connect(anedya_client_t *client) { + anedya_err_t err; + err = anedya_interface_mqtt_connect(client->mqtt_client); + if (err != ANEDYA_OK) { + return err; + } + return ANEDYA_OK; } -anedya_err_t anedya_client_disconnect(anedya_client_t *client) -{ - anedya_err_t err; - // Set is_connected to 0 to signify intentional shutdown - client->is_connected = 0; - err = anedya_interface_mqtt_disconnect(client->mqtt_client); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; +anedya_err_t anedya_client_disconnect(anedya_client_t *client) { + anedya_err_t err; + // Set is_connected to 0 to signify intentional shutdown + client->is_connected = 0; + err = anedya_interface_mqtt_disconnect(client->mqtt_client); + if (err != ANEDYA_OK) { + return err; + } + return ANEDYA_OK; } -anedya_err_t anedya_client_destroy(anedya_client_t *client) -{ - anedya_err_t err; - err = anedya_interface_mqtt_destroy(client->mqtt_client); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; +anedya_err_t anedya_client_destroy(anedya_client_t *client) { + anedya_err_t err; + err = anedya_interface_mqtt_destroy(client->mqtt_client); + if (err != ANEDYA_OK) { + return err; + } + return ANEDYA_OK; } #endif -anedya_err_t _anedya_txn_store_init(anedya_txn_store_t *store) -{ - for (int i = 0; i < ANEDYA_MAX_CONCURRENT_TXN; i++) - { - store->txn_slot_free[i] = 1; - store->txns[i] = NULL; - } - store->_lock = 0; - return ANEDYA_OK; +#ifdef ANEDYA_CONNECTION_METHOD_HTTP +anedya_err_t anedya_client_connect(anedya_client_t *client) { + /* HTTP is stateless – no persistent TCP connection needed. + * Just mark as connected so operation functions can proceed. */ + client->is_connected = 1; + return ANEDYA_OK; } -anedya_err_t _anedya_txn_store_aquire_slot(anedya_txn_store_t *store, anedya_txn_t *txn) -{ - // Aquire lock - if (store->_lock == 1) - { - // printf("Lock failed while aquiring\r\n"); - return ANEDYA_ERR_LOCK_FAILED; - } - // Take lock - store->_lock = 1; - // Loop through the slots, and aquire the first available one - for (int i = 0; i < ANEDYA_MAX_CONCURRENT_TXN; i++) - { - int64_t now = time(NULL); - if (store->txn_slot_free[i] == 0 && (now - store->aquired_time[i]) > 30) - { - // TXN has timed out. Free the aquired slot - store->txn_slot_free[i] = 1; - store->txns[i] = NULL; - // printf("Slot timed out: %d", i + 1); - } - if (store->txn_slot_free[i] == 1) - { - store->txn_slot_free[i] = 0; - store->txns[i] = txn; - store->aquired_time[i] = (int64_t)time(NULL); - txn->desc = i + 1; - store->_lock = 0; - // printf("Aquired slot: %d\r\n", txn->desc); - return ANEDYA_OK; - } - } - // Release the lock - store->_lock = 0; - return ANEDYA_ERR_MAX_TXN_EXCEEDED; +anedya_err_t anedya_client_disconnect(anedya_client_t *client) { + client->is_connected = 0; + return ANEDYA_OK; } +#endif -anedya_err_t _anedya_txn_store_release_slot(anedya_txn_store_t *store, anedya_txn_t *txn) -{ - // Aquire lock - if (store->_lock == 1) - { - // printf("Lock failed while releasing\r\n"); - return ANEDYA_ERR_LOCK_FAILED; - } - // Take lock - store->_lock = 1; - store->txn_slot_free[txn->desc - 1] = 1; - store->txns[txn->desc - 1] = NULL; - // printf("Released slot: %d\r\n", txn->desc); - // Release the lock - store->_lock = 0; - return ANEDYA_OK; +anedya_err_t _anedya_txn_store_init(anedya_txn_store_t *store) { + + for (int i = 0; i < ANEDYA_MAX_CONCURRENT_TXN; i++) { + store->txn_slot_free[i] = 1; + store->txns[i] = NULL; + } + store->_lock = 0; + return ANEDYA_OK; } -void _anedya_message_handler(anedya_client_t *cl, char *topic, int topic_len, char *payload, int payload_len) -{ - // Just received the message, now determine for which topic this message is delivered - //_anedya_interface_std_out("Processing message"); - // printf("Matching from: %.*s Len: %d\r\n", topic_len, topic, topic_len); - int i = 0; - for (i = 0; i < 4; i++) - { - // printf("Matching with: %s Len: %d\n", cl->_message_topics[i], strlen(cl->_message_topics[i])); - if (strncmp(topic, cl->_message_topics[i], strlen(cl->_message_topics[i]) - 1) == 0) - { - //_anedya_interface_std_out("Topic matched"); - // printf("Matching from: %.*s Len: %d\r\n", topic_len, topic, topic_len); - break; - } +anedya_err_t _anedya_txn_store_aquire_slot(anedya_txn_store_t *store, + anedya_txn_t *txn) { + // Aquire lock + if (store->_lock == 1) { + // printf("Lock failed while aquiring\r\n"); + return ANEDYA_ERR_LOCK_FAILED; + } + // Take lock + store->_lock = 1; + // Loop through the slots, and aquire the first available one + for (int i = 0; i < ANEDYA_MAX_CONCURRENT_TXN; i++) { + int64_t now = time(NULL); + if (store->txn_slot_free[i] == 0 && (now - store->aquired_time[i]) > 30) { + // TXN has timed out. Free the aquired slot + store->txn_slot_free[i] = 1; + store->txns[i] = NULL; + // printf("Slot timed out: %d", i + 1); } - // printf("Index: %d\r\n", i); - switch (i) - { - case 0: - _anedya_handle_txn_response(cl, payload, payload_len, 0); - break; - case 1: - // printf("Error case\r\n"); - _anedya_handle_txn_response(cl, payload, payload_len, 1); - break; - case 2: - _anedya_handle_event(cl, payload, payload_len, 2); - // Handle command - break; - case 3: - // Handle valuestore update - _anedya_handle_event(cl, payload, payload_len, 3); - break; + if (store->txn_slot_free[i] == 1) { + store->txn_slot_free[i] = 0; + store->txns[i] = txn; + store->aquired_time[i] = (int64_t)time(NULL); + txn->desc = i + 1; + store->_lock = 0; + // printf("Aquired slot: %d\r\n", txn->desc); + return ANEDYA_OK; } + } + // Release the lock + store->_lock = 0; + return ANEDYA_ERR_MAX_TXN_EXCEEDED; } -void _anedya_on_connect_handler(anedya_client_t *client) -{ - // Client just got connected to the broker, now subscribe to the topics - anedya_interface_mqtt_subscribe(client->mqtt_client, client->_message_topics[0], strlen(client->_message_topics[0]), 0); - anedya_interface_mqtt_subscribe(client->mqtt_client, client->_message_topics[1], strlen(client->_message_topics[1]), 0); - anedya_interface_mqtt_subscribe(client->mqtt_client, client->_message_topics[2], strlen(client->_message_topics[2]), 0); - anedya_interface_mqtt_subscribe(client->mqtt_client, client->_message_topics[3], strlen(client->_message_topics[3]), 0); - client->is_connected = 1; - if (client->config->on_connect != NULL) - { - client->config->on_connect(client->config->on_connect_ctx); - } - return; +anedya_err_t _anedya_txn_store_release_slot(anedya_txn_store_t *store, + anedya_txn_t *txn) { + // Aquire lock + if (store->_lock == 1) { + // printf("Lock failed while releasing\r\n"); + return ANEDYA_ERR_LOCK_FAILED; + } + // Take lock + store->_lock = 1; + store->txn_slot_free[txn->desc - 1] = 1; + store->txns[txn->desc - 1] = NULL; + // printf("Released slot: %d\r\n", txn->desc); + // Release the lock + store->_lock = 0; + return ANEDYA_OK; } -void _anedya_on_disconnect_handler(anedya_client_t *client) -{ - // Call the callback - if (client->config->on_disconnect != NULL) - { - client->config->on_disconnect(client->config->on_disconnect_ctx); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT +void _anedya_message_handler(anedya_client_t *cl, char *topic, int topic_len, + char *payload, int payload_len) { + // Just received the message, now determine for which topic this message is + // delivered + int i = 0; + for (i = 0; i < 4; i++) { + if (strncmp(topic, cl->_message_topics[i], + strlen(cl->_message_topics[i]) - 1) == 0) { + break; } + } + switch (i) { + case 0: + _anedya_handle_txn_response(cl, payload, payload_len, 0); + break; + case 1: + _anedya_handle_txn_response(cl, payload, payload_len, 1); + break; + case 2: + _anedya_handle_event(cl, payload, payload_len, 2); + break; + case 3: + _anedya_handle_event(cl, payload, payload_len, 3); + break; + } +} - if (client->is_connected == 1) - { - // This means the flow is coming from unintentional connection close - // Process retry logic - client->is_connected = 0; - anedya_interface_mqtt_connect(client->mqtt_client); - // TODO: Implement retry logic - } +void _anedya_on_connect_handler(anedya_client_t *client) { + // Client just got connected to the broker, now subscribe to the topics + anedya_interface_mqtt_subscribe(client->mqtt_client, + client->_message_topics[0], + strlen(client->_message_topics[0]), 0); + anedya_interface_mqtt_subscribe(client->mqtt_client, + client->_message_topics[1], + strlen(client->_message_topics[1]), 0); + anedya_interface_mqtt_subscribe(client->mqtt_client, + client->_message_topics[2], + strlen(client->_message_topics[2]), 0); + anedya_interface_mqtt_subscribe(client->mqtt_client, + client->_message_topics[3], + strlen(client->_message_topics[3]), 0); + client->is_connected = 1; + if (client->config->on_connect != NULL) { + client->config->on_connect(client->config->on_connect_ctx); + } + return; +} + +void _anedya_on_disconnect_handler(anedya_client_t *client) { + // Call the callback + if (client->config->on_disconnect != NULL) { + client->config->on_disconnect(client->config->on_disconnect_ctx); + } + + if (client->is_connected == 1) { + // This means the flow is coming from unintentional connection close + // Process retry logic + client->is_connected = 0; + anedya_interface_mqtt_connect(client->mqtt_client); + // TODO: Implement retry logic + } + return; +} +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP +void _anedya_handle_http_txn_response(anedya_client_t *cl, char *payload, + int payload_len, anedya_txn_t *txn) { + if (payload == NULL || payload_len <= 0) + return; + + txn->_rx_len = payload_len + 1; + if (txn->_rx_len > ANEDYA_RX_BUFFER_SIZE) { + txn->_op_err = ANEDYA_ERR_RX_BUFFER_OVERFLOW; + txn->is_complete = true; + txn->is_success = false; + _anedya_txn_complete(cl, txn); return; + } + + memcpy(txn->_rxbody, payload, payload_len); + txn->_rxbody[payload_len] = '\0'; + + switch (txn->_op) { + case ANEDYA_OP_BIND_DEVICE: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_HEARTBEAT: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_OTA_NEXT: + _anedya_op_ota_next_resp(cl, txn); + break; + case ANEDYA_OP_ONGOING_OTA: + _anedya_op_ongoing_ota_resp(cl, txn); + break; + case ANEDYA_OP_SUBMIT_DATA: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_VALUESTORE_SET: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_SUBMIT_EVENT: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_CMD_UPDATE_STATUS: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_SUBMIT_LOG: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_VALUESTORE_GET: + _anedya_op_valuestore_handle_get_resp(cl, txn); + break; + case ANEDYA_OP_VALUESTORE_GET_LIST: + _anedya_op_valuestore_handle_list_obj_resp(cl, txn); + break; + case ANEDYA_OP_VALUESTORE_DELETE: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_CMD_GET_LIST: + _anedya_op_command_handle_list_resp(cl, txn); + break; + case ANEDYA_OP_CMD_NEXT: + _anedya_op_cmd_handle_next_resp(cl, txn); + break; + default: + break; + } + _anedya_txn_complete(cl, txn); } +#endif -void _anedya_handle_txn_response(anedya_client_t *cl, char *payload, int payload_len, uint8_t topic) -{ - // Parse the payload, and get the txn id - // printf("Handling txn response\r\n"); - char buffer[ANEDYA_RX_BUFFER_SIZE]; - char str[ANEDYA_RX_BUFFER_SIZE]; - int str_len = payload_len; - for (int i = 0; i < ANEDYA_RX_BUFFER_SIZE; i++) - { - buffer[i] = 0; - str[i] = 0; - } - memcpy(str, payload, payload_len); - memcpy(buffer, str, str_len); - // printf("Payload Received: %s\r\n", str); - str[str_len] = '\0'; - buffer[str_len] = '\0'; - json_t mem[32]; - // Parse the json and get the txn id - json_t const *json = json_create(str, mem, sizeof mem / sizeof *mem); - if (!json) - { - _anedya_interface_std_out("Error while parsing JSON body in TXN handler"); - } - // Get the txn id - json_t const *txn_id = json_getProperty(json, "reqId"); - if (!txn_id || JSON_TEXT != json_getType(txn_id)) - { - _anedya_interface_std_out("Error, the first name property is not found."); +void _anedya_handle_txn_response(anedya_client_t *cl, char *payload, + int payload_len, uint8_t topic) { + // Parse the payload, and get the txn id + // printf("Handling txn response\r\n"); + // file-scope globals (BSS section, no runtime malloc) + static char buffer[ANEDYA_RX_BUFFER_SIZE]; + static char str[ANEDYA_RX_BUFFER_SIZE]; + if (payload_len >= ANEDYA_RX_BUFFER_SIZE) { + _anedya_interface_std_out("Error: Payload too large for RX buffer"); + return; + } + int str_len = payload_len; + memset(str, 0, ANEDYA_RX_BUFFER_SIZE); + memset(buffer, 0, ANEDYA_RX_BUFFER_SIZE); + memcpy(str, payload, payload_len); + memcpy(buffer, str, str_len); + // printf("Payload Received: %s\r\n", str); + str[str_len] = '\0'; + buffer[str_len] = '\0'; + json_t mem[32]; + // Parse the json and get the txn id + json_t const *json = json_create(str, mem, sizeof mem / sizeof *mem); + if (!json) { + _anedya_interface_std_out("Error while parsing JSON body in TXN handler"); + } + // Get the txn idL + json_t const *txn_id = json_getProperty(json, "reqId"); + if (!txn_id || JSON_TEXT != json_getType(txn_id)) { + _anedya_interface_std_out( + "Error, the reqId property is not found in the response."); + } + char const *txn_index = json_getValue(txn_id); + int index = atoi(txn_index); + // If the txn id is 0, then it is an error + // printf("Txn id: %d\r\n", index); + if (index == 0) { + _anedya_interface_std_out("Error, invalid txn id"); + } else { + + // Search for the txn in the txn store + anedya_txn_t *txn = cl->txn_store.txns[index - 1]; + if (txn == NULL) { + return; + } else { + strcpy(txn->_rxbody, buffer); } - char const *txn_index = json_getValue(txn_id); - int index = atoi(txn_index); - // If the txn id is 0, then it is an error - // printf("Txn id: %d\r\n", index); - if (index == 0) - { - _anedya_interface_std_out("Error, invalid txn id"); + txn->_rx_len = str_len + 1; + if (txn->_rx_len > ANEDYA_RX_BUFFER_SIZE) { + txn->_op_err = ANEDYA_ERR_RX_BUFFER_OVERFLOW; + txn->is_complete = true; + txn->is_success = false; + _anedya_txn_complete(cl, txn); + return; } - else - { - - // Search for the txn in the txn store - anedya_txn_t *txn = cl->txn_store.txns[index - 1]; - if (txn == NULL) - { - return; - } - else - { - strcpy(txn->_rxbody, buffer); - } - txn->_rx_len = str_len + 1; - if (txn->_rx_len > ANEDYA_RX_BUFFER_SIZE) - { - txn->_op_err = ANEDYA_ERR_RX_BUFFER_OVERFLOW; - txn->is_complete = true; - txn->is_success = false; - _anedya_txn_complete(cl, txn); - return; - } - // printf("Rx Body: %s", txn->_rxbody); - // Call the Operation handler - switch (txn->_op) - { - case ANEDYA_OP_BIND_DEVICE: - _anedya_device_handle_generic_resp(cl, txn); - break; - case ANEDYA_OP_HEARTBEAT: - _anedya_device_handle_generic_resp(cl, txn); - break; - case ANEDYA_OP_OTA_NEXT: - _anedya_op_ota_next_resp(cl, txn); - break; - case ANEDYA_OP_SUBMIT_DATA: - _anedya_device_handle_generic_resp(cl, txn); - break; - case ANEDYA_OP_VALUESTORE_SET: - _anedya_device_handle_generic_resp(cl, txn); - break; - case ANEDYA_OP_SUBMIT_EVENT: - _anedya_device_handle_generic_resp(cl, txn); - break; - case ANEDYA_OP_CMD_UPDATE_STATUS: - _anedya_device_handle_generic_resp(cl, txn); - break; - case ANEDYA_OP_SUBMIT_LOG: - _anedya_device_handle_generic_resp(cl, txn); - break; - case ANEDYA_OP_VALUESTORE_GET: - _anedya_op_valuestore_handle_get_resp(cl, txn); - break; - case ANEDYA_OP_VALUESTORE_GET_LIST: - _anedya_op_valuestore_handle_list_obj_resp(cl, txn); - break; - case ANEDYA_OP_VALUESTORE_DELETE: - _anedya_device_handle_generic_resp(cl, txn); - break; - case ANEDYA_OP_CMD_GET_LIST: - _anedya_op_command_handle_list_resp(cl, txn); - break; - case ANEDYA_OP_CMD_NEXT: - _anedya_op_cmd_handle_next_resp(cl, txn); - break; - default: - // Do nothing - break; - } - // Mark transaction as completed - _anedya_txn_complete(cl, txn); + // printf("Rx Body: %s", txn->_rxbody); + // Call the Operation handler + switch (txn->_op) { + case ANEDYA_OP_BIND_DEVICE: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_HEARTBEAT: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_OTA_NEXT: + _anedya_op_ota_next_resp(cl, txn); + break; + case ANEDYA_OP_ONGOING_OTA: + _anedya_op_ongoing_ota_resp(cl, txn); + break; + case ANEDYA_OP_SUBMIT_DATA: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_VALUESTORE_SET: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_SUBMIT_EVENT: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_CMD_UPDATE_STATUS: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_SUBMIT_LOG: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_VALUESTORE_GET: + _anedya_op_valuestore_handle_get_resp(cl, txn); + break; + case ANEDYA_OP_VALUESTORE_GET_LIST: + _anedya_op_valuestore_handle_list_obj_resp(cl, txn); + break; + case ANEDYA_OP_VALUESTORE_DELETE: + _anedya_device_handle_generic_resp(cl, txn); + break; + case ANEDYA_OP_CMD_GET_LIST: + _anedya_op_command_handle_list_resp(cl, txn); + break; + case ANEDYA_OP_CMD_NEXT: + _anedya_op_cmd_handle_next_resp(cl, txn); + break; + default: + // Do nothing + break; } - // If not found, handle error - return; + // Mark transaction as completed + _anedya_txn_complete(cl, txn); + } + // If not found, handle error + return; } -void _anedya_handle_event(anedya_client_t *cl, char *payload, int payload_len, uint8_t topic) -{ - // A new event has been triggerred - char buffer[ANEDYA_RX_BUFFER_SIZE]; - int buffer_len = payload_len; - memcpy(buffer, payload, payload_len); - // anedya_event_t event; - // void *event_data = NULL; - switch (topic) - { - case 2: - // Handle command - anedya_command_obj_t cmd; - cmd.cmd_data_type = ANEDYA_DATATYPE_UNKNOWN; - _anedya_parse_inbound_command(buffer, buffer_len, &cmd); - if (cl->config->event_handler != NULL) - { - cl->config->event_handler(cl, ANEDYA_EVENT_COMMAND, &cmd); - } - break; - case 3: - // Handle valuestore update - // First decode the valuestore object - uint8_t type = _anedya_parse_valuestore_type(buffer, buffer_len); - switch (type) - { - case ANEDYA_VALUESTORE_TYPE_FLOAT: - anedya_valuestore_obj_float_t float_data; - // printf("Buffer in: %s", buffer); - _anedya_parse_valuestore_float(buffer, buffer_len, &float_data); - // Call the event handler with data - if (cl->config->event_handler != NULL) - { - cl->config->event_handler(cl, ANEDYA_EVENT_VS_UPDATE_FLOAT, &float_data); - } - break; - case ANEDYA_VALUESTORE_TYPE_STRING: - // event_data = _anedya_parse_valuestore_string(payload, payload_len); - anedya_valuestore_obj_string_t str_data; - _anedya_parse_valuestore_string(buffer, buffer_len, &str_data); - // Call the event handler with data - if (cl->config->event_handler != NULL) - { - cl->config->event_handler(cl, ANEDYA_EVENT_VS_UPDATE_STRING, &str_data); - } - break; - case ANEDYA_VALUESTORE_TYPE_BOOL: - // event_data = _anedya_parse_valuestore_json(payload, payload_len); - anedya_valuestore_obj_bool_t bool_data; - _anedya_parse_valuestore_bool(buffer, buffer_len, &bool_data); - // Call the event handler with data - if (cl->config->event_handler != NULL) - { - cl->config->event_handler(cl, ANEDYA_EVENT_VS_UPDATE_BOOL, &bool_data); - } - break; - case ANEDYA_VALUESTORE_TYPE_BIN: - // event_data = _anedya_parse_valuestore_json(payload, payload_len); - anedya_valuestore_obj_bin_t bin_data; - _anedya_parse_valuestore_bin(buffer, buffer_len, &bin_data); - // Call the event handler with data - if (cl->config->event_handler != NULL) - { - cl->config->event_handler(cl, ANEDYA_EVENT_VS_UPDATE_BIN, &bin_data); - } - break; - default: - break; - } - break; +#ifdef ANEDYA_CONNECTION_METHOD_MQTT +void _anedya_handle_event(anedya_client_t *cl, char *payload, int payload_len, + uint8_t topic) { + // A new event has been triggered + char buffer[ANEDYA_RX_BUFFER_SIZE]; + int buffer_len = payload_len; + memcpy(buffer, payload, payload_len); + switch (topic) { + case 2: + // Handle command + anedya_command_obj_t cmd; + cmd.cmd_data_type = ANEDYA_DATATYPE_UNKNOWN; + _anedya_parse_inbound_command(buffer, buffer_len, &cmd); + if (cl->config->event_handler != NULL) { + cl->config->event_handler(cl, ANEDYA_EVENT_COMMAND, &cmd); } -} \ No newline at end of file + break; + case 3: + // Handle valuestore update + uint8_t type = _anedya_parse_valuestore_type(buffer, buffer_len); + switch (type) { + case ANEDYA_VALUESTORE_TYPE_FLOAT: + anedya_valuestore_obj_float_t float_data; + _anedya_parse_valuestore_float(buffer, buffer_len, &float_data); + if (cl->config->event_handler != NULL) { + cl->config->event_handler(cl, ANEDYA_EVENT_VS_UPDATE_FLOAT, + &float_data); + } + break; + case ANEDYA_VALUESTORE_TYPE_STRING: + anedya_valuestore_obj_string_t str_data; + _anedya_parse_valuestore_string(buffer, buffer_len, &str_data); + if (cl->config->event_handler != NULL) { + cl->config->event_handler(cl, ANEDYA_EVENT_VS_UPDATE_STRING, &str_data); + } + break; + case ANEDYA_VALUESTORE_TYPE_BOOL: + anedya_valuestore_obj_bool_t bool_data; + _anedya_parse_valuestore_bool(buffer, buffer_len, &bool_data); + if (cl->config->event_handler != NULL) { + cl->config->event_handler(cl, ANEDYA_EVENT_VS_UPDATE_BOOL, &bool_data); + } + break; + case ANEDYA_VALUESTORE_TYPE_BIN: + anedya_valuestore_obj_bin_t bin_data; + _anedya_parse_valuestore_bin(buffer, buffer_len, &bin_data); + if (cl->config->event_handler != NULL) { + cl->config->event_handler(cl, ANEDYA_EVENT_VS_UPDATE_BIN, &bin_data); + } + break; + default: + break; + } + break; + } +} +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ \ No newline at end of file diff --git a/src/anedya_config.c b/src/anedya_config.c index 187d8d0..00e74ef 100755 --- a/src/anedya_config.c +++ b/src/anedya_config.c @@ -63,9 +63,11 @@ anedya_err_t anedya_config_init(anedya_config_t *config, anedya_device_id_t devI devId[14], devId[15]); // printf("UUID: %s\n", uuid_str); memcpy(config->_device_id_str, uuid_str, 37); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT config->event_handler = NULL; config->on_connect = NULL; config->on_disconnect = NULL; +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ return ANEDYA_OK; } diff --git a/src/anedya_json_parse.c b/src/anedya_json_parse.c index 99c92a3..9a6bf0b 100644 --- a/src/anedya_json_parse.c +++ b/src/anedya_json_parse.c @@ -15,6 +15,11 @@ typedef struct jsonStaticPool_s /* Search a property by its name in a JSON object. */ json_t const *json_getProperty(json_t const *obj, char const *property) { + if (!obj || !property) + { + return NULL; // avoid crash + } + json_t const *sibling; for (sibling = obj->u.c.child; sibling; sibling = sibling->sibling) if (sibling->name && !strcmp(sibling->name, property)) diff --git a/src/anedya_op_cmd_list.c b/src/anedya_op_cmd_list.c index 1a80204..a0b7155 100644 --- a/src/anedya_op_cmd_list.c +++ b/src/anedya_op_cmd_list.c @@ -1,195 +1,198 @@ #include "anedya_operations.h" -anedya_err_t anedya_op_cmd_get_list(anedya_client_t *client, anedya_txn_t *txn, anedya_req_cmd_list_t obj) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_CMD_GET_LIST; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } - - // Generate the JSON body +anedya_err_t anedya_op_cmd_get_list(anedya_client_t *client, anedya_txn_t *txn, + anedya_req_cmd_list_t obj) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_CMD_GET_LIST; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } + + // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION - // TODO: Implement dynamic allocation + // TODO: Implement dynamic allocation #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_int(p, "limit", obj.limit, &marker); - p = anedya_json_int(p, "offset", obj.offset, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/commands/list/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); + p = anedya_json_int(p, "limit", obj.limit, &marker); + p = anedya_json_int(p, "offset", obj.offset, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + + // Body is ready now publish it to the MQTT + char topic[100]; + // printf("Req: %s", txbuffer); + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/commands/list/json"); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/commands/list", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; } -void _anedya_op_command_handle_list_resp(anedya_client_t *client, anedya_txn_t *txn) -{ - - // printf("Resp: %s\n", txn->_rxbody); - json_t mem[32]; - // Parse the json and get the txn id - json_t const *json = json_create(txn->_rxbody, mem, sizeof mem / sizeof *mem); - if (!json) - { - _anedya_interface_std_out("Error while parsing JSON body:response handler Get list value store"); - return; - } - // Check if success - json_t const *success = json_getProperty(json, "success"); - if (!success || JSON_BOOLEAN != json_getType(success)) - { - _anedya_interface_std_out("Error, the success property is not found."); - } - bool s = json_getBoolean(success); - if (s == true) - { - txn->is_success = true; - } - else - { - txn->is_success = false; - json_t const *error = json_getProperty(json, "errorcode"); - if (!error || JSON_INTEGER != json_getType(error)) - { - _anedya_interface_std_out("Error, the error property is not found."); - } - int err = (anedya_err_t)json_getInteger(error); - txn->_op_err = err; - return; +void _anedya_op_command_handle_list_resp(anedya_client_t *client, + anedya_txn_t *txn) { + + // printf("Resp: %s\n", txn->_rxbody); + json_t mem[32]; + // Parse the json and get the txn id + json_t const *json = json_create(txn->_rxbody, mem, sizeof mem / sizeof *mem); + if (!json) { + _anedya_interface_std_out( + "Error while parsing JSON body:response handler Get list value store"); + return; + } + // Check if success + json_t const *success = json_getProperty(json, "success"); + if (!success || JSON_BOOLEAN != json_getType(success)) { + _anedya_interface_std_out("Error, the success property is not found."); + } + bool s = json_getBoolean(success); + if (s == true) { + txn->is_success = true; + } else { + txn->is_success = false; + json_t const *error = json_getProperty(json, "errorcode"); + if (!error || JSON_INTEGER != json_getType(error)) { + _anedya_interface_std_out("Error, the error property is not found."); } + int err = (anedya_err_t)json_getInteger(error); + txn->_op_err = err; + return; + } - // Flow reaches here means, request was successful. - anedya_op_cmd_list_resp_t *resp = (anedya_op_cmd_list_resp_t *)txn->response; + // Flow reaches here means, request was successful. + anedya_op_cmd_list_resp_t *resp = (anedya_op_cmd_list_resp_t *)txn->response; - json_t const *totalcount_prop = json_getProperty(json, "totalcount"); - if (!totalcount_prop || JSON_INTEGER != json_getType(totalcount_prop)) - { - _anedya_interface_std_out("Error, the totalcount property is not found."); - } - else - { - resp->totalcount = (int)json_getInteger(totalcount_prop); + json_t const *totalcount_prop = json_getProperty(json, "totalcount"); + if (!totalcount_prop || JSON_INTEGER != json_getType(totalcount_prop)) { + _anedya_interface_std_out("Error, the totalcount property is not found."); + } else { + resp->totalcount = (int)json_getInteger(totalcount_prop); + } + + json_t const *count_prop = json_getProperty(json, "count"); + if (!count_prop || JSON_INTEGER != json_getType(count_prop)) { + _anedya_interface_std_out("Error, the count property is not found."); + return; + } + resp->count = (int)json_getInteger(count_prop); + if (resp->count == 0) { + resp->is_available = false; + return; + } + resp->is_available = true; + + json_t const *next_prop = json_getProperty(json, "next"); + if (!next_prop || JSON_INTEGER != json_getType(next_prop)) { + _anedya_interface_std_out("Error, the next property is not found."); + return; + } + resp->next = (int)json_getInteger(next_prop); + // printf("Next: %d\n", resp->next); + + json_t const *list_prop = json_getProperty(json, "commands"); + if (!list_prop || JSON_ARRAY != json_getType(list_prop)) { + _anedya_interface_std_out("Error, the keys property is not found."); + return; + } + + json_t const *cmds_prop = json_getChild(list_prop); + int i = 0; + while (cmds_prop && i < resp->count) { + if (JSON_OBJ != json_getType(cmds_prop)) { + _anedya_interface_std_out("Error, the key property is not an object."); + return; } - json_t const *count_prop = json_getProperty(json, "count"); - if (!count_prop || JSON_INTEGER != json_getType(count_prop)) - { - _anedya_interface_std_out("Error, the count property is not found."); - return; + json_t const *command_id_prop = json_getProperty(cmds_prop, "commandId"); + if (!command_id_prop || JSON_TEXT != json_getType(command_id_prop)) { + _anedya_interface_std_out( + "Error, the key property is not found or is not text."); + return; } - resp->count = (int)json_getInteger(count_prop); - if (resp->count == 0) - { - resp->is_available = false; - return; + + const char *cmd_id = json_getValue(command_id_prop); + anedya_err_t err = _anedya_uuid_parse(cmd_id, resp->commands[i].cmdId); + if (err != ANEDYA_OK) { + _anedya_interface_std_out("Error, failed to parse the command id."); + return; } - resp->is_available = true; - json_t const *next_prop = json_getProperty(json, "next"); - if (!next_prop || JSON_INTEGER != json_getType(next_prop)) - { - _anedya_interface_std_out("Error, the next property is not found."); - return; + json_t const *cmd_prop = json_getProperty(cmds_prop, "command"); + if (!cmd_prop || JSON_TEXT != json_getType(cmd_prop)) { + _anedya_interface_std_out( + "Error, the type property is not found or is not text."); + return; } - resp->next = (int)json_getInteger(next_prop); - // printf("Next: %d\n", resp->next); - - json_t const *list_prop = json_getProperty(json, "commands"); - if (!list_prop || JSON_ARRAY != json_getType(list_prop)) - { - _anedya_interface_std_out("Error, the keys property is not found."); - return; + const char *cmd = (char *)json_getValue(cmd_prop); + snprintf(resp->commands[i].command, sizeof(resp->commands[i].command), "%s", + cmd); + + json_t const *status_prop = json_getProperty(cmds_prop, "status"); + if (!status_prop || JSON_TEXT != json_getType(status_prop)) { + _anedya_interface_std_out( + "Error, the type property is not found or is not text."); + return; } - - json_t const *cmds_prop = json_getChild(list_prop); - int i = 0; - while (cmds_prop && i < resp->count) - { - if (JSON_OBJ != json_getType(cmds_prop)) - { - _anedya_interface_std_out("Error, the key property is not an object."); - return; - } - - json_t const *command_id_prop = json_getProperty(cmds_prop, "commandId"); - if (!command_id_prop || JSON_TEXT != json_getType(command_id_prop)) - { - _anedya_interface_std_out("Error, the key property is not found or is not text."); - return; - } - - const char *cmd_id = json_getValue(command_id_prop); - anedya_err_t err = _anedya_uuid_parse(cmd_id, resp->commands[i].cmdId); - if (err != ANEDYA_OK) - { - _anedya_interface_std_out("Error, failed to parse the command id."); - return; - } - - json_t const *cmd_prop = json_getProperty(cmds_prop, "command"); - if (!cmd_prop || JSON_TEXT != json_getType(cmd_prop)) - { - _anedya_interface_std_out("Error, the type property is not found or is not text."); - return; - } - const char *cmd = (char *)json_getValue(cmd_prop); - snprintf(resp->commands[i].command, sizeof(resp->commands[i].command), "%s", cmd); - - json_t const *status_prop = json_getProperty(cmds_prop, "status"); - if (!status_prop || JSON_TEXT != json_getType(status_prop)) - { - _anedya_interface_std_out("Error, the type property is not found or is not text."); - return; - } - const char *status = (char *)json_getValue(status_prop); - snprintf(resp->commands[i].status, sizeof(resp->commands[i].status), "%s", status); - - json_t const *issued_at_prop = json_getProperty(cmds_prop, "issuedAt"); - if (!issued_at_prop || JSON_INTEGER != json_getType(issued_at_prop)) - { - _anedya_interface_std_out("Error, the modified property is not found or is not text."); - return; - } - resp->commands[i].issued_at = (unsigned long long)json_getInteger(issued_at_prop); - - json_t const *updated_prop = json_getProperty(cmds_prop, "updated"); - if (!updated_prop || JSON_INTEGER != json_getType(updated_prop)) - { - _anedya_interface_std_out("Error, the modified property is not found or is not text."); - return; - } - resp->commands[i].updated = (unsigned long long)json_getInteger(updated_prop); - - cmds_prop = json_getSibling(cmds_prop); // Move to the next sibling in the array - i++; + const char *status = (char *)json_getValue(status_prop); + snprintf(resp->commands[i].status, sizeof(resp->commands[i].status), "%s", + status); + + json_t const *issued_at_prop = json_getProperty(cmds_prop, "issuedAt"); + if (!issued_at_prop || JSON_INTEGER != json_getType(issued_at_prop)) { + _anedya_interface_std_out( + "Error, the modified property is not found or is not text."); + return; } + resp->commands[i].issued_at = + (unsigned long long)json_getInteger(issued_at_prop); + + json_t const *updated_prop = json_getProperty(cmds_prop, "updated"); + if (!updated_prop || JSON_INTEGER != json_getType(updated_prop)) { + _anedya_interface_std_out( + "Error, the modified property is not found or is not text."); + return; + } + resp->commands[i].updated = + (unsigned long long)json_getInteger(updated_prop); - return; + cmds_prop = + json_getSibling(cmds_prop); // Move to the next sibling in the array + i++; + } + + return; } diff --git a/src/anedya_op_cmd_next.c b/src/anedya_op_cmd_next.c index 8256a39..6a00e02 100644 --- a/src/anedya_op_cmd_next.c +++ b/src/anedya_op_cmd_next.c @@ -1,195 +1,192 @@ #include "anedya_operations.h" -anedya_err_t anedya_op_cmd_next(anedya_client_t *client, anedya_txn_t *txn) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_CMD_NEXT; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } - - // Generate the JSON body +anedya_err_t anedya_op_cmd_next(anedya_client_t *client, anedya_txn_t *txn) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_CMD_NEXT; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } + + // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION - // TODO: Implement dynamic allocation + // TODO: Implement dynamic allocation #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/commands/next/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + + // Body is ready now publish it to the MQTT + char topic[100]; + // printf("Req: %s", txbuffer); + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/commands/next/json"); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/commands/next", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; } -void _anedya_op_cmd_handle_next_resp(anedya_client_t *client, anedya_txn_t *txn) -{ - - anedya_op_cmd_next_resp_t *resp = (anedya_op_cmd_next_resp_t *)txn->response; - // printf("Resp: %s\n", txn->_rxbody); - json_t mem[32]; - // Parse the json and get the txn id - json_t const *json = json_create(txn->_rxbody, mem, sizeof mem / sizeof *mem); - if (!json) - { - _anedya_interface_std_out("Error while parsing JSON body:response handler Get list value store"); - return; - } - // Check if success - json_t const *success = json_getProperty(json, "success"); - if (!success || JSON_BOOLEAN != json_getType(success)) - { - _anedya_interface_std_out("Error, the success property is not found."); - } - bool s = json_getBoolean(success); - if (s == true) - { - txn->is_success = true; - } - else - { - txn->is_success = false; - json_t const *error = json_getProperty(json, "errorcode"); - if (!error || JSON_INTEGER != json_getType(error)) - { - _anedya_interface_std_out("Error, the error property is not found."); - } - int err = (anedya_err_t)json_getInteger(error); - txn->_op_err = err; - return; - } - - // Flow reaches here means, request was successful. - json_t const *available = json_getProperty(json, "available"); - if (!available || JSON_BOOLEAN != json_getType(available)) - { - _anedya_interface_std_out("Error, the available property is not found."); - } - resp->is_available = json_getBoolean(available); - if (!resp->is_available) - { - printf("No more commands available\n"); - return; - } - - json_t const *command_id_prop = json_getProperty(json, "commandId"); - if (!command_id_prop || JSON_TEXT != json_getType(command_id_prop)) - { - _anedya_interface_std_out("Error, the key property is not found or is not text."); - return; - } - - const char *cmd_id = json_getValue(command_id_prop); - anedya_err_t err = _anedya_uuid_parse(cmd_id, resp->cmdId); - if (err != ANEDYA_OK) - { - _anedya_interface_std_out("Error, failed to parse the command id."); - // return; - } - - json_t const *cmd_prop = json_getProperty(json, "command"); - if (!cmd_prop || JSON_TEXT != json_getType(cmd_prop)) - { - _anedya_interface_std_out("Error, the type property is not found or is not text."); - return; - } - const char *cmd = json_getValue(cmd_prop); - snprintf(resp->command, sizeof(resp->command), "%s", cmd); - resp->command_len = strlen(cmd); - - json_t const *status_prop = json_getProperty(json, "status"); - if (!status_prop || JSON_TEXT != json_getType(status_prop)) - { - _anedya_interface_std_out("Error, the status property is not found or is not text."); - return; - } - const char *status = json_getValue(status_prop); - snprintf(resp->status, sizeof(resp->status), "%s", status); - - json_t const *data_prop = json_getProperty(json, "data"); - if (!data_prop || JSON_TEXT != json_getType(data_prop)) - { - _anedya_interface_std_out("Error, the data property is not found or is not text."); - return; - } - const char *data = json_getValue(data_prop); - if (data) - { - resp->data = (uint8_t *)data; - resp->data_len = strlen(data); - } - - json_t const *datatype_prop = json_getProperty(json, "datatype"); - if (!datatype_prop || JSON_TEXT != json_getType(datatype_prop)) - { - _anedya_interface_std_out("Error, the datatype property is not found or is not text."); - return; - } - const char *datatype = (char *)json_getValue(datatype_prop); - if (datatype) - { - if (strcmp(datatype, "string") == 0) - { - resp->data_type = ANEDYA_DATATYPE_STRING; - } - else if (strcmp(datatype, "binary") == 0) - { - resp->data_type = ANEDYA_DATATYPE_BINARY; - } - else - { - resp->data_type = ANEDYA_DATATYPE_UNKNOWN; - } - } - - json_t const *issued_at_prop = json_getProperty(json, "issuedAt"); - if (!issued_at_prop || JSON_INTEGER != json_getType(issued_at_prop)) - { - _anedya_interface_std_out("Error, the issued at property is not found or is not text."); - return; - } - resp->issued_at = (unsigned long long)json_getInteger(issued_at_prop); +void _anedya_op_cmd_handle_next_resp(anedya_client_t *client, + anedya_txn_t *txn) { + + anedya_op_cmd_next_resp_t *resp = (anedya_op_cmd_next_resp_t *)txn->response; + // printf("Resp: %s\n", txn->_rxbody); + json_t mem[32]; + // Parse the json and get the txn id + json_t const *json = json_create(txn->_rxbody, mem, sizeof mem / sizeof *mem); + if (!json) { + _anedya_interface_std_out( + "Error while parsing JSON body:response handler Get list value store"); + return; + } + // Check if success + json_t const *success = json_getProperty(json, "success"); + if (!success || JSON_BOOLEAN != json_getType(success)) { + _anedya_interface_std_out("Error, the success property is not found."); + } + bool s = json_getBoolean(success); + if (s == true) { + txn->is_success = true; + } else { + txn->is_success = false; + json_t const *error = json_getProperty(json, "errorcode"); + if (!error || JSON_INTEGER != json_getType(error)) { + _anedya_interface_std_out("Error, the error property is not found."); + } + int err = (anedya_err_t)json_getInteger(error); + txn->_op_err = err; + return; + } + + // Flow reaches here means, request was successful. + json_t const *available = json_getProperty(json, "available"); + if (!available || JSON_BOOLEAN != json_getType(available)) { + _anedya_interface_std_out("Error, the available property is not found."); + } + resp->is_available = json_getBoolean(available); + if (!resp->is_available) { + printf("No more commands available\n"); + return; + } - json_t const *updated_prop = json_getProperty(json, "updated"); - if (!updated_prop || JSON_INTEGER != json_getType(updated_prop)) - { - _anedya_interface_std_out("Error, the updated property is not found or is not text."); - return; - } - resp->updated = (unsigned long long)json_getInteger(updated_prop); + json_t const *command_id_prop = json_getProperty(json, "commandId"); + if (!command_id_prop || JSON_TEXT != json_getType(command_id_prop)) { + _anedya_interface_std_out( + "Error, the key property is not found or is not text."); + return; + } + + const char *cmd_id = json_getValue(command_id_prop); + anedya_err_t err = _anedya_uuid_parse(cmd_id, resp->cmdId); + if (err != ANEDYA_OK) { + _anedya_interface_std_out("Error, failed to parse the command id."); + // return; + } + + json_t const *cmd_prop = json_getProperty(json, "command"); + if (!cmd_prop || JSON_TEXT != json_getType(cmd_prop)) { + _anedya_interface_std_out( + "Error, the type property is not found or is not text."); + return; + } + const char *cmd = json_getValue(cmd_prop); + snprintf(resp->command, sizeof(resp->command), "%s", cmd); + resp->command_len = strlen(cmd); + + json_t const *status_prop = json_getProperty(json, "status"); + if (!status_prop || JSON_TEXT != json_getType(status_prop)) { + _anedya_interface_std_out( + "Error, the status property is not found or is not text."); + return; + } + const char *status = json_getValue(status_prop); + snprintf(resp->status, sizeof(resp->status), "%s", status); + + json_t const *data_prop = json_getProperty(json, "data"); + if (!data_prop || JSON_TEXT != json_getType(data_prop)) { + _anedya_interface_std_out( + "Error, the data property is not found or is not text."); + return; + } + const char *data = json_getValue(data_prop); + if (data) { + resp->data = (uint8_t *)data; + resp->data_len = strlen(data); + } + + json_t const *datatype_prop = json_getProperty(json, "datatype"); + if (!datatype_prop || JSON_TEXT != json_getType(datatype_prop)) { + _anedya_interface_std_out( + "Error, the datatype property is not found or is not text."); + return; + } + const char *datatype = (char *)json_getValue(datatype_prop); + if (datatype) { + if (strcmp(datatype, "string") == 0) { + resp->data_type = ANEDYA_DATATYPE_STRING; + } else if (strcmp(datatype, "binary") == 0) { + resp->data_type = ANEDYA_DATATYPE_BINARY; + } else { + resp->data_type = ANEDYA_DATATYPE_UNKNOWN; + } + } + + json_t const *issued_at_prop = json_getProperty(json, "issuedAt"); + if (!issued_at_prop || JSON_INTEGER != json_getType(issued_at_prop)) { + _anedya_interface_std_out( + "Error, the issued at property is not found or is not text."); + return; + } + resp->issued_at = (unsigned long long)json_getInteger(issued_at_prop); - json_t const *nextavailable_prop = json_getProperty(json, "nextavailable"); - if (!nextavailable_prop || JSON_BOOLEAN != json_getType(nextavailable_prop)) - { - _anedya_interface_std_out("Error, the next available property is not found or is not text."); - return; - } - resp->nextavailable = json_getBoolean(nextavailable_prop); + json_t const *updated_prop = json_getProperty(json, "updated"); + if (!updated_prop || JSON_INTEGER != json_getType(updated_prop)) { + _anedya_interface_std_out( + "Error, the updated property is not found or is not text."); + return; + } + resp->updated = (unsigned long long)json_getInteger(updated_prop); + json_t const *nextavailable_prop = json_getProperty(json, "nextavailable"); + if (!nextavailable_prop || JSON_BOOLEAN != json_getType(nextavailable_prop)) { + _anedya_interface_std_out( + "Error, the next available property is not found or is not text."); return; + } + resp->nextavailable = json_getBoolean(nextavailable_prop); + + return; } diff --git a/src/anedya_op_commands.c b/src/anedya_op_commands.c index c44a39c..99876fe 100644 --- a/src/anedya_op_commands.c +++ b/src/anedya_op_commands.c @@ -1,153 +1,160 @@ -#include "anedya_operations.h" #include "anedya_op_commands.h" #include "anedya_commons.h" +#include "anedya_operations.h" -anedya_err_t _anedya_parse_inbound_command(char *payload, unsigned int payload_len, anedya_command_obj_t *obj) -{ - json_t mem[32]; - char temp[ANEDYA_RX_BUFFER_SIZE]; - strcpy(temp, payload); - // Parse the json and get the txn id - json_t const *json = json_create(temp, mem, sizeof mem / sizeof *mem); - if (!json) - { - _anedya_interface_std_out("Error while parsing JSON body: Valuestore type"); - } - json_t const *cmdID = json_getProperty(json, "commandId"); - if (!cmdID || JSON_TEXT != json_getType(cmdID)) - { - _anedya_interface_std_out("Error, the deploymentId property is not found."); - return ANEDYA_ERR_PARSE_ERROR; - } - const char *cmd_id = json_getValue(cmdID); - anedya_err_t err = _anedya_uuid_parse(cmd_id, obj->cmdId); - if (err != ANEDYA_OK) - { - return err; - } +anedya_err_t _anedya_parse_inbound_command(char *payload, + unsigned int payload_len, + anedya_command_obj_t *obj) { + json_t mem[32]; + char temp[ANEDYA_RX_BUFFER_SIZE]; + strcpy(temp, payload); + // Parse the json and get the txn id + json_t const *json = json_create(temp, mem, sizeof mem / sizeof *mem); + if (!json) { + _anedya_interface_std_out("Error while parsing JSON body: Valuestore type"); + } + json_t const *cmdID = json_getProperty(json, "commandId"); + if (!cmdID || JSON_TEXT != json_getType(cmdID)) { + _anedya_interface_std_out("Error, the deploymentId property is not found."); + return ANEDYA_ERR_PARSE_ERROR; + } + const char *cmd_id = json_getValue(cmdID); + anedya_err_t err = _anedya_uuid_parse(cmd_id, obj->cmdId); + if (err != ANEDYA_OK) { + return err; + } - json_t const *cmd = json_getProperty(json, "command"); - if (!cmd || JSON_TEXT != json_getType(cmd)) - { - _anedya_interface_std_out("Error, the deploymentId property is not found."); - return ANEDYA_ERR_PARSE_ERROR; - } - const char *cmd_val = json_getValue(cmd); - strcpy(obj->command, cmd_val); - obj->command_len = strlen(cmd_val); - json_t const *dt = json_getProperty(json, "datatype"); - if (!dt || JSON_TEXT != json_getType(dt)) - { - _anedya_interface_std_out("Error, the deploymentId property is not found."); - return ANEDYA_ERR_PARSE_ERROR; - } - const char *dt_val = json_getValue(dt); - if (_anedya_strcmp(dt_val, "string") == 0) - { - // Copy data as it is - json_t const *data = json_getProperty(json, "data"); - if (!data || JSON_TEXT != json_getType(data)) - { - _anedya_interface_std_out("Error, the deploymentId property is not found."); - return ANEDYA_ERR_PARSE_ERROR; - } - const char *data_val = json_getValue(data); - strcpy(obj->data, data_val); - obj->data_len = strlen(data_val); - obj->cmd_data_type = ANEDYA_DATATYPE_STRING; + json_t const *cmd = json_getProperty(json, "command"); + if (!cmd || JSON_TEXT != json_getType(cmd)) { + _anedya_interface_std_out("Error, the deploymentId property is not found."); + return ANEDYA_ERR_PARSE_ERROR; + } + const char *cmd_val = json_getValue(cmd); + strcpy(obj->command, cmd_val); + obj->command_len = strlen(cmd_val); + json_t const *dt = json_getProperty(json, "datatype"); + if (!dt || JSON_TEXT != json_getType(dt)) { + _anedya_interface_std_out("Error, the deploymentId property is not found."); + return ANEDYA_ERR_PARSE_ERROR; + } + const char *dt_val = json_getValue(dt); + if (_anedya_strcmp(dt_val, "string") == 0) { + // Copy data as it is + json_t const *data = json_getProperty(json, "data"); + if (!data || JSON_TEXT != json_getType(data)) { + _anedya_interface_std_out( + "Error, the deploymentId property is not found."); + return ANEDYA_ERR_PARSE_ERROR; } + const char *data_val = json_getValue(data); + strcpy(obj->data, data_val); + obj->data_len = strlen(data_val); + obj->cmd_data_type = ANEDYA_DATATYPE_STRING; + } - if (_anedya_strcmp(dt_val, "binary") == 0) - { - // Copy data as it is - json_t const *data = json_getProperty(json, "data"); - if (!data || JSON_TEXT != json_getType(data)) - { - _anedya_interface_std_out("Error, the deploymentId property is not found."); - return ANEDYA_ERR_PARSE_ERROR; - } - const char *data_content = json_getValue(data); - // Decode binary data from - obj->data_len = _anedya_base64_decode((unsigned char *)data_content, obj->data); - obj->cmd_data_type = (unsigned int)ANEDYA_DATATYPE_BINARY; + if (_anedya_strcmp(dt_val, "binary") == 0) { + // Copy data as it is + json_t const *data = json_getProperty(json, "data"); + if (!data || JSON_TEXT != json_getType(data)) { + _anedya_interface_std_out( + "Error, the deploymentId property is not found."); + return ANEDYA_ERR_PARSE_ERROR; } + const char *data_content = json_getValue(data); + // Decode binary data from + obj->data_len = + _anedya_base64_decode((unsigned char *)data_content, obj->data); + obj->cmd_data_type = (unsigned int)ANEDYA_DATATYPE_BINARY; + } - json_t const *exp = json_getProperty(json, "exp"); - if (!exp || JSON_INTEGER != json_getType(exp)) - { - _anedya_interface_std_out("Error, the deploymentId property is not found."); - return ANEDYA_ERR_PARSE_ERROR; - } - obj->exp = json_getInteger(exp); - return ANEDYA_OK; + json_t const *exp = json_getProperty(json, "exp"); + if (!exp || JSON_INTEGER != json_getType(exp)) { + _anedya_interface_std_out("Error, the deploymentId property is not found."); + return ANEDYA_ERR_PARSE_ERROR; + } + obj->exp = json_getInteger(exp); + return ANEDYA_OK; } -anedya_err_t anedya_op_cmd_status_update(anedya_client_t *client, anedya_txn_t *txn, anedya_req_cmd_status_update_t *req_config) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_CMD_UPDATE_STATUS; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } +anedya_err_t +anedya_op_cmd_status_update(anedya_client_t *client, anedya_txn_t *txn, + anedya_req_cmd_status_update_t *req_config) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_CMD_UPDATE_STATUS; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION // TODO: Implement dynamic allocation #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - char uuid[37]; - _anedya_uuid_marshal(req_config->cmdId, uuid); - p = anedya_json_str(p, "commandId", uuid, &marker); - p = anedya_json_str(p, "status", req_config->status, &marker); - if (req_config->data_len > 0 && req_config->data != NULL) - { - switch (req_config->data_type) - { - case ANEDYA_DATATYPE_STRING: - p = anedya_json_str(p, "ackdata", (char *)req_config->data, &marker); - p = anedya_json_str(p, "ackdatatype", "string", &marker); - break; - case ANEDYA_DATATYPE_BINARY: - unsigned char encoded[1024]; - int encoded_len = _anedya_base64_encode(req_config->data, encoded); - p = anedya_json_nstr(p, "ackdata", (char *)encoded, encoded_len, &marker); - p = anedya_json_str(p, "ackdatatype", "binary", &marker); - break; - default: - return ANEDYA_ERR_INVALID_DATATYPE; - break; - } - } - if (req_config->data_len != 0 && req_config->data == NULL) - { - return ANEDYA_ERR_INVALID_DATA; - } - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/commands/updateStatus/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); +#endif + char uuid[37]; + _anedya_uuid_marshal(req_config->cmdId, uuid); + p = anedya_json_str(p, "commandId", uuid, &marker); + p = anedya_json_str(p, "status", req_config->status, &marker); + if (req_config->data_len > 0 && req_config->data != NULL) { + switch (req_config->data_type) { + case ANEDYA_DATATYPE_STRING: + p = anedya_json_str(p, "ackdata", (char *)req_config->data, &marker); + p = anedya_json_str(p, "ackdatatype", "string", &marker); + break; + case ANEDYA_DATATYPE_BINARY: + unsigned char encoded[1024]; + int encoded_len = _anedya_base64_encode(req_config->data, encoded); + p = anedya_json_nstr(p, "ackdata", (char *)encoded, encoded_len, &marker); + p = anedya_json_str(p, "ackdatatype", "binary", &marker); + break; + default: + return ANEDYA_ERR_INVALID_DATATYPE; + break; } - return ANEDYA_OK; + } + if (req_config->data_len != 0 && req_config->data == NULL) { + return ANEDYA_ERR_INVALID_DATA; + } + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + // Body is ready now publish it to the MQTT + char topic[100]; + // printf("Req: %s", txbuffer); + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/commands/updateStatus/json"); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/commands/updateStatus", + txbuffer, (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; } \ No newline at end of file diff --git a/src/anedya_op_getvaluestore.c b/src/anedya_op_getvaluestore.c index 02baa39..0b21357 100644 --- a/src/anedya_op_getvaluestore.c +++ b/src/anedya_op_getvaluestore.c @@ -1,286 +1,269 @@ #include "anedya_operations.h" -anedya_err_t anedya_op_valuestore_get_key(anedya_client_t *client, anedya_txn_t *txn, anedya_req_valuestore_get_key_t obj) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } +anedya_err_t anedya_op_valuestore_get_key(anedya_client_t *client, + anedya_txn_t *txn, + anedya_req_valuestore_get_key_t obj) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_VALUESTORE_GET; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_VALUESTORE_GET; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } - // Generate the JSON body + // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION - // TODO: Implement dynamic allocation + // TODO: Implement dynamic allocation #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_objOpen(p, "namespace", &marker); - p = anedya_json_str(p, "scope", obj.ns.scope, &marker); - p = anedya_json_str(p, "id", obj.ns.id, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_str(p, "key", obj.key, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); +#endif + p = anedya_json_objOpen(p, "namespace", &marker); + p = anedya_json_str(p, "scope", obj.ns.scope, &marker); + p = anedya_json_str(p, "id", obj.ns.id, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_str(p, "key", obj.key, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/valuestore/getValue/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; + // Body is ready now publish it to the MQTT + char topic[100]; + // printf("Req: %s", txbuffer); + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/valuestore/getValue/json"); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/valuestore/getValue", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; } -void _anedya_op_valuestore_handle_get_resp(anedya_client_t *client, anedya_txn_t *txn) -{ - // printf("Resp: %s\n", txn->_rxbody); - json_t mem[32]; - // Parse the json and get the txn id - json_t const *json = json_create(txn->_rxbody, mem, sizeof mem / sizeof *mem); - if (!json) - { - _anedya_interface_std_out("Error while parsing JSON body:response handler Get value store"); - return; - } - // Check if success - json_t const *success = json_getProperty(json, "success"); - if (!success || JSON_BOOLEAN != json_getType(success)) - { - _anedya_interface_std_out("Error, the success property is not found."); - } - bool s = json_getBoolean(success); - if (s == true) - { - txn->is_success = true; +void _anedya_op_valuestore_handle_get_resp(anedya_client_t *client, + anedya_txn_t *txn) { + // printf("Resp: %s\n", txn->_rxbody); + json_t mem[32]; + // Parse the json and get the txn id + json_t const *json = json_create(txn->_rxbody, mem, sizeof mem / sizeof *mem); + if (!json) { + _anedya_interface_std_out( + "Error while parsing JSON body:response handler Get value store"); + return; + } + // Check if success + json_t const *success = json_getProperty(json, "success"); + if (!success || JSON_BOOLEAN != json_getType(success)) { + _anedya_interface_std_out("Error, the success property is not found."); + } + bool s = json_getBoolean(success); + if (s == true) { + txn->is_success = true; + } else { + txn->is_success = false; + json_t const *error = json_getProperty(json, "errorcode"); + if (!error || JSON_INTEGER != json_getType(error)) { + _anedya_interface_std_out("Error, the error property is not found."); } - else - { - txn->is_success = false; - json_t const *error = json_getProperty(json, "errorcode"); - if (!error || JSON_INTEGER != json_getType(error)) - { - _anedya_interface_std_out("Error, the error property is not found."); - } - int err = (anedya_err_t)json_getInteger(error); - txn->_op_err = err; - return; + int err = (anedya_err_t)json_getInteger(error); + txn->_op_err = err; + return; + } + // Flow reaches here means, request was successful. + json_t const *namespace = json_getProperty(json, "namespace"); + if (!namespace || JSON_OBJ != json_getType(namespace)) { + _anedya_interface_std_out("Error, the namespace property is not found."); + return; + } + + json_t const *modified = json_getProperty(json, "modified"); + if (!modified || JSON_INTEGER != json_getType(modified)) { + _anedya_interface_std_out("Error, the modified property is not found."); + return; + } + + json_t const *type = json_getProperty(json, "type"); + if (!type || JSON_TEXT != json_getType(type)) { + _anedya_interface_std_out("Error, the type property is not found."); + return; + } + const char *t = (char *)json_getValue(type); + if (strcmp(t, "string") == 0) { + anedya_valuestore_obj_string_t *resp = + (anedya_valuestore_obj_string_t *)txn->response; + json_t const *scope = json_getProperty(namespace, "scope"); + if (!scope || JSON_TEXT != json_getType(scope)) { + _anedya_interface_std_out("Error, the scope property is not found."); + return; } - // Flow reaches here means, request was successful. - json_t const *namespace = json_getProperty(json, "namespace"); - if (!namespace || JSON_OBJ != json_getType(namespace)) - { - _anedya_interface_std_out("Error, the namespace property is not found."); + + resp->ns.scope = (char *)json_getValue(scope); + if (strcmp(resp->ns.scope, "global") == 0) { + json_t const *id_prop = json_getProperty(namespace, "id"); + if (!id_prop || JSON_TEXT != json_getType(id_prop)) { + _anedya_interface_std_out("Error, the id property is not found."); return; + } + const char *id = (char *)json_getValue(id_prop); + strcpy(resp->ns.id, id); } - json_t const *modified = json_getProperty(json, "modified"); - if (!modified || JSON_INTEGER != json_getType(modified)) - { - _anedya_interface_std_out("Error, the modified property is not found."); - return; + json_t const *key = json_getProperty(json, "key"); + if (!key || JSON_TEXT != json_getType(key)) { + _anedya_interface_std_out("Error, the key property is not found."); + return; } + const char *k = (char *)json_getValue(key); + strcpy(resp->key, k); - json_t const *type = json_getProperty(json, "type"); - if (!type || JSON_TEXT != json_getType(type)) - { - _anedya_interface_std_out("Error, the type property is not found."); + json_t const *value = json_getProperty(json, "value"); + if (!value || JSON_TEXT != json_getType(value)) { + _anedya_interface_std_out("Error, the value property is not found."); + return; + } + resp->value = json_getValue(value); + resp->value_len = strlen(resp->value); + resp->modified = json_getInteger(modified); + } else if (strcmp(t, "float") == 0) { + anedya_valuestore_obj_float_t *resp = + (anedya_valuestore_obj_float_t *)txn->response; + json_t const *scope = json_getProperty(namespace, "scope"); + if (!scope || JSON_TEXT != json_getType(scope)) { + _anedya_interface_std_out("Error, the scope property is not found."); + return; + } + resp->ns.scope = (char *)json_getValue(scope); + if (strcmp(resp->ns.scope, "global") == 0) { + json_t const *id_prop = json_getProperty(namespace, "id"); + if (!id_prop || JSON_TEXT != json_getType(id_prop)) { + _anedya_interface_std_out("Error, the id property is not found."); return; + } + const char *id = (char *)json_getValue(id_prop); + strcpy(resp->ns.id, id); } - const char *t = (char *)json_getValue(type); - if (strcmp(t, "string") == 0) - { - anedya_valuestore_obj_string_t *resp = (anedya_valuestore_obj_string_t *)txn->response; - json_t const *scope = json_getProperty(namespace, "scope"); - if (!scope || JSON_TEXT != json_getType(scope)) - { - _anedya_interface_std_out("Error, the scope property is not found."); - return; - } - - resp->ns.scope = (char *)json_getValue(scope); - if (strcmp(resp->ns.scope, "global") == 0) - { - json_t const *id_prop = json_getProperty(namespace, "id"); - if (!id_prop || JSON_TEXT != json_getType(id_prop)) - { - _anedya_interface_std_out("Error, the id property is not found."); - return; - } - const char *id = (char *)json_getValue(id_prop); - strcpy(resp->ns.id, id); - } - - json_t const *key = json_getProperty(json, "key"); - if (!key || JSON_TEXT != json_getType(key)) - { - _anedya_interface_std_out("Error, the key property is not found."); - return; - } - const char *k = (char *)json_getValue(key); - strcpy(resp->key, k); - json_t const *value = json_getProperty(json, "value"); - if (!value || JSON_TEXT != json_getType(value)) - { - _anedya_interface_std_out("Error, the value property is not found."); - return; - } - resp->value = json_getValue(value); - resp->value_len = strlen(resp->value); - resp->modified = json_getInteger(modified); + json_t const *key = json_getProperty(json, "key"); + if (!key || JSON_TEXT != json_getType(key)) { + _anedya_interface_std_out("Error, the key property is not found."); + return; } - else if (strcmp(t, "float") == 0) - { - anedya_valuestore_obj_float_t *resp = (anedya_valuestore_obj_float_t *)txn->response; - json_t const *scope = json_getProperty(namespace, "scope"); - if (!scope || JSON_TEXT != json_getType(scope)) - { - _anedya_interface_std_out("Error, the scope property is not found."); - return; - } - resp->ns.scope = (char *)json_getValue(scope); - if (strcmp(resp->ns.scope, "global") == 0) - { - json_t const *id_prop = json_getProperty(namespace, "id"); - if (!id_prop || JSON_TEXT != json_getType(id_prop)) - { - _anedya_interface_std_out("Error, the id property is not found."); - return; - } - const char *id = (char *)json_getValue(id_prop); - strcpy(resp->ns.id, id); - } + const char *k = (char *)json_getValue(key); + strcpy(resp->key, k); - json_t const *key = json_getProperty(json, "key"); - if (!key || JSON_TEXT != json_getType(key)) - { - _anedya_interface_std_out("Error, the key property is not found."); - return; - } - const char *k = (char *)json_getValue(key); - strcpy(resp->key, k); - - json_t const *value = json_getProperty(json, "value"); - jsonType_t val_type = json_getType(value); - if (!value || (JSON_REAL != val_type && JSON_INTEGER != val_type)) - { - _anedya_interface_std_out("Error, the value property is not found."); - return; - } - if (val_type == JSON_REAL) - { - resp->value = json_getReal(value); - } - if (val_type == JSON_INTEGER) - { - resp->value = (float)json_getInteger(value); - } + json_t const *value = json_getProperty(json, "value"); + jsonType_t val_type = json_getType(value); + if (!value || (JSON_REAL != val_type && JSON_INTEGER != val_type)) { + _anedya_interface_std_out("Error, the value property is not found."); + return; + } + if (val_type == JSON_REAL) { + resp->value = json_getReal(value); + } + if (val_type == JSON_INTEGER) { + resp->value = (float)json_getInteger(value); + } - resp->modified = json_getInteger(modified); + resp->modified = json_getInteger(modified); + } else if (strcmp(t, "binary") == 0) { + anedya_valuestore_obj_bin_t *resp = + (anedya_valuestore_obj_bin_t *)txn->response; + json_t const *scope = json_getProperty(namespace, "scope"); + if (!scope || JSON_TEXT != json_getType(scope)) { + _anedya_interface_std_out("Error, the scope property is not found."); + return; + } + resp->ns.scope = (char *)json_getValue(scope); + if (strcmp(resp->ns.scope, "global") == 0) { + json_t const *id_prop = json_getProperty(namespace, "id"); + if (!id_prop || JSON_TEXT != json_getType(id_prop)) { + _anedya_interface_std_out("Error, the id property is not found."); + return; + } + const char *id = (char *)json_getValue(id_prop); + strcpy(resp->ns.id, id); } - else if (strcmp(t, "binary") == 0) - { - anedya_valuestore_obj_bin_t *resp = (anedya_valuestore_obj_bin_t *)txn->response; - json_t const *scope = json_getProperty(namespace, "scope"); - if (!scope || JSON_TEXT != json_getType(scope)) - { - _anedya_interface_std_out("Error, the scope property is not found."); - return; - } - resp->ns.scope = (char *)json_getValue(scope); - if (strcmp(resp->ns.scope, "global") == 0) - { - json_t const *id_prop = json_getProperty(namespace, "id"); - if (!id_prop || JSON_TEXT != json_getType(id_prop)) - { - _anedya_interface_std_out("Error, the id property is not found."); - return; - } - const char *id = (char *)json_getValue(id_prop); - strcpy(resp->ns.id, id); - } - json_t const *key = json_getProperty(json, "key"); - if (!key || JSON_TEXT != json_getType(key)) - { - _anedya_interface_std_out("Error, the key property is not found."); - return; - } - const char *k = (char *)json_getValue(key); - strcpy(resp->key, k); + json_t const *key = json_getProperty(json, "key"); + if (!key || JSON_TEXT != json_getType(key)) { + _anedya_interface_std_out("Error, the key property is not found."); + return; + } + const char *k = (char *)json_getValue(key); + strcpy(resp->key, k); - json_t const *value = json_getProperty(json, "value"); - if (!value || JSON_TEXT != json_getType(value)) - { - _anedya_interface_std_out("Error, the value property is not found."); - return; - } - const char *v = json_getValue(value); - resp->value = (char *)v; - resp->value_len = strlen(resp->value); - resp->modified = json_getInteger(modified); + json_t const *value = json_getProperty(json, "value"); + if (!value || JSON_TEXT != json_getType(value)) { + _anedya_interface_std_out("Error, the value property is not found."); + return; + } + const char *v = json_getValue(value); + resp->value = (char *)v; + resp->value_len = strlen(resp->value); + resp->modified = json_getInteger(modified); + } else if (strcmp(t, "boolean") == 0) { + anedya_valuestore_obj_bool_t *resp = + (anedya_valuestore_obj_bool_t *)txn->response; + json_t const *scope = json_getProperty(namespace, "scope"); + if (!scope || JSON_TEXT != json_getType(scope)) { + _anedya_interface_std_out("Error, the scope property is not found."); + return; + } + resp->ns.scope = (char *)json_getValue(scope); + if (strcmp(resp->ns.scope, "global") == 0) { + json_t const *id_prop = json_getProperty(namespace, "id"); + if (!id_prop || JSON_TEXT != json_getType(id_prop)) { + _anedya_interface_std_out("Error, the id property is not found."); + return; + } + const char *id = (char *)json_getValue(id_prop); + strcpy(resp->ns.id, id); } - else if (strcmp(t, "boolean") == 0) - { - anedya_valuestore_obj_bool_t *resp = (anedya_valuestore_obj_bool_t *)txn->response; - json_t const *scope = json_getProperty(namespace, "scope"); - if (!scope || JSON_TEXT != json_getType(scope)) - { - _anedya_interface_std_out("Error, the scope property is not found."); - return; - } - resp->ns.scope = (char *)json_getValue(scope); - if (strcmp(resp->ns.scope, "global") == 0) - { - json_t const *id_prop = json_getProperty(namespace, "id"); - if (!id_prop || JSON_TEXT != json_getType(id_prop)) - { - _anedya_interface_std_out("Error, the id property is not found."); - return; - } - const char *id = (char *)json_getValue(id_prop); - strcpy(resp->ns.id, id); - } - json_t const *key = json_getProperty(json, "key"); - if (!key || JSON_TEXT != json_getType(key)) - { - _anedya_interface_std_out("Error, the key property is not found."); - return; - } - const char *k = (char *)json_getValue(key); - strcpy(resp->key, k); + json_t const *key = json_getProperty(json, "key"); + if (!key || JSON_TEXT != json_getType(key)) { + _anedya_interface_std_out("Error, the key property is not found."); + return; + } + const char *k = (char *)json_getValue(key); + strcpy(resp->key, k); - json_t const *value = json_getProperty(json, "value"); - if (!value || JSON_BOOLEAN != json_getType(value)) - { - _anedya_interface_std_out("Error, the value property is not found."); - return; - } - resp->value = json_getBoolean(value); - resp->modified = json_getInteger(modified); + json_t const *value = json_getProperty(json, "value"); + if (!value || JSON_BOOLEAN != json_getType(value)) { + _anedya_interface_std_out("Error, the value property is not found."); + return; } + resp->value = json_getBoolean(value); + resp->modified = json_getInteger(modified); + } - return; + return; } diff --git a/src/anedya_op_heartbeat.c b/src/anedya_op_heartbeat.c index e93e35f..a8cdb75 100644 --- a/src/anedya_op_heartbeat.c +++ b/src/anedya_op_heartbeat.c @@ -1,43 +1,56 @@ #include "anedya_operations.h" -anedya_err_t anedya_device_send_heartbeat(anedya_client_t *client, anedya_txn_t *txn) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_HEARTBEAT; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } +anedya_err_t anedya_device_send_heartbeat(anedya_client_t *client, + anedya_txn_t *txn) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_HEARTBEAT; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION // TODO: Implement dynamic allocation #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - char topic[100]; + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + char topic[100]; - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/heartbeat/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/heartbeat/json"); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/heartbeat", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; } \ No newline at end of file diff --git a/src/anedya_op_log.c b/src/anedya_op_log.c index c11fb1e..7a13837 100644 --- a/src/anedya_op_log.c +++ b/src/anedya_op_log.c @@ -1,51 +1,65 @@ #include "anedya_operations.h" -anedya_err_t anedya_op_submit_log(anedya_client_t *client, anedya_txn_t *txn, char *log, unsigned int log_len, unsigned long long timestamp_ms) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_SUBMIT_LOG; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } +anedya_err_t anedya_op_submit_log(anedya_client_t *client, anedya_txn_t *txn, + char *log, unsigned int log_len, + unsigned long long timestamp_ms) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_SUBMIT_LOG; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION // TODO: Implement dynamic allocation #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_arrOpen(p, "data", &marker); - p = anedya_json_objOpen(p, NULL, &marker); - p = anedya_json_nstr(p, "log", log, log_len, &marker); - p = anedya_json_verylong(p, "timestamp", timestamp_ms, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_arrClose(p, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); + p = anedya_json_arrOpen(p, "data", &marker); + p = anedya_json_objOpen(p, NULL, &marker); + p = anedya_json_nstr(p, "log", log, log_len, &marker); + p = anedya_json_verylong(p, "timestamp", timestamp_ms, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_arrClose(p, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/logs/submitLogs/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; + // Body is ready now publish it to the MQTT + char topic[100]; + // printf("Req: %s", txbuffer); + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/logs/submitLogs/json"); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/logs/submitLogs", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; } \ No newline at end of file diff --git a/src/anedya_op_setvaluestore.c b/src/anedya_op_setvaluestore.c index 9b037be..81f7961 100644 --- a/src/anedya_op_setvaluestore.c +++ b/src/anedya_op_setvaluestore.c @@ -1,220 +1,283 @@ #include "anedya_operations.h" +#include #include #include #include -#include -anedya_err_t anedya_op_valuestore_set_float(anedya_client_t *client, anedya_txn_t *txn, const char *key, float value) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_VALUESTORE_SET; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } +anedya_err_t anedya_op_valuestore_set_float(anedya_client_t *client, + anedya_txn_t *txn, const char *key, + float value) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_VALUESTORE_SET; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION // TODO: Implement dynamic allocation #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_str(p, "key", key, &marker); - p = anedya_json_double(p, "value", value, &marker); - p = anedya_json_str(p, "type", "float", &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/valuestore/setValue/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); +#endif + p = anedya_json_str(p, "key", key, &marker); + p = anedya_json_double(p, "value", value, &marker); + p = anedya_json_str(p, "type", "float", &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + + // Body is ready now publish it to the MQTT + char topic[100]; + // printf("Req: %s", txbuffer); + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/valuestore/setValue/json"); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/valuestore/setValue", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; } -anedya_err_t anedya_op_valuestore_set_string(anedya_client_t *client, anedya_txn_t *txn, const char *key, const char *value, size_t value_len) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - - // Check the length of the value - size_t value_length = strlen(value); // todo : have to remove strlen - if (value_length != value_len) - { - return ANEDYA_ERR_VALUE_MISMATCH_LEN; - } - if (value_length > 1000) - { - return ANEDYA_ERR_VALUE_TOO_LONG; - } - - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_VALUESTORE_SET; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } - - // Generate the JSON body +anedya_err_t anedya_op_valuestore_set_string(anedya_client_t *client, + anedya_txn_t *txn, const char *key, + const char *value, + size_t value_len) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + + // Check the length of the value + size_t value_length = strlen(value); // todo : have to remove strlen + if (value_length != value_len) { + return ANEDYA_ERR_VALUE_MISMATCH_LEN; + } + if (value_length > 1000) { + return ANEDYA_ERR_VALUE_TOO_LONG; + } + + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_VALUESTORE_SET; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } + + // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION - // TODO: Implement dynamic allocation + // TODO: Implement dynamic allocation +#endif + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_str(p, "key", key, &marker); - p = anedya_json_str(p, "value", value, &marker); - p = anedya_json_str(p, "type", "string", &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/valuestore/setValue/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; + p = anedya_json_str(p, "key", key, &marker); + p = anedya_json_str(p, "value", value, &marker); + p = anedya_json_str(p, "type", "string", &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + + // Body is ready now publish it to the MQTT + char topic[100]; + // printf("Req: %s", txbuffer); + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/valuestore/setValue/json"); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/valuestore/setValue", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; } -anedya_err_t anedya_op_valuestore_set_bool(anedya_client_t *client, anedya_txn_t *txn, const char *key, bool value) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_VALUESTORE_SET; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } +anedya_err_t anedya_op_valuestore_set_bool(anedya_client_t *client, + anedya_txn_t *txn, const char *key, + bool value) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_VALUESTORE_SET; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION // TODO: Implement dynamic allocation #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_str(p, "key", key, &marker); - p = anedya_json_bool(p, "value", value, &marker); - p = anedya_json_str(p, "type", "boolean", &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/valuestore/setValue/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); +#endif + p = anedya_json_str(p, "key", key, &marker); + p = anedya_json_bool(p, "value", value, &marker); + p = anedya_json_str(p, "type", "boolean", &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + + // Body is ready now publish it to the MQTT + char topic[100]; + // printf("Req: %s", txbuffer); + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/valuestore/setValue/json"); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/valuestore/setValue", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; } -anedya_err_t anedya_op_valuestore_set_bin(anedya_client_t *client, anedya_txn_t *txn, const char *key, const char *base64_value, size_t base64_value_len) -{ - // Check if the client is connected - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - - // Check the length of the Base64 value - if (base64_value_len > 1000) - { - return ANEDYA_ERR_VALUE_TOO_LONG; - } - - // Check the length of the value - size_t value_length = strlen(base64_value); // todo : have to remove strlen - if (value_length != base64_value_len) - { - return ANEDYA_ERR_VALUE_MISMATCH_LEN; - } - - // If connected, create a transaction - txn->_op = ANEDYA_OP_VALUESTORE_SET; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } - - // Generate the JSON body +anedya_err_t anedya_op_valuestore_set_bin(anedya_client_t *client, + anedya_txn_t *txn, const char *key, + const char *base64_value, + size_t base64_value_len) { + // Check if the client is connected + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + + // Check the length of the Base64 value + if (base64_value_len > 1000) { + return ANEDYA_ERR_VALUE_TOO_LONG; + } + + // Check the length of the value + size_t value_length = strlen(base64_value); // todo : have to remove strlen + if (value_length != base64_value_len) { + return ANEDYA_ERR_VALUE_MISMATCH_LEN; + } + + // If connected, create a transaction + txn->_op = ANEDYA_OP_VALUESTORE_SET; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } + + // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION - // TODO: Implement dynamic allocation + // TODO: Implement dynamic allocation +#endif + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_str(p, "key", key, &marker); - p = anedya_json_str(p, "value", base64_value, &marker); // Use the provided Base64 value - p = anedya_json_str(p, "type", "binary", &marker); // Indicate that the value is Base64-encoded - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - - // Body is ready; now publish it to MQTT - char topic[100]; - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/valuestore/setValue/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - - return ANEDYA_OK; + p = anedya_json_str(p, "key", key, &marker); + p = anedya_json_str(p, "value", base64_value, + &marker); // Use the provided Base64 value + p = anedya_json_str(p, "type", "binary", + &marker); // Indicate that the value is Base64-encoded + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + + // Body is ready; now publish it to MQTT + char topic[100]; + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/valuestore/setValue/json"); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/valuestore/setValue", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; } diff --git a/src/anedya_op_submitdata.c b/src/anedya_op_submitdata.c index a4d092e..aab4abe 100644 --- a/src/anedya_op_submitdata.c +++ b/src/anedya_op_submitdata.c @@ -1,157 +1,242 @@ -#include "anedya_operations.h" #include "anedya_op_submitdata.h" +#include "anedya_operations.h" -anedya_err_t anedya_op_submit_float_req(anedya_client_t *client, anedya_txn_t *txn, const char *variable_identifier, float value, uint64_t timestamp_ms) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_SUBMIT_DATA; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } -// Generate the JSON body +#ifdef ANEDYA_CONNECTION_METHOD_HTTP +static anedya_err_t _anedya_http_submit_data(anedya_client_t *client, + anedya_txn_t *txn, + const char *txbuffer) { #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; #endif -#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_arrOpen(p, "data", &marker); - p = anedya_json_objOpen(p, NULL, &marker); - p = anedya_json_str(p, "variable", variable_identifier, &marker); - p = anedya_json_double(p, "value", value, &marker); - p = anedya_json_verylong(p, "timestamp", timestamp_ms, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_arrClose(p, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/submitdata/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } + int resp_len = 0; + + anedya_err_t err = _anedya_interface_http_post( + client, "/v1/submitData", txbuffer, (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + + if (err != ANEDYA_OK) { + txn->is_complete = true; + txn->is_success = false; + txn->_op_err = err; + _anedya_txn_complete(client, txn); return ANEDYA_OK; + } + strcpy(txn->_rxbody, resp_buf); + txn->_rx_len = resp_len + 1; + + if (txn->_rx_len > ANEDYA_RX_BUFFER_SIZE) { + txn->_op_err = ANEDYA_ERR_RX_BUFFER_OVERFLOW; + txn->is_complete = true; + txn->is_success = false; + _anedya_txn_complete(client, txn); + return ANEDYA_OK; + } + + // Call the specific parser for Submit Data operations + _anedya_device_handle_generic_resp(client, txn); + + // Mark the transaction as complete + txn->is_complete = true; + _anedya_txn_complete(client, txn); + + return ANEDYA_OK; } +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + +/* ──────────────────────────────────────────────────────────────────────────── + * anedya_op_submit_float_req + * ─────────────────────────────────────────────────────────────────────────── + */ +anedya_err_t anedya_op_submit_float_req(anedya_client_t *client, + anedya_txn_t *txn, + const char *variable_identifier, + float value, uint64_t timestamp_ms) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_SUBMIT_DATA; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } -anedya_err_t anedya_op_submit_geo_req(anedya_client_t *client, anedya_txn_t *txn, const char *variable_identifier, anedya_geo_data_t *value, uint64_t timestamp_ms) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_SUBMIT_DATA; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } -// Generate the JSON body + // Generate the JSON body (identical for both MQTT and HTTP) #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_arrOpen(p, "data", &marker); - p = anedya_json_objOpen(p, NULL, &marker); - p = anedya_json_str(p, "variable", variable_identifier, &marker); - p = anedya_json_objOpen(p, "value", &marker); - p = anedya_json_double(p, "lat", value->lat, &marker); - p = anedya_json_double(p, "long", value->lon, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_verylong(p, "timestamp", timestamp_ms, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_arrClose(p, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/submitdata/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; + // TODO: Implement dynamic allocation +#endif + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); +#endif + p = anedya_json_arrOpen(p, "data", &marker); + p = anedya_json_objOpen(p, NULL, &marker); + p = anedya_json_str(p, "variable", variable_identifier, &marker); + p = anedya_json_double(p, "value", value, &marker); + p = anedya_json_verylong(p, "timestamp", timestamp_ms, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_arrClose(p, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + // Send via MQTT + char topic[100]; + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/submitdata/json"); + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + // Send via HTTP (synchronous) + err = _anedya_http_submit_data(client, txn, txbuffer); + if (err != ANEDYA_OK) { + return err; + } +#endif + + return ANEDYA_OK; } -anedya_err_t anedya_op_submit_status_req(anedya_client_t *client, anedya_txn_t *txn, const char *variable_identifier, const char *value, uint64_t timestamp_ms) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_SUBMIT_DATA; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } -// Generate the JSON body +/* ──────────────────────────────────────────────────────────────────────────── + * anedya_op_submit_geo_req + * ─────────────────────────────────────────────────────────────────────────── + */ +anedya_err_t anedya_op_submit_geo_req(anedya_client_t *client, + anedya_txn_t *txn, + const char *variable_identifier, + anedya_geo_data_t *value, + uint64_t timestamp_ms) { + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + txn->_op = ANEDYA_OP_SUBMIT_DATA; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } + #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION -// TODO: Implement dynamic allocation -#endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_arrOpen(p, "data", &marker); - p = anedya_json_objOpen(p, NULL, &marker); - p = anedya_json_str(p, "variable", variable_identifier, &marker); - p = anedya_json_str(p, "value", value, &marker); - p = anedya_json_verylong(p, "timestamp", timestamp_ms, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_arrClose(p, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/submitdata/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; + // TODO: Implement dynamic allocation +#endif + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); +#endif + p = anedya_json_arrOpen(p, "data", &marker); + p = anedya_json_objOpen(p, NULL, &marker); + p = anedya_json_str(p, "variable", variable_identifier, &marker); + p = anedya_json_objOpen(p, "value", &marker); + p = anedya_json_double(p, "lat", value->lat, &marker); + p = anedya_json_double(p, "long", value->lon, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_verylong(p, "timestamp", timestamp_ms, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_arrClose(p, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + char topic[100]; + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/submitdata/json"); + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + err = _anedya_http_submit_data(client, txn, txbuffer); + if (err != ANEDYA_OK) { + return err; + } +#endif + + return ANEDYA_OK; +} + +/* ──────────────────────────────────────────────────────────────────────────── + * anedya_op_submit_status_req + * ─────────────────────────────────────────────────────────────────────────── + */ +anedya_err_t anedya_op_submit_status_req(anedya_client_t *client, + anedya_txn_t *txn, + const char *variable_identifier, + const char *value, + uint64_t timestamp_ms) { + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + txn->_op = ANEDYA_OP_SUBMIT_DATA; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } + +#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); +#endif +#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION + // TODO: Implement dynamic allocation +#endif + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); +#endif +#endif + p = anedya_json_arrOpen(p, "data", &marker); + p = anedya_json_objOpen(p, NULL, &marker); + p = anedya_json_str(p, "variable", variable_identifier, &marker); + p = anedya_json_str(p, "value", value, &marker); + p = anedya_json_verylong(p, "timestamp", timestamp_ms, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_arrClose(p, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + char topic[100]; + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/submitdata/json"); + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + err = _anedya_http_submit_data(client, txn, txbuffer); + if (err != ANEDYA_OK) { + return err; + } +#endif + + return ANEDYA_OK; } \ No newline at end of file diff --git a/src/anedya_op_submitevent.c b/src/anedya_op_submitevent.c index 6d2381a..3795756 100644 --- a/src/anedya_op_submitevent.c +++ b/src/anedya_op_submitevent.c @@ -1,53 +1,69 @@ #include "anedya_operations.h" -anedya_err_t anedya_op_submit_event(anedya_client_t *client, anedya_txn_t *txn, anedya_req_submit_event_t *req_config) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_SUBMIT_EVENT; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } +anedya_err_t anedya_op_submit_event(anedya_client_t *client, anedya_txn_t *txn, + anedya_req_submit_event_t *req_config) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_SUBMIT_EVENT; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION // TODO: Implement dynamic allocation #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_nstr(p, "eventType", req_config->event_type, strlen(req_config->event_type), &marker); - p = anedya_json_verylong(p, "timestamp", req_config->timestamp, &marker); - p = anedya_json_objOpen(p, "data", &marker); - for (int i = 0; i < req_config->data_count; i++) - { - p = anedya_json_nstr(p, req_config->data[i].key, req_config->data[i].value, strlen(req_config->data[i].value), &marker); - } - p = anedya_json_objClose(p, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); +#endif + p = anedya_json_nstr(p, "eventType", req_config->event_type, + strlen(req_config->event_type), &marker); + p = anedya_json_verylong(p, "timestamp", req_config->timestamp, &marker); + p = anedya_json_objOpen(p, "data", &marker); + for (int i = 0; i < req_config->data_count; i++) { + p = anedya_json_nstr(p, req_config->data[i].key, req_config->data[i].value, + strlen(req_config->data[i].value), &marker); + } + p = anedya_json_objClose(p, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + + // Body is ready now publish it to the MQTT + char topic[100]; + // printf("Req: %s", txbuffer); + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/events/submit/json"); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/events/submit", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/events/submit/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; + return ANEDYA_OK; } \ No newline at end of file diff --git a/src/anedya_op_valuestore_delete.c b/src/anedya_op_valuestore_delete.c index 6ce0787..d95e916 100644 --- a/src/anedya_op_valuestore_delete.c +++ b/src/anedya_op_valuestore_delete.c @@ -1,46 +1,61 @@ #include "anedya_operations.h" -anedya_err_t anedya_op_valuestore_delete(anedya_client_t *client, anedya_txn_t *txn, const char *key) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_VALUESTORE_DELETE; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } +anedya_err_t anedya_op_valuestore_delete(anedya_client_t *client, + anedya_txn_t *txn, const char *key) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_VALUESTORE_DELETE; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION // TODO: Implement dynamic allocation #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_str(p, "key", key, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); +#endif + p = anedya_json_str(p, "key", key, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + + // Body is ready now publish it to the MQTT + char topic[100]; + // printf("Req: %s", txbuffer); + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/valuestore/delete/json"); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/valuestore/delete", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/valuestore/delete/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; + return ANEDYA_OK; } diff --git a/src/anedya_op_valuestore_listobj.c b/src/anedya_op_valuestore_listobj.c index e4aea2f..e5d7dbd 100644 --- a/src/anedya_op_valuestore_listobj.c +++ b/src/anedya_op_valuestore_listobj.c @@ -1,192 +1,197 @@ #include "anedya_operations.h" -anedya_err_t anedya_op_valuestore_list_obj(anedya_client_t *client, anedya_txn_t *txn, anedya_req_valuestore_list_obj_t obj) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_VALUESTORE_GET_LIST; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } - - // Generate the JSON body +anedya_err_t +anedya_op_valuestore_list_obj(anedya_client_t *client, anedya_txn_t *txn, + anedya_req_valuestore_list_obj_t obj) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_VALUESTORE_GET_LIST; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } + + // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION - // TODO: Implement dynamic allocation + // TODO: Implement dynamic allocation #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_int(p, "limit", obj.limit, &marker); - p = anedya_json_int(p, "offset", obj.offset, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/valuestore/scan/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); +#endif + p = anedya_json_int(p, "limit", obj.limit, &marker); + p = anedya_json_int(p, "offset", obj.offset, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + + // Body is ready now publish it to the MQTT + char topic[100]; + // printf("Req: %s", txbuffer); + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/valuestore/scan/json"); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/valuestore/scan", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; } -void _anedya_op_valuestore_handle_list_obj_resp(anedya_client_t *client, anedya_txn_t *txn) -{ - - // printf("Resp: %s\n", txn->_rxbody); - json_t mem[32]; - // Parse the json and get the txn id - json_t const *json = json_create(txn->_rxbody, mem, sizeof mem / sizeof *mem); - if (!json) - { - _anedya_interface_std_out("Error while parsing JSON body:response handler Get list value store"); - return; +void _anedya_op_valuestore_handle_list_obj_resp(anedya_client_t *client, + anedya_txn_t *txn) { + + // printf("Resp: %s\n", txn->_rxbody); + json_t mem[32]; + // Parse the json and get the txn id + json_t const *json = json_create(txn->_rxbody, mem, sizeof mem / sizeof *mem); + if (!json) { + _anedya_interface_std_out( + "Error while parsing JSON body:response handler Get list value store"); + return; + } + // Check if success + json_t const *success = json_getProperty(json, "success"); + if (!success || JSON_BOOLEAN != json_getType(success)) { + _anedya_interface_std_out("Error, the success property is not found."); + } + bool s = json_getBoolean(success); + if (s == true) { + txn->is_success = true; + } else { + txn->is_success = false; + json_t const *error = json_getProperty(json, "errorcode"); + if (!error || JSON_INTEGER != json_getType(error)) { + _anedya_interface_std_out("Error, the error property is not found."); + } + int err = (anedya_err_t)json_getInteger(error); + txn->_op_err = err; + return; + } + + // Flow reaches here means, request was successful. + anedya_op_valuestore_list_obj_resp_t *resp = + (anedya_op_valuestore_list_obj_resp_t *)txn->response; + + json_t const *totalcount_prop = json_getProperty(json, "count"); + if (!totalcount_prop || JSON_INTEGER != json_getType(totalcount_prop)) { + _anedya_interface_std_out("Error, the totalcount property is not found."); + return; + } + resp->totalcount = (int)json_getInteger(totalcount_prop); + + json_t const *count_prop = json_getProperty(json, "count"); + if (!count_prop || JSON_INTEGER != json_getType(count_prop)) { + _anedya_interface_std_out("Error, the count property is not found."); + return; + } + resp->count = (int)json_getInteger(count_prop); + + json_t const *next_prop = json_getProperty(json, "next"); + if (!next_prop || JSON_INTEGER != json_getType(next_prop)) { + _anedya_interface_std_out("Error, the next property is not found."); + return; + } + resp->next = (int)json_getInteger(next_prop); + // printf("Next: %d\n", resp->next); + + json_t const *list_prop = json_getProperty(json, "keys"); + if (!list_prop || JSON_ARRAY != json_getType(list_prop)) { + _anedya_interface_std_out("Error, the keys property is not found."); + return; + } + + json_t const *keys_prop = json_getChild(list_prop); + int i = 0; + while (keys_prop && i < resp->count) { + if (JSON_OBJ != json_getType(keys_prop)) { + _anedya_interface_std_out("Error, the key property is not an object."); + return; } - // Check if success - json_t const *success = json_getProperty(json, "success"); - if (!success || JSON_BOOLEAN != json_getType(success)) - { - _anedya_interface_std_out("Error, the success property is not found."); + + json_t const *namespace_prop = json_getProperty(keys_prop, "namespace"); + if (!namespace_prop || JSON_OBJ != json_getType(namespace_prop)) { + _anedya_interface_std_out( + "Error, the namespace property is not found or is not text."); + return; } - bool s = json_getBoolean(success); - if (s == true) - { - txn->is_success = true; + json_t const *scope_prop = json_getProperty(namespace_prop, "scope"); + if (!scope_prop || JSON_TEXT != json_getType(scope_prop)) { + _anedya_interface_std_out( + "Error, the scope property is not found or is not text."); + return; } - else - { - txn->is_success = false; - json_t const *error = json_getProperty(json, "errorcode"); - if (!error || JSON_INTEGER != json_getType(error)) - { - _anedya_interface_std_out("Error, the error property is not found."); - } - int err = (anedya_err_t)json_getInteger(error); - txn->_op_err = err; - return; + resp->keys[i].ns.scope = (char *)json_getValue(scope_prop); + + json_t const *id_prop = json_getProperty(namespace_prop, "id"); + if (!id_prop || JSON_TEXT != json_getType(id_prop)) { + _anedya_interface_std_out( + "Error, the id property is not found or is not text."); + const char *id = ""; + snprintf(resp->keys[i].ns.id, sizeof(resp->keys[i].ns.id), "%s", id); + } else { + const char *id = (const char *)json_getValue(id_prop); + snprintf(resp->keys[i].ns.id, sizeof(resp->keys[i].ns.id), "%s", id); } - // Flow reaches here means, request was successful. - anedya_op_valuestore_list_obj_resp_t *resp = (anedya_op_valuestore_list_obj_resp_t *)txn->response; - - json_t const *totalcount_prop = json_getProperty(json, "count"); - if (!totalcount_prop || JSON_INTEGER != json_getType(totalcount_prop)) - { - _anedya_interface_std_out("Error, the totalcount property is not found."); - return; + json_t const *key_prop = json_getProperty(keys_prop, "key"); + if (!key_prop || JSON_TEXT != json_getType(key_prop)) { + _anedya_interface_std_out( + "Error, the key property is not found or is not text."); + return; } - resp->totalcount = (int)json_getInteger(totalcount_prop); - json_t const *count_prop = json_getProperty(json, "count"); - if (!count_prop || JSON_INTEGER != json_getType(count_prop)) - { - _anedya_interface_std_out("Error, the count property is not found."); - return; - } - resp->count = (int)json_getInteger(count_prop); + const char *key = (const char *)json_getValue(key_prop); + snprintf(resp->keys[i].key, sizeof(resp->keys[i].key), "%s", key); - json_t const *next_prop = json_getProperty(json, "next"); - if (!next_prop || JSON_INTEGER != json_getType(next_prop)) - { - _anedya_interface_std_out("Error, the next property is not found."); - return; + json_t const *type_prop = json_getProperty(keys_prop, "type"); + if (!type_prop || JSON_TEXT != json_getType(type_prop)) { + _anedya_interface_std_out( + "Error, the type property is not found or is not text."); + return; } - resp->next = (int)json_getInteger(next_prop); - // printf("Next: %d\n", resp->next); - - json_t const *list_prop = json_getProperty(json, "keys"); - if (!list_prop || JSON_ARRAY != json_getType(list_prop)) - { - _anedya_interface_std_out("Error, the keys property is not found."); - return; + const char *type = (char *)json_getValue(type_prop); + snprintf(resp->keys[i].type, sizeof(resp->keys[i].type), "%s", type); + + json_t const *modified_prop = json_getProperty(keys_prop, "modified"); + if (!modified_prop || JSON_INTEGER != json_getType(modified_prop)) { + _anedya_interface_std_out( + "Error, the modified property is not found or is not text."); + return; } + resp->keys[i].modified = (int64_t)json_getInteger(modified_prop); - json_t const *keys_prop = json_getChild(list_prop); - int i = 0; - while (keys_prop && i < resp->count) - { - if (JSON_OBJ != json_getType(keys_prop)) - { - _anedya_interface_std_out("Error, the key property is not an object."); - return; - } - - json_t const *namespace_prop = json_getProperty(keys_prop, "namespace"); - if (!namespace_prop || JSON_OBJ != json_getType(namespace_prop)) - { - _anedya_interface_std_out("Error, the namespace property is not found or is not text."); - return; - } - json_t const *scope_prop = json_getProperty(namespace_prop, "scope"); - if (!scope_prop || JSON_TEXT != json_getType(scope_prop)) - { - _anedya_interface_std_out("Error, the scope property is not found or is not text."); - return; - } - resp->keys[i].ns.scope = (char *)json_getValue(scope_prop); - - json_t const *id_prop = json_getProperty(namespace_prop, "id"); - if (!id_prop || JSON_TEXT != json_getType(id_prop)) - { - _anedya_interface_std_out("Error, the id property is not found or is not text."); - const char *id = ""; - snprintf(resp->keys[i].ns.id, sizeof(resp->keys[i].ns.id), "%s", id); - } - else - { - const char *id = (const char *)json_getValue(id_prop); - snprintf(resp->keys[i].ns.id, sizeof(resp->keys[i].ns.id), "%s", id); - } - - json_t const *key_prop = json_getProperty(keys_prop, "key"); - if (!key_prop || JSON_TEXT != json_getType(key_prop)) - { - _anedya_interface_std_out("Error, the key property is not found or is not text."); - return; - } - - const char *key = (const char *)json_getValue(key_prop); - snprintf(resp->keys[i].key, sizeof(resp->keys[i].key), "%s", key); - - json_t const *type_prop = json_getProperty(keys_prop, "type"); - if (!type_prop || JSON_TEXT != json_getType(type_prop)) - { - _anedya_interface_std_out("Error, the type property is not found or is not text."); - return; - } - const char *type = (char *)json_getValue(type_prop); - snprintf(resp->keys[i].type, sizeof(resp->keys[i].type), "%s", type); - - json_t const *modified_prop = json_getProperty(keys_prop, "modified"); - if (!modified_prop || JSON_INTEGER != json_getType(modified_prop)) - { - _anedya_interface_std_out("Error, the modified property is not found or is not text."); - return; - } - resp->keys[i].modified = (int64_t)json_getInteger(modified_prop); - - keys_prop = json_getSibling(keys_prop); // Move to the next sibling in the array - i++; - } + keys_prop = + json_getSibling(keys_prop); // Move to the next sibling in the array + i++; + } - return; + return; } diff --git a/src/anedya_operations.c b/src/anedya_operations.c index 4fefb68..617e0d4 100755 --- a/src/anedya_operations.c +++ b/src/anedya_operations.c @@ -1,91 +1,120 @@ #include "anedya_operations.h" -#include "anedya_sdk_config.h" #include "anedya_json_builder.h" #include "anedya_json_parse.h" #include "anedya_op_commands.h" -#include +#include "anedya_sdk_config.h" #include +#include -anedya_err_t anedya_device_bind_req(anedya_client_t *client, anedya_txn_t *txn, anedya_req_bind_device_t *req_config) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_BIND_DEVICE; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } +anedya_err_t anedya_device_bind_req(anedya_client_t *client, anedya_txn_t *txn, + anedya_req_bind_device_t *req_config) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_BIND_DEVICE; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION // TODO: Implement dynamic allocation #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_nstr(p, "deviceid", client->config->_device_id_str, strlen((char *)client->config->_device_id_str), &marker); - p = anedya_json_nstr(p, "bindingsecret", req_config->binding_secret, req_config->binding_secret_len, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - char topic[100]; + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); +#endif + p = anedya_json_nstr(p, "deviceid", client->config->_device_id_str, + strlen((char *)client->config->_device_id_str), &marker); + p = anedya_json_nstr(p, "bindingsecret", req_config->binding_secret, + req_config->binding_secret_len, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + char topic[100]; - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/bindDevice/json"); - // Body is ready - // printf("BODY : %s", txbuffer); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/bindDevice/json"); + // Body is ready + // printf("BODY : %s", txbuffer); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/device/bind", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + txn->is_complete = true; + txn->is_success = false; + txn->_op_err = err; + _anedya_txn_complete(client, txn); + return err; + } + + // For HTTP, bypass MQTT reqId parsing + strcpy(txn->_rxbody, resp_buf); + txn->_rx_len = resp_len + 1; + if (txn->_rx_len > ANEDYA_RX_BUFFER_SIZE) { + txn->_op_err = ANEDYA_ERR_RX_BUFFER_OVERFLOW; + txn->is_complete = true; + txn->is_success = false; + _anedya_txn_complete(client, txn); return ANEDYA_OK; + } + _anedya_device_handle_generic_resp(client, txn); + txn->is_complete = true; + _anedya_txn_complete(client, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; } -void _anedya_device_handle_generic_resp(anedya_client_t *client, anedya_txn_t *txn) -{ - // Parse JSON and check for error - json_t mem[32]; - // Parse the json and get the txn id - json_t const *json = json_create(txn->_rxbody, mem, sizeof mem / sizeof *mem); - if (!json) - { - printf("Error while parsing for txn: %d\n", txn->desc); - _anedya_interface_std_out("Error while parsing JSON body : Generic Response"); - return; - } - // printf("parsed: txn: %d", txn->desc); - // Check if success - json_t const *success = json_getProperty(json, "success"); - if (!success || JSON_BOOLEAN != json_getType(success)) - { - _anedya_interface_std_out("Error, the success property is not found."); - } - bool s = json_getBoolean(success); - if (s == true) - { - txn->is_success = true; - } - else - { - txn->is_success = false; - json_t const *error = json_getProperty(json, "errorcode"); - if (!error || JSON_INTEGER != json_getType(error)) - { - _anedya_interface_std_out("Error, the error property is not found."); - } - int err = json_getInteger(error); - txn->_op_err = err; - } +void _anedya_device_handle_generic_resp(anedya_client_t *client, + anedya_txn_t *txn) { + // Parse JSON and check for error + json_t mem[32]; + // Parse the json and get the txn id + json_t const *json = json_create(txn->_rxbody, mem, sizeof mem / sizeof *mem); + if (!json) { + printf("Error while parsing for txn: %d\n", txn->desc); + _anedya_interface_std_out( + "Error while parsing JSON body : Generic Response"); return; + } + // printf("parsed: txn: %d", txn->desc); + // Check if success + json_t const *success = json_getProperty(json, "success"); + if (!success || JSON_BOOLEAN != json_getType(success)) { + _anedya_interface_std_out("Error, the success property is not found."); + } + bool s = json_getBoolean(success); + if (s == true) { + txn->is_success = true; + } else { + txn->is_success = false; + json_t const *error = json_getProperty(json, "errorcode"); + if (!error || JSON_INTEGER != json_getType(error)) { + _anedya_interface_std_out("Error, the error property is not found."); + } + int err = json_getInteger(error); + txn->_op_err = err; + } + return; } \ No newline at end of file diff --git a/src/anedya_ota.c b/src/anedya_ota.c index a8bf4cb..e0633ca 100644 --- a/src/anedya_ota.c +++ b/src/anedya_ota.c @@ -1,327 +1,579 @@ -#include "anedya_operations.h" +#include "anedya_ota.h" #include "anedya_json_builder.h" #include "anedya_json_parse.h" -#include "anedya_ota.h" +#include "anedya_operations.h" -anedya_err_t anedya_op_ota_next_req(anedya_client_t *client, anedya_txn_t *txn) -{ - anedya_op_next_ota_resp_t *resp = (anedya_op_next_ota_resp_t *)txn->response; - resp->deployment_available = false; - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_OTA_NEXT; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } +//===================== OTA NEXT OPERATION =====================// +anedya_err_t anedya_op_ota_next_req(anedya_client_t *client, + anedya_txn_t *txn) { + anedya_op_next_ota_resp_t *resp = (anedya_op_next_ota_resp_t *)txn->response; + resp->deployment_available = false; + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_OTA_NEXT; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } - // Generate the JSON body + // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION // TODO: Implement dynamic allocation #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - char topic[100]; - - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/ota/next/json"); - // printf("REQ: %s", txbuffer); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + char topic[100]; + + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/ota/next/json"); + // printf("REQ: %s", txbuffer); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/ota/next", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; +} + +void _anedya_op_ota_next_resp(anedya_client_t *client, anedya_txn_t *txn) { + // Parse JSON and check for error + anedya_op_next_ota_resp_t *resp = (anedya_op_next_ota_resp_t *)txn->response; + json_t mem[32]; + // Parse the json and get the txn id + json_t const *json = json_create(txn->_rxbody, mem, sizeof mem / sizeof *mem); + if (!json) { + _anedya_interface_std_out( + "Error while parsing JSON body:response handler OTA Next"); + return; + } + // Check if success + json_t const *success = json_getProperty(json, "success"); + if (!success || JSON_BOOLEAN != json_getType(success)) { + _anedya_interface_std_out("Error, the success property is not found."); + } + bool s = json_getBoolean(success); + if (s == true) { + txn->is_success = true; + } else { + txn->is_success = false; + json_t const *error = json_getProperty(json, "errorcode"); + if (!error || JSON_INTEGER != json_getType(error)) { + _anedya_interface_std_out("Error, the error property is not found."); } - return ANEDYA_OK; + int err = json_getInteger(error); + txn->_op_err = err; + return; + } + // Flow reaches here means, request was successful. + // Now, parse the response + _anedya_op_ota_next_parser((json_t *)json, resp); } -void _anedya_op_ota_next_resp(anedya_client_t *client, anedya_txn_t *txn) -{ - // Parse JSON and check for error - anedya_op_next_ota_resp_t *resp = (anedya_op_next_ota_resp_t *)txn->response; - json_t mem[32]; - // Parse the json and get the txn id - json_t const *json = json_create(txn->_rxbody, mem, sizeof mem / sizeof *mem); - if (!json) - { - _anedya_interface_std_out("Error while parsing JSON body:response handler OTA Next"); - return; +anedya_err_t _anedya_op_ota_next_parser(json_t *json, + anedya_op_next_ota_resp_t *resp) { + // Parse whether deployment is available or not + json_t const *da = json_getProperty(json, "deploymentAvailable"); + if (!da || JSON_BOOLEAN != json_getType(da)) { + _anedya_interface_std_out("Error, the success property is not found."); + return ANEDYA_ERR_PARSE_ERROR; + } + bool dep_available = json_getBoolean(da); + if (dep_available == false) { + resp->deployment_available = false; + return ANEDYA_OK; + } + + // Flow reaches here, that means the OTA is available. + resp->deployment_available = true; + json_t const *dpdata = json_getProperty(json, "data"); + if (!dpdata || JSON_OBJ != json_getType(dpdata)) { + _anedya_interface_std_out("Error, the data property is not found."); + return ANEDYA_ERR_PARSE_ERROR; + } + + // Parse deploymentId + json_t const *dpID = json_getProperty(dpdata, "deploymentId"); + if (!dpID || JSON_TEXT != json_getType(dpID)) { + _anedya_interface_std_out("Error, the deploymentId property is not found."); + return ANEDYA_ERR_PARSE_ERROR; + } + const char *deployment_id = json_getValue(dpID); + + // Parse assetId + json_t const *aID = json_getProperty(dpdata, "assetId"); + if (!aID || JSON_TEXT != json_getType(aID)) { + _anedya_interface_std_out("Error, the deploymentId property is not found."); + return ANEDYA_ERR_PARSE_ERROR; + } + const char *asset_id = json_getValue(aID); + + // Parse assetIdentifier + json_t const *aidentifier = json_getProperty(dpdata, "assetIdentifier"); + if (!aidentifier || JSON_TEXT != json_getType(aidentifier)) { + _anedya_interface_std_out("Error, the deploymentId property is not found."); + return ANEDYA_ERR_PARSE_ERROR; + } + const char *asset_identifier = json_getValue(aidentifier); + strcpy(resp->asset.asset_identifier, asset_identifier); + resp->asset.asset_identifier_len = strlen(resp->asset.asset_identifier); + + // Parse assetVersion + json_t const *aversion = json_getProperty(dpdata, "assetVersion"); + if (!aversion || JSON_TEXT != json_getType(aversion)) { + _anedya_interface_std_out("Error, the assetVersion property is not found."); + return ANEDYA_ERR_PARSE_ERROR; + } + const char *asset_version = json_getValue(aversion); + strcpy(resp->asset.asset_version, asset_version); + resp->asset.asset_version_len = strlen(resp->asset.asset_version); + + // Parse assetSigned + json_t const *asigned = json_getProperty(dpdata, "assetSigned"); + if (!asigned || JSON_BOOLEAN != json_getType(asigned)) { + _anedya_interface_std_out("Error, the assetSigned property is not found."); + return ANEDYA_ERR_PARSE_ERROR; + } + const bool asset_signed = json_getBoolean(asigned); + resp->asset.asset_signed = asset_signed; + + if (asset_signed) { + resp->asset.asset_signed = true; + // Parse assetSignature + json_t const *asign = json_getProperty(dpdata, "assetSignature"); + if (!asign || JSON_TEXT != json_getType(asign)) { + _anedya_interface_std_out( + "Error, the assetSignature property is not found."); + return ANEDYA_ERR_PARSE_ERROR; } - // Check if success - json_t const *success = json_getProperty(json, "success"); - if (!success || JSON_BOOLEAN != json_getType(success)) - { - _anedya_interface_std_out("Error, the success property is not found."); + const char *asset_signature = json_getValue(asign); + strcpy(resp->asset.asset_signature, asset_signature); + resp->asset.asset_signature_len = strlen(resp->asset.asset_signature); + } + + // Parse Asset Metadata + json_t const *ametadata = json_getProperty(dpdata, "assetMeta"); + size_t i = 0; + json_t const *child; + for (child = json_getChild(ametadata); i < resp->asset.asset_metadata_len; + child = json_getSibling(child)) { + if (child == 0) { + // List terminated + break; } - bool s = json_getBoolean(success); - if (s == true) - { - txn->is_success = true; + if (JSON_TEXT != json_getType(child)) { + continue; } - else - { - txn->is_success = false; - json_t const *error = json_getProperty(json, "errorcode"); - if (!error || JSON_INTEGER != json_getType(error)) - { - _anedya_interface_std_out("Error, the error property is not found."); - } - int err = json_getInteger(error); - txn->_op_err = err; - return; + const char *key = json_getName(child); + if (key == NULL) { + continue; } - // Flow reaches here means, request was successful. - // Now, parse the response - _anedya_op_ota_next_parser((json_t *)json, resp); -} - -anedya_err_t _anedya_op_ota_next_parser(json_t *json, anedya_op_next_ota_resp_t *resp) -{ - // Parse whether deployment is available or not - json_t const *da = json_getProperty(json, "deploymentAvailable"); - if (!da || JSON_BOOLEAN != json_getType(da)) - { - _anedya_interface_std_out("Error, the success property is not found."); - return ANEDYA_ERR_PARSE_ERROR; + const char *value = json_getValue(child); + if (strlen(key) > 50 || strlen(value) > 50) { + continue; } - bool dep_available = json_getBoolean(da); - if (dep_available == false) - { - resp->deployment_available = false; - return ANEDYA_OK; + strcpy(resp->asset.asset_metadata[i].key, key); + strcpy(resp->asset.asset_metadata[i].value, value); + i++; + } + + // Parse asset checksum + json_t const *achecksum = json_getProperty(dpdata, "assetChecksum"); + if (!achecksum || JSON_TEXT != json_getType(achecksum)) { + _anedya_interface_std_out( + "Error, the assetChecksum property is not found."); + return ANEDYA_ERR_PARSE_ERROR; + } + const char *asset_checksum = json_getValue(achecksum); + strcpy(resp->asset.asset_checksum, asset_checksum); + resp->asset.asset_checksum_len = strlen(resp->asset.asset_checksum); + + // Parse asset size + json_t const *asize = json_getProperty(dpdata, "assetSize"); + if (!asize || JSON_INTEGER != json_getType(asize)) { + _anedya_interface_std_out("Error, the assetSize property is not found."); + return ANEDYA_ERR_PARSE_ERROR; + } + int asset_size = json_getInteger(asize); + resp->asset.asset_size = asset_size; + + // Parse asset URL + json_t const *aurl = json_getProperty(dpdata, "asseturl"); + if (!aurl || JSON_TEXT != json_getType(aurl)) { + _anedya_interface_std_out("Error, the asseturl property is not found."); + return ANEDYA_ERR_PARSE_ERROR; + } + const char *asset_url = json_getValue(aurl); + bool firstChar = 0; + strcpy(resp->asset.asset_url, asset_url); + for (int i = 0; i < strlen(resp->asset.asset_url) + 1; i++) { + char c; + if (resp->asset.asset_url[i] == '?') { + if (firstChar) { + c = '&'; + } else { + firstChar = 1; + c = resp->asset.asset_url[i]; + } + } else { + c = resp->asset.asset_url[i]; } + resp->asset.asset_url[i] = c; + } + resp->asset.asset_url_len = strlen(resp->asset.asset_url); + + // All data has been parsed now set the data in response structure. + anedya_err_t err = _anedya_uuid_parse(deployment_id, resp->deployment_id); + if (err != ANEDYA_OK) { + return err; + } + err = _anedya_uuid_parse(asset_id, resp->asset.asset_id); + if (err != ANEDYA_OK) { + return err; + } + + return ANEDYA_OK; +} + +//===================== ONGOING OTA OPERATION =====================// +anedya_err_t anedya_op_ongoing_ota_req(anedya_client_t *client, + anedya_txn_t *txn, + anedya_req_ongoing_ota_obj_t obj) { + anedya_op_ongoing_ota_resp_t *resp = + (anedya_op_ongoing_ota_resp_t *)txn->response; + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_ONGOING_OTA; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } + + // Generate the JSON body +#ifdef ANEDYA_ENABLE_STATIC_ALLOCATION + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); +#endif +#ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION +// TODO: Implement dynamic allocation +#endif + + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); +#endif + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + char topic[100]; + + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/ota/current/json"); + // printf("REQ: %s", txbuffer); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/ota/current", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; +} - // Flow reaches here, that means the OTA is available. - resp->deployment_available = true; - json_t const *dpdata = json_getProperty(json, "data"); - if (!dpdata || JSON_OBJ != json_getType(dpdata)) - { - _anedya_interface_std_out("Error, the data property is not found."); - return ANEDYA_ERR_PARSE_ERROR; +void _anedya_op_ongoing_ota_resp(anedya_client_t *client, anedya_txn_t *txn) { + // Parse JSON and check for error + anedya_op_ongoing_ota_resp_t *resp = + (anedya_op_ongoing_ota_resp_t *)txn->response; + json_t mem[32]; + // Parse the json and get the txn id + json_t const *json = json_create(txn->_rxbody, mem, sizeof mem / sizeof *mem); + if (!json) { + _anedya_interface_std_out( + "Error while parsing JSON body:response handler OTA Next"); + return; + } + // Check if success + json_t const *success = json_getProperty(json, "success"); + if (!success || JSON_BOOLEAN != json_getType(success)) { + _anedya_interface_std_out("Error, the success property is not found."); + } + bool s = json_getBoolean(success); + if (s == true) { + txn->is_success = true; + } else { + txn->is_success = false; + json_t const *error = json_getProperty(json, "errorcode"); + if (!error || JSON_INTEGER != json_getType(error)) { + _anedya_interface_std_out("Error, the error property is not found."); } + int err = json_getInteger(error); + txn->_op_err = err; + return; + } + // Flow reaches here means, request was successful. + // Now, parse the response + _anedya_op_ongoing_ota_parser((json_t *)json, resp); +} + +anedya_err_t _anedya_op_ongoing_ota_parser(json_t *json, + anedya_op_ongoing_ota_resp_t *resp) { + // Parse count + json_t const *count = json_getProperty(json, "count"); + if (!count || json_getType(count) != JSON_INTEGER) { + _anedya_interface_std_out("Error, count property missing."); + return ANEDYA_ERR_PARSE_ERROR; + } + + int c = json_getInteger(count); + if (c == 0) { + resp->count = 0; + return ANEDYA_OK; + } + + // resp->count = json_getInteger(count); // #remove + // Parse data array + json_t const *arr = json_getProperty(json, "data"); + if (!arr || json_getType(arr) != JSON_ARRAY) { + _anedya_interface_std_out("Error, data array missing."); + return ANEDYA_ERR_PARSE_ERROR; + } - // Parse deploymentId - json_t const *dpID = json_getProperty(dpdata, "deploymentId"); - if (!dpID || JSON_TEXT != json_getType(dpID)) - { - _anedya_interface_std_out("Error, the deploymentId property is not found."); - return ANEDYA_ERR_PARSE_ERROR; + int parsed = 0; + json_t const *node = json_getChild(arr); + + while (node && parsed < resp->count) { + if (c == parsed) { + resp->count = parsed; + break; } + + anedya_op_ongoing_asset_list_t *dst = &resp->assets[parsed]; + + // deploymentId + json_t const *dpID = json_getProperty(node, "deploymentId"); + if (!dpID || json_getType(dpID) != JSON_TEXT) + return ANEDYA_ERR_PARSE_ERROR; const char *deployment_id = json_getValue(dpID); - // Parse assetId - json_t const *aID = json_getProperty(dpdata, "assetId"); - if (!aID || JSON_TEXT != json_getType(aID)) - { - _anedya_interface_std_out("Error, the deploymentId property is not found."); - return ANEDYA_ERR_PARSE_ERROR; - } + if (_anedya_uuid_parse(deployment_id, dst->deployment_id) != ANEDYA_OK) + return ANEDYA_ERR_PARSE_ERROR; + + // assetId + json_t const *aID = json_getProperty(node, "assetId"); + if (!aID || json_getType(aID) != JSON_TEXT) + return ANEDYA_ERR_PARSE_ERROR; const char *asset_id = json_getValue(aID); - // Parse assetIdentifier - json_t const *aidentifier = json_getProperty(dpdata, "assetIdentifier"); - if (!aidentifier || JSON_TEXT != json_getType(aidentifier)) - { - _anedya_interface_std_out("Error, the deploymentId property is not found."); - return ANEDYA_ERR_PARSE_ERROR; - } - const char *asset_identifier = json_getValue(aidentifier); - strcpy(resp->asset.asset_identifier, asset_identifier); - resp->asset.asset_identifier_len = strlen(resp->asset.asset_identifier); - - // Parse assetVersion - json_t const *aversion = json_getProperty(dpdata, "assetVersion"); - if (!aversion || JSON_TEXT != json_getType(aversion)) - { - _anedya_interface_std_out("Error, the assetVersion property is not found."); - return ANEDYA_ERR_PARSE_ERROR; - } - const char *asset_version = json_getValue(aversion); - strcpy(resp->asset.asset_version, asset_version); - resp->asset.asset_version_len = strlen(resp->asset.asset_version); - - // Parse assetSigned - json_t const *asigned = json_getProperty(dpdata, "assetSigned"); - if (!asigned || JSON_BOOLEAN != json_getType(asigned)) - { - _anedya_interface_std_out("Error, the assetSigned property is not found."); - return ANEDYA_ERR_PARSE_ERROR; - } - const bool asset_signed = json_getBoolean(asigned); - resp->asset.asset_signed = asset_signed; - - if (asset_signed) - { - resp->asset.asset_signed = true; - // Parse assetSignature - json_t const *asign = json_getProperty(dpdata, "assetSignature"); - if (!asign || JSON_TEXT != json_getType(asign)) - { - _anedya_interface_std_out("Error, the assetSignature property is not found."); - return ANEDYA_ERR_PARSE_ERROR; - } - const char *asset_signature = json_getValue(asign); - strcpy(resp->asset.asset_signature, asset_signature); - resp->asset.asset_signature_len = strlen(resp->asset.asset_signature); + if (_anedya_uuid_parse(asset_id, dst->asset->asset_id) != ANEDYA_OK) + return ANEDYA_ERR_PARSE_ERROR; + + // assetIdentifier + json_t const *aident = json_getProperty(node, "assetIdentifier"); + if (!aident || json_getType(aident) != JSON_TEXT) + return ANEDYA_ERR_PARSE_ERROR; + strcpy(dst->asset->asset_identifier, json_getValue(aident)); + dst->asset->asset_identifier_len = strlen(dst->asset->asset_identifier); + + // assetVersion + json_t const *aver = json_getProperty(node, "assetVersion"); + if (!aver || json_getType(aver) != JSON_TEXT) + return ANEDYA_ERR_PARSE_ERROR; + strcpy(dst->asset->asset_version, json_getValue(aver)); + dst->asset->asset_version_len = strlen(dst->asset->asset_version); + + // assetSigned + json_t const *asigned = json_getProperty(node, "assetSigned"); + if (!asigned || json_getType(asigned) != JSON_BOOLEAN) + return ANEDYA_ERR_PARSE_ERROR; + dst->asset->asset_signed = json_getBoolean(asigned); + + // assetSignature (optional) + json_t const *asign = json_getProperty(node, "assetSignature"); + if (asign && json_getType(asign) == JSON_TEXT) { + strcpy(dst->asset->asset_signature, json_getValue(asign)); + dst->asset->asset_signature_len = strlen(dst->asset->asset_signature); } - // Parse Asset Metadata - json_t const *ametadata = json_getProperty(dpdata, "assetMeta"); - size_t i = 0; - json_t const *child; - for (child = json_getChild(ametadata); i < resp->asset.asset_metadata_len; child = json_getSibling(child)) - { - if (child == 0) - { - // List terminated - break; - } - if (JSON_TEXT != json_getType(child)) - { - continue; - } - const char *key = json_getName(child); - if (key == NULL) - { - continue; - } - const char *value = json_getValue(child); - if (strlen(key) > 50 || strlen(value) > 50) - { - continue; - } - strcpy(resp->asset.asset_metadata[i].key, key); - strcpy(resp->asset.asset_metadata[i].value, value); + // assetMeta (object) + json_t const *ameta = json_getProperty(node, "assetMeta"); + if (ameta && json_getType(ameta) == JSON_OBJ) { + size_t i = 0; + json_t const *child; + for (child = json_getChild(ameta); + child && i < dst->asset->asset_metadata_len; + child = json_getSibling(child)) { + if (json_getType(child) != JSON_TEXT) + continue; + + const char *k = json_getName(child); + const char *v = json_getValue(child); + + if (!k || !v) + continue; + + strcpy(dst->asset->asset_metadata[i].key, k); + strcpy(dst->asset->asset_metadata[i].value, v); i++; + } } - // Parse asset checksum - json_t const *achecksum = json_getProperty(dpdata, "assetChecksum"); - if (!achecksum || JSON_TEXT != json_getType(achecksum)) - { - _anedya_interface_std_out("Error, the assetChecksum property is not found."); - return ANEDYA_ERR_PARSE_ERROR; - } - const char *asset_checksum = json_getValue(achecksum); - strcpy(resp->asset.asset_checksum, asset_checksum); - resp->asset.asset_checksum_len = strlen(resp->asset.asset_checksum); - - // Parse asset size - json_t const *asize = json_getProperty(dpdata, "assetSize"); - if (!asize || JSON_INTEGER != json_getType(asize)) - { - _anedya_interface_std_out("Error, the assetSize property is not found."); - return ANEDYA_ERR_PARSE_ERROR; - } - int asset_size = json_getInteger(asize); - resp->asset.asset_size = asset_size; - - // Parse asset URL - json_t const *aurl = json_getProperty(dpdata, "asseturl"); - if (!aurl || JSON_TEXT != json_getType(aurl)) - { - _anedya_interface_std_out("Error, the asseturl property is not found."); - return ANEDYA_ERR_PARSE_ERROR; - } + // assetChecksum + json_t const *acksum = json_getProperty(node, "assetChecksum"); + if (!acksum || json_getType(acksum) != JSON_TEXT) + return ANEDYA_ERR_PARSE_ERROR; + strcpy(dst->asset->asset_checksum, json_getValue(acksum)); + dst->asset->asset_checksum_len = strlen(dst->asset->asset_checksum); + + // assetSize + json_t const *asize = json_getProperty(node, "assetSize"); + if (!asize || json_getType(asize) != JSON_INTEGER) + return ANEDYA_ERR_PARSE_ERROR; + dst->asset->asset_size = json_getInteger(asize); + + // asseturl + json_t const *aurl = json_getProperty(node, "asseturl"); + if (!aurl || json_getType(aurl) != JSON_TEXT) + return ANEDYA_ERR_PARSE_ERROR; + const char *asset_url = json_getValue(aurl); bool firstChar = 0; - strcpy(resp->asset.asset_url, asset_url); - for (int i = 0; i < strlen(resp->asset.asset_url) + 1; i++) - { - char c; - if (resp->asset.asset_url[i] == '?') - { - if (firstChar) - { - c = '&'; - } - else - { - firstChar = 1; - c = resp->asset.asset_url[i]; - } - } - else - { - c = resp->asset.asset_url[i]; + strcpy(dst->asset->asset_url, asset_url); + for (int i = 0; i < strlen(dst->asset->asset_url) + 1; i++) { + char c; + if (dst->asset->asset_url[i] == '?') { + if (firstChar) { + c = '&'; + } else { + firstChar = 1; + c = dst->asset->asset_url[i]; } - resp->asset.asset_url[i] = c; + } else { + c = dst->asset->asset_url[i]; + } + dst->asset->asset_url[i] = c; } - resp->asset.asset_url_len = strlen(resp->asset.asset_url); + dst->asset->asset_url_len = strlen(dst->asset->asset_url); - // All data has been parsed now set the data in response structure. - anedya_err_t err = _anedya_uuid_parse(deployment_id, resp->deployment_id); - if (err != ANEDYA_OK) - { - return err; - } - err = _anedya_uuid_parse(asset_id, resp->asset.asset_id); - if (err != ANEDYA_OK) - { - return err; - } + // status + json_t const *stat = json_getProperty(node, "status"); + if (!stat || json_getType(stat) != JSON_TEXT) + return ANEDYA_ERR_PARSE_ERROR; + strcpy(dst->status, json_getValue(stat)); - return ANEDYA_OK; + parsed++; + node = json_getSibling(node); + } + + return ANEDYA_OK; } -anedya_err_t anedya_op_ota_update_status_req(anedya_client_t *client, anedya_txn_t *txn, anedya_req_ota_update_status_t *req) -{ - // First check if client is already connected or not - if (client->is_connected == 0) - { - return ANEDYA_ERR_NOT_CONNECTED; - } - // If it is connected, then create a txn - txn->_op = ANEDYA_OP_SUBMIT_DATA; - anedya_err_t err = _anedya_txn_register(client, txn); - if (err != ANEDYA_OK) - { - return err; - } +// ===================== OTA UPDATE STATUS OPERATION =====================// +anedya_err_t +anedya_op_ota_update_status_req(anedya_client_t *client, anedya_txn_t *txn, + anedya_req_ota_update_status_t *req) { + // First check if client is already connected or not + if (client->is_connected == 0) { + return ANEDYA_ERR_NOT_CONNECTED; + } + // If it is connected, then create a txn + txn->_op = ANEDYA_OP_SUBMIT_DATA; + anedya_err_t err = _anedya_txn_register(client, txn); + if (err != ANEDYA_OK) { + return err; + } // Generate the JSON body #ifdef ANEDYA_ENABLE_STATIC_ALLOCATION - char txbuffer[ANEDYA_TX_BUFFER_SIZE]; - size_t marker = sizeof(txbuffer); + char txbuffer[ANEDYA_TX_BUFFER_SIZE]; + size_t marker = sizeof(txbuffer); #endif #ifdef ANEDYA_ENABLE_DYNAMIC_ALLOCATION // TODO: Implement dynamic allocation #endif - char slot_number[4]; - int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); - char *p = anedya_json_objOpen(txbuffer, NULL, &marker); - // Get the reqId based on slot. - char dep_id[37]; - _anedya_uuid_marshal(*req->deployment_id, dep_id); - p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); - p = anedya_json_str(p, "deploymentId", dep_id, &marker); - p = anedya_json_str(p, "status", req->status, &marker); - p = anedya_json_objClose(p, &marker); - p = anedya_json_end(p, &marker); - // Body is ready now publish it to the MQTT - char topic[100]; - // printf("Req: %s", txbuffer); - strcpy(topic, "$anedya/device/"); - strcat(topic, client->config->_device_id_str); - strcat(topic, "/ota/updateStatus/json"); - err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), txbuffer, strlen(txbuffer), 0, 0); - if (err != ANEDYA_OK) - { - return err; - } - return ANEDYA_OK; + char slot_number[4]; + int digitLen = snprintf(slot_number, sizeof(slot_number), "%d", txn->desc); + char *p = anedya_json_objOpen(txbuffer, NULL, &marker); + // Get the reqId based on slot. + char dep_id[37]; + _anedya_uuid_marshal(*req->deployment_id, dep_id); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + p = anedya_json_nstr(p, "reqId", slot_number, digitLen, &marker); +#endif + p = anedya_json_str(p, "deploymentId", dep_id, &marker); + p = anedya_json_str(p, "status", req->status, &marker); + p = anedya_json_objClose(p, &marker); + p = anedya_json_end(p, &marker); + // Body is ready now publish it to the MQTT + char topic[100]; + // printf("Req: %s", txbuffer); + strcpy(topic, "$anedya/device/"); + strcat(topic, client->config->_device_id_str); + strcat(topic, "/ota/updateStatus/json"); +#ifdef ANEDYA_CONNECTION_METHOD_MQTT + err = anedya_interface_mqtt_publish(client->mqtt_client, topic, strlen(topic), + txbuffer, strlen(txbuffer), 0, 0); + if (err != ANEDYA_OK) { + return err; + } +#endif /* ANEDYA_CONNECTION_METHOD_MQTT */ + +#ifdef ANEDYA_CONNECTION_METHOD_HTTP + char resp_buf[ANEDYA_RX_BUFFER_SIZE]; + int resp_len = 0; + err = _anedya_interface_http_post(client, "/v1/ota/updateStatus", txbuffer, + (int)strlen(txbuffer), resp_buf, + ANEDYA_RX_BUFFER_SIZE, &resp_len); + if (err != ANEDYA_OK) { + return err; + } + _anedya_handle_http_txn_response(client, resp_buf, resp_len, txn); +#endif /* ANEDYA_CONNECTION_METHOD_HTTP */ + + return ANEDYA_OK; } \ No newline at end of file