diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 985efd3..42d90ed 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - name: Install dependencies - run: sudo apt update && sudo apt-get install -y libz-dev wget gcc g++ cmake libssl-dev clang-format ruby + run: sudo apt update && sudo apt-get install -y libz-dev wget gcc g++ cmake libssl-dev clang-format ruby valgrind doxygen - name: Install Unit Test toolset run: sudo gem install ceedling @@ -30,14 +30,32 @@ jobs: run: ./configure - name: Build - working-directory: ${{github.workspace}}/build + working-directory: ${{github.workspace}}/out shell: bash - # Execute the build. You can specify a specific target with "--target " - run: make all -j$(nproc) + # Execute the out. You can specify a specific target with "--target " + run: sudo make all -j$(nproc) - name: Test - working-directory: ${{github.workspace}}/build + working-directory: ${{github.workspace}}/out shell: bash # Execute tests defined by the CMake configuration. # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: make tests + + # Build the Doxygen documentation + - name: Doxygen Action + uses: mattnotmitt/doxygen-action@v1.1.0 + with: + doxyfile-path: ./Doxyfile + working-directory: . + + # Deploy the HTML documentation to GitHub Pages + - name: GH Pages Deployment + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./docs/html/ + enable_jekyll: false + allow_empty_commit: false + force_orphan: true + publish_branch: gh-pages diff --git a/.gitignore b/.gitignore index 35426fc..3903d88 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ release cmake-build-release build cmake-build-debug +.vscode # Out directory out diff --git a/CMakeLists.txt b/CMakeLists.txt index bd5cc0e..db403d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,21 +45,23 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic \ -Wcast-qual \ -Wstrict-prototypes \ -Wmissing-prototypes \ - -Wconversion \ - -fsanitize=address \ - -static-libasan") + -Wconversion") set(LIBRARY_NAME "WolkConnector-C") -include_directories("sources") file(GLOB_RECURSE HEADER_FILES "sources/*.h") file(GLOB_RECURSE SOURCE_FILES "sources/*.c") include_directories("examples") file(GLOB_RECURSE SIMPLE_HEADER_FILES "examples/simple/*.h") file(GLOB_RECURSE SIMPLE_SOURCE_FILES "examples/simple/*.c") +file(GLOB_RECURSE PULL_HEADER_FILES "examples/pull/*.h") +file(GLOB_RECURSE PULL_SOURCE_FILES "examples/pull/*.c") +file(GLOB_RECURSE REGISTER_FEED_AND_ATTRIBUTE_HEADER_FILES "examples/register_feed_and_attribute/*.h") +file(GLOB_RECURSE REGISTER_FEED_AND_ATTRIBUTE_SOURCE_FILES "examples/register_feed_and_attribute/*.c") file(GLOB_RECURSE FULL_EXAMPLE_HEADER_FILES "examples/full_feature_set/*.h") file(GLOB_RECURSE FULL_EXAMPLE_SOURCE_FILES "examples/full_feature_set/*.c") +file(GLOB_RECURSE TESTS_SOURCE_FILES "tests/test/*.c") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/bin") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/out/lib") @@ -68,9 +70,10 @@ link_directories(${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) #Dependencies add_subdirectory(dependencies) -include_directories(dependencies/pahomqttembeddedc/MQTTPacket/src) add_library(${LIBRARY_NAME} SHARED ${HEADER_FILES} ${SOURCE_FILES}) +target_include_directories(${LIBRARY_NAME} PUBLIC sources) +target_include_directories(${LIBRARY_NAME} PUBLIC dependencies/pahomqttembeddedc/MQTTPacket/src) target_link_libraries(${LIBRARY_NAME} paho-embed-mqtt3c ssl crypto) set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-Wl,-rpath,./") @@ -81,15 +84,18 @@ add_custom_target(format ALL COMMAND "clang-format" -i -sort-includes -style=file ${HEADER_FILES} ${SOURCE_FILES} ${FULL_EXAMPLE_HEADER_FILES} ${FULL_EXAMPLE_SOURCE_FILES} + ${PULL_HEADER_FILES} ${PULL_SOURCE_FILES} + ${REGISTER_FEED_AND_ATTRIBUTE_HEADER_FILES} ${REGISTER_FEED_AND_ATTRIBUTE_SOURCE_FILES} ${SIMPLE_HEADER_FILES} ${SIMPLE_SOURCE_FILES} + ${TESTS_SOURCE_FILES} WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" COMMENT "[Formatting source code]" VERBATIM) # Run Unit tests -set(TEST_FILES "${CMAKE_SOURCE_DIR}/tests") +set(TEST_FILES "${CMAKE_CURRENT_LIST_DIR}/tests") -add_custom_target(tests ALL +add_custom_target(tests WORKING_DIRECTORY "${TEST_FILES}" DEPENDS pahomqttembeddedc COMMAND ceedling clean @@ -97,6 +103,21 @@ add_custom_target(tests ALL COMMENT "[Run Unit tests]" VERBATIM) +file(GLOB_RECURSE PAHO_MQTT_HEADER_FILES "dependencies/pahomqttembeddedc/MQTTPacket/src/*.h") +#install library at /usr/lib +install(DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} DESTINATION /usr + FILES_MATCHING + PATTERN "*so*") +#install headers at /usr/include +install(FILES ${PAHO_MQTT_HEADER_FILES} DESTINATION /usr/include) +install(FILES ${HEADER_FILES} DESTINATION /usr/include) +install(CODE "MESSAGE(\"Installed WolkConnector-C\")") + # Examples -add_subdirectory(examples/simple) -add_subdirectory(examples/full_feature_set) +OPTION(BUILD_EXAMPLES "Build the library examples" ON) +if (${BUILD_EXAMPLES}) + add_subdirectory(examples/simple) + add_subdirectory(examples/pull) + add_subdirectory(examples/register_feed_and_attribute) + add_subdirectory(examples/full_feature_set) +endif() diff --git a/README.md b/README.md index 4710c63..7169644 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ ╚██████╗ ╚═════╝ ``` -[![Build Status](https://travis-ci.com/Wolkabout/WolkConnect-C.svg?branch=master)](https://travis-ci.com/Wolkabout/WolkConnect-C) +[![CMake](https://github.com/Wolkabout/WolkConnect-C/actions/workflows/cmake.yml/badge.svg?branch=development)](https://github.com/Wolkabout/WolkConnect-C/actions/workflows/cmake.yml) ----- WolkAbout C99 Connector library for connecting devices to WolkAbout IoT platform instance. @@ -24,9 +24,6 @@ This allows WolkConnect-C Connector to work on wide variety of systems, bare met Given examples are intended to be run on Debian based system. -Supported protocol(s): -* WOLKABOUT PROTOCOL - Prerequisite ------ Following tools/libraries are required in order to build WolkConnect-C Connector @@ -38,18 +35,19 @@ Following tools/libraries are required in order to build WolkConnect-C Connector * clang-format * ruby * ceedling +* valgrind Former can be installed on Debian based system from terminal by invoking -`sudo apt-get install libz-dev wget gcc g++ cmake libssl-dev clang-format ruby` +`sudo apt-get install libz-dev wget gcc g++ cmake libssl-dev clang-format ruby valgrind` `gem install ceedling` -When dependencies are installed, Unix Makefiles build system can generated by invoking `./configure` +When dependencies are installed, Unix Makefiles build system can be generated by invoking `./configure` Generated build system is located inside `build` directory. -WolkConnect-C Connector library, and example are built from `build` directory by invoking `make` in terminal. +WolkConnect-C Connector library, and example are built from `build` directory by invoking `make all` in terminal. Library application is built to `out/lib` directory, and example application is built to `out/bin` directory. @@ -58,7 +56,7 @@ Example Usage **Initialize WolkConnect-C Connector** Create a device on WolkAbout IoT platform using `Simple example` device type. -This device type fits [simple example](https://github.com/Wolkabout/WolkConnect-C/blob/master/examples/simple/main.c) and demonstrates the periodic sending of a temperature sensor reading. +This device type fits [simple example](https://github.com/Wolkabout/WolkConnect-C/blob/master/examples/simple/main.c) and demonstrates the periodic sending of a temperature_value sensor reading. ```c /* WolkAbout Platform device connection parameters */ @@ -81,19 +79,18 @@ static wolk_ctx_t wolk; wolk_init(&wolk, /* Context */ send_buffer, /* See send_func_t */ receive_buffer, /* See recv_func_t */ - NULL, /* Actuation handler - see actuation_handler_t */ - ACTUATOR_STATE_READY, /* Actuator status provider - see actuator_status_provider_t */ - NULL, /* Configuration handler - see configuration_handler_t */ - NULL, /* Configuration provider - see configuration_provider_t */ device_key, device_password, /* Device key and password provided by WolkAbout IoT Platform upon device creation */ - PROTOCOL_WOLKABOUT, /* Protocol specified for device */ - NULL, /* Array of actuator references */ - NULL); /* Number of actuator references */ + PUSH, /* Device outbound mode - see outbound_mode_t */ + NULL, /* Feeds handler - see feed_handler_t */ + NULL, /* Parameters handler - see parameter_handler_t */ + NULL); /* Details synchronization handler - see details_synchronization_handler_t */ wolk_init_in_memory_persistence(&wolk, /* Context */ persistence_storage, /* Address to start of the memory which will be used by persistence mechanism */ sizeof(persistence_storage), /* Size of memory in bytes */ - true); /* If storage is full overwrite oldest item when pushing */ + false); /* If storage is full overwrite the oldest item when pushing */ + +wolk_connect(&wolk); ``` Considering that WolkConnect C Connector is transportation layer agnostic, it is up to the user of it to open connection to WolkAbout IoT Platform, optionally setup TLS, and forward read/write callbacks WolkConnect-C Connector in initialization @@ -105,24 +102,26 @@ See `send_func_t` and `send_func_t` in `sources/wolk_connector.h` ```c wolk_connect(&wolk); ``` -**Adding sensor readings:** +**Adding feed example:** ```c -wolk_add_numeric_sensor_reading(&wolk, "T", 23.4, 0); +wolk_numeric_feeds_t feed = {0}; +feed.value = 23; +wolk_add_numeric_feed(&wolk, "T", &feed, 1) ``` **Data publish strategy:** -Sensor reading is pushed to WolkAbout IoT platform on demand by calling +Data is pushed to WolkAbout IoT platform on demand by calling ```c wolk_publish(&wolk); ``` **Cooperative scheduling:** -Fuction `wolk_process(wolk_ctx_t *ctx)` is non-blocking in order to comply with cooperative scheduling, -and it must to be called periodically. +Function `wolk_process(wolk_ctx_t *ctx)` is non-blocking in order to comply with cooperative scheduling, +and it must be called periodically. ```c -wolk_process(&wolk, 5); +wolk_process(&wolk, 1); ``` **Disconnecting from the platform:** @@ -146,7 +145,7 @@ wolk_init_custom_persistence(&wolk, persistence_is_empty_impl); ``` -For more info on persistence mechanism see `sources/persistence.h` and `sources/in_memory_persistence.h` files. +For more info on persistence mechanism see `sources/persistence/persistence.h` and `sources/persistence/in_memory_persistence.h` files. **Additional functionality** diff --git a/configure b/configure index 15ebc32..b0dc332 100755 --- a/configure +++ b/configure @@ -13,7 +13,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -mkdir -p build +mkdir -p out -cd build || exit +cd out || exit cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .. diff --git a/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index 61a2f4d..9791d00 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -18,15 +18,14 @@ include(ExternalProject) set(PAHO_MQTT_EMBEDDED_C_VERSION "1.1.0") if(NOT DEFINED CMAKE_PREFIX_PATH) - set(CMAKE_PREFIX_PATH "${CMAKE_CURRENT_BINARY_DIR}/build") + set(CMAKE_PREFIX_PATH "${CMAKE_CURRENT_BINARY_DIR}/out") endif(NOT DEFINED CMAKE_PREFIX_PATH) include_directories(SYSTEM "${CMAKE_PREFIX_PATH}/include") ExternalProject_Add(pahomqttembeddedc - SOURCE_DIR "${CMAKE_SOURCE_DIR}/dependencies/pahomqttembeddedc" + SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/pahomqttembeddedc" GIT_REPOSITORY "https://github.com/eclipse/paho.mqtt.embedded-c" GIT_TAG "v${PAHO_MQTT_EMBEDDED_C_VERSION}" UPDATE_COMMAND "" - INSTALL_COMMAND "" - CMAKE_ARGS -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${CMAKE_LIBRARY_OUTPUT_DIRECTORY} -DCMAKE_INSTALL_PREFIX=${CMAKE_PREFIX_PATH} -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} -DCMAKE_INSTALL_RPATH='.' - ) \ No newline at end of file + CMAKE_ARGS -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${CMAKE_LIBRARY_OUTPUT_DIRECTORY} -DCMAKE_INSTALL_PREFIX=${CMAKE_PREFIX_PATH} -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} -DCMAKE_INSTALL_RPATH='.' INSTALL_COMMAND "" + ) diff --git a/docs/templates/WolkConnect-Functional-Documentation.md b/docs/templates/WolkConnect-Functional-Documentation.md index 560a864..c7c2bb7 100644 --- a/docs/templates/WolkConnect-Functional-Documentation.md +++ b/docs/templates/WolkConnect-Functional-Documentation.md @@ -112,7 +112,7 @@ Sensor readings like GPS and accelerometers that hold more than one single infor ####Alarms -Alarms are derived from some data on the device and are used to indicate the state of a condition, eg. high-temperature alarm which emerged as a result of exceeding a threshold value on the device. Alarm value can either be on or off. +Alarms are derived from some data on the device and are used to indicate the state of a condition, eg. high-temperature_value alarm which emerged as a result of exceeding a threshold value on the device. Alarm value can either be on or off. Like sensor readings, alarm messages are stored on the device before being published to WolkAbout IoT Platform. Alarms can also have a UTC timestamp to denote when the alarm occurred, but if the timestamp is omitted then WolkAbout IoT Platform will assign a timestamp when it receives the alarm message. @@ -141,7 +141,7 @@ To summarize, when the actuation command is issued from WolkAbout IoT Platform, ####Configuration -Configuration is the dynamical modification of the device properties from WolkAbout IoT Platform with the goal to change device behavior, eg. measurement heartbeat, sensors delivery reduction, enabling/disabling device interfaces, increase/decrease device logging level, etc. +Configuration is the dynamical modification of the device properties from WolkAbout IoT Platform with the goal to change device behavior, eg. measurement heartbeat_value, sensors delivery reduction, enabling/disabling device interfaces, increase/decrease device logging level, etc. Configuration requires the same way of handling messages as actuations do. When a configuration command is issued from WolkAbout IoT Platform, it will be passed to the configuration handler that will attempt to execute the command. Then the configuration status provider will report back to WolkAbout IoT Platform with the current values of the configuration parameters, with the addition that configuration parameters are always sent as a whole, even when only one value changes. @@ -179,5 +179,5 @@ This firmware handler will specify the following parameters: To see how to utilize WolkConnect library APIs, visit one of the following files and look up detailed information in the Example Usage section: -- [Simple example README.md](https://github.com/Wolkabout/WolkConnect-C/blob/master/README.md) - demonstrates the sending of a temperature sensor reading +- [Simple example README.md](https://github.com/Wolkabout/WolkConnect-C/blob/master/README.md) - demonstrates the sending of a temperature_value sensor reading - [Full feature set example README.md](https://github.com/Wolkabout/WolkConnect-C/blob/master/examples/full_feature_set/README.md) - demonstrates full WolkAbout IoT Platform potential \ No newline at end of file diff --git a/examples/full_feature_set/CMakeLists.txt b/examples/full_feature_set/CMakeLists.txt index e371315..cb77e9a 100644 --- a/examples/full_feature_set/CMakeLists.txt +++ b/examples/full_feature_set/CMakeLists.txt @@ -14,6 +14,6 @@ # limitations under the License. # -add_executable(full-feature-set main.c sensor_readings.c file_management_implementation.c firmware_update_implementation.h firmware_update_implementation.c) +add_executable(full-feature-set main.c file_management_implementation.c file_management_implementation.h firmware_update_implementation.h firmware_update_implementation.c) target_link_libraries(full-feature-set WolkConnector-C pthread) diff --git a/examples/full_feature_set/README.md b/examples/full_feature_set/README.md index ea99ee1..4ba0205 100644 --- a/examples/full_feature_set/README.md +++ b/examples/full_feature_set/README.md @@ -13,7 +13,7 @@ ╚██████╗ ╚═════╝ ``` -[![Build Status](https://travis-ci.com/Wolkabout/WolkConnect-C.svg?branch=master)](https://travis-ci.com/Wolkabout/WolkConnect-C) +[![CMake](https:/*github.com/Wolkabout/WolkConnect-C/actions/workflows/cmake.yml/badge.svg?branch=development)](https:/*github.com/Wolkabout/WolkConnect-C/actions/workflows/cmake.yml) ----- WolkAbout C99 Connector library for connecting devices to WolkAbout IoT platform instance. @@ -24,24 +24,30 @@ This allows WolkConnect-C Connector to work on wide variety of systems, bare met Given examples are intended to be run on Debian based system. -Supported protocol(s): -* JSON single - Prerequisite ------ Following tools/libraries are required in order to build WolkConnect-C Connector +* libz-dev & wget +* gcc & g++ * cmake - version 2.8 or later +* libssl-dev +* clang-format +* ruby +* ceedling +* valgrind Former can be installed on Debian based system from terminal by invoking -`apt-get install cmake` +`sudo apt-get install libz-dev wget gcc g++ cmake libssl-dev clang-format ruby valgrind` + +`gem install ceedling` -When dependencies are installed, Unix Makefiles build system can generated by invoking `./configure` +When dependencies are installed, Unix Makefiles build system can be generated by invoking `./configure` Generated build system is located inside `build` directory. -WolkConnect-C Connector library, and example are built from `build` directory by invoking `make` in terminal. +WolkConnect-C Connector library, and example are built from `build` directory by invoking `make all` in terminal. Library application is built to `out/lib` directory, and example application is built to `out/bin` directory. @@ -49,7 +55,7 @@ Example Usage ------------- **Initialize WolkConnect-C Connector** -Create a device on WolkAbout IoT platform using [Full example](https://github.com/Wolkabout/WolkConnect-C/blob/master/examples/full_feature_set/full_example.json) device type. This device type fits `full_feature_set` example and demonstrates all the functionality of WolkConnect-C library. +Create a device on WolkAbout IoT platform using [Full Feature Set example](https:/*github.com/Wolkabout/WolkConnect-C/blob/master/examples/full_feature_set/full_example.json) device type. This device type fits `full_feature_set` example and demonstrates all the functionality of WolkConnect-C library. **Establishing connection with WolkAbout IoT platform:** @@ -67,26 +73,23 @@ static uint8_t persistence_storage[1024 * 1024]; /* WolkConnect-C Connector context */ static wolk_ctx_t wolk; -//... -//... -//... +/*... +/*... +/*... wolk_init(&wolk, /* Context */ send_buffer, /* See send_func_t */ receive_buffer, /* See recv_func_t */ - actuation_handler, /* Actuation handler - see actuation_handler_t */ - actuator_status_provider, /* Actuator status provider - see actuator_status_provider_t */ - configuration_handler, /* Configuration handler - see configuration_handler_t */ - configuration_provider, /* Configuration status provider - see configuration_provider_t */ device_key, device_password, /* Device key and password provided by WolkAbout IoT Platform upon device creation */ - PROTOCOL_WOLKABOUT, /* Protocol specified for device */ - actuator_references, /* Array of actuator references */ - num_actuator_references); /* Number of actuator references */ + PUSH, /* Device outbound mode - see outbound_mode_t */ + feed_value_handler, /* Feeds handler - see feed_handler_t */ + parameter_value_handler, /* Parameters handler - see parameter_handler_t */ + details_synchronization_value_handler); /* Details synchronization handler - see details_synchronization_handler_t */ wolk_init_in_memory_persistence(&wolk, /* Context */ persistence_storage, /* Address to start of the memory which will be used by persistence mechanism */ sizeof(persistence_storage), /* Size of memory in bytes */ - true); /* If storage is full overwrite oldest item when pushing */ + false); /* If storage is full overwrite the oldest item when pushing */ wolk_connect(&wolk); ``` @@ -96,40 +99,45 @@ step. See `send_func_t` and `send_func_t` in `sources/wolk_connector.h` -**Adding sensor readings:** +***Send feed value example:*** ```c -wolk_add_numeric_sensor_reading(&wolk, "T", 25.6, 0); +// Numeric +wolk_numeric_feeds_t temperature_value = {0}; +temperature_value.value = 23; +wolk_add_numeric_feed(&wolk, "T", &temperature_value, 1) -wolk_add_multi_value_numeric_sensor_reading(&wolk, "ACL", &accl_readings, 3, 0); -``` +//Boolean +wolk_boolean_feeds_t switch_value = {0}; +switch_value.switch_value = true; +wolk_add_bool_feeds(&wolk, "SW", &switch_value, 1); -**Adding events:** -```c -wolk_add_alarm(&wolk, "HH", true, 0); ``` -**Data publish strategy:** - -Sensor readings, and alarms are pushed to WolkAbout IoT platform on demand by calling +**Sending parameter example:** ```c -wolk_publish(&wolk); +wolk_parameter_t parameter; +wolk_init_parameter(¶meter, PARAMETER_MAXIMUM_MESSAGE_SIZE, "1"); +wolk_change_parameter(&wolk, ¶meter, 1); ``` -**Publishing actuator statuses:** +**Details synchronization** +Requesting all data about device from the WolkAbout IoT platform example: ```c -wolk_publish_actuator_status(&wolk, "SW"); +wolk_details_synchronization(&wolk) ``` -This will invoke the `actuator_status_provider` to read the actuator status, and publish actuator status. +Data will be received at the `details_synchronization_value_handler`. + +**Data publish strategy:** -**Publish device configuration to platform:** +Sensor readings, and alarms are pushed to WolkAbout IoT platform on demand by calling ```c -wolk_publish_configuration_status(&wolk, "CONFIGURATION_REF"); +wolk_publish(&wolk); ``` **Cooperative scheduling:** -Fuction `wolk_process(wolk_ctx_t *ctx)` is non-blocking in order to comply with cooperative scheduling, -and it must to be called periodically. +Function `wolk_process(wolk_ctx_t *ctx)` is non-blocking in order to comply with cooperative scheduling, +and it must be called periodically. ```c wolk_process(&wolk, 5); @@ -156,7 +164,7 @@ wolk_init_custom_persistence(&wolk, persistence_is_empty_impl); ``` -For more info on persistence mechanism see `sources/persistence.h` and `sources/in_memory_persistence.h` files. +For more info on persistence mechanism see `sources/persistence/persistence.h` and `sources/persistence/in_memory_persistence.h` files. **File Management:** @@ -165,56 +173,43 @@ WolkAbout C Connector provides mechanism for file management. By default this feature is disabled. See code snippet below on how to enable device file management. ```c -wolk_init_file_management(&wolk, - 128 * 1024 * 1024, // Maximum acceptable size of file, in bytes - 256, // Size of file transfer chunk, in bytes, can't be higher that MQTT_PACKET_SIZE - file_management_start, // Prepares device for receiving file - file_management_write, // Writes received file chunk - file_management_chunk_read, // Reads requested file chunk - file_management_abort, // Aborts file update sequence - file_management_finalize, // Reboots device - file_management_url_download, // Handler that obtains file from URL - file_management_is_url_download_done, // Reports URL download state (in progress | done), and it's result (success | failure) - file_management_get_file_list, // Return list of the files from directory `files` - file_management_remove_file, // Delete specific file - file_management_purge_list) // Delete all files from directory `files` +wolk_init_file_management(&wolk, /* Context */ + 128 * 1024 * 1024, /* Maximum acceptable size of file, in bytes */ + 1, /* Size of file transfer chunk, in kB, can't be higher that MQTT_PACKET_SIZE. define as parameter on the platform side */ + file_management_start, /* Prepares device for receiving file */ + file_management_write, /* Writes received file chunk */ + file_management_chunk_read, /* Reads requested file chunk */ + file_management_abort, /* Aborts file update sequence */ + file_management_finalize, /* Reboots device */ + file_management_url_download, /* Handler that obtains file from URL */ + file_management_is_url_download_done, /* Reports URL download state (in progress | done), and it's result (success | failure) */ + file_management_get_file_list, /* Return list of the files from directory `files` */ + file_management_remove_file, /* Delete specific file */ + file_management_purge_list) /* Delete all files from directory `files` */ ``` -For more info on device File Management mechanism see `file_management.h` file. +For more info on device File Management mechanism see `sources/model/file_management/file_management.h` file. **Firmware Update:** -WolkAbout C Connector provides mechanism for triggering Firmware Update. Firmware update itself isn't covered, it is platform specific and it is up to user to implement it. +WolkAbout C Connector provides mechanism for triggering Firmware Update. Firmware installation isn't covered, it is platform specific, and it is up to user to implement it. -By default this feature is disabled. See code snippet below on how to enable device file management. ```c -wolk_init_firmware_update(&wolk, - firmware_update_start_installation, // Trigger start of the firmware update - firmware_update_is_installation_completed, // Check status of the firmware update - firmware_update_verification_store, // Store verification parameters into permanent memory, obligatory - firmware_update_verification_read, // Read verification parameters from permanent memory - firmware_update_get_version, // Return current version of the firmware - firmware_update_abort_installation) // Abort current installation +wolk_init_firmware_update(&wolk, /* Context */ + firmware_update_start_installation, /* Trigger start of the firmware update */ + firmware_update_is_installation_completed, /* Check status of the firmware update */ + firmware_update_verification_store, /* Store verification parameters into permanent memory, obligatory */ + firmware_update_verification_read, /* Read verification parameters from permanent memory */ + firmware_update_abort_installation) /* Abort current installation */ ``` -For more info on device File Management mechanism see `firmware_update.h` file. - -**Ping Keep Alive Mechanism:** - -WolkAbout C Connector by default uses Keep Alive mechanism to notify WolkAbout IoT Platform that device is still connected. -Keep alive message is sent to WolkAbout IoT Platform every 10 minutes. - -To reduce network usage Ping Keep Alive mechanism can be disabled in following manner: - -```c -wolk_disable_ping_keep_alive(&wolk); -``` +For more info on device File Management mechanism see `sources/model/firmware_update.h` file. **Timestamp request** If you need access to the server's current time, you can request it in the following manner: ```c -wolk_request_timestamp(&wolk) +wolk_sync_time_request(&wolk) ``` diff --git a/examples/full_feature_set/file_management_implementation.c b/examples/full_feature_set/file_management_implementation.c index 589fe7e..8968ee0 100644 --- a/examples/full_feature_set/file_management_implementation.c +++ b/examples/full_feature_set/file_management_implementation.c @@ -31,11 +31,11 @@ static size_t file_management_current_number_of_files = 0; static size_t get_downloaded_file_position_in_list(char* first_file_list, size_t first_file_list_number_of_files, char* second_file_list, size_t second_file_list_number_of_files) { - int position_in_list = 0; - for (int i = 0; i < (first_file_list_number_of_files); i++) { + size_t position_in_list = 0; + for (size_t i = 0; i < (first_file_list_number_of_files); i++) { bool found_match = false; - for (int y = 0; y < second_file_list_number_of_files; y++) { + for (size_t y = 0; y < second_file_list_number_of_files; y++) { if (strcmp(&first_file_list[i * FILE_MANAGEMENT_FILE_NAME_SIZE], &second_file_list[y * FILE_MANAGEMENT_FILE_NAME_SIZE]) == 0) { @@ -137,7 +137,7 @@ bool file_management_start_url_download(const char* url) /* Download from URL */ /* NOTE: system() function works only on UNIX systems, for bare-metal implementation this is irrelevant */ - int8_t WGET_COMMAND_LENGTH = 9; + size_t WGET_COMMAND_LENGTH = 9; char web_address[FILE_MANAGEMENT_URL_SIZE + DIRECTORY_NAME_SIZE + WGET_COMMAND_LENGTH]; if (snprintf(web_address, FILE_MANAGEMENT_URL_SIZE + DIRECTORY_NAME_SIZE + WGET_COMMAND_LENGTH, "wget -P files/ %s", url) @@ -159,7 +159,7 @@ bool file_management_is_url_download_done(bool* success, char* downloaded_file_n memset(file_management_file_name, '\0', FILE_MANAGEMENT_FILE_NAME_SIZE + DIRECTORY_NAME_SIZE); char after_url_download_file_list[FILE_MANAGEMENT_FILE_NAME_SIZE][FILE_MANAGEMENT_FILE_NAME_SIZE] = {0}; size_t file_management_after_url_download_number_of_files = - file_management_get_file_list(after_url_download_file_list); + file_management_get_file_list((char*)after_url_download_file_list); if (file_management_after_url_download_number_of_files - file_management_current_number_of_files < 1) { return false; @@ -184,9 +184,9 @@ bool file_management_is_url_download_done(bool* success, char* downloaded_file_n return true; } -size_t file_management_get_file_list(char* file_list) +size_t file_management_get_file_list(file_list_t* file_list) { - struct dirent* de; + struct dirent* de = {0}; DIR* dr = opendir(directory_name); if (dr == NULL) { @@ -199,7 +199,19 @@ size_t file_management_get_file_list(char* file_list) if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { // Ignore unix hidden files continue; } else { - strncpy(file_list + (file_list_items * FILE_MANAGEMENT_FILE_NAME_SIZE), de->d_name, strlen(de->d_name)); + // getting file name + strncpy(file_list->file_name, de->d_name, strlen(de->d_name)); + + // getting file size + struct stat stats = {0}; + char path[FILE_MANAGEMENT_FILE_NAME_SIZE + DIRECTORY_NAME_SIZE] = {0}; + snprintf(path, FILE_MANAGEMENT_FILE_NAME_SIZE + DIRECTORY_NAME_SIZE, "%s%s", directory_name, de->d_name); + stat(path, &stats); + file_list->file_size = (size_t)stats.st_size; + + // move to next file list element + printf("File name: %s and size %d\n", file_list->file_name, (int)file_list->file_size); + file_list++; file_list_items++; } } diff --git a/examples/full_feature_set/file_management_implementation.h b/examples/full_feature_set/file_management_implementation.h index 63d6088..e3073cb 100644 --- a/examples/full_feature_set/file_management_implementation.h +++ b/examples/full_feature_set/file_management_implementation.h @@ -31,7 +31,7 @@ bool file_management_abort(void); void file_management_finalize(void); bool file_management_start_url_download(const char* url); bool file_management_is_url_download_done(bool* success, char* downloaded_file_name); -size_t file_management_get_file_list(char* file_list); +size_t file_management_get_file_list(file_list_t* file_list); bool file_management_remove_file(const char* file_name); bool file_management_purge_files(void); diff --git a/examples/full_feature_set/firmware_update_implementation.c b/examples/full_feature_set/firmware_update_implementation.c index 4cde8ee..d30a573 100644 --- a/examples/full_feature_set/firmware_update_implementation.c +++ b/examples/full_feature_set/firmware_update_implementation.c @@ -31,28 +31,15 @@ #define FIRMWARE_UPDATE_VERSION_NUMBER_OF_ELEMENTS 3 static int8_t version_major = 0; -static int8_t version_minor = 0; -static int8_t version_patch = 1; +static int8_t version_minor = 1; +static int8_t version_patch = 2; -static bool get_version(char* version); static bool get_version_from_file_content(char* source, int8_t* version); -static bool get_status_from_file_content(char* source, int8_t* status); +static bool get_status_from_file_content(char* source, uint8_t* status); static bool file_write(uint8_t* status, int8_t* version); static bool file_read(uint8_t* status, int8_t* version); -static bool get_version(char* version) -{ - if (snprintf(version, FIRMWARE_UPDATE_VERSION_SIZE, "%d%s%d%s%d", version_major, - FIRMWARE_UPDATE_VERSION_FORMAT_DELIMITER, version_minor, FIRMWARE_UPDATE_VERSION_FORMAT_DELIMITER, - version_patch) - > FIRMWARE_UPDATE_VERSION_SIZE) { - return false; - } - - return true; -} - static bool get_version_from_file_content(char* source, int8_t* version) { /* From source extract version */ @@ -63,7 +50,7 @@ static bool get_version_from_file_content(char* source, int8_t* version) return false; } while (version_string != NULL) { - *version = atoi(version_string); + *version = (int8_t)atoi(version_string); version++; version_string = strtok(NULL, FIRMWARE_UPDATE_VERSION_FORMAT_DELIMITER); } @@ -71,7 +58,7 @@ static bool get_version_from_file_content(char* source, int8_t* version) return true; } -static bool get_status_from_file_content(char* source, int8_t* status) +static bool get_status_from_file_content(char* source, uint8_t* status) { /* From source extract status */ char* element = strtok(source, FIRMWARE_UPDATE_VERIFICATION_FILE_DELIMITER); @@ -79,7 +66,7 @@ static bool get_status_from_file_content(char* source, int8_t* status) return false; } - uint8_t tmp_status = atoi(element); + uint8_t tmp_status = (uint8_t)atoi(element); if (!tmp_status) { return false; } @@ -90,11 +77,10 @@ static bool get_status_from_file_content(char* source, int8_t* status) static bool file_write(uint8_t* status, int8_t* version) { - char file_content[FIRMWARE_UPDATE_VERSION_SIZE]; - memset(file_content, '\0', FIRMWARE_UPDATE_VERSION_SIZE); - int8_t tmp_status = 0; + char file_content[FIRMWARE_UPDATE_VERSION_SIZE] = {0}; + uint8_t tmp_status = 0; int8_t tmp_version[FIRMWARE_UPDATE_VERSION_NUMBER_OF_ELEMENTS] = {0}; - *tmp_version = version; + *tmp_version = *version; if (status == NULL && version == NULL) { return false; @@ -106,13 +92,13 @@ static bool file_write(uint8_t* status, int8_t* version) tmp_status = *status; } if (version == NULL) { - if (!file_read(NULL, &tmp_version)) { + if (!file_read(NULL, tmp_version)) { tmp_version[0] = version_major; tmp_version[1] = version_minor; tmp_version[2] = version_patch; } } else { - for (int i = 0; i < FIRMWARE_UPDATE_VERSION_NUMBER_OF_ELEMENTS; i++) { + for (size_t i = 0; i < FIRMWARE_UPDATE_VERSION_NUMBER_OF_ELEMENTS; i++) { tmp_version[i] = version[i]; } } @@ -157,10 +143,7 @@ static bool file_read(uint8_t* status, int8_t* version) return true; } - if (fread(file_content, FIRMWARE_UPDATE_VERSION_SIZE, 1, file_pointer) < 0) { - printf("Firmware Update verification file read error!\n"); - return false; - } + fread(file_content, FIRMWARE_UPDATE_VERSION_SIZE, 1, file_pointer); if (strlen(file_content) == 0) { printf("Firmware Update verification file is empty!\n"); return false; @@ -192,7 +175,7 @@ bool firmware_update_start_installation(const char* file_name) int8_t firmware_update_version[FIRMWARE_UPDATE_VERSION_NUMBER_OF_ELEMENTS] = {version_major, version_minor, version_patch}; - if (!file_write(NULL, &firmware_update_version)) { + if (!file_write(NULL, firmware_update_version)) { return false; } @@ -214,17 +197,18 @@ bool firmware_update_is_installation_completed(bool* success) { int8_t firmware_update_version[FIRMWARE_UPDATE_VERSION_NUMBER_OF_ELEMENTS]; - if (!file_read(NULL, &firmware_update_version)) { + if (!file_read(NULL, firmware_update_version)) { return false; } if (version_major >= firmware_update_version[0] || version_minor >= firmware_update_version[1] || version_patch >= firmware_update_version[2]) { *success = true; - int8_t firmware_update_version[FIRMWARE_UPDATE_VERSION_NUMBER_OF_ELEMENTS] = {version_major, version_minor, - version_patch}; + firmware_update_version[0] = version_major; + firmware_update_version[1] = version_minor; + firmware_update_version[2] = version_patch; - if (!file_write(NULL, &firmware_update_version)) { + if (!file_write(NULL, firmware_update_version)) { return false; } printf("Installation is completed\n"); @@ -252,19 +236,9 @@ uint8_t firmware_update_verification_read(void) return parameter; } -bool firmware_update_get_version(const char* version) -{ - if (!get_version(version)) { - return false; - } - printf("Current Firmware Version is: %s\n", version); - - return true; -} - bool firmware_update_abort_installation(void) { - printf("Trying to abort current installation\n"); + printf("Abort current installation\n"); return true; } diff --git a/examples/full_feature_set/firmware_update_implementation.h b/examples/full_feature_set/firmware_update_implementation.h index 9fe65f7..8238256 100644 --- a/examples/full_feature_set/firmware_update_implementation.h +++ b/examples/full_feature_set/firmware_update_implementation.h @@ -24,7 +24,6 @@ bool firmware_update_start_installation(const char* file_name); bool firmware_update_is_installation_completed(bool* success); bool firmware_update_verification_store(uint8_t parameter); uint8_t firmware_update_verification_read(void); -bool firmware_update_get_version(const char* version); bool firmware_update_abort_installation(void); #endif // WOLKCONNECTOR_C_FIRMWARE_UPDATE_IMPLEMENTATION_H diff --git a/examples/full_feature_set/full_example.json b/examples/full_feature_set/full_example.json index 24cc8d7..d8bcb58 100644 --- a/examples/full_feature_set/full_example.json +++ b/examples/full_feature_set/full_example.json @@ -1 +1,54 @@ -[{"name":"Full example","description":"This device type covers all functionality provided by WolkConnect libraries implementing Wolkabout Protocol","guid":"a62f8038-242e-4e0a-82d4-af1c53477732","deviceType":"STANDARD","protocol":"JSON","connectivityType":null,"firmwareUpdateType":null,"feeds":[{"name":"Temperature","description":null,"reference":"T","unit":{"name":"CELSIUS","guid":"7c805d10-a879-11e9-83cd-0a0027000005"}},{"name":"Humidity","description":null,"reference":"H","unit":{"name":"HUMIDITY_PERCENT","guid":"7c8080a3-a879-11e9-83cd-0a0027000005"}},{"name":"Pressure","description":null,"reference":"P","unit":{"name":"MILLIBAR","guid":"7c807980-a879-11e9-83cd-0a0027000005"}},{"name":"Accelerometer","description":null,"reference":"ACL","unit":{"name":"METRES_PER_SQUARE_SECOND","guid":"7c805931-a879-11e9-83cd-0a0027000005"}}],"actuators":[{"name":"Switch","description":null,"minimum":null,"maximum":null,"reference":"SW","unit":{"name":"SWITCH(ACTUATOR)","guid":"7c8088a0-a879-11e9-83cd-0a0027000005"}},{"name":"Slider","description":null,"minimum":null,"maximum":null,"reference":"SL","unit":{"name":"RANGE (ACTUATOR)","guid":"7c8086f2-a879-11e9-83cd-0a0027000005"}}],"alarms":[{"name":"High Humidity","description":null,"reference":"HH","message":"High humidity has been detected"}],"configs":[{"name":"Heartbeat","description":null,"reference":"HB","minimum":1,"maximum":3600,"dataType":"NUMERIC","size":1,"defaultValue":"","labels":null},{"name":"Log level","description":null,"reference":"LL","minimum":null,"maximum":null,"dataType":"STRING","size":1,"defaultValue":"","labels":null},{"name":"Enabled feeds","description":null,"reference":"EF","minimum":null,"maximum":null,"dataType":"STRING","size":1,"defaultValue":"","labels":null}],"attributes":[{"name":"CONNECTIVITY_TYPE","dataType":"ENUM","validationRegex":"^(MQTT|HTTP)$","options":["MQTT","HTTP"],"defaultValue":"MQTT","required":true,"readOnly":true},{"name":"FIRMWARE_UPDATE_ENABLED","dataType":"BOOLEAN","validationRegex":"^(true|false)$","options":null,"defaultValue":null,"required":false,"readOnly":true},{"name":"FIRMWARE_VERSION","dataType":"STRING","validationRegex":null,"options":null,"defaultValue":null,"required":false,"readOnly":true},{"name":"FILE_DIRECT_DOWNLOAD_ENABLED","dataType":"BOOLEAN","validationRegex":"^(true|false)$","options":null,"defaultValue":null,"required":false,"readOnly":true},{"name":"FILE_URL_DOWNLOAD_ENABLED","dataType":"BOOLEAN","validationRegex":"^(true|false)$","options":null,"defaultValue":null,"required":false,"readOnly":true}]}] +[ + { + "semanticTypeId": 1306, + "name": "WolkConnect: Full Feature Set", + "guid": "fc49c3c8-3480-4c5d-b1a3-5d1ad3b8a272", + "description": "This device type covers all the functionality provided by WolkConnect libraries.", + "deviceType": true, + "attributes": [], + "feeds": [ + { + "id": 1309, + "name": "Temperature", + "type": "IN", + "sourceType": "DEVICE", + "unitGuid": "CELSIUS", + "reference": "T" + }, + { + "id": 1311, + "name": "Heart Beat", + "type": "IN_OUT", + "sourceType": "DEVICE", + "unitGuid": "NUMERIC", + "reference": "HB" + }, + { + "id": 1312, + "name": "Switch", + "type": "IN_OUT", + "sourceType": "DEVICE", + "unitGuid": "BOOLEAN", + "reference": "SW" + } + ], + "deviceTypeId": 1306, + "protocol": "WOLKABOUT", + "postProvisioning": "STANDARD", + "parameters": { + "FIRMWARE_UPDATE_CHECK_TIME": null, + "GATEWAY": "false", + "CONNECTIVITY_TYPE": "MQTT", + "FIRMWARE_VERSION": null, + "OUTBOUND_DATA_MODE": "PUSH", + "EXTERNAL_ID": null, + "MAXIMUM_MESSAGE_SIZE": "0", + "GATEWAY_PARENT": null, + "OUTBOUND_DATA_RETENTION_TIME": "0", + "FIRMWARE_UPDATE_ENABLED": "true", + "FILE_TRANSFER_PLATFORM_ENABLED": "true", + "FILE_TRANSFER_URL_ENABLED": "true" + }, + "id": 1306 + } +] diff --git a/examples/full_feature_set/main.c b/examples/full_feature_set/main.c index 33342d1..0b11ef3 100644 --- a/examples/full_feature_set/main.c +++ b/examples/full_feature_set/main.c @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "utility/wolk_utils.h" #include "wolk_connector.h" -#include "wolk_utils.h" #include #include @@ -29,7 +29,6 @@ #include "file_management_implementation.h" #include "firmware_update_implementation.h" -#include "sensor_readings.h" #define DEFAULT_PUBLISH_PERIOD_SECONDS 15 @@ -37,11 +36,11 @@ static SSL_CTX* ctx; static BIO* sockfd; /* WolkAbout Platform device connection parameters */ -static const char* device_key = "device_key"; -static const char* device_password = "some_password"; -static const char* hostname = "insert_host"; -static int portno = 80; // TODO: insert port -static char certs[] = "../ca.crt"; +static const char* device_key = "device_key"; +static const char* device_password = "some_password"; +static const char* hostname = "insert_host"; +static int portno = 80; // TODO: insert port +static char certs[] = "path/to/your/ca/crt/file"; /* Sample in-memory persistence storage - size 1MB */ static uint8_t persistence_storage[1024 * 1024]; @@ -49,6 +48,14 @@ static uint8_t persistence_storage[1024 * 1024]; /* WolkConnect-C Connector context */ static wolk_ctx_t wolk; +wolk_numeric_feeds_t temperature_value = {0}; +wolk_numeric_feeds_t heartbeat_value = {0}; +wolk_boolean_feeds_t switch_value = {0}; +void feed_value_handler(wolk_feed_t* feeds, size_t number_of_feeds); +void parameter_value_handler(wolk_parameter_t* parameter_message, size_t number_of_parameters); +void details_synchronization_value_handler(wolk_feed_registration_t* feeds, size_t number_of_received_feeds, + wolk_attribute_t* attributes, size_t number_of_received_attributes); + /* System dependencies */ static volatile bool keep_running = true; static void int_handler(int dummy) @@ -132,95 +139,46 @@ static void open_socket(BIO** bio, SSL_CTX** ssl_ctx, const char* addr, const in } } -/* Actuation setup and call-backs */ -static const char* actuator_references[] = {"SW", "SL"}; -static char actuator_value[READING_SIZE] = {"0"}; -static const uint32_t num_actuator_references = 2; - -static void actuation_handler(const char* reference, const char* value) +void feed_value_handler(wolk_feed_t* feeds, size_t number_of_feeds) { - printf("Actuation handler - Reference: %s Value: %s\n", reference, value); - - if ((strcmp(reference, actuator_references[0]) == 0) || (strcmp(reference, actuator_references[1]) == 0)) { - strcpy(actuator_value, value); - } else { - printf("Actuation handler - Wrong Reference\n"); + for (int i = 0; i < (int)number_of_feeds; ++i) { + printf("Received is feed with reference %s and value %s\n", feeds->reference, feeds->data[0]); + if (strstr(feeds->reference, "SW")) { + if (strstr(feeds->data[0], "true")) + switch_value.value = (bool)true; + else + switch_value.value = (bool)false; + } else if (strstr(feeds->reference, "HB")) { + heartbeat_value.value = (double)atol(feeds->data[0]); + } + feeds++; } } -static actuator_status_t actuator_status_provider(const char* reference) +void parameter_value_handler(wolk_parameter_t* parameter_message, size_t number_of_parameters) { - printf("Actuator status provider - Reference: %s\n", reference); + for (int i = 0; i < (int)number_of_parameters; ++i) { + printf("Received is parameter with name: %s and value: %s\n", parameter_message->name, + parameter_message->value); - actuator_status_t actuator_status; - actuator_status_init(&actuator_status, "", ACTUATOR_STATE_ERROR); - - if (strcmp(reference, "SW") == 0 || strcmp(reference, "SL") == 0) { - actuator_status_init(&actuator_status, actuator_value, ACTUATOR_STATE_READY); + parameter_message++; } - - return actuator_status; -} - -/* Configuration setup and call-backs */ -static int publish_period_seconds = DEFAULT_PUBLISH_PERIOD_SECONDS; -static char device_configuration_references[CONFIGURATION_ITEMS_SIZE][CONFIGURATION_REFERENCE_SIZE] = {"HB", "LL", - "EF"}; -static char device_configuration_values[CONFIGURATION_ITEMS_SIZE][CONFIGURATION_VALUE_SIZE] = {"", "INFO", "P,T,H,ACL"}; - -static void -update_default_device_configuration_values(char (*default_device_configuration_values)[CONFIGURATION_VALUE_SIZE], - int default_value) -{ - char default_publish_period[10]; - - int number_size = snprintf(default_publish_period, 10, "%d", default_value); - strncpy(&default_device_configuration_values[0], default_publish_period, (unsigned long)number_size); - enable_feeds(&default_device_configuration_values[2]); } -static void configuration_handler(char (*reference)[CONFIGURATION_REFERENCE_SIZE], - char (*value)[CONFIGURATION_VALUE_SIZE], size_t num_configuration_items) +void details_synchronization_value_handler(wolk_feed_registration_t* feeds, size_t number_of_received_feeds, + wolk_attribute_t* attributes, size_t number_of_received_attributes) { - for (size_t i = 0; i < num_configuration_items; ++i) { - size_t iteration_counter = 0; - - for (size_t j = 0; j < CONFIGURATION_ITEMS_SIZE; ++j) { - if (!strcmp(reference[i], device_configuration_references[j])) { - strcpy(device_configuration_values[j], value[i]); - printf("Configuration handler - Reference: %s | Value: %s\n", reference[i], value[i]); - - if (!strcmp(reference[i], device_configuration_references[0])) { - publish_period_seconds = atoi(value[i]); - } else if (!strcmp(reference[i], device_configuration_references[2])) { - enable_feeds(value[i]); - } - } else - iteration_counter++; - - if (iteration_counter == CONFIGURATION_ITEMS_SIZE) { - printf("Unrecognised Reference received!\n"); - } - } + for (int i = 0; i < (int)number_of_received_feeds; ++i) { + printf("Received is feed with name: %s\n", feeds->name); + feeds++; } -} - -static size_t configuration_provider(char (*reference)[CONFIGURATION_REFERENCE_SIZE], - char (*value)[CONFIGURATION_VALUE_SIZE], size_t max_num_configuration_items) -{ - WOLK_UNUSED(max_num_configuration_items); - WOLK_ASSERT(max_num_configuration_items >= NUMBER_OF_CONFIGURATION); - for (size_t i = 0; i < CONFIGURATION_ITEMS_SIZE; ++i) { - strcpy(reference[i], device_configuration_references[i]); - strncpy(value[i], device_configuration_values[i], CONFIGURATION_VALUE_SIZE); - printf("Configuration provider - Reference: %s | Value: %s\n", reference[i], value[i]); + for (int i = 0; i < (int)number_of_received_attributes; ++i) { + printf("Received is attributes with name: %s\n", attributes->name); + attributes++; } - - return CONFIGURATION_ITEMS_SIZE; } - int main(int argc, char* argv[]) { WOLK_UNUSED(argc); @@ -229,6 +187,8 @@ int main(int argc, char* argv[]) signal(SIGINT, int_handler); signal(SIGTERM, int_handler); + heartbeat_value.value = DEFAULT_PUBLISH_PERIOD_SECONDS; + if (strcmp(device_key, "device_key") == 0) { printf("Wolk client - Error, device key not provided\n"); return 1; @@ -246,20 +206,19 @@ int main(int argc, char* argv[]) return 1; } - if (wolk_init(&wolk, send_buffer, receive_buffer, actuation_handler, actuator_status_provider, - configuration_handler, configuration_provider, device_key, device_password, PROTOCOL_WOLKABOUT, - actuator_references, num_actuator_references) + if (wolk_init(&wolk, send_buffer, receive_buffer, device_key, device_password, PUSH, feed_value_handler, + parameter_value_handler, details_synchronization_value_handler) != W_FALSE) { - printf("Error initializing WolkConnect-C\n"); + printf("Wolk client - Error initializing WolkConnect-C\n"); return 1; } if (wolk_init_in_memory_persistence(&wolk, persistence_storage, sizeof(persistence_storage), false) != W_FALSE) { - printf("Error initializing in-memory persistence\n"); + printf("Wolk client - Error initializing in-memory persistence\n"); return 1; } - if (wolk_init_file_management(&wolk, 128 * 1024 * 1024, 500, file_management_start, file_management_chunk_write, + if (wolk_init_file_management(&wolk, 128 * 1024 * 1024, 1024, file_management_start, file_management_chunk_write, file_management_chunk_read, file_management_abort, file_management_finalize, file_management_start_url_download, file_management_is_url_download_done, file_management_get_file_list, file_management_remove_file, @@ -271,31 +230,54 @@ int main(int argc, char* argv[]) if (wolk_init_firmware_update(&wolk, firmware_update_start_installation, firmware_update_is_installation_completed, firmware_update_verification_store, firmware_update_verification_read, - firmware_update_get_version, firmware_update_abort_installation) + firmware_update_abort_installation) != W_FALSE) { printf("Error initializing Firmware Update"); return 1; } - update_default_device_configuration_values(device_configuration_values, DEFAULT_PUBLISH_PERIOD_SECONDS); - printf("Wolk client - Connecting to server\n"); if (wolk_connect(&wolk) != W_FALSE) { printf("Wolk client - Error connecting to server\n"); - return -1; + return 1; } printf("Wolk client - Connected to server\n"); - wolk_add_alarm(&wolk, "HH", true, 0); + wolk_sync_time_request(&wolk); + wolk_details_synchronization(&wolk); wolk_publish(&wolk); + int32_t tick_count = 0; + while (keep_running) { + // Sending feeds on heartbeat + if (tick_count > (heartbeat_value.value) * 100000) { + printf("Wolk client - Sending feed readings:\n"); + + temperature_value.value = rand() % 100 - 20; + printf("Temperature feed with value: %lf °C\n", temperature_value.value); + wolk_add_numeric_feed(&wolk, "T", &temperature_value, 1); + + printf("Heartbeat feed with value: %lf seconds\n", heartbeat_value.value); + wolk_add_numeric_feed(&wolk, "HB", &heartbeat_value, 1); + + printf("Switch feed with value: %s\n", switch_value.value == (bool)true ? "true" : "false"); + wolk_add_bool_feeds(&wolk, "SW", &switch_value, 1); + + if (wolk_publish(&wolk)) { + printf("Wolk client - Error publishing feeds!\n"); + return 1; + } + + tick_count = 0; + } + // MANDATORY: sleep(currently 1000us) and number of tick(currently 1) when are multiplied needs to give 1ms. // you can change this parameters, but keep it's multiplication - usleep(1000); + usleep(10); wolk_process(&wolk, 1); - sensor_readings_process(&wolk, &publish_period_seconds, DEFAULT_PUBLISH_PERIOD_SECONDS); + tick_count++; } printf("Wolk client - Disconnecting\n"); diff --git a/examples/full_feature_set/sensor_readings.c b/examples/full_feature_set/sensor_readings.c deleted file mode 100644 index 1755c49..0000000 --- a/examples/full_feature_set/sensor_readings.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2020 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sensor_readings.h" - -static bool device_configuration_enable_feeds[4][1] = {true, true, true, true}; - -static void sending_pressure_reading(wolk_ctx_t* ctx) -{ - if (device_configuration_enable_feeds[2][0]) { - int8_t pressure = 0; - - pressure = (rand() % 800) + 300; - wolk_add_numeric_sensor_reading(ctx, "P", pressure, 0); - wolk_publish(ctx); - printf("\tPressure\t: %dmb\n", pressure); - } -} - -static void sending_temperature_reading(wolk_ctx_t* ctx) -{ - if (device_configuration_enable_feeds[0][0]) { - int8_t temperature = 0; - - temperature = (rand() % 125) - 40; - wolk_add_numeric_sensor_reading(ctx, "T", temperature, 0); - wolk_publish(ctx); - printf("\tTemperature\t: %d°C\n", temperature); - } -} - -static void sending_humidity_reading(wolk_ctx_t* ctx) -{ - if (device_configuration_enable_feeds[1][0]) { - int8_t humidity = 0; - - humidity = rand() % 100; - wolk_add_numeric_sensor_reading(ctx, "H", humidity, 0); - wolk_publish(ctx); - printf("\tHumidity\t: %d%%\n", humidity); - } -} - -static void sending_accl_readings(wolk_ctx_t* ctx) -{ - if (device_configuration_enable_feeds[3][0]) { - double accl_readings[3] = {1, 0, 0}; - - wolk_add_multi_value_numeric_sensor_reading(ctx, "ACL", &accl_readings[0], 3, 0); - printf("\tAcceleration on XYZ\t: %fg, %fg, %fg\n", accl_readings[0], accl_readings[1], accl_readings[2]); - wolk_publish(ctx); - } -} - - -bool enable_feeds(char* value) -{ - int8_t elements_counter = 0; - const char delimiter[2] = ","; - char tmp_value[CONFIGURATION_VALUE_SIZE]; - strncpy(tmp_value, value, strlen(value)); - char* element = strtok(tmp_value, delimiter); - - for (int i = 0; i < 4; i++) { - device_configuration_enable_feeds[i][0] = false; - } - - while (element != NULL) { - if (!strcmp(element, "T")) - device_configuration_enable_feeds[0][0] = true; - else if (!strcmp(element, "H")) - device_configuration_enable_feeds[1][0] = true; - else if (!strcmp(element, "P")) - device_configuration_enable_feeds[2][0] = true; - else if (!strcmp(element, "ACL")) - device_configuration_enable_feeds[3][0] = true; - - element = strtok(NULL, delimiter); - - if (elements_counter++ > 4) - break; - } - return 0; -} - -bool sensor_readings_process(wolk_ctx_t* ctx, int* publish_period_seconds, int default_publish_value) -{ - static double publish_period_counter = 0; - - if (publish_period_seconds < default_publish_value) - return 1; - - publish_period_counter++; - if (publish_period_counter > (*publish_period_seconds) * 1000) { - printf("Sending sensor readings:\n"); - sending_pressure_reading(ctx); - sending_temperature_reading(ctx); - sending_humidity_reading(ctx); - sending_accl_readings(ctx); - - publish_period_counter = 0; - } - return 0; -} diff --git a/examples/pull/CMakeLists.txt b/examples/pull/CMakeLists.txt new file mode 100644 index 0000000..f0b299c --- /dev/null +++ b/examples/pull/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# Copyright 2022 WolkAbout Technology s.r.o. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +add_executable(pull main.c) + +target_link_libraries(pull WolkConnector-C) diff --git a/examples/pull/main.c b/examples/pull/main.c new file mode 100644 index 0000000..2f2d3c8 --- /dev/null +++ b/examples/pull/main.c @@ -0,0 +1,259 @@ +/* + * Copyright 2022 WolkAbout Technology s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utility/wolk_utils.h" +#include "wolk_connector.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +static SSL_CTX* ctx; +static BIO* sockfd; + +/* WolkAbout Platform device connection parameters */ +static const char* device_key = "device_key"; +static const char* device_password = "some_password"; +static const char* hostname = "insert_host"; +static int portno = 80; // TODO: insert port +static char certs[] = "path/to/your/ca/crt/file"; + +/* Sample in-memory persistence storage - size 1MB */ +static uint8_t persistence_storage[1024 * 1024]; + +/* WolkConnect-C Connector context */ +static wolk_ctx_t wolk; + +static volatile bool keep_running = true; + +static volatile bool received_feeds = false; +static volatile bool received_parameters = false; +wolk_boolean_feeds_t switch_feed = {0}; +wolk_numeric_feeds_t heartbeat_feed = {0}; + +void feed_value_handler(wolk_feed_t* feeds, size_t number_of_feeds); +void parameters_value_handler(wolk_parameter_t* parameters, size_t number_of_parameters); + +static void int_handler(int dummy) +{ + WOLK_UNUSED(dummy); + + keep_running = false; +} + +static int send_buffer(unsigned char* buffer, unsigned int len) +{ + int n; + + n = (int)BIO_write(sockfd, buffer, (int)len); + if (n < 0) { + return -1; + } + + return n; +} + +static int receive_buffer(unsigned char* buffer, unsigned int max_bytes) +{ + bzero(buffer, max_bytes); + int n; + + n = (int)BIO_read(sockfd, buffer, (int)max_bytes); + if (n < 0) { + return -1; + } + + return n; +} + +static void open_socket(BIO** bio, SSL_CTX** ssl_ctx, const char* addr, const int port_number, const char* ca_file, + const char* ca_path) +{ + SSL* ssl; + char port[5]; + snprintf(port, 5, "%d", port_number); + + /* Load OpenSSL */ + SSL_load_error_strings(); + ERR_load_BIO_strings(); + OpenSSL_add_all_algorithms(); + SSL_library_init(); + + *ssl_ctx = SSL_CTX_new(SSLv23_client_method()); + + /* Load Certificate */ + if (!SSL_CTX_load_verify_locations(*ssl_ctx, ca_file, ca_path)) { + printf("Wolk client - Error, failed to load certificate\n"); + exit(1); + } + + /* Open BIO Socket */ + *bio = BIO_new_ssl_connect(*ssl_ctx); + BIO_get_ssl(*bio, &ssl); + SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); + BIO_set_conn_hostname(*bio, addr); + BIO_set_nbio(*bio, 1); + BIO_set_conn_port(*bio, port); + + /* Wait for connection in 15 second timeout */ + int start_time = (int)time(NULL); + while (BIO_do_connect(*bio) <= 0 && (int)time(NULL) - start_time < 15) + ; + if (BIO_do_connect(*bio) <= 0) { + printf("Wolk client - Error, do connect\n"); + BIO_free_all(*bio); + SSL_CTX_free(*ssl_ctx); + *bio = NULL; + *ssl_ctx = NULL; + return; + } + + /* Verify Certificate */ + if (SSL_get_verify_result(ssl) != X509_V_OK) { + printf("Wolk client - Error, x509 certificate verification failed\n"); + exit(1); + } +} + +void feed_value_handler(wolk_feed_t* feeds, size_t number_of_feeds) +{ + printf("Receiving feeds.\n"); + + for (size_t i = 0; i < number_of_feeds; ++i) { + printf("Received is feed with reference %s and value %s\n", feeds->reference, feeds->data[i]); + if (strstr(feeds->reference, "SW")) { + if (strstr(feeds->data[0], "true")) + switch_feed.value = (bool)true; + else + switch_feed.value = (bool)false; + } else if (strstr(feeds->reference, "HB")) { + heartbeat_feed.value = (double)atol(feeds->data[0]); + } + feeds++; + } + received_feeds = true; +} + +void parameters_value_handler(wolk_parameter_t* parameters, size_t number_of_parameters) +{ + printf("Receiving parameters.\n"); + + for (size_t i = 0; i < number_of_parameters; ++i) { + printf("Received is parameters with name %s and value %s\n", parameters->name, parameters->value); + parameters++; + } + received_parameters = true; +} + +int main(int argc, char* argv[]) +{ + WOLK_UNUSED(argc); + WOLK_UNUSED(argv); + + signal(SIGINT, int_handler); + signal(SIGTERM, int_handler); + + heartbeat_feed.value = 10; // default heartbeat_value + + if (strcmp(device_key, "device_key") == 0) { + printf("Wolk client - Error, device key not provided\n"); + return 1; + } + + if (strcmp(device_password, "password") == 0) { + printf("Wolk client - Error, password key not provided\n"); + return 1; + } + + + while (keep_running) { + printf("Wolk client - Establishing connection to WolkAbout IoT platform\n"); + open_socket(&sockfd, &ctx, hostname, portno, certs, NULL); + if (sockfd == NULL) { + printf("Wolk client - Error establishing connection to WolkAbout IoT platform\n"); + return 1; + } + + if (wolk_init(&wolk, send_buffer, receive_buffer, device_key, device_password, PULL, feed_value_handler, + parameters_value_handler, NULL) + != W_FALSE) { + printf("Wolk client - Error initializing WolkConnect-C\n"); + return 1; + } + + if (wolk_init_in_memory_persistence(&wolk, persistence_storage, sizeof(persistence_storage), false) + != W_FALSE) { + printf("Wolk client - Error initializing in-memory persistence\n"); + return 1; + } + + printf("Wolk client - Connecting to server\n"); + if (wolk_connect(&wolk) != W_FALSE) { + printf("Wolk client - Error connecting to server\n"); + return 1; + } + printf("Wolk client - Connected to server\n"); + + printf("Wolk client - Pulling values from platform\n"); + wolk_pull_feed_values(&wolk); + wolk_pull_parameters(&wolk); + if (wolk_publish(&wolk)) { + printf("Wolk client - Error publishing pull values!\n"); + return 1; + } + + int32_t awake_time = 0; + while (!received_feeds && !received_parameters) { + // MANDATORY: keep looping for a new messages. Sleep(currently 1000us) and number of tick(currently 1) + // you can change this parameter, but keep it's multiplication + usleep(1000); + wolk_process(&wolk, 1); + awake_time++; + + if (awake_time > 3000) // wait for platform response 3 seconds + break; + } + + printf("Wolk client - Sending feeds\n"); + wolk_add_bool_feeds(&wolk, "SW", &switch_feed, 1); + wolk_add_numeric_feed(&wolk, "HB", &heartbeat_feed, 1); + if (wolk_publish(&wolk)) { + printf("Wolk client - Error publishing feeds!\n"); + return 1; + } + + printf("Wolk client - Disconnecting\n"); + wolk_disconnect(&wolk); + BIO_free_all(sockfd); + + printf("Wolk client - Entering sleep mode.\n"); + sleep((unsigned int)heartbeat_feed.value); // Sleep commanded value from platform + } + + printf("Wolk client - Disconnecting\n"); + wolk_disconnect(&wolk); + BIO_free_all(sockfd); + + return 0; +} diff --git a/examples/pull/pull_example.json b/examples/pull/pull_example.json new file mode 100644 index 0000000..d59d19e --- /dev/null +++ b/examples/pull/pull_example.json @@ -0,0 +1,46 @@ +[ + { + "semanticTypeId": 1002, + "name": "WolkConnect: Pull Example", + "guid": "da2c9674-0d86-4772-a502-6a15e8d0a16b", + "description": "Device type that periodically connects to the Platform to pull feed values for its Switch and Heart beat feeds.", + "deviceType": true, + "attributes": [], + "feeds": [ + { + "id": 1003, + "name": "Heart Beat", + "type": "IN_OUT", + "sourceType": "DEVICE", + "unitGuid": "NUMERIC", + "reference": "HB" + }, + { + "id": 1002, + "name": "Switch", + "type": "IN_OUT", + "sourceType": "DEVICE", + "unitGuid": "BOOLEAN", + "reference": "SW" + } + ], + "deviceTypeId": 1002, + "protocol": "WOLKABOUT", + "postProvisioning": "STANDARD", + "parameters": { + "FIRMWARE_UPDATE_CHECK_TIME": null, + "GATEWAY": "false", + "CONNECTIVITY_TYPE": "MQTT", + "FIRMWARE_VERSION": null, + "OUTBOUND_DATA_MODE": "PULL", + "EXTERNAL_ID": null, + "MAXIMUM_MESSAGE_SIZE": "0", + "GATEWAY_PARENT": null, + "OUTBOUND_DATA_RETENTION_TIME": "0", + "FIRMWARE_UPDATE_ENABLED": "false", + "FILE_TRANSFER_PLATFORM_ENABLED": "false", + "FILE_TRANSFER_URL_ENABLED": "false" + }, + "id": 1002 + } +] \ No newline at end of file diff --git a/examples/register_feed_and_attribute/CMakeLists.txt b/examples/register_feed_and_attribute/CMakeLists.txt new file mode 100644 index 0000000..503db52 --- /dev/null +++ b/examples/register_feed_and_attribute/CMakeLists.txt @@ -0,0 +1,19 @@ +# +# Copyright 2022 WolkAbout Technology s.r.o. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +add_executable(register_feed_and_attribute main.c) + +target_link_libraries(register_feed_and_attribute WolkConnector-C) diff --git a/examples/register_feed_and_attribute/main.c b/examples/register_feed_and_attribute/main.c new file mode 100644 index 0000000..1cce110 --- /dev/null +++ b/examples/register_feed_and_attribute/main.c @@ -0,0 +1,211 @@ +/* + * Copyright 2022 WolkAbout Technology s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utility/wolk_utils.h" +#include "wolk_connector.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +static SSL_CTX* ctx; +static BIO* sockfd; + +/* WolkAbout Platform device connection parameters */ +static const char* device_key = "device_key"; +static const char* device_password = "some_password"; +static const char* hostname = "insert_host"; +static int portno = 80; // TODO: insert port +static char certs[] = "../ca.crt"; + +/* Sample in-memory persistence storage - size 1MB */ +static uint8_t persistence_storage[1024 * 1024]; + +/* WolkConnect-C Connector context */ +static wolk_ctx_t wolk; + +static volatile bool keep_running = true; + + +static void int_handler(int dummy) +{ + WOLK_UNUSED(dummy); + + keep_running = false; +} + +static int send_buffer(unsigned char* buffer, unsigned int len) +{ + int n; + + n = (int)BIO_write(sockfd, buffer, (int)len); + if (n < 0) { + return -1; + } + + return n; +} + +static int receive_buffer(unsigned char* buffer, unsigned int max_bytes) +{ + bzero(buffer, max_bytes); + int n; + + n = (int)BIO_read(sockfd, buffer, (int)max_bytes); + if (n < 0) { + return -1; + } + + return n; +} + +static void open_socket(BIO** bio, SSL_CTX** ssl_ctx, const char* addr, const int port_number, const char* ca_file, + const char* ca_path) +{ + SSL* ssl; + char port[5]; + snprintf(port, 5, "%d", port_number); + + /* Load OpenSSL */ + SSL_load_error_strings(); + ERR_load_BIO_strings(); + OpenSSL_add_all_algorithms(); + SSL_library_init(); + + *ssl_ctx = SSL_CTX_new(SSLv23_client_method()); + + /* Load Certificate */ + if (!SSL_CTX_load_verify_locations(*ssl_ctx, ca_file, ca_path)) { + printf("Wolk client - Error, failed to load certificate\n"); + exit(1); + } + + /* Open BIO Socket */ + *bio = BIO_new_ssl_connect(*ssl_ctx); + BIO_get_ssl(*bio, &ssl); + SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); + BIO_set_conn_hostname(*bio, addr); + BIO_set_nbio(*bio, 1); + BIO_set_conn_port(*bio, port); + + /* Wait for connection in 15 second timeout */ + int start_time = (int)time(NULL); + while (BIO_do_connect(*bio) <= 0 && (int)time(NULL) - start_time < 15) + ; + if (BIO_do_connect(*bio) <= 0) { + printf("Wolk client - Error, do connect\n"); + BIO_free_all(*bio); + SSL_CTX_free(*ssl_ctx); + *bio = NULL; + *ssl_ctx = NULL; + return; + } + + /* Verify Certificate */ + if (SSL_get_verify_result(ssl) != X509_V_OK) { + printf("Wolk client - Error, x509 certificate verification failed\n"); + exit(1); + } +} + + +int main(int argc, char* argv[]) +{ + WOLK_UNUSED(argc); + WOLK_UNUSED(argv); + + signal(SIGINT, int_handler); + signal(SIGTERM, int_handler); + + if (strcmp(device_key, "device_key") == 0) { + printf("Wolk client - Error, device key not provided\n"); + return 1; + } + + if (strcmp(device_password, "password") == 0) { + printf("Wolk client - Error, password key not provided\n"); + return 1; + } + + printf("Wolk client - Establishing connection to WolkAbout IoT platform\n"); + open_socket(&sockfd, &ctx, hostname, portno, certs, NULL); + if (sockfd == NULL) { + printf("Wolk client - Error establishing connection to WolkAbout IoT platform\n"); + return 1; + } + + if (wolk_init(&wolk, send_buffer, receive_buffer, device_key, device_password, PUSH, NULL, NULL, NULL) != W_FALSE) { + printf("Wolk client - Error initializing WolkConnect-C\n"); + return 1; + } + + if (wolk_init_in_memory_persistence(&wolk, persistence_storage, sizeof(persistence_storage), false) != W_FALSE) { + printf("Wolk client - Error initializing in-memory persistence\n"); + return 1; + } + + printf("Wolk client - Connecting to server\n"); + if (wolk_connect(&wolk) != W_FALSE) { + printf("Wolk client - Error connecting to server\n"); + return -1; + } + printf("Wolk client - Connected to server\n"); + + wolk_feed_registration_t feed_registration; + wolk_init_feed(&feed_registration, "New Feed", "NF", UNIT_NUMERIC, IN); + wolk_register_feed(&wolk, &feed_registration, 1); + if (wolk_publish(&wolk)) { + printf("Wolk client - Error publishing feed registration!\n"); + return 1; + } + + int32_t tick_count = 0; + wolk_numeric_feeds_t feed = {0}; + int32_t heartbeat = 60000; // 60 000ms == 1min + + while (keep_running) { + if (tick_count > heartbeat) { + tick_count = 0; + feed.value = rand() % 100 - 20; + if (wolk_add_numeric_feed(&wolk, feed_registration.reference, &feed, 1)) + printf("Wolk client - Error serializing numeric feed!\n"); + if (wolk_publish(&wolk)) + printf("Wolk client - Error publishing numeric feed!\n"); + else + printf("Wolk client - for feed reference T published value is %lf\n", feed.value); + } + + // MANDATORY: keep looping for a new messages. Sleep(currently 1000us) and number of tick(currently 1) + // you can change this parameter, but keep it's multiplication + usleep(1000); + wolk_process(&wolk, 1); + tick_count++; + } + + printf("Wolk client - Diconnecting\n"); + wolk_disconnect(&wolk); + BIO_free_all(sockfd); + + return 0; +} diff --git a/examples/simple/CMakeLists.txt b/examples/simple/CMakeLists.txt old mode 100644 new mode 100755 index 091a4a5..45d849f --- a/examples/simple/CMakeLists.txt +++ b/examples/simple/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2018 WolkAbout Technology s.r.o. +# Copyright 2022 WolkAbout Technology s.r.o. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/examples/simple/main.c b/examples/simple/main.c index cff9472..62696b2 100644 --- a/examples/simple/main.c +++ b/examples/simple/main.c @@ -1,5 +1,5 @@ /* - * Copyright 2018 WolkAbout Technology s.r.o. + * Copyright 2022 WolkAbout Technology s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,8 +14,8 @@ * limitations under the License. */ +#include "utility/wolk_utils.h" #include "wolk_connector.h" -#include "wolk_utils.h" #include #include @@ -33,11 +33,11 @@ static SSL_CTX* ctx; static BIO* sockfd; /* WolkAbout Platform device connection parameters */ -static const char* device_key = "device_key"; -static const char* device_password = "some_password"; -static const char* hostname = "insert_host"; -static int portno = 80; // TODO: insert port -static char certs[] = "../ca.crt"; +static const char* device_key = "device_key"; +static const char* device_password = "some_password"; +static const char* hostname = "insert_host"; +static int portno = 80; // TODO: insert port +static char certs[] = "path/to/your/ca/crt/file"; /* Sample in-memory persistence storage - size 1MB */ static uint8_t persistence_storage[1024 * 1024]; @@ -155,15 +155,13 @@ int main(int argc, char* argv[]) return 1; } - if (wolk_init(&wolk, send_buffer, receive_buffer, NULL, ACTUATOR_STATE_READY, NULL, NULL, device_key, - device_password, PROTOCOL_WOLKABOUT, NULL, 0) - != W_FALSE) { - printf("Error initializing WolkConnect-C\n"); + if (wolk_init(&wolk, send_buffer, receive_buffer, device_key, device_password, PUSH, NULL, NULL, NULL) != W_FALSE) { + printf("Wolk client - Error initializing WolkConnect-C\n"); return 1; } if (wolk_init_in_memory_persistence(&wolk, persistence_storage, sizeof(persistence_storage), false) != W_FALSE) { - printf("Error initializing in-memory persistence\n"); + printf("Wolk client - Error initializing in-memory persistence\n"); return 1; } @@ -174,15 +172,28 @@ int main(int argc, char* argv[]) } printf("Wolk client - Connected to server\n"); - wolk_add_numeric_sensor_reading(&wolk, "T", rand() % 100 - 20, 0); - wolk_publish(&wolk); - + int32_t tick_count = 0; + wolk_numeric_feeds_t feed = {0}; + int32_t heartbeat = 60000; // 60 000ms == 1min while (keep_running) { - // MANDATORY: sleep(currently 1000us) and number of tick(currently 1) when are multiplied needs to give 1ms. - // you can change this parameters, but keep it's multiplication + // Sending random values for reference "T" + if (tick_count > heartbeat) { + tick_count = 0; + feed.value = rand() % 100 - 20; + if (wolk_add_numeric_feed(&wolk, "T", &feed, 1)) + printf("Wolk client - Error serializing numeric feed!\n"); + if (wolk_publish(&wolk)) + printf("Wolk client - Error publishing data!\n"); + else + printf("Wolk client - for feed reference T published value is %lf\n", feed.value); + } + + // MANDATORY: keep looping for a new messages. Sleep(currently 1000us) and number of tick(currently 1) + // you can change this parameter, but keep it's multiplication usleep(1000); wolk_process(&wolk, 1); + tick_count++; } printf("Wolk client - Diconnecting\n"); diff --git a/examples/simple/simple_example.json b/examples/simple/simple_example.json old mode 100644 new mode 100755 index cd7e02b..8ec18ee --- a/examples/simple/simple_example.json +++ b/examples/simple/simple_example.json @@ -1 +1,38 @@ -[{"name":"Simple example","description":"A minimal device type with one sensor temperature sensor","guid":"eb7b6faa-f45b-4ebb-a68b-52f81fb33fdf","deviceType":"STANDARD","protocol":"JSON","connectivityType":null,"firmwareUpdateType":null,"feeds":[{"name":"Temperature","description":"","reference":"T","unit":{"name":"CELSIUS","guid":"7c805d10-a879-11e9-83cd-0a0027000005"}}],"actuators":[],"alarms":[],"configs":[],"attributes":[{"name":"CONNECTIVITY_TYPE","dataType":"ENUM","validationRegex":"^(MQTT|HTTP)$","options":["MQTT","HTTP"],"defaultValue":"MQTT","required":true,"readOnly":true}]}] +[ + { + "semanticTypeId": 2215, + "name": "WolkConnect: Simple Example", + "guid": "759e5590-8e1d-4e69-9522-9d2830d7b1f0", + "description": "A minimalistic device type that contains a single temperature feed, measured in Celsius.", + "deviceType": true, + "attributes": [], + "feeds": [ + { + "id": 2233, + "name": "Temperature", + "type": "IN", + "sourceType": "DEVICE", + "unitGuid": "CELSIUS", + "reference": "T" + } + ], + "deviceTypeId": 2207, + "protocol": "WOLKABOUT", + "postProvisioning": "STANDARD", + "parameters": { + "FIRMWARE_UPDATE_CHECK_TIME": null, + "GATEWAY": "false", + "CONNECTIVITY_TYPE": "MQTT", + "FIRMWARE_VERSION": null, + "OUTBOUND_DATA_MODE": "PUSH", + "EXTERNAL_ID": null, + "MAXIMUM_MESSAGE_SIZE": "0", + "GATEWAY_PARENT": null, + "OUTBOUND_DATA_RETENTION_TIME": "0", + "FIRMWARE_UPDATE_ENABLED": "false", + "FILE_TRANSFER_PLATFORM_ENABLED": "false", + "FILE_TRANSFER_URL_ENABLED": "false" + }, + "id": 2207 + } +] diff --git a/out/ca.crt b/out/ca.crt deleted file mode 100644 index 5fda874..0000000 --- a/out/ca.crt +++ /dev/null @@ -1,24 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID+TCCAuGgAwIBAgIJALziVdQtf/cdMA0GCSqGSIb3DQEBCwUAMIGRMQswCQYD -VQQGEwJSUzEPMA0GA1UECAwGU2VyYmlhMREwDwYDVQQHDAhOb3ZpIFNhZDESMBAG -A1UECgwJd29sa2Fib3V0MQwwCgYDVQQLDANSJkQxFjAUBgNVBAMMDXdvbGthYm91 -dC5jb20xJDAiBgkqhkiG9w0BCQEWFXN1cHBvcnRAd29sa2Fib3V0LmNvbTAgFw0x -NTEyMTAxMjM5MTBaGA8yMDY1MTEyNzEyMzkxMFowgZExCzAJBgNVBAYTAlJTMQ8w -DQYDVQQIDAZTZXJiaWExETAPBgNVBAcMCE5vdmkgU2FkMRIwEAYDVQQKDAl3b2xr -YWJvdXQxDDAKBgNVBAsMA1ImRDEWMBQGA1UEAwwNd29sa2Fib3V0LmNvbTEkMCIG -CSqGSIb3DQEJARYVc3VwcG9ydEB3b2xrYWJvdXQuY29tMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEArtC2J/J8VKhXMkta6OowpWKAF0h3CawDUlTYew8n -nlegp+cM1taKyNuvUd5BZnuij7gvHXGk5QAndRZ9/fJZxAx9xmi62Z43721lnx/3 -YRgfbE11ZFwtPx8yNg26LjxswXE4fiUSIFnyePcHvEfnOYPsTPl/uKtD6DsJKJ1j -uWZH9UZJ5xbeazHKSV3UXdnz8nCMm/1Cka6p+Pa8op94/ffWe663NiUl71kRH3Nw -j8Em3FAbygbDT91DjLfwow1uOUpZmegBlzYhjgquIZNQKVSXf6RzHaAx11WMr5b5 -vGUF0YFcx6Aupw0plQ8Qu2nqcUjaVmJs8SaMnsTrhfVJgwIDAQABo1AwTjAdBgNV -HQ4EFgQUC5OcSxux5M+3DPsaN1RKKMx9MZ8wHwYDVR0jBBgwFoAUC5OcSxux5M+3 -DPsaN1RKKMx9MZ8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAnEfo -crjsLcf2dCeA5G7snqQR/V2KMm6VUR0oGaOYK6ADLDoHm+HbCYlMP5P6NGJixBCn -vvbT/cIiyineGQNTAf8Z+XNcN6IOyyB6p8NqATznfr+IlWTAa/qmLfpx8UIYS5NP -pG0oUpQPsuULTB4H4vOsowXxarkUgvlOoXw3oL5jVvWZ6chvFL6WkkBap84IK78j -4rqabTWVRA+X55KN5nlaXtp+6pW4XYQ3MCBfWFdstYOvz9pN85Sv5GgJDuylg/GH -GXg8iLE7Y/Ckt/7rjUftNV8BH95mkA9f7va/VAgXCt9Y1i+pAEm9Rm6p0hi+ha2f -OI8oa7ayZdHo/ihrpQ== ------END CERTIFICATE----- diff --git a/sources/actuator_command.c b/sources/actuator_command.c deleted file mode 100644 index 5699705..0000000 --- a/sources/actuator_command.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "actuator_command.h" -#include "wolk_utils.h" - -#include - -void actuator_command_init(actuator_command_t* command, actuator_command_type_t type, const char* reference, - const char* argument) -{ /* Sanity check */ - WOLK_ASSERT(strlen(reference) <= MANIFEST_ITEM_REFERENCE_SIZE); - WOLK_ASSERT(strlen(argument) <= COMMAND_ARGUMENT_SIZE); - - command->type = type; - - strcpy(command->reference, reference); - strcpy(command->argument, argument); -} - -actuator_command_type_t actuator_command_get_type(actuator_command_t* command) -{ - return command->type; -} - -char* actuator_command_get_reference(actuator_command_t* command) -{ - return command->reference; -} - -void actuator_command_set_reference(actuator_command_t* command, const char* reference) -{ - /* Sanity check */ - WOLK_ASSERT(strlen(reference) < MANIFEST_ITEM_REFERENCE_SIZE); - - strcpy(command->reference, reference); -} - -char* actuator_command_get_value(actuator_command_t* command) -{ - return command->argument; -} diff --git a/sources/actuator_command.h b/sources/actuator_command.h deleted file mode 100644 index fc54360..0000000 --- a/sources/actuator_command.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ACTUATOR_COMMAND_H -#define ACTUATOR_COMMAND_H - -#include "size_definitions.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - ACTUATOR_COMMAND_TYPE_STATUS = 0, - ACTUATOR_COMMAND_TYPE_SET, - - ACTUATOR_COMMAND_TYPE_UNKNOWN -} actuator_command_type_t; - -typedef struct { - actuator_command_type_t type; - - char reference[MANIFEST_ITEM_REFERENCE_SIZE]; - char argument[COMMAND_ARGUMENT_SIZE]; -} actuator_command_t; - -void actuator_command_init(actuator_command_t* command, actuator_command_type_t type, const char* reference, - const char* argument); - -actuator_command_type_t actuator_command_get_type(actuator_command_t* command); - -char* actuator_command_get_reference(actuator_command_t* command); -void actuator_command_set_reference(actuator_command_t* command, const char* reference); - -char* actuator_command_get_value(actuator_command_t* command); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/sources/configuration_command.c b/sources/configuration_command.c deleted file mode 100644 index e1612f6..0000000 --- a/sources/configuration_command.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2018 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "configuration_command.h" -#include "size_definitions.h" -#include "wolk_utils.h" - -#include - -void configuration_command_init(configuration_command_t* command, configuration_command_type_t type) -{ - /* Sanity check */ - WOLK_ASSERT(command); - - command->type = type; - - command->num_configuration_items = 0; -} - -configuration_command_type_t configuration_command_get_type(configuration_command_t* command) -{ - return command->type; -} - -void configuration_command_add(configuration_command_t* command, char* reference, char* value) -{ - /* Sanity check */ - WOLK_ASSERT(strlen(reference) < CONFIGURATION_REFERENCE_SIZE); - WOLK_ASSERT(strlen(value) < CONFIGURATION_VALUE_SIZE); - - strcpy(command->reference[command->num_configuration_items], reference); - strcpy(command->value[command->num_configuration_items], value); - - command->num_configuration_items += 1; -} - -size_t configuration_command_get_number_of_items(configuration_command_t* command) -{ - return command->num_configuration_items; -} - -char (*configuration_command_get_references(configuration_command_t* command))[CONFIGURATION_REFERENCE_SIZE] -{ - return &command->reference[0]; -} - -char (*configuration_command_get_values(configuration_command_t* command))[CONFIGURATION_VALUE_SIZE] -{ - return &command->value[0]; -} diff --git a/sources/configuration_command.h b/sources/configuration_command.h deleted file mode 100644 index 5068b2a..0000000 --- a/sources/configuration_command.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2018 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef CONFIGURATION_COMMAND_H -#define CONFIGURATION_COMMAND_H - -#include "size_definitions.h" - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - CONFIGURATION_COMMAND_TYPE_GET = 0, - CONFIGURATION_COMMAND_TYPE_SET, - - CONFIGURATION_COMMAND_TYPE_UNKNOWN -} configuration_command_type_t; - -typedef struct { - configuration_command_type_t type; - - char reference[CONFIGURATION_ITEMS_SIZE][CONFIGURATION_REFERENCE_SIZE]; - char value[CONFIGURATION_ITEMS_SIZE][CONFIGURATION_VALUE_SIZE]; - - size_t num_configuration_items; -} configuration_command_t; - -void configuration_command_init(configuration_command_t* command, configuration_command_type_t type); - -configuration_command_type_t configuration_command_get_type(configuration_command_t* command); - -void configuration_command_add(configuration_command_t* command, char* reference, char* value); - -size_t configuration_command_get_number_of_items(configuration_command_t* command); - -char (*configuration_command_get_references(configuration_command_t* command))[CONFIGURATION_REFERENCE_SIZE]; - -char (*configuration_command_get_values(configuration_command_t* command))[CONFIGURATION_VALUE_SIZE]; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/sources/configuration_item.c b/sources/configuration_item.c deleted file mode 100644 index 21cc1da..0000000 --- a/sources/configuration_item.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2018 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "configuration_item.h" -#include "wolk_utils.h" - -#include -#include -#include - -void configuration_item_init(configuration_item_t* configuration_item, char* name, char* value) -{ - strcpy(configuration_item->name, name); - strcpy(configuration_item->value, value); -} - -char* configuration_item_get_name(configuration_item_t* configuration_item) -{ - return configuration_item->name; -} - -char* configuration_item_get_value(configuration_item_t* configuration_item) -{ - return configuration_item->value; -} - -void configuration_item_set_value(configuration_item_t* configuration_item, char* buffer) -{ - /* Sanity check */ - WOLK_ASSERT(strlen(buffer) < CONFIGURATION_VALUE_SIZE); - - strcpy(configuration_item->value, buffer); -} diff --git a/sources/data_transmission.c b/sources/connectivity/data_transmission.c old mode 100644 new mode 100755 similarity index 97% rename from sources/data_transmission.c rename to sources/connectivity/data_transmission.c index 4368ba5..7df07b1 --- a/sources/data_transmission.c +++ b/sources/connectivity/data_transmission.c @@ -16,7 +16,7 @@ #include #include "data_transmission.h" -#include "wolk_utils.h" +#include "utility/wolk_utils.h" static transmission_io_functions_t* io_functions = NULL; static unsigned char* starting_add = NULL; @@ -75,7 +75,7 @@ int transmission_buffer_nb(int socket) int transmission_buffer(int socket, unsigned char* buffer, int buffer_length) { - int response = NULL; + int response = 0; transmission_buffer_nb_start(socket, buffer, buffer_length); while ((response = transmission_buffer_nb(socket)) == TRANSPORT_AGAIN) { diff --git a/sources/data_transmission.h b/sources/connectivity/data_transmission.h old mode 100644 new mode 100755 similarity index 100% rename from sources/data_transmission.h rename to sources/connectivity/data_transmission.h diff --git a/sources/json_parser.c b/sources/json_parser.c deleted file mode 100644 index 576faad..0000000 --- a/sources/json_parser.c +++ /dev/null @@ -1,862 +0,0 @@ -/* - * Copyright 2018 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "json_parser.h" -#include "actuator_command.h" -#include "base64.h" -#include "file_management_packet_request.h" -#include "file_management_parameter.h" -#include "file_management_status.h" -#include "firmware_update.h" -#include "jsmn.h" -#include "reading.h" -#include "size_definitions.h" -#include "wolk_utils.h" - -#include -#include -#include -#include -#include -#include - -static const char* PING_TOPIC = "ping/"; -static const char* READINGS_TOPIC = "d2p/sensor_reading/d/"; - -static const char* ACTUATORS_STATUS_TOPIC = "d2p/actuator_status/d/"; - -static const char* EVENTS_TOPIC = "d2p/events/d/"; - -static const char* CONFIGURATION_GET_TOPIC = "d2p/configuration_get/d/"; - -static const char* FILE_MANAGEMENT_UPLOAD_STATUS_TOPIC = "d2p/file_upload_status/d/"; -static const char* FILE_MANAGEMENT_PACKET_REQUEST_TOPIC = "d2p/file_binary_request/d/"; -static const char* FILE_MANAGEMENT_URL_DOWNLOAD_STATUS = "d2p/file_url_download_status/d/"; -static const char* FILE_MANAGEMENT_FILE_LIST_UPDATE = "d2p/file_list_update/d/"; - -static const char* FIRMWARE_UPDATE_STATUS_TOPIC = "d2p/firmware_update_status/d/"; -static const char* FIRMWARE_UPDATE_VERSION_TOPIC = "d2p/firmware_version_update/d/"; - -static bool all_readings_have_equal_rtc(reading_t* first_reading, size_t num_readings) -{ - reading_t* current_reading = first_reading; - uint64_t rtc = reading_get_rtc(current_reading); - - for (size_t i = 0; i < num_readings; ++i, ++current_reading) { - if (rtc != reading_get_rtc(current_reading)) { - return false; - } - } - - return true; -} - -static bool serialize_sensor(reading_t* reading, char* buffer, size_t buffer_size) -{ - char data_buffer[PARSER_INTERNAL_BUFFER_SIZE]; - if (!reading_get_delimited_data(reading, data_buffer, PARSER_INTERNAL_BUFFER_SIZE)) { - return false; - } - - if (reading_get_rtc(reading) > 0 - && snprintf(buffer, buffer_size, "{\"utc\":%ld,\"data\":\"%s\"}", reading_get_rtc(reading), data_buffer) - >= (int)buffer_size) { - return false; - } else if (reading_get_rtc(reading) == 0 - && snprintf(buffer, buffer_size, "{\"data\":\"%s\"}", data_buffer) >= (int)buffer_size) { - return false; - } - - return true; -} - -static bool serialize_actuator(reading_t* reading, char* buffer, size_t buffer_size) -{ - char data_buffer[PARSER_INTERNAL_BUFFER_SIZE]; - if (!reading_get_delimited_data(reading, data_buffer, PARSER_INTERNAL_BUFFER_SIZE)) { - return false; - } - - switch (reading_get_actuator_state(reading)) { - case ACTUATOR_STATE_READY: - if (snprintf(buffer, buffer_size, "{\"status\":%s,\"value\":\"%s\"}", "\"READY\"", data_buffer) - >= (int)buffer_size) { - return false; - } - break; - - case ACTUATOR_STATE_BUSY: - if (snprintf(buffer, buffer_size, "{\"status\":%s,\"value\":\"%s\"}", "\"BUSY\"", data_buffer) - >= (int)buffer_size) { - return false; - } - break; - - case ACTUATOR_STATE_ERROR: - if (snprintf(buffer, buffer_size, "{\"status\":%s,\"value\":\"%s\"}", "\"ERROR\"", data_buffer) - >= (int)buffer_size) { - return false; - } - break; - - default: - /* Sanity check */ - WOLK_ASSERT(false); - return false; - } - - return true; -} - -static bool serialize_alarm(reading_t* reading, char* buffer, size_t buffer_size) -{ - char data_buffer[PARSER_INTERNAL_BUFFER_SIZE]; - if (!reading_get_delimited_data(reading, data_buffer, PARSER_INTERNAL_BUFFER_SIZE)) { - return false; - } - - if (reading_get_rtc(reading) > 0 - && snprintf(buffer, buffer_size, "{\"utc\":%ld,\"data\":\"%s\"}", reading_get_rtc(reading), data_buffer) - >= (int)buffer_size) { - return false; - } else if (reading_get_rtc(reading) == 0 - && snprintf(buffer, buffer_size, "{\"data\":\"%s\"}", data_buffer) >= (int)buffer_size) { - return false; - } - - return true; -} - -static bool serialize_reading(reading_t* reading, char* buffer, size_t buffer_size) -{ - switch (manifest_item_get_reading_type(reading_get_manifest_item(reading))) { - case READING_TYPE_SENSOR: - return serialize_sensor(reading, buffer, buffer_size); - - case READING_TYPE_ACTUATOR: - return serialize_actuator(reading, buffer, buffer_size); - - case READING_TYPE_ALARM: - return serialize_alarm(reading, buffer, buffer_size); - - default: - /* Sanity check*/ - WOLK_ASSERT(false); - return false; - } -} - -static size_t serialize_readings(reading_t* first_reading, size_t num_readings, char* buffer, size_t buffer_size) -{ - WOLK_UNUSED(num_readings); - - return serialize_reading(first_reading, buffer, buffer_size) ? 1 : 0; -} - -size_t json_serialize_readings(reading_t* first_reading, size_t num_readings, char* buffer, size_t buffer_size) -{ - /* Sanity check */ - WOLK_ASSERT(num_readings > 0); - - if (num_readings > 1 && all_readings_have_equal_rtc(first_reading, num_readings)) { - return serialize_readings(first_reading, num_readings, buffer, buffer_size); - } else { - return serialize_reading(first_reading, buffer, buffer_size) ? 1 : 0; - } -} - -static bool json_token_str_equal(const char* json, jsmntok_t* tok, const char* s) -{ - if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start - && strncmp(json + tok->start, s, (size_t)(tok->end - tok->start)) == 0) { - return true; - } - - return false; -} - -static bool deserialize_actuator_command(char* topic, size_t topic_size, char* buffer, size_t buffer_size, - actuator_command_t* command) -{ - WOLK_UNUSED(topic_size); - - jsmn_parser parser; - jsmntok_t tokens[10]; /* No more than 10 JSON token(s) are expected, check - jsmn documentation for token definition */ - jsmn_init(&parser); - int parser_result = jsmn_parse(&parser, buffer, buffer_size, tokens, WOLK_ARRAY_LENGTH(tokens)); - - /* Received JSON must be valid, and top level element must be object */ - if (parser_result < 1 || tokens[0].type != JSMN_OBJECT || parser_result >= (int)WOLK_ARRAY_LENGTH(tokens)) { - return false; - } - - char command_buffer[COMMAND_MAX_SIZE]; - char value_buffer[READING_SIZE]; - - /* Obtain reference */ - char* reference_start = strrchr(topic, '/'); - if (reference_start == NULL) { - return false; - } - - /*Obtain command type*/ - char* command_start = strchr(topic, '/'); - if (command_start == NULL) { - return false; - } - strncpy(command_buffer, strtok(command_start, "/"), COMMAND_MAX_SIZE); - if (strlen(command_buffer) == NULL) { - return false; - } - - /*Obtain values*/ - for (int i = 1; i < parser_result; i++) { - if (json_token_str_equal(buffer, &tokens[i], "value")) { - if (snprintf(value_buffer, WOLK_ARRAY_LENGTH(value_buffer), "%.*s", tokens[i + 1].end - tokens[i + 1].start, - buffer + tokens[i + 1].start) - >= (int)WOLK_ARRAY_LENGTH(value_buffer)) { - return false; - } - - i++; - - } else { - return false; - } - } - - /*Init actuation*/ - if (strcmp(command_buffer, "actuator_set") == 0) { - actuator_command_init(command, ACTUATOR_COMMAND_TYPE_SET, "", value_buffer); - } else { - actuator_command_init(command, ACTUATOR_COMMAND_TYPE_UNKNOWN, "", value_buffer); - } - - strncpy(&command->reference[0], reference_start + 1, MANIFEST_ITEM_REFERENCE_SIZE); - return true; -} - -size_t json_deserialize_actuator_commands(char* topic, size_t topic_size, char* buffer, size_t buffer_size, - actuator_command_t* commands_buffer, size_t commands_buffer_size) -{ - WOLK_UNUSED(topic_size); - WOLK_UNUSED(buffer_size); - WOLK_UNUSED(commands_buffer_size); - - return deserialize_actuator_command(topic, topic_size, buffer, buffer_size, commands_buffer) ? 1 : 0; -} - -bool json_serialize_readings_topic(reading_t* first_Reading, size_t num_readings, const char* device_key, char* buffer, - size_t buffer_size) -{ - WOLK_UNUSED(num_readings); - - manifest_item_t* manifest_item = reading_get_manifest_item(first_Reading); - reading_type_t reading_type = manifest_item_get_reading_type(manifest_item); - - memset(buffer, '\0', buffer_size); - - switch (reading_type) { - case READING_TYPE_SENSOR: - strcpy(buffer, READINGS_TOPIC); - strcat(buffer, device_key); - strcat(buffer, "/r/"); - strcat(buffer, manifest_item_get_reference(manifest_item)); - break; - - case READING_TYPE_ACTUATOR: - strcpy(buffer, ACTUATORS_STATUS_TOPIC); - strcat(buffer, device_key); - strcat(buffer, "/r/"); - strcat(buffer, manifest_item_get_reference(manifest_item)); - break; - - case READING_TYPE_ALARM: - strcpy(buffer, EVENTS_TOPIC); - strcat(buffer, device_key); - strcat(buffer, "/r/"); - strcat(buffer, manifest_item_get_reference(manifest_item)); - break; - - default: - /* Sanity check */ - WOLK_ASSERT(false); - return false; - } - - return true; -} - -static char* replace_str(char* str, char* orig, char* rep, int start) -{ - static char temp[PARSER_INTERNAL_BUFFER_SIZE]; - static char buffer[PARSER_INTERNAL_BUFFER_SIZE]; - - WOLK_ASSERT(sizeof(temp) > strlen(str) - start); - strcpy(temp, str + start); - - char* p; - if (!(p = strstr(temp, orig))) { - return temp; - } - - WOLK_ASSERT(sizeof(buffer) > p - temp); - strncpy(buffer, temp, p - temp); - buffer[p - temp] = '\0'; - - sprintf(buffer + (p - temp), "%s%s", rep, p + strlen(orig)); - sprintf(str + start, "%s", buffer); - - return replace_str(str, orig, rep, start + p - temp + 2); -} - -size_t json_serialize_configuration(const char* device_key, char (*reference)[CONFIGURATION_REFERENCE_SIZE], - char (*value)[CONFIGURATION_VALUE_SIZE], size_t num_configuration_items, - outbound_message_t* outbound_message) -{ - outbound_message_init(outbound_message, "", ""); - - strncpy(outbound_message->topic, CONFIGURATION_GET_TOPIC, strlen(CONFIGURATION_GET_TOPIC)); - /* Serialize topic */ - if (snprintf(outbound_message->topic + strlen(CONFIGURATION_GET_TOPIC), WOLK_ARRAY_LENGTH(outbound_message->topic), - "%s", device_key) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->topic)) { - return 0; - } - - /* Serialize payload */ - char* payload = &outbound_message->payload[0]; - const size_t payload_size = sizeof(outbound_message->payload); - memset(payload, '\0', payload_size); - - if (snprintf(payload, payload_size, "{\"values\":{") >= (int)payload_size) { - return 0; - } - - for (size_t i = 0; i < num_configuration_items; ++i) { - char* configuration_item_reference = reference[i]; - char* configuration_item_value = value[i]; - - /* Escape value according to JSON specification */ - replace_str(configuration_item_value, "\\", "\\\\", 0); - replace_str(configuration_item_value, "\"", "\\\"", 0); - - /* -1 so we can have enough space left to append closing '}' */ - size_t num_bytes_to_write = payload_size - strlen(payload); - if (snprintf(payload + strlen(payload), payload_size - strlen(payload) - 1, "\"%s\":\"%s\"", - configuration_item_reference, configuration_item_value) - >= (int)num_bytes_to_write - 1) { - break; - } - - if (i >= num_configuration_items - 1) { - break; - } - - /* +4 for '"', +1 for ':', +1 for ',' delimiter between configuration - * items, +1 for closing '}' => +7 */ - if (strlen(payload) + strlen(configuration_item_reference) + strlen(configuration_item_value) + 7 - > payload_size) { - break; - } - - num_bytes_to_write = payload_size - strlen(payload); - if (snprintf(payload + strlen(payload), payload_size - strlen(payload), ",") >= (int)num_bytes_to_write) { - break; - } - } - - const size_t num_bytes_to_write = payload_size - strlen(payload); - if (snprintf(payload + strlen(payload), payload_size - strlen(payload), "}}") >= (int)num_bytes_to_write) { - return 0; - } - return 1; -} - -size_t json_deserialize_configuration_command(char* buffer, size_t buffer_size, - configuration_command_t* commands_buffer, size_t commands_buffer_size) -{ - WOLK_UNUSED(commands_buffer_size); - - jsmn_parser parser; - jsmntok_t tokens[50]; - - configuration_command_t* current_config_command = commands_buffer; - current_config_command->num_configuration_items = 0; - - size_t num_deserialized_config_items = 0; - - jsmn_init(&parser); - int num_json_tokens = jsmn_parse(&parser, buffer, buffer_size, &tokens[0], WOLK_ARRAY_LENGTH(tokens)); - - /* Received JSON must be valid, and top level element must be object*/ - if (num_json_tokens < 1 || tokens[0].type != JSMN_OBJECT) { - return num_deserialized_config_items; - } - - configuration_command_init(current_config_command, CONFIGURATION_COMMAND_TYPE_SET); - - for (int i = 0; i < num_json_tokens; i += 2) { - if (i + 1 >= num_json_tokens || tokens[i + 1].type != JSMN_STRING) { - continue; - } - - num_deserialized_config_items++; - - char configuration_item_reference[CONFIGURATION_REFERENCE_SIZE]; - char configuration_item_value[CONFIGURATION_VALUE_SIZE]; - - if (snprintf(configuration_item_reference, WOLK_ARRAY_LENGTH(configuration_item_reference), "%.*s", - tokens[i + 1].end - tokens[i + 1].start, buffer + tokens[i + 1].start) - >= (int)WOLK_ARRAY_LENGTH(configuration_item_reference)) { - continue; - } - - if (snprintf(configuration_item_value, WOLK_ARRAY_LENGTH(configuration_item_value), "%.*s", - tokens[i + 2].end - tokens[i + 2].start, buffer + tokens[i + 2].start) - >= (int)WOLK_ARRAY_LENGTH(configuration_item_value)) { - continue; - } - - configuration_command_add(current_config_command, configuration_item_reference, configuration_item_value); - } - - return num_deserialized_config_items; -} - -static const char* file_management_status_as_str(file_management_status_t* status) -{ - /* Sanity check */ - WOLK_ASSERT(status); - - switch (status->state) { - case FILE_MANAGEMENT_STATE_FILE_TRANSFER: - return "FILE_TRANSFER"; - - case FILE_MANAGEMENT_STATE_FILE_READY: - return "FILE_READY"; - - case FILE_MANAGEMENT_STATE_ERROR: - return "ERROR"; - - case FILE_MANAGEMENT_STATE_ABORTED: - return "ABORTED"; - - default: - WOLK_ASSERT(false); - return ""; - } -} - -bool json_serialize_file_management_status(const char* device_key, - file_management_packet_request_t* file_management_packet_request, - file_management_status_t* status, outbound_message_t* outbound_message) -{ - outbound_message_init(outbound_message, "", ""); - - /* Serialize topic */ - strncpy(outbound_message->topic, FILE_MANAGEMENT_UPLOAD_STATUS_TOPIC, strlen(FILE_MANAGEMENT_UPLOAD_STATUS_TOPIC)); - if (snprintf(outbound_message->topic + strlen(FILE_MANAGEMENT_UPLOAD_STATUS_TOPIC), - WOLK_ARRAY_LENGTH(outbound_message->topic), "%s", device_key) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->topic)) { - return false; - } - - /* Serialize payload */ - if (snprintf(outbound_message->payload, WOLK_ARRAY_LENGTH(outbound_message->payload), - "{\"fileName\": \"%s\", \"status\": \"%s\"}", - file_management_packet_request_get_file_name(file_management_packet_request), - file_management_status_as_str(status)) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { - return false; - } - - file_management_error_t error = file_management_status_get_error(status); - if (error >= 0) { - if (snprintf(outbound_message->payload + strlen(outbound_message->payload) - 1, - WOLK_ARRAY_LENGTH(outbound_message->payload), ",\"error\":%d}", error) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { - return false; - } - } - - return true; -} - -bool json_deserialize_file_management_parameter(char* buffer, size_t buffer_size, - file_management_parameter_t* parameter) -{ - jsmn_parser parser; - jsmntok_t tokens[12]; /* No more than 12 JSON token(s) are expected, check - jsmn documentation for token definition */ - jsmn_init(&parser); - const int parser_result = jsmn_parse(&parser, buffer, buffer_size, tokens, WOLK_ARRAY_LENGTH(tokens)); - - /* Received JSON must be valid, and top level element must be object */ - if (parser_result < 1 || tokens[0].type != JSMN_OBJECT || parser_result >= (int)WOLK_ARRAY_LENGTH(tokens)) { - return false; - } - - file_management_parameter_init(parameter); - - /* Obtain command type and value */ - char value_buffer[COMMAND_ARGUMENT_SIZE]; - - for (int i = 1; i < parser_result; i++) { - if (json_token_str_equal(buffer, &tokens[i], "fileName")) { - if (snprintf(value_buffer, WOLK_ARRAY_LENGTH(value_buffer), "%.*s", tokens[i + 1].end - tokens[i + 1].start, - buffer + tokens[i + 1].start) - >= (int)WOLK_ARRAY_LENGTH(value_buffer)) { - return false; - } - - if (strlen(value_buffer) > FILE_MANAGEMENT_FILE_NAME_SIZE) { - /* Leave file name array empty */ - return true; - } else { - file_management_parameter_set_filename(parameter, value_buffer); - i++; - } - } else if (json_token_str_equal(buffer, &tokens[i], "fileSize")) { - if (snprintf(value_buffer, WOLK_ARRAY_LENGTH(value_buffer), "%.*s", tokens[i + 1].end - tokens[i + 1].start, - buffer + tokens[i + 1].start) - >= (int)WOLK_ARRAY_LENGTH(value_buffer)) { - return false; - } - - file_management_parameter_set_file_size(parameter, (size_t)atoi(value_buffer)); - i++; - } else if (json_token_str_equal(buffer, &tokens[i], "fileHash")) { - if (snprintf(value_buffer, WOLK_ARRAY_LENGTH(value_buffer), "%.*s", tokens[i + 1].end - tokens[i + 1].start, - buffer + tokens[i + 1].start) - >= (int)WOLK_ARRAY_LENGTH(value_buffer)) { - return false; - } - - const size_t output_size = base64_decode(value_buffer, NULL, strlen(value_buffer)); - if (output_size > FILE_MANAGEMENT_HASH_SIZE) { - return false; - } - base64_decode(value_buffer, (BYTE*)parameter->file_hash, strlen(value_buffer)); - i++; - } else if (json_token_str_equal(buffer, &tokens[i], "fileUrl")) { - if (snprintf(value_buffer, WOLK_ARRAY_LENGTH(value_buffer), "%.*s", tokens[i + 1].end - tokens[i + 1].start, - buffer + tokens[i + 1].start) - >= (int)WOLK_ARRAY_LENGTH(value_buffer)) { - return false; - } - - file_management_parameter_set_file_url(parameter, value_buffer); - i++; - } else if (json_token_str_equal(buffer, &tokens[i], "result")) { - if (snprintf(value_buffer, WOLK_ARRAY_LENGTH(value_buffer), "%.*s", tokens[i + 1].end - tokens[i + 1].start, - buffer + tokens[i + 1].start) - >= (int)WOLK_ARRAY_LENGTH(value_buffer)) { - return false; - } - file_management_parameter_set_result(parameter, value_buffer); - i++; - } else { - return false; - } - } - return true; -} - -bool json_serialize_file_management_packet_request(const char* device_key, - file_management_packet_request_t* file_management_packet_request, - outbound_message_t* outbound_message) -{ - outbound_message_init(outbound_message, "", ""); - - /* Serialize topic */ - strncpy(outbound_message->topic, FILE_MANAGEMENT_PACKET_REQUEST_TOPIC, - strlen(FILE_MANAGEMENT_PACKET_REQUEST_TOPIC)); - if (snprintf(outbound_message->topic + strlen(FILE_MANAGEMENT_PACKET_REQUEST_TOPIC), - WOLK_ARRAY_LENGTH(outbound_message->topic), "%s", device_key) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->topic)) { - return false; - } - - /* Serialize payload */ - if (snprintf(outbound_message->payload, WOLK_ARRAY_LENGTH(outbound_message->payload), - "{\"fileName\": \"%s\", \"chunkIndex\":%llu, \"chunkSize\":%llu}", - file_management_packet_request_get_file_name(file_management_packet_request), - (unsigned long long int)file_management_packet_request_get_chunk_index(file_management_packet_request), - (unsigned long long int)file_management_packet_request_get_chunk_size(file_management_packet_request)) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { - return false; - } - - return true; -} - -bool json_serialize_file_management_url_download_status(const char* device_key, - file_management_parameter_t* file_management_parameter, - file_management_status_t* status, - outbound_message_t* outbound_message) -{ - outbound_message_init(outbound_message, "", ""); - - /* Serialize topic */ - strncpy(outbound_message->topic, FILE_MANAGEMENT_URL_DOWNLOAD_STATUS, strlen(FILE_MANAGEMENT_URL_DOWNLOAD_STATUS)); - if (snprintf(outbound_message->topic + strlen(FILE_MANAGEMENT_URL_DOWNLOAD_STATUS), - WOLK_ARRAY_LENGTH(outbound_message->topic), "%s", device_key) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->topic)) { - return false; - } - - /* Serialize payload */ - if (snprintf(outbound_message->payload, WOLK_ARRAY_LENGTH(outbound_message->payload), - "{\"fileUrl\": \"%s\", \"status\": \"%s\"}", - file_management_parameter_get_file_url(file_management_parameter), - file_management_status_as_str(status)) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { - return false; - } - - file_management_error_t error = file_management_status_get_error(status); - if (error >= 0) { - if (snprintf(outbound_message->payload + strlen(outbound_message->payload) - 1, - WOLK_ARRAY_LENGTH(outbound_message->payload), ",\"error\":%d}", error) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { - return false; - } - } - - file_management_state_t state = file_management_status_get_state(status); - if (state == FILE_MANAGEMENT_STATE_FILE_READY) { - if (snprintf(outbound_message->payload + strlen(outbound_message->payload) - 1, - WOLK_ARRAY_LENGTH(outbound_message->payload), ",\"fileName\":\"%s\"}", - file_management_packet_request_get_file_name(file_management_parameter)) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { - return false; - } - } - - return true; -} - -bool json_serialize_file_management_file_list_update(const char* device_key, char* file_list, size_t file_list_items, - outbound_message_t* outbound_message) -{ - outbound_message_init(outbound_message, "", ""); - memset(outbound_message->topic, '\0', TOPIC_SIZE); - memset(outbound_message->payload, '\0', PAYLOAD_SIZE); - - /* Serialize topic */ - strncpy(outbound_message->topic, FILE_MANAGEMENT_FILE_LIST_UPDATE, strlen(FILE_MANAGEMENT_FILE_LIST_UPDATE)); - if (snprintf(outbound_message->topic + strlen(FILE_MANAGEMENT_FILE_LIST_UPDATE), - WOLK_ARRAY_LENGTH(outbound_message->topic), "%s", device_key) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->topic)) { - return false; - } - - /* Serialize payload */ - strncpy(outbound_message->payload, "[", strlen("[")); - for (int i = 0; i < file_list_items; i++) { - if (snprintf(outbound_message->payload + strlen(outbound_message->payload), - WOLK_ARRAY_LENGTH(outbound_message->payload), "{\"fileName\":\"%s\"},", - (const char*)file_list + (i * FILE_MANAGEMENT_FILE_NAME_SIZE)) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { - return false; - } - } - - file_list_items == 0 ? strncpy(outbound_message->payload + strlen(outbound_message->payload), "]", strlen("]")) - : strncpy(outbound_message->payload + strlen(outbound_message->payload) - 1, "]", strlen("]")); - - return true; -} - -bool json_serialize_ping_keep_alive_message(const char* device_key, outbound_message_t* outbound_message) -{ - outbound_message_init(outbound_message, "", ""); - - /* Serialize topic */ - strncpy(outbound_message->topic, PING_TOPIC, strlen(PING_TOPIC)); - - if (snprintf(outbound_message->topic + strlen(PING_TOPIC), WOLK_ARRAY_LENGTH(outbound_message->topic), "%s", - device_key) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->topic)) { - return false; - } - - return true; -} - -bool json_deserialize_pong_keep_alive_message(char* buffer, size_t buffer_size, utc_command_t* utc_command) -{ - jsmn_parser parser; - jsmntok_t tokens[10]; /* No more than 10 JSON token(s) are expected, check - jsmn documentation for token definition */ - jsmn_init(&parser); - int parser_result = jsmn_parse(&parser, buffer, buffer_size, tokens, WOLK_ARRAY_LENGTH(tokens)); - - /* Received JSON must be valid, and top level element must be object */ - if (parser_result < 1 || tokens[0].type != JSMN_OBJECT || parser_result >= (int)WOLK_ARRAY_LENGTH(tokens)) { - return false; - } - - char value_buffer[READING_SIZE]; - /*Obtain values*/ - for (int i = 1; i < parser_result; i++) { - if (i >= parser_result || tokens[i].type != JSMN_STRING) { - continue; - } - - if (json_token_str_equal(buffer, &tokens[i], "value")) { - if (tokens[i + 1].type == JSMN_PRIMITIVE) { - if (snprintf(value_buffer, WOLK_ARRAY_LENGTH(value_buffer), "%.*s", - tokens[i + 1].end - tokens[i + 1].start, buffer + tokens[i + 1].start) - >= (int)WOLK_ARRAY_LENGTH(value_buffer)) { - return false; - } - - uint64_t conversion_result = strtod(value_buffer, NULL); - if (conversion_result == NULL) { - return false; - } - utc_command->utc = conversion_result; - } - } - } - - return true; -} - -static const char* firmware_update_status_as_str(firmware_update_t* firmware_update) -{ - /* Sanity check */ - WOLK_ASSERT(firmware_update); - - switch (firmware_update->status) { - case FIRMWARE_UPDATE_STATUS_INSTALLATION: - return "INSTALLATION"; - - case FIRMWARE_UPDATE_STATUS_COMPLETED: - return "COMPLETED"; - - case FIRMWARE_UPDATE_STATUS_ERROR: - return "ERROR"; - - case FIRMWARE_UPDATE_STATUS_ABORTED: - return "ABORTED"; - - default: - WOLK_ASSERT(false); - return ""; - } -} - -bool json_deserialize_firmware_update_parameter(char* device_key, char* buffer, size_t buffer_size, - firmware_update_t* parameter) -{ - jsmn_parser parser; - jsmntok_t tokens[12]; /* No more than 12 JSON token(s) are expected, check - jsmn documentation for token definition */ - jsmn_init(&parser); - const int parser_result = jsmn_parse(&parser, buffer, buffer_size, tokens, WOLK_ARRAY_LENGTH(tokens)); - - /* Received JSON must be valid, and top level element must be object */ - if (parser_result < 1 || tokens[0].type != JSMN_OBJECT || parser_result >= (int)WOLK_ARRAY_LENGTH(tokens)) { - return false; - } - - firmware_update_parameter_init(parameter); - - /* Obtain command type and value */ - char value_buffer[COMMAND_ARGUMENT_SIZE]; - - for (int i = 1; i < parser_result; i++) { - if (json_token_str_equal(buffer, &tokens[i], "devices")) { - if (!json_token_str_equal(buffer, &tokens[i + 2], device_key)) { - return false; - } - i += 2; // jump over JSON array - } else if (json_token_str_equal(buffer, &tokens[i], "fileName")) { - if (snprintf(value_buffer, WOLK_ARRAY_LENGTH(value_buffer), "%.*s", tokens[i + 1].end - tokens[i + 1].start, - buffer + tokens[i + 1].start) - >= (int)WOLK_ARRAY_LENGTH(value_buffer)) { - return false; - } - - firmware_update_parameter_set_filename(parameter, value_buffer); - i++; - } else { - return false; - } - } - return true; -} - -bool json_serialize_firmware_update_status(const char* device_key, firmware_update_t* firmware_update, - outbound_message_t* outbound_message) -{ - outbound_message_init(outbound_message, "", ""); - - /* Serialize topic */ - strncpy(outbound_message->topic, FIRMWARE_UPDATE_STATUS_TOPIC, strlen(FIRMWARE_UPDATE_STATUS_TOPIC)); - if (snprintf(outbound_message->topic + strlen(FIRMWARE_UPDATE_STATUS_TOPIC), - WOLK_ARRAY_LENGTH(outbound_message->topic), "%s", device_key) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->topic)) { - return false; - } - - /* Serialize payload */ - if (snprintf(outbound_message->payload, WOLK_ARRAY_LENGTH(outbound_message->payload), "{\"status\": \"%s\"}", - firmware_update_status_as_str(firmware_update)) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { - return false; - } - - size_t error = firmware_update->error; - if (error >= 0) { - if (snprintf(outbound_message->payload + strlen(outbound_message->payload) - 1, - WOLK_ARRAY_LENGTH(outbound_message->payload), ",\"error\":%d}", error) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { - return false; - } - } - - return true; -} - -bool json_serialize_firmware_update_version(const char* device_key, char* firmware_update_version, - outbound_message_t* outbound_message) -{ - outbound_message_init(outbound_message, "", ""); - - memset(outbound_message->topic, '\0', sizeof(outbound_message->topic)); - memset(outbound_message->payload, '\0', sizeof(outbound_message->payload)); - - /* Serialize topic */ - strncpy(outbound_message->topic, FIRMWARE_UPDATE_VERSION_TOPIC, strlen(FIRMWARE_UPDATE_VERSION_TOPIC)); - if (snprintf(outbound_message->topic + strlen(FIRMWARE_UPDATE_VERSION_TOPIC), - WOLK_ARRAY_LENGTH(outbound_message->topic), "%s", device_key) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->topic)) { - return false; - } - - /* Serialize payload */ - if (snprintf(outbound_message->payload, WOLK_ARRAY_LENGTH(outbound_message->payload), "%s", firmware_update_version) - >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { - return false; - } - - return true; -} diff --git a/sources/json_parser.h b/sources/json_parser.h deleted file mode 100644 index c9dcd63..0000000 --- a/sources/json_parser.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2018 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef JSON_PARSER_H -#define JSON_PARSER_H - -#include "actuator_command.h" -#include "configuration_command.h" -#include "configuration_item.h" -#include "file_management_packet_request.h" -#include "file_management_parameter.h" -#include "file_management_status.h" -#include "firmware_update.h" -#include "outbound_message.h" -#include "reading.h" -#include "utc_command.h" - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -size_t json_serialize_readings(reading_t* first_reading, size_t num_readings, char* buffer, size_t buffer_size); - -size_t json_deserialize_actuator_commands(char* topic, size_t topic_size, char* buffer, size_t buffer_size, - actuator_command_t* commands_buffer, size_t commands_buffer_size); - -bool json_serialize_readings_topic(reading_t* first_Reading, size_t num_readings, const char* device_key, char* buffer, - size_t buffer_size); - -size_t json_serialize_configuration(const char* device_key, char (*reference)[CONFIGURATION_REFERENCE_SIZE], - char (*value)[CONFIGURATION_VALUE_SIZE], size_t num_configuration_items, - outbound_message_t* outbound_message); - -size_t json_deserialize_configuration_command(char* buffer, size_t buffer_size, - configuration_command_t* commands_buffer, size_t commands_buffer_size); - -bool json_serialize_file_management_status(const char* device_key, - file_management_packet_request_t* file_management_packet_request, - file_management_status_t* status, outbound_message_t* outbound_message); - -bool json_deserialize_file_management_parameter(char* buffer, size_t buffer_size, - file_management_parameter_t* parameter); - -bool json_serialize_file_management_packet_request(const char* device_key, - file_management_packet_request_t* file_management_packet_request, - outbound_message_t* outbound_message); - -bool json_serialize_file_management_url_download_status(const char* device_key, - file_management_parameter_t* file_management_parameter, - file_management_status_t* status, - outbound_message_t* outbound_message); -bool json_serialize_file_management_file_list_update(const char* device_key, char* file_list, size_t file_list_items, - outbound_message_t* outbound_message); - -bool json_deserialize_firmware_update_parameter(char* device_key, char* buffer, size_t buffer_size, - firmware_update_t* parameter); -bool json_serialize_firmware_update_status(const char* device_key, firmware_update_t* firmware_update, - outbound_message_t* outbound_message); -bool json_serialize_firmware_update_version(const char* device_key, char* firmware_update_version, - outbound_message_t* outbound_message); - -bool json_serialize_ping_keep_alive_message(const char* device_key, outbound_message_t* outbound_message); -bool json_deserialize_pong_keep_alive_message(char* buffer, size_t buffer_size, utc_command_t* utc_command); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/sources/manifest_item.c b/sources/manifest_item.c deleted file mode 100644 index 7ad54ba..0000000 --- a/sources/manifest_item.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2018 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "manifest_item.h" -#include "size_definitions.h" -#include "wolk_utils.h" - -#include -#include - -void manifest_item_init(manifest_item_t* item, const char* reference, reading_type_t reading_type, - data_type_t data_type) -{ - /* Sanity check*/ - WOLK_ASSERT(strlen(reference) <= MANIFEST_ITEM_REFERENCE_SIZE); - - strcpy(item->reference, reference); - - item->reading_type = reading_type; - item->data_type = data_type; - - item->data_dimensions = 1; - - memset(item->data_delimiter, '\0', MANIFEST_ITEM_DATA_DELIMITER_SIZE); -} - -void manifest_item_set_reading_dimensions_and_delimiter(manifest_item_t* item, size_t data_size, const char* delimiter) -{ - /* Sanity check */ - WOLK_ASSERT(data_size > 1); - WOLK_ASSERT(strlen(delimiter) <= MANIFEST_ITEM_DATA_DELIMITER_SIZE); - - item->data_dimensions = data_size; - strcpy(item->data_delimiter, delimiter); -} - -char* manifest_item_get_reference(manifest_item_t* item) -{ - return item->reference; -} - -data_type_t manifest_item_get_data_type(manifest_item_t* item) -{ - return item->data_type; -} - -reading_type_t manifest_item_get_reading_type(manifest_item_t* item) -{ - return item->reading_type; -} - -size_t manifest_item_get_data_dimensions(manifest_item_t* item) -{ - return item->data_dimensions; -} - -char* manifest_item_get_data_delimiter(manifest_item_t* item) -{ - return item->data_delimiter; -} diff --git a/sources/manifest_item.h b/sources/manifest_item.h deleted file mode 100644 index cedfef8..0000000 --- a/sources/manifest_item.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2018 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SENSOR_H -#define SENSOR_H - -#include "size_definitions.h" - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -static const char* DATA_DELIMITER = ","; - -typedef enum { READING_TYPE_SENSOR = 0, READING_TYPE_ACTUATOR, READING_TYPE_ALARM } reading_type_t; - -typedef enum { DATA_TYPE_NUMERIC = 0, DATA_TYPE_BOOLEAN, DATA_TYPE_STRING } data_type_t; - -typedef struct { - char reference[MANIFEST_ITEM_REFERENCE_SIZE]; - - reading_type_t reading_type; - data_type_t data_type; - - size_t data_dimensions; - - char data_delimiter[MANIFEST_ITEM_DATA_DELIMITER_SIZE]; -} manifest_item_t; - -void manifest_item_init(manifest_item_t* item, const char* reference, reading_type_t reading_type, - data_type_t data_type); -void manifest_item_set_reading_dimensions_and_delimiter(manifest_item_t* item, size_t data_size, const char* delimiter); - -char* manifest_item_get_reference(manifest_item_t* item); - -data_type_t manifest_item_get_data_type(manifest_item_t* item); - -reading_type_t manifest_item_get_reading_type(manifest_item_t* item); - -size_t manifest_item_get_data_dimensions(manifest_item_t* item); -char* manifest_item_get_data_delimiter(manifest_item_t* item); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/examples/full_feature_set/sensor_readings.h b/sources/model/attribute.c similarity index 59% rename from examples/full_feature_set/sensor_readings.h rename to sources/model/attribute.c index bb59b1e..8fdd6a6 100644 --- a/examples/full_feature_set/sensor_readings.h +++ b/sources/model/attribute.c @@ -1,5 +1,5 @@ /* - * Copyright 2020 WolkAbout Technology s.r.o. + * Copyright 2022 WolkAbout Technology s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,17 +14,12 @@ * limitations under the License. */ -#ifndef WOLKCONNECTOR_C_SENSOR_READINGS_H -#define WOLKCONNECTOR_C_SENSOR_READINGS_H - -#include -#include -#include +#include "model/attribute.h" #include -#include "wolk_connector.h" - -bool enable_feeds(char* value); -bool sensor_readings_process(wolk_ctx_t* ctx, int* publish_period_seconds, int default_publish_value); - -#endif // WOLKCONNECTOR_C_SENSOR_READINGS_H +void attribute_init(attribute_t* attribute, char* name, char* data_type, char* value) +{ + strncpy(attribute->name, name, ITEM_NAME_SIZE); + strncpy(attribute->data_type, data_type, ITEM_DATA_TYPE_SIZE); + strncpy(attribute->value, value, ATTRIBUTE_VALUE_SIZE); +} diff --git a/sources/configuration_item.h b/sources/model/attribute.h similarity index 53% rename from sources/configuration_item.h rename to sources/model/attribute.h index bb9e7a3..ee138e0 100644 --- a/sources/configuration_item.h +++ b/sources/model/attribute.h @@ -1,5 +1,5 @@ /* - * Copyright 2018 WolkAbout Technology s.r.o. + * Copyright 2022 WolkAbout Technology s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,32 +14,25 @@ * limitations under the License. */ -#ifndef CONFIGURATION_ITEM_H -#define CONFIGURATION_ITEM_H +#ifndef ATTRIBUTE_H +#define ATTRIBUTE_H + +#include "size_definitions.h" #ifdef __cplusplus extern "C" { #endif -#include "size_definitions.h" - -#include -#include - typedef struct { - char name[CONFIGURATION_REFERENCE_SIZE]; - char value[CONFIGURATION_VALUE_SIZE]; -} configuration_item_t; - -void configuration_item_init(configuration_item_t* configuration_item, char* name, char* value); + char name[ITEM_NAME_SIZE]; + char data_type[ITEM_DATA_TYPE_SIZE]; + char value[FEED_ELEMENT_SIZE]; +} attribute_t; -char* configuration_item_get_name(configuration_item_t* configuration_item); - -char* configuration_item_get_value(configuration_item_t* configuration_item); -void configuration_item_set_value(configuration_item_t* configuration_item, char* buffer); +void attribute_init(attribute_t* attribute, char* name, char* data_type, char* value); #ifdef __cplusplus } #endif -#endif +#endif // ATTRIBUTE_H diff --git a/sources/model/feed.c b/sources/model/feed.c new file mode 100644 index 0000000..7c6718e --- /dev/null +++ b/sources/model/feed.c @@ -0,0 +1,84 @@ +/* + * Copyright 2022 WolkAbout Technology s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "feed.h" + + +void feed_initialize(feed_t* feed, uint16_t feed_size, const char* reference) +{ + feed->size = feed_size > FEEDS_MAX_NUMBER ? FEEDS_MAX_NUMBER : feed_size; + + feed->utc = 0; + + feed_clear(feed); + strcpy(feed->reference, reference); +} + +void feed_clear(feed_t* feed) +{ + for (size_t i = 0; i < feed->size; ++i) { + feed_set_data_at(feed, "", i); + } +} + +void feed_set_data(feed_t* feed, const char** data) +{ + for (size_t i = 0; i < feed->size; ++i) { + WOLK_ASSERT(strlen(data[i]) < READING_SIZE); + + strcpy(feed->data[i], data[i]); + } +} + +void feed_set_data_at(feed_t* feed, const char* data, size_t data_position) +{ + /* Sanity check */ + WOLK_ASSERT(strlen(data) < READING_SIZE); + + strcpy(feed->data[data_position], data); +} + +char** feed_get_data(feed_t* feed) +{ + return feed->data; +} + +char* feed_get_data_at(feed_t* feed, size_t data_position) +{ + /* Sanity check */ + WOLK_ASSERT(data_position < feed->manifest_item.data_dimensions); + + return feed->data[data_position]; +} + +void feed_set_utc(feed_t* feed, uint64_t utc) +{ + feed->utc = utc; +} + +uint64_t feed_get_utc(feed_t* feed) +{ + return feed->utc; +} + +void feed_initialize_registration(feed_registration_t* feed, char* name, const char* reference, char* unit, + const feed_type_t feedType) +{ + strncpy(feed->name, name, ITEM_NAME_SIZE); + strncpy(feed->reference, reference, REFERENCE_SIZE); + strncpy(feed->unit, unit, ITEM_UNIT_SIZE); + feed->feedType = feedType; +} diff --git a/sources/model/feed.h b/sources/model/feed.h new file mode 100644 index 0000000..04cbe62 --- /dev/null +++ b/sources/model/feed.h @@ -0,0 +1,70 @@ +/* + * Copyright 2022 WolkAbout Technology s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FEED_H +#define FEED_H + +#include "size_definitions.h" +#include "types.h" +#include "utility/wolk_utils.h" + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + char name[ITEM_NAME_SIZE]; + char reference[REFERENCE_SIZE]; + char unit[ITEM_UNIT_SIZE]; + + feed_type_t feedType; +} feed_registration_t; + +typedef struct { + char data[FEEDS_MAX_NUMBER][FEED_ELEMENT_SIZE]; + uint16_t size; + + char reference[REFERENCE_SIZE]; + + uint64_t utc; +} feed_t; + +void feed_initialize(feed_t* feed, uint16_t feed_size, const char* reference); + +void feed_clear(feed_t* feed); + +void feed_set_data(feed_t* feed, const char** data); +char** feed_get_data(feed_t* feed); + +void feed_set_data_at(feed_t* feed, const char* data, size_t data_position); +char* feed_get_data_at(feed_t* feed, size_t data_position); + +void feed_set_utc(feed_t* feed, uint64_t utc); +uint64_t feed_get_utc(feed_t* feed); + +void feed_initialize_registration(feed_registration_t* feed, char* name, const char* reference, char* unit, + feed_type_t feedType); + +#ifdef __cplusplus +} +#endif + +#endif // FEED_H diff --git a/sources/file_management.c b/sources/model/file_management/file_management.c similarity index 77% rename from sources/file_management.c rename to sources/model/file_management/file_management.c index 346db1c..11df126 100644 --- a/sources/file_management.c +++ b/sources/model/file_management/file_management.c @@ -17,25 +17,25 @@ #include "file_management.h" #include "file_management_packet.h" #include "file_management_parameter.h" -#include "sha256.h" #include "size_definitions.h" -#include "wolk_utils.h" +#include "utility/md5.h" +#include "utility/wolk_utils.h" #include #include #include +#include #include typedef enum { STATE_IDLE = 0, STATE_PACKET_FILE_TRANSFER, STATE_URL_DOWNLOAD, STATE_FILE_OBTAINED } state_t; enum { MAX_RETRIES = 3 }; -enum { FILE_VERIFICATION_CHUNK_SIZE = 1024 }; - static void handle_file_management(file_management_t* file_management, file_management_parameter_t* parameter); -static void handle_url_download(file_management_t* file_management, file_management_parameter_t* parameter); -static void handle_abort(file_management_t* file_management); -static void handle_file_delete(file_management_t* file_management, file_management_parameter_t* parameter); +static void handle_url_download(file_management_t* file_management, char* url_download); +static void handle_abort(file_management_t* file_management, uint8_t* packet); +static void handle_file_list(file_management_t* file_management); +static void handle_file_delete(file_management_t* file_management, file_list_t* file_list, size_t number_of_files); static void handle_file_purge(file_management_t* file_management); static bool update_sequence_init(file_management_t* file_management, const char* file_name, size_t file_size); @@ -50,7 +50,7 @@ static bool has_url_download(file_management_t* file_management); static void check_url_download(file_management_t* file_management); -static uint8_t get_file_list(file_management_t* file_management, char* file_list); +static uint8_t get_file_list(file_management_t* file_management, file_list_t* file_list); static bool remove_file(file_management_t* file_management, char* file_name); static bool purge_files(file_management_t* file_management); @@ -61,15 +61,17 @@ static bool is_file_valid(file_management_t* file_management); static void listener_on_status(file_management_t* file_management, file_management_status_t status); static void listener_on_packet_request(file_management_t* file_management, file_management_packet_request_t request); static void listener_on_url_download_status(file_management_t* file_management, file_management_status_t status); -static void listener_on_file_list_status(file_management_t* file_management, char* file_list, size_t* file_list_size); - -void file_management_init(file_management_t* file_management, const char* device_key, size_t maximum_file_size, - size_t chunk_size, file_management_start_t start, file_management_write_chunk_t write_chunk, - file_management_read_chunk_t read_chunk, file_management_abort_t abort, - file_management_finalize_t finalize, file_management_start_url_download_t start_url_download, +static void listener_on_file_list_status(file_management_t* file_management, file_list_t* file_list, + size_t* file_list_size); + +bool file_management_init(void* wolk_ctx, file_management_t* file_management, const char* device_key, + size_t maximum_file_size, size_t chunk_size, file_management_start_t start, + file_management_write_chunk_t write_chunk, file_management_read_chunk_t read_chunk, + file_management_abort_t abort, file_management_finalize_t finalize, + file_management_start_url_download_t start_url_download, file_management_is_url_download_done_t is_url_download_done, file_management_get_file_list_t get_file_list, file_management_remove_file_t remove_file, - file_management_purge_files_t purge_files, void* wolk_ctx) + file_management_purge_files_t purge_files) { /* Sanity check */ WOLK_ASSERT(file_management); @@ -95,7 +97,8 @@ void file_management_init(file_management_t* file_management, const char* device file_management->purge_files = purge_files; file_management->state = STATE_IDLE; - memset(file_management->last_packet_hash, 0, WOLK_ARRAY_LENGTH(file_management->last_packet_hash)); + memset(file_management->previous_packet_hash, 0, WOLK_ARRAY_LENGTH(file_management->previous_packet_hash)); + memset(file_management->current_packet_hash, 0, WOLK_ARRAY_LENGTH(file_management->current_packet_hash)); file_management->next_chunk_index = 0; file_management->expected_number_of_chunks = 0; file_management->retry_count = 0; @@ -110,7 +113,10 @@ void file_management_init(file_management_t* file_management, const char* device if (device_key == NULL || maximum_file_size == 0 || chunk_size == 0 || start == NULL || write_chunk == NULL || read_chunk == NULL || abort == NULL || finalize == NULL || wolk_ctx == NULL) { file_management->has_valid_configuration = false; + return false; } + + return true; } void file_management_handle_parameter(file_management_t* file_management, @@ -146,10 +152,10 @@ void file_management_handle_packet(file_management_t* file_management, uint8_t* file_management->retry_count += 1; if (file_management->retry_count >= MAX_RETRIES) { update_abort(file_management); - reset_state(file_management); - listener_on_status(file_management, file_management_status_error(FILE_MANAGEMENT_ERROR_RETRY_COUNT_EXCEEDED)); + + reset_state(file_management); return; } @@ -161,8 +167,9 @@ void file_management_handle_packet(file_management_t* file_management, uint8_t* return; } - if (memcmp(file_management->last_packet_hash, file_management_packet_get_previous_packet_hash(packet, packet_size), - WOLK_ARRAY_LENGTH(file_management->last_packet_hash)) + if (memcmp(file_management->previous_packet_hash, + file_management_packet_get_previous_packet_hash(packet, packet_size), + WOLK_ARRAY_LENGTH(file_management->previous_packet_hash)) != 0) { file_management_packet_request_t packet_request; file_management_packet_request_init(&packet_request, file_management->file_name, @@ -172,14 +179,14 @@ void file_management_handle_packet(file_management_t* file_management, uint8_t* return; } - memcpy(file_management->last_packet_hash, file_management_packet_get_hash(packet, packet_size), - WOLK_ARRAY_LENGTH(file_management->last_packet_hash)); + memcpy(file_management->previous_packet_hash, file_management_packet_get_hash(packet, packet_size), + WOLK_ARRAY_LENGTH(file_management->previous_packet_hash)); if (!write_chunk(file_management, file_management_packet_get_data(packet, packet_size), file_management_packet_get_data_size(packet, packet_size))) { - reset_state(file_management); - listener_on_status(file_management, file_management_status_error(FILE_MANAGEMENT_ERROR_FILE_SYSTEM)); + + reset_state(file_management); return; } @@ -196,9 +203,9 @@ void file_management_handle_packet(file_management_t* file_management, uint8_t* if (!is_file_valid(file_management)) { update_abort(file_management); - reset_state(file_management); + listener_on_status(file_management, file_management_status_error(FILE_MANAGEMENT_ERROR_FILE_HASH_MISMATCH)); - listener_on_status(file_management, file_management_status_error(FILE_MANAGEMENT_ERROR_FILE_SYSTEM)); + reset_state(file_management); return; } @@ -206,39 +213,49 @@ void file_management_handle_packet(file_management_t* file_management, uint8_t* listener_on_status(file_management, file_management_status_ok(FILE_MANAGEMENT_STATE_FILE_READY)); update_finalize(file_management); - char file_list[FILE_MANAGEMENT_FILE_LIST_SIZE][FILE_MANAGEMENT_FILE_NAME_SIZE] = {0}; + file_list_t file_list[FILE_MANAGEMENT_FILE_LIST_SIZE] = {0}; listener_on_file_list_status(file_management, file_list, get_file_list(file_management, file_list)); reset_state(file_management); } -void file_management_handle_abort(file_management_t* file_management) +void file_management_handle_abort(file_management_t* file_management, uint8_t* packet, size_t packet_size) { /* Sanity check */ WOLK_ASSERT(file_management); + WOLK_ASSERT(packet_size > FILE_MANAGEMENT_FILE_NAME_SIZE); if (!file_management->has_valid_configuration) { return; } - handle_abort(file_management); + handle_abort(file_management, packet); } -void file_management_handle_url_download(file_management_t* file_management, file_management_parameter_t* parameter) +void file_management_handle_url_download(file_management_t* file_management, char* url_download) { /*Sanity check*/ WOLK_ASSERT(file_management); WOLK_ASSERT(parameter); - handle_url_download(file_management, parameter); + handle_url_download(file_management, url_download); } -void file_management_handle_file_delete(file_management_t* file_management, file_management_t* parameter) +void file_management_handle_file_list(file_management_t* file_management) +{ + /*Sanity check*/ + WOLK_ASSERT(file_management); + + handle_file_list(file_management); +} + +void file_management_handle_file_delete(file_management_t* file_management, file_list_t* file_list, + size_t number_of_files) { /* Sanity Check*/ WOLK_ASSERT(file_management); WOLK_ASSERT(parameter); - handle_file_delete(file_management, parameter); + handle_file_delete(file_management, file_list, number_of_files); } void file_management_handle_file_purge(file_management_t* file_management) @@ -316,7 +333,7 @@ static void handle_file_management(file_management_t* file_management, file_mana } if (!strlen(file_management_parameter_get_file_name(parameter))) { - listener_on_status(file_management, file_management_status_error(FILE_MANAGEMENT_ERROR_UNSPECIFIED)); + listener_on_status(file_management, file_management_status_error(FILE_MANAGEMENT_ERROR_UNKNOWN)); return; } @@ -328,7 +345,7 @@ static void handle_file_management(file_management_t* file_management, file_mana if (!update_sequence_init(file_management, file_management_parameter_get_file_name(parameter), file_management_parameter_get_file_size(parameter))) { - listener_on_status(file_management, file_management_status_error(FILE_MANAGEMENT_ERROR_UNSPECIFIED)); + listener_on_status(file_management, file_management_status_error(FILE_MANAGEMENT_ERROR_UNKNOWN)); return; } @@ -348,7 +365,8 @@ static void handle_file_management(file_management_t* file_management, file_mana file_management->next_chunk_index = 0; file_management->expected_number_of_chunks = - (size_t)WOLK_CEIL((double)file_management_parameter_get_file_size(parameter) / file_management->chunk_size); + (size_t)WOLK_CEIL((double)file_management_parameter_get_file_size(parameter) + / (file_management->chunk_size - 2 * FILE_MANAGEMENT_HASH_SIZE)); file_management->retry_count = 0; listener_on_status(file_management, file_management_status_ok(FILE_MANAGEMENT_STATE_FILE_TRANSFER)); @@ -373,7 +391,7 @@ static void handle_file_management(file_management_t* file_management, file_mana } } -static void handle_url_download(file_management_t* file_management, file_management_parameter_t* parameter) +static void handle_url_download(file_management_t* file_management, char* url_download) { /* Sanity check */ WOLK_ASSERT(file_management); @@ -382,12 +400,12 @@ static void handle_url_download(file_management_t* file_management, file_managem switch (file_management->state) { case STATE_IDLE: case STATE_PACKET_FILE_TRANSFER: - if ((strlen(parameter->file_url) >= FILE_MANAGEMENT_URL_SIZE) || (strlen(parameter->file_url) == 0)) { + if ((strlen(url_download) >= FILE_MANAGEMENT_URL_SIZE) || (strlen(url_download) == 0)) { listener_on_url_download_status(file_management, file_management_status_error(FILE_MANAGEMENT_ERROR_MALFORMED_URL)); return; } - strcpy(file_management->file_url, file_management_parameter_get_file_url(parameter)); + strcpy(file_management->file_url, url_download); memset(file_management->file_name, '\0', sizeof(file_management->file_name)); if (!has_url_download(file_management)) { @@ -396,6 +414,8 @@ static void handle_url_download(file_management_t* file_management, file_managem return; } + listener_on_url_download_status(file_management, + file_management_status_ok(FILE_MANAGEMENT_STATE_FILE_TRANSFER)); file_management->state = STATE_URL_DOWNLOAD; break; @@ -432,7 +452,7 @@ static void check_url_download(file_management_t* file_management) file_management_status_ok(FILE_MANAGEMENT_STATE_FILE_TRANSFER)); if (!start_url_download(file_management, file_management->file_url)) { listener_on_url_download_status(file_management, - file_management_status_error(FILE_MANAGEMENT_ERROR_UNSPECIFIED)); + file_management_status_error(FILE_MANAGEMENT_ERROR_UNKNOWN)); reset_state(file_management); return; @@ -443,20 +463,25 @@ static void check_url_download(file_management_t* file_management) case STATE_FILE_OBTAINED: if (!is_url_download_done(file_management, &success, &downloaded_file_name)) { + listener_on_url_download_status(file_management, + file_management_status_error(FILE_MANAGEMENT_ERROR_MALFORMED_URL)); + + reset_state(file_management); return; } if (!success) { - reset_state(file_management); listener_on_url_download_status(file_management, - file_management_status_error(FILE_MANAGEMENT_ERROR_UNSPECIFIED)); + file_management_status_error(FILE_MANAGEMENT_ERROR_UNKNOWN)); + + reset_state(file_management); return; } strncpy(file_management->file_name, downloaded_file_name, strlen(downloaded_file_name)); listener_on_url_download_status(file_management, file_management_status_ok(FILE_MANAGEMENT_STATE_FILE_READY)); - char file_list[FILE_MANAGEMENT_FILE_LIST_SIZE][FILE_MANAGEMENT_FILE_NAME_SIZE] = {0}; + file_list_t file_list[FILE_MANAGEMENT_FILE_LIST_SIZE] = {0}; listener_on_file_list_status(file_management, file_list, get_file_list(file_management, file_list)); file_management->state = STATE_IDLE; @@ -468,50 +493,70 @@ static void check_url_download(file_management_t* file_management) } } -static void handle_abort(file_management_t* file_management) +static void handle_abort(file_management_t* file_management, uint8_t* packet) { /* Sanity check */ WOLK_ASSERT(file_management); - char file_list[FILE_MANAGEMENT_FILE_LIST_SIZE][FILE_MANAGEMENT_FILE_NAME_SIZE] = {0}; + file_list_t file_list[FILE_MANAGEMENT_FILE_LIST_SIZE] = {0}; - switch (file_management->state) { - case STATE_IDLE: - break; - case STATE_FILE_OBTAINED: - case STATE_PACKET_FILE_TRANSFER: - update_abort(file_management); - listener_on_status(file_management, file_management_status_ok(FILE_MANAGEMENT_STATE_ABORTED)); + if (strstr(packet, file_management->file_name)) { - listener_on_file_list_status(file_management, file_list, get_file_list(file_management, file_list)); + switch (file_management->state) { + case STATE_IDLE: + break; + case STATE_FILE_OBTAINED: + case STATE_PACKET_FILE_TRANSFER: + update_abort(file_management); + listener_on_status(file_management, file_management_status_ok(FILE_MANAGEMENT_STATE_ABORTED)); - reset_state(file_management); - break; - case STATE_URL_DOWNLOAD: - update_abort(file_management); - file_management_parameter_t file_management_parameter; - file_management_parameter_set_file_url(&file_management_parameter, file_management->file_url); - listener_on_url_download_status(file_management, file_management_status_ok(FILE_MANAGEMENT_STATE_ABORTED)); + listener_on_file_list_status(file_management, file_list, get_file_list(file_management, file_list)); - listener_on_file_list_status(file_management, file_list, get_file_list(file_management, file_list)); + reset_state(file_management); + break; + case STATE_URL_DOWNLOAD: + update_abort(file_management); + file_management_parameter_t file_management_parameter; + file_management_parameter_set_file_url(&file_management_parameter, file_management->file_url); + listener_on_url_download_status(file_management, file_management_status_ok(FILE_MANAGEMENT_STATE_ABORTED)); + + listener_on_file_list_status(file_management, file_list, get_file_list(file_management, file_list)); + reset_state(file_management); + break; + default: + /* Sanity check */ + WOLK_ASSERT(false); + } + } else { + listener_on_status(file_management, file_management_status_ok(FILE_MANAGEMENT_STATE_ERROR)); + listener_on_file_list_status(file_management, file_list, get_file_list(file_management, file_list)); reset_state(file_management); - break; - default: - /* Sanity check */ - WOLK_ASSERT(false); } } -static void handle_file_delete(file_management_t* file_management, file_management_parameter_t* parameter) +static void handle_file_list(file_management_t* file_management) { /* Sanity Check */ WOLK_ASSERT(file_management); WOLK_ASSERT(parameter); + file_list_t file_list[FILE_MANAGEMENT_FILE_LIST_SIZE] = {0}; - remove_file(file_management, parameter->file_name); + listener_on_file_list_status(file_management, file_list, get_file_list(file_management, file_list)); +} + +static void handle_file_delete(file_management_t* file_management, file_list_t* file_list, size_t number_of_files) +{ + /* Sanity Check */ + WOLK_ASSERT(file_management); + WOLK_ASSERT(parameter); + + // remove one by one file + for (int i = 0; i < number_of_files; ++i) { + remove_file(file_management, file_list); + file_list++; + } - char file_list[FILE_MANAGEMENT_FILE_LIST_SIZE][FILE_MANAGEMENT_FILE_NAME_SIZE] = {0}; listener_on_file_list_status(file_management, file_list, get_file_list(file_management, file_list)); } @@ -521,7 +566,7 @@ static void handle_file_purge(file_management_t* file_management) purge_files(file_management); - char file_list[FILE_MANAGEMENT_FILE_LIST_SIZE][FILE_MANAGEMENT_FILE_NAME_SIZE] = {0}; + file_list_t file_list[FILE_MANAGEMENT_FILE_LIST_SIZE] = {0}; listener_on_file_list_status(file_management, file_list, get_file_list(file_management, file_list)); } @@ -578,7 +623,8 @@ static void reset_state(file_management_t* file_management) WOLK_ASSERT(file_management); file_management->state = STATE_IDLE; - memset(file_management->last_packet_hash, 0, WOLK_ARRAY_LENGTH(file_management->last_packet_hash)); + memset(file_management->previous_packet_hash, 0, WOLK_ARRAY_LENGTH(file_management->previous_packet_hash)); + memset(file_management->current_packet_hash, 0, WOLK_ARRAY_LENGTH(file_management->current_packet_hash)); file_management->next_chunk_index = 0; file_management->expected_number_of_chunks = 0; @@ -592,19 +638,25 @@ static bool is_file_valid(file_management_t* file_management) /* Sanity check */ WOLK_ASSERT(file_management); - sha256_context sha256_ctx; - sha256_init(&sha256_ctx); + uint8_t read_data[FILE_MANAGEMENT_VERIFICATION_CHUNK_SIZE] = {0}; + uint8_t calculated_file_hash[FILE_MANAGEMENT_HASH_SIZE] = {0}; + uint8_t calculated_file_checksum[FILE_MANAGEMENT_HASH_SIZE] = {0}; + MD5_CTX md5_ctx; + md5_init(&md5_ctx); - for (size_t i = 0; i < (size_t)WOLK_CEIL((double)file_management->file_size / FILE_VERIFICATION_CHUNK_SIZE); ++i) { - uint8_t read_data[FILE_VERIFICATION_CHUNK_SIZE]; + for (size_t i = 0; i < file_management->expected_number_of_chunks; ++i) { const size_t read_data_size = read_chunk(file_management, i, read_data, WOLK_ARRAY_LENGTH(read_data)); - sha256_hash(&sha256_ctx, read_data, read_data_size); + md5_update(&md5_ctx, read_data, read_data_size); } + md5_final(&md5_ctx, calculated_file_hash); - uint8_t calculated_hash[FILE_MANAGEMENT_HASH_SIZE]; - sha256_done(&sha256_ctx, calculated_hash); + // hash to checksum + for (int i = 0; i < FILE_MANAGEMENT_HASH_SIZE; ++i) { + sprintf(&calculated_file_checksum[i * 2], "%02x", (unsigned int)calculated_file_hash[i]); + } - return memcmp(calculated_hash, file_management->file_hash, WOLK_ARRAY_LENGTH(calculated_hash)) == 0; + return memcmp(calculated_file_checksum, file_management->file_hash, WOLK_ARRAY_LENGTH(calculated_file_checksum)) + == 0; } static void listener_on_status(file_management_t* file_management, file_management_status_t status) @@ -656,7 +708,7 @@ static bool has_url_download(file_management_t* file_management) return file_management->start_url_download != NULL; } -static uint8_t get_file_list(file_management_t* file_management, char* file_list) +static uint8_t get_file_list(file_management_t* file_management, file_list_t* file_list) { /* Sanity Check */ WOLK_ASSERT(file_management); @@ -693,7 +745,8 @@ static void listener_on_url_download_status(file_management_t* file_management, } } -static void listener_on_file_list_status(file_management_t* file_management, char* file_list, size_t* file_list_size) +static void listener_on_file_list_status(file_management_t* file_management, file_list_t* file_list, + size_t* file_list_size) { /* Sanity check */ WOLK_ASSERT(file_mangement); diff --git a/sources/file_management.h b/sources/model/file_management/file_management.h similarity index 85% rename from sources/file_management.h rename to sources/model/file_management/file_management.h index 19bf014..67bbfee 100644 --- a/sources/file_management.h +++ b/sources/model/file_management/file_management.h @@ -21,15 +21,21 @@ extern "C" { #endif -#include "file_management_packet_request.h" #include "file_management_parameter.h" -#include "file_management_status.h" +#include "model/file_management/file_management_packet_request.h" +#include "model/file_management/file_management_status.h" #include "size_definitions.h" #include #include #include + +typedef struct file_list_t { + char file_name[FILE_MANAGEMENT_FILE_NAME_SIZE]; + size_t file_size; +} file_list_t; + /** * @brief file_management_start signature. * Initializes File Management procedure with file named 'file_name' of size 'file_size'. @@ -92,11 +98,11 @@ typedef bool (*file_management_is_url_download_done_t)(bool* success, char* down /** * @brief file_management_get_file_list_t signature. - * Get file list in "file_list" as string array followed with number of files in "file_list_size" + * Get file list in "file_list" as file list array which consist of file name and size * * @return number of file presented in the list */ -typedef size_t (*file_management_get_file_list_t)(char* file_list); +typedef size_t (*file_management_get_file_list_t)(file_list_t* file_list); /** * @brief file_management_remove_file_t signature. @@ -145,7 +151,8 @@ struct file_management { file_management_purge_files_t purge_files; uint8_t state; - uint8_t last_packet_hash[FILE_MANAGEMENT_HASH_SIZE]; + uint8_t previous_packet_hash[FILE_MANAGEMENT_HASH_SIZE]; + uint8_t current_packet_hash[FILE_MANAGEMENT_HASH_SIZE]; size_t next_chunk_index; size_t expected_number_of_chunks; @@ -173,24 +180,26 @@ struct file_management { bool has_valid_configuration; }; -void file_management_init(file_management_t* file_management, const char* device_key, size_t maximum_file_size, - size_t chunk_size, file_management_start_t start, file_management_write_chunk_t write_chunk, - file_management_read_chunk_t read_chunk, file_management_abort_t abort, - file_management_finalize_t finalize, file_management_start_url_download_t start_url_download, +bool file_management_init(void* wolk_ctx, file_management_t* file_management, const char* device_key, + size_t maximum_file_size, size_t chunk_size, file_management_start_t start, + file_management_write_chunk_t write_chunk, file_management_read_chunk_t read_chunk, + file_management_abort_t abort, file_management_finalize_t finalize, + file_management_start_url_download_t start_url_download, file_management_is_url_download_done_t is_url_download_done, file_management_get_file_list_t get_file_list, file_management_remove_file_t remove_file, - file_management_purge_files_t purge_files, void* wolk_ctx); + file_management_purge_files_t purge_files); void file_management_handle_parameter(file_management_t* file_management, file_management_parameter_t* file_management_parameter); void file_management_handle_packet(file_management_t* file_management, uint8_t* packet, size_t packet_size); -void file_management_handle_abort(file_management_t* file_management); - -void file_management_handle_url_download(file_management_t* file_management, file_management_parameter_t* parameter); +void file_management_handle_abort(file_management_t* file_management, uint8_t* packet, size_t packet_size); -void file_management_handle_file_delete(file_management_t* file_management, file_management_t* parameter); +void file_management_handle_url_download(file_management_t* file_management, char* url_download); +void file_management_handle_file_list(file_management_t* file_management); +void file_management_handle_file_delete(file_management_t* file_management, file_list_t* file_list, + size_t number_of_files); void file_management_handle_file_purge(file_management_t* file_management); void file_management_process(file_management_t* file_management); diff --git a/sources/file_management_packet.c b/sources/model/file_management/file_management_packet.c old mode 100644 new mode 100755 similarity index 95% rename from sources/file_management_packet.c rename to sources/model/file_management/file_management_packet.c index 645eb81..8137e38 --- a/sources/file_management_packet.c +++ b/sources/model/file_management/file_management_packet.c @@ -15,9 +15,9 @@ */ #include "file_management_packet.h" -#include "sha256.h" #include "size_definitions.h" -#include "wolk_utils.h" +#include "utility/sha256.h" +#include "utility/wolk_utils.h" #include #include @@ -62,9 +62,9 @@ uint8_t* file_management_packet_get_previous_packet_hash(uint8_t* packet, size_t /* Sanity check */ WOLK_ASSERT(packet); WOLK_ASSERT(packet_size > 2 * FILE_MANAGEMENT_HASH_SIZE); - WOLK_UNUSED(packet_size); + // previous sha256 hash is located at the first 32 bytes return packet; } diff --git a/sources/file_management_packet.h b/sources/model/file_management/file_management_packet.h old mode 100644 new mode 100755 similarity index 100% rename from sources/file_management_packet.h rename to sources/model/file_management/file_management_packet.h diff --git a/sources/file_management_packet_request.c b/sources/model/file_management/file_management_packet_request.c old mode 100644 new mode 100755 similarity index 94% rename from sources/file_management_packet_request.c rename to sources/model/file_management/file_management_packet_request.c index 7fbd4f6..d0ad9e8 --- a/sources/file_management_packet_request.c +++ b/sources/model/file_management/file_management_packet_request.c @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "file_management_packet_request.h" -#include "wolk_utils.h" +#include "model/file_management/file_management_packet_request.h" +#include "utility/wolk_utils.h" #include #include diff --git a/sources/file_management_packet_request.h b/sources/model/file_management/file_management_packet_request.h old mode 100644 new mode 100755 similarity index 100% rename from sources/file_management_packet_request.h rename to sources/model/file_management/file_management_packet_request.h diff --git a/sources/file_management_parameter.c b/sources/model/file_management/file_management_parameter.c old mode 100644 new mode 100755 similarity index 99% rename from sources/file_management_parameter.c rename to sources/model/file_management/file_management_parameter.c index 21cf047..9a7c348 --- a/sources/file_management_parameter.c +++ b/sources/model/file_management/file_management_parameter.c @@ -15,7 +15,7 @@ */ #include "file_management_parameter.h" -#include "wolk_utils.h" +#include "utility/wolk_utils.h" #include #include diff --git a/sources/file_management_parameter.h b/sources/model/file_management/file_management_parameter.h old mode 100644 new mode 100755 similarity index 100% rename from sources/file_management_parameter.h rename to sources/model/file_management/file_management_parameter.h diff --git a/sources/file_management_status.c b/sources/model/file_management/file_management_status.c old mode 100644 new mode 100755 similarity index 93% rename from sources/file_management_status.c rename to sources/model/file_management/file_management_status.c index 7f18419..d485038 --- a/sources/file_management_status.c +++ b/sources/model/file_management/file_management_status.c @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "file_management_status.h" -#include "wolk_utils.h" +#include "model/file_management/file_management_status.h" +#include "utility/wolk_utils.h" file_management_status_t file_management_status_ok(file_management_state_t state) { diff --git a/sources/file_management_status.h b/sources/model/file_management/file_management_status.h old mode 100644 new mode 100755 similarity index 60% rename from sources/file_management_status.h rename to sources/model/file_management/file_management_status.h index acf97e5..d0cc956 --- a/sources/file_management_status.h +++ b/sources/model/file_management/file_management_status.h @@ -17,33 +17,12 @@ #ifndef FILE_MANAGEMENT_STATUS_H #define FILE_MANAGEMENT_STATUS_H +#include "types.h" + #ifdef __cplusplus extern "C" { #endif -typedef enum { - FILE_MANAGEMENT_STATE_FILE_TRANSFER, - FILE_MANAGEMENT_STATE_FILE_READY, - FILE_MANAGEMENT_STATE_ERROR, - FILE_MANAGEMENT_STATE_ABORTED -} file_management_state_t; - -typedef enum { - FILE_MANAGEMENT_ERROR_NONE = -1, - FILE_MANAGEMENT_ERROR_UNSPECIFIED = 0, - FILE_MANAGEMENT_ERROR_TRANSFER_PROTOCOL_DISABLED = 1, - FILE_MANAGEMENT_ERROR_UNSUPPORTED_FILE_SIZE = 2, - FILE_MANAGEMENT_ERROR_MALFORMED_URL = 3, - FILE_MANAGEMENT_ERROR_FILE_HASH_MISMATCH = 4, - FILE_MANAGEMENT_ERROR_FILE_SYSTEM = 5, - FILE_MANAGEMENT_ERROR_RETRY_COUNT_EXCEEDED = 10 -} file_management_error_t; - -typedef struct { - file_management_state_t state; - file_management_error_t error; -} file_management_status_t; - file_management_status_t file_management_status_ok(file_management_state_t state); file_management_status_t file_management_status_error(file_management_error_t error); diff --git a/sources/firmware_update.c b/sources/model/firmware_update.c similarity index 79% rename from sources/firmware_update.c rename to sources/model/firmware_update.c index b3eccdd..d0abd37 100644 --- a/sources/firmware_update.c +++ b/sources/model/firmware_update.c @@ -16,7 +16,7 @@ #include #include "firmware_update.h" -#include "wolk_utils.h" +#include "utility/wolk_utils.h" typedef enum { STATE_IDLE = 1, STATE_INSTALLATION, STATE_COMPLETED, STATE_ERROR } state_t; @@ -26,13 +26,12 @@ static void handle_abort(firmware_update_t* firmware_update); static void check_firmware_update(firmware_update_t* firmware_update); static void reset_state(firmware_update_t* firmware_update); -static bool get_version(firmware_update_t* firmware_update, char* version); static bool update_abort(firmware_update_t* firmware_update); static void set_error(firmware_update_t* firmware_update, firmware_update_error_t error); static void set_status(firmware_update_t* firmware_update, firmware_update_status_t status); static void listener_on_firmware_update_status(firmware_update_t* firmware_update); -static void listener_on_version_status(firmware_update_t* firmware_update, char* version); +static void listener_on_verification(firmware_update_t* firmware_update); static void handle(firmware_update_t* firmware_update, firmware_update_t* parameter) @@ -44,29 +43,29 @@ static void handle(firmware_update_t* firmware_update, firmware_update_t* parame switch (firmware_update->state) { case STATE_IDLE: if (firmware_update->start_installation != NULL) { - set_status(firmware_update, FIRMWARE_UPDATE_STATUS_INSTALLATION); + set_status(firmware_update, FIRMWARE_UPDATE_STATUS_INSTALLING); listener_on_firmware_update_status(firmware_update); firmware_update->state = STATE_INSTALLATION; if (!firmware_update->verification_store(firmware_update->state)) { firmware_update->state = STATE_ERROR; - firmware_update->error = FIRMWARE_UPDATE_FILE_SYSTEM_ERROR; + firmware_update->error = FIRMWARE_UPDATE_ERROR_UNKNOWN_FILE; } if (!firmware_update->start_installation(parameter->file_name)) { firmware_update->state = STATE_ERROR; - firmware_update->error = FIRMWARE_UPDATE_FILE_SYSTEM_ERROR; + firmware_update->error = FIRMWARE_UPDATE_ERROR_UNKNOWN; } } else { firmware_update->state = STATE_ERROR; - firmware_update->error = FIRMWARE_UPDATE_INSTALLATION_FAILED; + firmware_update->error = FIRMWARE_UPDATE_ERROR_INSTALLATION_FAILED; } break; case STATE_INSTALLATION: - set_status(firmware_update, FIRMWARE_UPDATE_STATUS_INSTALLATION); + set_status(firmware_update, FIRMWARE_UPDATE_STATUS_INSTALLING); listener_on_firmware_update_status(firmware_update); break; case STATE_COMPLETED: @@ -99,7 +98,7 @@ static void handle_verification(firmware_update_t* firmware_update) /* Sanity check */ WOLK_ASSERT(false); - firmware_update->state = STATE_ERROR; + firmware_update->state = STATE_IDLE; } } @@ -112,16 +111,20 @@ static void handle_abort(firmware_update_t* firmware_update) case STATE_IDLE: case STATE_COMPLETED: case STATE_ERROR: + if (update_abort(firmware_update)) { + set_status(firmware_update, FIRMWARE_UPDATE_STATUS_ABORTED); + } listener_on_firmware_update_status(firmware_update); break; case STATE_INSTALLATION: if (!update_abort(firmware_update)) { - set_error(firmware_update, FIRMWARE_UPDATE_UNSPECIFIED_ERROR); + set_error(firmware_update, FIRMWARE_UPDATE_ERROR_UNKNOWN); set_status(firmware_update, FIRMWARE_UPDATE_STATUS_ERROR); listener_on_firmware_update_status(firmware_update); + } else { + set_status(firmware_update, FIRMWARE_UPDATE_STATUS_ABORTED); + listener_on_firmware_update_status(firmware_update); } - set_status(firmware_update, FIRMWARE_UPDATE_STATUS_ABORTED); - listener_on_firmware_update_status(firmware_update); break; default: /* Sanity check */ @@ -146,24 +149,20 @@ static void check_firmware_update(firmware_update_t* firmware_update) if (!success) { firmware_update->state = STATE_ERROR; - firmware_update->error = FIRMWARE_UPDATE_INSTALLATION_FAILED; + firmware_update->error = FIRMWARE_UPDATE_ERROR_INSTALLATION_FAILED; } else { firmware_update->state = STATE_COMPLETED; } } break; case STATE_COMPLETED: - set_status(firmware_update, FIRMWARE_UPDATE_STATUS_COMPLETED); + set_status(firmware_update, FIRMWARE_UPDATE_STATUS_SUCCESS); listener_on_firmware_update_status(firmware_update); - char firmware_update_version[FIRMWARE_UPDATE_VERSION_SIZE]; - get_version(firmware_update, firmware_update_version); - listener_on_version_status(firmware_update, firmware_update_version); - reset_state(firmware_update); if (!firmware_update->verification_store(firmware_update->state)) { firmware_update->state = STATE_ERROR; - firmware_update->error = FIRMWARE_UPDATE_FILE_SYSTEM_ERROR; + firmware_update->error = FIRMWARE_UPDATE_ERROR_UNKNOWN_FILE; } break; case STATE_ERROR: @@ -187,15 +186,6 @@ static void reset_state(firmware_update_t* firmware_update) memset(firmware_update->file_name, '\0', WOLK_ARRAY_LENGTH(firmware_update->file_name)); } -static bool get_version(firmware_update_t* firmware_update, char* version) -{ - /* Sanity Check */ - WOLK_ASSERT(firmware_update); - WOLK_ASSERT(version); - - return firmware_update->get_version(version); -} - static bool update_abort(firmware_update_t* firmware_update) { /* Sanity check */ @@ -232,43 +222,40 @@ static void listener_on_firmware_update_status(firmware_update_t* firmware_updat } } -static void listener_on_version_status(firmware_update_t* firmware_update, char* version) +static void listener_on_verification(firmware_update_t* firmware_update) { - /* Sanity check */ + /* Sanity Check */ WOLK_ASSERT(firmware_update); - WOLK_ASSERT(version); - if (firmware_update->on_version != NULL) { - firmware_update->on_version(firmware_update, version); + if (firmware_update->on_verification != NULL) { + firmware_update->on_verification(firmware_update); } } - /* Public implementations */ void firmware_update_init(firmware_update_t* firmware_update, firmware_update_start_installation_t start_installation, firmware_update_is_installation_completed_t is_installation_completed, firmware_update_verification_store_t verification_store, firmware_update_verification_read_t verification_read, - firmware_update_get_version_t get_version, firmware_update_abort_t abort_installation, - void* wolk_ctx) + firmware_update_abort_t abort_installation, void* wolk_ctx) { /* Sanity check */ WOLK_ASSERT(firmware_update); WOLK_ASSERT(wolk_ctx); firmware_update->state = STATE_IDLE; + firmware_update->error = FIRMWARE_UPDATE_ERROR_NONE; firmware_update->start_installation = start_installation; firmware_update->is_installation_completed = is_installation_completed; firmware_update->verification_store = verification_store; firmware_update->verification_read = verification_read; - firmware_update->get_version = get_version; firmware_update->abort_installation = abort_installation; firmware_update->wolk_ctx = wolk_ctx; firmware_update->is_initialized = true; if (start_installation == NULL || is_installation_completed == NULL || verification_store == NULL - || verification_read == NULL || get_version == NULL || abort_installation == NULL) { + || verification_read == NULL || abort_installation == NULL) { firmware_update->is_initialized = false; } } @@ -338,16 +325,6 @@ void firmware_update_set_on_status_listener(firmware_update_t* firmware_update, firmware_update->get_status = status; } -void firmware_update_set_on_version_listener(firmware_update_t* firmware_update, - firmware_update_on_version_listener version) -{ - /* Sanity Check */ - WOLK_ASSERT(firmware_update); - WOLK_ASSERT(version); - - firmware_update->on_version = version; -} - void firmware_update_set_on_verification_listener(firmware_update_t* firmware_update, firmware_update_on_verification_listener verification) { @@ -369,3 +346,54 @@ void firmware_update_process(firmware_update_t* firmware_update) check_firmware_update(firmware_update); } + +const char* firmware_update_status_as_str(firmware_update_t* firmware_update) +{ + /* Sanity check */ + WOLK_ASSERT(firmware_update); + + switch (firmware_update->status) { + case FIRMWARE_UPDATE_STATUS_AWAITING_DEVICE: + return "AWAITING_DEVICE"; + + case FIRMWARE_UPDATE_STATUS_INSTALLING: + return "INSTALLING"; + + case FIRMWARE_UPDATE_STATUS_SUCCESS: + return "SUCCESS"; + + case FIRMWARE_UPDATE_STATUS_ERROR: + return "ERROR"; + + case FIRMWARE_UPDATE_STATUS_ABORTED: + return "ABORTED"; + + case FIRMWARE_UPDATE_STATUS_UNKNOWN: + return "UNKNOWN"; + + default: + WOLK_ASSERT(false); + return ""; + } +} + +const char* firmware_update_error_as_str(firmware_update_t* firmware_update) +{ + /* Sanity check */ + WOLK_ASSERT(firmware_update); + + switch (firmware_update->error) { + case FIRMWARE_UPDATE_ERROR_UNKNOWN: + return "UNKNOWN"; + + case FIRMWARE_UPDATE_ERROR_UNKNOWN_FILE: + return "UNKNOWN_FILE"; + + case FIRMWARE_UPDATE_ERROR_INSTALLATION_FAILED: + return "INSTALLATION_FAILED"; + + default: + WOLK_ASSERT(false); + return ""; + } +} diff --git a/sources/firmware_update.h b/sources/model/firmware_update.h similarity index 86% rename from sources/firmware_update.h rename to sources/model/firmware_update.h index 68cb613..6d07589 100644 --- a/sources/firmware_update.h +++ b/sources/model/firmware_update.h @@ -73,18 +73,19 @@ typedef uint8_t (*firmware_update_verification_read_t)(void); typedef enum { - FIRMWARE_UPDATE_STATUS_INSTALLATION = 0, - FIRMWARE_UPDATE_STATUS_COMPLETED = 1, - FIRMWARE_UPDATE_STATUS_ERROR = 2, - FIRMWARE_UPDATE_STATUS_ABORTED = 3 + FIRMWARE_UPDATE_STATUS_AWAITING_DEVICE = 0, + FIRMWARE_UPDATE_STATUS_INSTALLING = 1, + FIRMWARE_UPDATE_STATUS_SUCCESS = 2, + FIRMWARE_UPDATE_STATUS_ERROR = 3, + FIRMWARE_UPDATE_STATUS_ABORTED = 4, + FIRMWARE_UPDATE_STATUS_UNKNOWN = 5 } firmware_update_status_t; typedef enum { FIRMWARE_UPDATE_ERROR_NONE = -1, - FIRMWARE_UPDATE_UNSPECIFIED_ERROR = 0, - FIRMWARE_UPDATE_FILE_NOT_PRESENT = 1, - FIRMWARE_UPDATE_FILE_SYSTEM_ERROR = 2, - FIRMWARE_UPDATE_INSTALLATION_FAILED = 3 + FIRMWARE_UPDATE_ERROR_UNKNOWN = 0, + FIRMWARE_UPDATE_ERROR_UNKNOWN_FILE = 1, + FIRMWARE_UPDATE_ERROR_INSTALLATION_FAILED = 2 } firmware_update_error_t; typedef struct firmware_update firmware_update_t; @@ -105,12 +106,10 @@ struct firmware_update { firmware_update_is_installation_completed_t is_installation_completed; firmware_update_verification_store_t verification_store; firmware_update_verification_read_t verification_read; - firmware_update_get_version_t get_version; firmware_update_abort_t abort_installation; /* Listeners */ firmware_update_on_status_listener get_status; - firmware_update_on_version_listener on_version; firmware_update_on_verification_listener on_verification; /* Listeners */ @@ -121,8 +120,7 @@ void firmware_update_init(firmware_update_t* firmware_update, firmware_update_st firmware_update_is_installation_completed_t is_installation_completed, firmware_update_verification_store_t verification_store, firmware_update_verification_read_t verification_read, - firmware_update_get_version_t get_version, firmware_update_abort_t abort_installation, - void* wolk_ctx); + firmware_update_abort_t abort_installation, void* wolk_ctx); void firmware_update_parameter_init(firmware_update_t* parameter); void firmware_update_parameter_set_filename(firmware_update_t* parameter, const char* file_name); void firmware_update_handle_parameter(firmware_update_t* firmware_update, firmware_update_t* parameter); @@ -130,10 +128,11 @@ void firmware_update_handle_verification(firmware_update_t* firmware_update); void firmware_update_handle_abort(firmware_update_t* firmware_update); void firmware_update_set_on_status_listener(firmware_update_t* firmware_update, firmware_update_on_status_listener status); -void firmware_update_set_on_version_listener(firmware_update_t* firmware_update, - firmware_update_on_version_listener version); void firmware_update_set_on_verification_listener(firmware_update_t* firmware_update, firmware_update_on_verification_listener verification); void firmware_update_process(firmware_update_t* firmware_update); +const char* firmware_update_status_as_str(firmware_update_t* firmware_update); +const char* firmware_update_error_as_str(firmware_update_t* firmware_update); + #endif // WOLKCONNECTOR_C_FIRMWARE_UPDATE_H diff --git a/sources/outbound_message.c b/sources/model/outbound_message.c old mode 100644 new mode 100755 similarity index 94% rename from sources/outbound_message.c rename to sources/model/outbound_message.c index 14ec2b6..8b1c9b0 --- a/sources/outbound_message.c +++ b/sources/model/outbound_message.c @@ -14,8 +14,8 @@ * limitations under the License. */ -#include "outbound_message.h" -#include "wolk_utils.h" +#include "model/outbound_message.h" +#include "utility/wolk_utils.h" #include diff --git a/sources/outbound_message.h b/sources/model/outbound_message.h old mode 100644 new mode 100755 similarity index 100% rename from sources/outbound_message.h rename to sources/model/outbound_message.h diff --git a/sources/outbound_message_factory.c b/sources/model/outbound_message_factory.c similarity index 50% rename from sources/outbound_message_factory.c rename to sources/model/outbound_message_factory.c index 4b63b02..3bdbda1 100644 --- a/sources/outbound_message_factory.c +++ b/sources/model/outbound_message_factory.c @@ -1,5 +1,5 @@ /* - * Copyright 2018 WolkAbout Technology s.r.o. + * Copyright 2022 WolkAbout Technology s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,91 +15,41 @@ */ #include "outbound_message_factory.h" -#include "outbound_message.h" -#include "parser.h" -#include "reading.h" -#include "wolk_utils.h" +#include "model/feed.h" +#include "model/outbound_message.h" +#include "protocol/parser.h" +#include "utility/wolk_utils.h" #include #include #include -size_t outbound_message_make_from_readings(parser_t* parser, const char* device_key, reading_t* first_reading, - size_t num_readings, outbound_message_t* outbound_message) +size_t outbound_message_make_from_feeds(parser_t* parser, const char* device_key, feed_t* readings, data_type_t type, + size_t readings_number, size_t reading_element_size, + outbound_message_t* outbound_message) { /* Sanity check */ WOLK_ASSERT(parser); WOLK_ASSERT(device_key); - WOLK_ASSERT(first_reading); + WOLK_ASSERT(readings); + WOLK_ASSERT(readings_number); + WOLK_ASSERT(reading_element_size); WOLK_ASSERT(outbound_message); - char topic[TOPIC_SIZE]; - char payload[PAYLOAD_SIZE]; + char topic[TOPIC_SIZE] = ""; + char payload[PAYLOAD_SIZE] = ""; size_t num_serialized = 0; - memset(topic, '\0', sizeof(topic)); - memset(payload, '\0', sizeof(payload)); + parser->create_topic(parser->D2P_TOPIC, device_key, parser->FEED_VALUES_MESSAGE_TOPIC, topic); - if (!parser_serialize_readings_topic(parser, device_key, first_reading, num_readings, topic, sizeof(topic))) { - return num_serialized; - } + num_serialized = + parser_serialize_feeds(parser, readings, type, readings_number, reading_element_size, payload, sizeof(payload)); + if (num_serialized != 0) + outbound_message_init(outbound_message, topic, payload); - num_serialized = parser_serialize_readings(parser, first_reading, num_readings, payload, sizeof(payload)); - outbound_message_init(outbound_message, topic, payload); return num_serialized; } -bool outbound_message_make_from_actuator_status(parser_t* parser, const char* device_key, - actuator_status_t* actuator_status, const char* reference, - outbound_message_t* outbound_message) -{ - /* Sanity check */ - WOLK_ASSERT(parser); - WOLK_ASSERT(device_key); - WOLK_ASSERT(actuator_status); - WOLK_ASSERT(reference); - WOLK_ASSERT(outbound_message); - - manifest_item_t manifest_item; - manifest_item_init(&manifest_item, reference, READING_TYPE_ACTUATOR, DATA_TYPE_STRING); - - reading_t reading; - reading_init(&reading, &manifest_item); - reading_set_data(&reading, actuator_status_get_value(actuator_status)); - reading_set_actuator_state(&reading, actuator_status_get_state(actuator_status)); - - char topic[TOPIC_SIZE]; - memset(topic, '\0', sizeof(topic)); - if (!parser_serialize_readings_topic(parser, device_key, &reading, 1, topic, sizeof(topic))) { - return false; - } - - char payload[PAYLOAD_SIZE]; - memset(payload, '\0', sizeof(payload)); - if (parser_serialize_readings(parser, &reading, 1, payload, sizeof(payload)) == 0) { - return false; - } - - outbound_message_init(outbound_message, topic, payload); - return true; -} - -bool outbound_message_make_from_configuration(parser_t* parser, const char* device_key, - char (*reference)[CONFIGURATION_REFERENCE_SIZE], - char (*value)[CONFIGURATION_VALUE_SIZE], size_t num_configuration_items, - outbound_message_t* outbound_message) -{ - /* Sanity check */ - WOLK_ASSERT(parser); - WOLK_ASSERT(device_key); - WOLK_ASSERT(reference); - WOLK_ASSERT(value); - WOLK_ASSERT(outbound_message); - - return parser_serialize_configuration(parser, device_key, reference, value, num_configuration_items, - outbound_message); -} - bool outbound_message_make_from_file_management_status(parser_t* parser, const char* device_key, file_management_packet_request_t* file_management_packet_request, file_management_status_t* file_management_status, @@ -143,8 +93,9 @@ bool outbound_message_make_from_file_management_url_download_status( outbound_message); } -bool outbound_message_make_from_file_management_file_list(parser_t* parser, const char* device_key, char* file_list, - size_t file_list_items, outbound_message_t* outbound_message) +bool outbound_message_make_from_file_management_file_list(parser_t* parser, const char* device_key, + file_list_t* file_list, size_t file_list_items, + outbound_message_t* outbound_message) { /* Sanity check */ WOLK_ASSERT(parser); @@ -168,27 +119,75 @@ bool outbound_message_make_from_firmware_update_status(parser_t* parser, const c return parse_serialize_firmware_update_status(parser, device_key, firmware_update, outbound_message); } - -bool outbound_message_make_from_firmware_update_version(parser_t* parser, const char* device_key, - char* firmware_update_version, - outbound_message_t* outbound_message) +bool outbound_message_feed_registration(parser_t* parser, const char* device_key, feed_registration_t* feed, + size_t number_of_feeds, outbound_message_t* outbound_message) { /* Sanity check */ WOLK_ASSERT(parser); WOLK_ASSERT(device_key); - WOLK_ASSERT(firmware_update_version); + WOLK_ASSERT(feed); WOLK_ASSERT(outbound_message); - - return parse_serialize_firmware_update_version(parser, device_key, firmware_update_version, outbound_message); + return parser_serialize_feed_registration(parser, device_key, feed, number_of_feeds, outbound_message); } - -bool outbound_message_make_from_keep_alive_message(parser_t* parser, const char* device_key, - outbound_message_t* outbound_message) +bool outbound_message_feed_removal(parser_t* parser, const char* device_key, feed_registration_t* feed, + size_t number_of_feeds, outbound_message_t* outbound_message) { /* Sanity check */ WOLK_ASSERT(parser); WOLK_ASSERT(device_key); + WOLK_ASSERT(feed); WOLK_ASSERT(outbound_message); + return parser_serialize_feed_removal(parser, device_key, feed, number_of_feeds, outbound_message); +} + +bool outbound_message_pull_feed_values(parser_t* parser, const char* device_key, outbound_message_t* outbound_message) +{ + WOLK_ASSERT(parser); + WOLK_ASSERT(device_key); - return parser_serialize_ping_keep_alive_message(parser, device_key, outbound_message); + return parser_serialize_pull_feed_values(parser, device_key, outbound_message); } +bool outbound_message_attribute_registration(parser_t* parser, const char* device_key, attribute_t* attributes, + size_t number_of_attributes, outbound_message_t* outbound_message) +{ + WOLK_ASSERT(parser); + WOLK_ASSERT(device_key); + + return parser_serialize_attribute(parser, device_key, attributes, number_of_attributes, outbound_message); +} +bool outbound_message_update_parameters(parser_t* parser, const char* device_key, parameter_t* parameter, + size_t number_of_parameters, outbound_message_t* outbound_message) +{ + WOLK_ASSERT(parser); + WOLK_ASSERT(device_key); + + return parser_serialize_parameter(parser, device_key, parameter, number_of_parameters, outbound_message); +} +bool outbound_message_pull_parameters(parser_t* parser, const char* device_key, outbound_message_t* outbound_message) +{ + WOLK_ASSERT(parser); + WOLK_ASSERT(device_key); + return parser_serialize_pull_parameters(parser, device_key, outbound_message); +} +bool outbound_message_synchronize_parameters(parser_t* parser, const char* device_key, parameter_t* parameters, + size_t number_of_parameters, outbound_message_t* outbound_message) +{ + WOLK_ASSERT(parser); + WOLK_ASSERT(device_key); + return parser_serialize_sync_parameters(parser, device_key, parameters, number_of_parameters, outbound_message); +} +bool outbound_message_synchronize_time(parser_t* parser, const char* device_key, outbound_message_t* outbound_message) +{ + WOLK_ASSERT(parser); + WOLK_ASSERT(device_key); + return parser_serialize_sync_time(parser, device_key, outbound_message); +} + +bool outbound_message_details_synchronize(parser_t* parser, const char* device_key, + outbound_message_t* outbound_message) +{ + WOLK_ASSERT(parser); + WOLK_ASSERT(device_key); + + return parser_serialize_details_synchronization(parser, device_key, outbound_message); +} \ No newline at end of file diff --git a/sources/model/outbound_message_factory.h b/sources/model/outbound_message_factory.h new file mode 100644 index 0000000..aea7a75 --- /dev/null +++ b/sources/model/outbound_message_factory.h @@ -0,0 +1,86 @@ +/* + * Copyright 2018 WolkAbout Technology s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OUTBOUND_MESSAGE_FACTORY_H +#define OUTBOUND_MESSAGE_FACTORY_H + +#include "model/attribute.h" +#include "model/feed.h" +#include "model/file_management/file_management_status.h" +#include "model/outbound_message.h" +#include "protocol/parser.h" +#include "size_definitions.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +bool outbound_message_make_from_file_management_status(parser_t* parser, const char* device_key, + file_management_packet_request_t* file_management_packet_request, + file_management_status_t* file_management_status, + outbound_message_t* outbound_message); + +bool outbound_message_make_from_file_management_url_download_status( + parser_t* parser, const char* device_key, file_management_parameter_t* file_management_parameter, + file_management_status_t* status, outbound_message_t* outbound_message); + +bool outbound_message_make_from_file_management_packet_request( + parser_t* parser, const char* device_key, file_management_packet_request_t* file_management_packet_request, + outbound_message_t* outbound_message); + +bool outbound_message_make_from_file_management_file_list(parser_t* parser, const char* device_key, + file_list_t* file_list, size_t file_list_items, + outbound_message_t* outbound_message); + +bool outbound_message_make_from_firmware_update_status(parser_t* parser, const char* device_key, + firmware_update_t* firmware_update, + outbound_message_t* outbound_message); + +bool outbound_message_feed_registration(parser_t* parser, const char* device_key, feed_registration_t* feed, + size_t number_of_feeds, outbound_message_t* outbound_message); + +bool outbound_message_feed_removal(parser_t* parser, const char* device_key, feed_registration_t* feed, + size_t number_of_feeds, outbound_message_t* outbound_message); + +size_t outbound_message_make_from_feeds(parser_t* parser, const char* device_key, feed_t* readings, data_type_t type, + size_t readings_number, size_t reading_element_size, + outbound_message_t* outbound_message); + +bool outbound_message_pull_feed_values(parser_t* parser, const char* device_key, outbound_message_t* outbound_message); + +bool outbound_message_attribute_registration(parser_t* parser, const char* device_key, attribute_t* attributes, + size_t number_of_attributes, outbound_message_t* outbound_message); + +bool outbound_message_update_parameters(parser_t* parser, const char* device_key, parameter_t* parameter, + size_t number_of_parameters, outbound_message_t* outbound_message); + +bool outbound_message_pull_parameters(parser_t* parser, const char* device_key, outbound_message_t* outbound_message); + +bool outbound_message_synchronize_parameters(parser_t* parser, const char* device_key, parameter_t* parameters, + size_t number_of_parameters, outbound_message_t* outbound_message); + +bool outbound_message_synchronize_time(parser_t* parser, const char* device_key, outbound_message_t* outbound_message); +bool outbound_message_details_synchronize(parser_t* parser, const char* device_key, + outbound_message_t* outbound_message); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sources/actuator_status.c b/sources/model/parameter.c similarity index 56% rename from sources/actuator_status.c rename to sources/model/parameter.c index 19e0fec..7d1ca98 100644 --- a/sources/actuator_status.c +++ b/sources/model/parameter.c @@ -14,26 +14,21 @@ * limitations under the License. */ -#include "actuator_status.h" -#include "wolk_utils.h" +#include "model/parameter.h" +#include "utility/wolk_utils.h" #include -void actuator_status_init(actuator_status_t* actuator_status, char* value, actuator_state_t state) +void parameter_init(parameter_t* message, char* name, char* value) { - /* Sanity check */ - WOLK_ASSERT(strlen(value) < READING_SIZE); - - strcpy(&actuator_status->value[0], value); - actuator_status->state = state; + strcpy(message->name, name); + parameter_set_value(message, value); } -char* actuator_status_get_value(actuator_status_t* actuator_status) +void parameter_set_value(parameter_t* message, char* buffer) { - return actuator_status->value; -} + /* Sanity check */ + WOLK_ASSERT(strlen(buffer) < CONFIGURATION_VALUE_SIZE); -actuator_state_t actuator_status_get_state(actuator_status_t* actuator_status) -{ - return actuator_status->state; + strcpy(message->value, buffer); } diff --git a/sources/actuator_status.h b/sources/model/parameter.h old mode 100644 new mode 100755 similarity index 60% rename from sources/actuator_status.h rename to sources/model/parameter.h index 3f4c682..611ba6f --- a/sources/actuator_status.h +++ b/sources/model/parameter.h @@ -14,27 +14,26 @@ * limitations under the License. */ -#ifndef ACTUATOR_STATUS_H -#define ACTUATOR_STATUS_H - -#include "size_definitions.h" +#ifndef PARAMETER_H +#define PARAMETER_H #ifdef __cplusplus extern "C" { #endif -typedef enum { ACTUATOR_STATE_READY = 0, ACTUATOR_STATE_BUSY, ACTUATOR_STATE_ERROR } actuator_state_t; +#include "size_definitions.h" -typedef struct { - char value[READING_SIZE]; - actuator_state_t state; -} actuator_status_t; +#include +#include -void actuator_status_init(actuator_status_t* actuator_status, char* value, actuator_state_t state); +typedef struct { + char name[PARAMETER_TYPE_SIZE]; + char value[PARAMETER_VALUE_SIZE]; +} parameter_t; -char* actuator_status_get_value(actuator_status_t* actuator_status); +void parameter_init(parameter_t* parameter_message, char* name, char* value); -actuator_state_t actuator_status_get_state(actuator_status_t* actuator_status); +void parameter_set_value(parameter_t* parameter_message, char* buffer); #ifdef __cplusplus } diff --git a/sources/utc_command.c b/sources/model/utc_command.c old mode 100644 new mode 100755 similarity index 95% rename from sources/utc_command.c rename to sources/model/utc_command.c index 0c3ee14..1bdf4ce --- a/sources/utc_command.c +++ b/sources/model/utc_command.c @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "utc_command.h" +#include "model/utc_command.h" uint64_t utc_command_get(utc_command_t* utc_command) { diff --git a/sources/utc_command.h b/sources/model/utc_command.h old mode 100644 new mode 100755 similarity index 100% rename from sources/utc_command.h rename to sources/model/utc_command.h diff --git a/sources/outbound_message_factory.h b/sources/outbound_message_factory.h deleted file mode 100644 index f42f9ab..0000000 --- a/sources/outbound_message_factory.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2018 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef OUTBOUND_MESSAGE_FACTORY_H -#define OUTBOUND_MESSAGE_FACTORY_H - -#include "actuator_status.h" -#include "file_management_status.h" -#include "outbound_message.h" -#include "parser.h" -#include "reading.h" -#include "size_definitions.h" - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -size_t outbound_message_make_from_readings(parser_t* parser, const char* device_key, reading_t* first_reading, - size_t num_readings, outbound_message_t* outbound_message); - -bool outbound_message_make_from_actuator_status(parser_t* parser, const char* device_key, - actuator_status_t* actuator_status, const char* reference, - outbound_message_t* outbound_message); - -bool outbound_message_make_from_configuration(parser_t* parser, const char* device_key, - char (*reference)[CONFIGURATION_REFERENCE_SIZE], - char (*value)[CONFIGURATION_VALUE_SIZE], size_t num_configuration_items, - outbound_message_t* outbound_message); - -bool outbound_message_make_from_file_management_status(parser_t* parser, const char* device_key, - file_management_packet_request_t* file_management_packet_request, - file_management_status_t* file_management_status, - outbound_message_t* outbound_message); - -bool outbound_message_make_from_file_management_url_download_status( - parser_t* parser, const char* device_key, file_management_parameter_t* file_management_parameter, - file_management_status_t* status, outbound_message_t* outbound_message); - -bool outbound_message_make_from_file_management_packet_request( - parser_t* parser, const char* device_key, file_management_packet_request_t* file_management_packet_request, - outbound_message_t* outbound_message); - -bool outbound_message_make_from_file_management_file_list(parser_t* parser, const char* device_key, char* file_list, - size_t file_list_items, outbound_message_t* outbound_message); - -bool outbound_message_make_from_firmware_update_status(parser_t* parser, const char* device_key, - firmware_update_t* firmware_update, - outbound_message_t* outbound_message); - -bool outbound_message_make_from_firmware_update_version(parser_t* parser, const char* device_key, - char* firmware_update_version, - outbound_message_t* outbound_message); - -bool outbound_message_make_from_keep_alive_message(parser_t* parser, const char* device_key, - outbound_message_t* outbound_message); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/sources/parser.c b/sources/parser.c deleted file mode 100644 index 063cea9..0000000 --- a/sources/parser.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright 2018 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "parser.h" -#include "actuator_command.h" -#include "file_management_parameter.h" -#include "file_management_status.h" -#include "json_parser.h" -#include "wolk_utils.h" - -#include -#include - - -void parser_init(parser_t* parser, parser_type_t parser_type) -{ - /* Sanity check */ - WOLK_ASSERT(parser); - - parser->type = parser_type; - parser->is_initialized = true; - - switch (parser->type) { - case PARSER_TYPE_WOLKABOUT: - parser->serialize_readings = json_serialize_readings; - parser->deserialize_actuator_commands = json_deserialize_actuator_commands; - - parser->serialize_readings_topic = json_serialize_readings_topic; - - parser->serialize_configuration = json_serialize_configuration; - parser->deserialize_configuration_commands = json_deserialize_configuration_command; - - parser->serialize_file_management_status = json_serialize_file_management_status; - parser->deserialize_file_management_parameter = json_deserialize_file_management_parameter; - parser->serialize_file_management_packet_request = json_serialize_file_management_packet_request; - parser->serialize_file_management_url_download_status = json_serialize_file_management_url_download_status; - parser->serialize_file_management_file_list = json_serialize_file_management_file_list_update; - - parser->deserialize_firmware_update_parameter = json_deserialize_firmware_update_parameter; - parser->serialize_firmware_update_status = json_serialize_firmware_update_status; - parser->serialize_firmware_update_version = json_serialize_firmware_update_version; - - parser->serialize_ping_keep_alive_message = json_serialize_ping_keep_alive_message; - parser->deserialize_pong_keep_alive_message = json_deserialize_pong_keep_alive_message; - break; - - default: - /* Sanity check */ - WOLK_ASSERT(false); - } -} - -size_t parser_serialize_readings(parser_t* parser, reading_t* first_reading, size_t num_readings, char* buffer, - size_t buffer_size) -{ - /* Sanity check */ - WOLK_ASSERT(parser); - WOLK_ASSERT(num_readings > 0); - WOLK_ASSERT(buffer_size >= PAYLOAD_SIZE); - - return parser->serialize_readings(first_reading, num_readings, buffer, buffer_size); -} - -size_t parser_deserialize_actuator_commands(parser_t* parser, char* topic, size_t topic_size, char* buffer, - size_t buffer_size, actuator_command_t* commands_buffer, - size_t commands_buffer_size) -{ - /* Sanity check */ - WOLK_ASSERT(parser); - WOLK_ASSERT(buffer_size < PAYLOAD_SIZE); - WOLK_ASSERT(commands_buffer_size > 0); - - return parser->deserialize_actuator_commands(topic, topic_size, buffer, buffer_size, commands_buffer, - commands_buffer_size); -} - -bool parser_serialize_readings_topic(parser_t* parser, const char* device_key, reading_t* first_reading, - size_t num_readings, char* buffer, size_t buffer_size) -{ - /* Sanity check */ - WOLK_ASSERT(parser); - WOLK_ASSERT(num_readings > 0); - WOLK_ASSERT(buffer_size >= TOPIC_SIZE); - - return parser->serialize_readings_topic(first_reading, num_readings, device_key, buffer, buffer_size); -} - -bool parser_serialize_configuration(parser_t* parser, const char* device_key, - char (*reference)[CONFIGURATION_REFERENCE_SIZE], - char (*value)[CONFIGURATION_VALUE_SIZE], size_t num_configuration_items, - outbound_message_t* outbound_message) -{ - /* Sanity check */ - WOLK_ASSERT(parser); - WOLK_ASSERT(num_configuration_items > 0); - - return parser->serialize_configuration(device_key, reference, value, num_configuration_items, outbound_message); -} - -size_t parser_deserialize_configuration_commands(parser_t* parser, char* buffer, size_t buffer_size, - configuration_command_t* first_configuration_command, - size_t num_configuration_commands) -{ - /* Sanity check */ - WOLK_ASSERT(parser); - WOLK_ASSERT(buffer_size < PAYLOAD_SIZE); - WOLK_ASSERT(num_configuration_commands > 0); - - return parser->deserialize_configuration_commands(buffer, buffer_size, first_configuration_command, - num_configuration_commands); -} - -bool parser_serialize_file_management_status(parser_t* parser, const char* device_key, - file_management_packet_request_t* file_management_packet_request, - file_management_status_t* status, outbound_message_t* outbound_message) -{ - /* Sanity check */ - WOLK_ASSERT(parser); - WOLK_ASSERT(device_key); - WOLK_ASSERT(status); - WOLK_ASSERT(outbound_message); - - return parser->serialize_file_management_status(device_key, file_management_packet_request, status, - outbound_message); -} - -bool parser_deserialize_file_management_parameter(parser_t* parser, char* buffer, size_t buffer_size, - file_management_parameter_t* parameter) -{ - /* Sanity check */ - WOLK_ASSERT(parser); - WOLK_ASSERT(buffer); - WOLK_ASSERT(parameter); - - return parser->deserialize_file_management_parameter(buffer, buffer_size, parameter); -} - -bool parser_serialize_file_management_packet_request(parser_t* parser, const char* device_key, - file_management_packet_request_t* file_management_packet_request, - outbound_message_t* outbound_message) -{ - /* Sanity check */ - WOLK_ASSERT(parser); - WOLK_ASSERT(device_key); - WOLK_ASSERT(file_management_packet_request); - WOLK_ASSERT(outbound_message); - - return parser->serialize_file_management_packet_request(device_key, file_management_packet_request, - outbound_message); -} - -bool parser_serialize_file_management_url_download(parser_t* parser, const char* device_key, - file_management_parameter_t* file_management_parameter, - file_management_status_t* status, - outbound_message_t* outbound_message) -{ - /* Sanity check */ - WOLK_ASSERT(parser); - WOLK_ASSERT(device_key); - WOLK_ASSERT(file_management_parameter); - WOLK_ASSERT(status); - WOLK_ASSERT(outbound_message); - - return parser->serialize_file_management_url_download_status(device_key, file_management_parameter, status, - outbound_message); -} - -bool parser_serialize_file_management_file_list(parser_t* parser, const char* device_key, char* file_list, - size_t file_list_items, outbound_message_t* outbound_message) -{ - /* Sanity Check */ - WOLK_ASSERT(parser); - WOLK_ASSERT(device_key); - WOLK_ASSERT(file_list); - WOLK_ASSERT(file_list_items); - WOLK_ASSERT(outbound_message); - - return parser->serialize_file_management_file_list(device_key, file_list, file_list_items, outbound_message); -} - -bool parse_deserialize_firmware_update_parameter(parser_t* parser, char* device_key, char* buffer, size_t buffer_size, - firmware_update_t* firmware_update_parameter) -{ - WOLK_ASSERT(parser); - WOLK_ASSERT(buffer); - WOLK_ASSERT(buffer_size); - WOLK_ASSERT(firmware_update_parameter); - - return parser->deserialize_firmware_update_parameter(device_key, buffer, buffer_size, firmware_update_parameter); -} - -bool parse_serialize_firmware_update_status(parser_t* parser, const char* device_key, - firmware_update_t* firmware_update, outbound_message_t* outbound_message) -{ - /* Sanity Check */ - WOLK_ASSERT(parser); - WOLK_ASSERT(device_key); - WOLK_ASSERT(firmware_update); - WOLK_ASSERT(outbound_message); - - return parser->serialize_firmware_update_status(device_key, firmware_update, outbound_message); -} - -bool parse_serialize_firmware_update_version(parser_t* parser, const char* device_key, char* firmware_update_version, - outbound_message_t* outbound_message) -{ - /* Sanity Check */ - WOLK_ASSERT(parser); - WOLK_ASSERT(device_key); - WOLK_ASSERT(firmware_update_version); - WOLK_ASSERT(outbound_message); - - return parser->serialize_firmware_update_version(device_key, firmware_update_version, outbound_message); -} - -bool parser_serialize_ping_keep_alive_message(parser_t* parser, const char* device_key, - outbound_message_t* outbound_message) -{ - WOLK_ASSERT(parser); - WOLK_ASSERT(device_key); - - return parser->serialize_ping_keep_alive_message(device_key, outbound_message); -} - -bool parser_deserialize_pong_keep_alive_message(parser_t* parser, char* buffer, size_t buffer_size, utc_command_t* utc) -{ - WOLK_ASSERT(parser); - WOLK_ASSERT(device_key); - - return parser->deserialize_pong_keep_alive_message(buffer, buffer_size, utc); -} - -parser_type_t parser_get_type(parser_t* parser) -{ - /* Sanity check */ - WOLK_ASSERT(parser); - - return parser->type; -} - -bool parser_is_initialized(parser_t* parser) -{ - /* Sanity check */ - WOLK_ASSERT(parser); - - return parser->is_initialized; -} diff --git a/sources/parser.h b/sources/parser.h deleted file mode 100644 index f8e4bba..0000000 --- a/sources/parser.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2018 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef PARSER_H -#define PARSER_H - -#include "actuator_command.h" -#include "configuration_command.h" -#include "configuration_item.h" -#include "file_management_packet_request.h" -#include "file_management_parameter.h" -#include "file_management_status.h" -#include "firmware_update.h" -#include "outbound_message.h" -#include "reading.h" -#include "utc_command.h" - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { PARSER_TYPE_WOLKABOUT = 0 } parser_type_t; - -typedef struct { - parser_type_t type; - bool is_initialized; - - size_t (*serialize_readings)(reading_t* first_reading, size_t num_readings, char* buffer, size_t buffer_size); - size_t (*deserialize_actuator_commands)(char* topic, size_t topic_size, char* buffer, size_t buffer_size, - actuator_command_t* commands_buffer, size_t commands_buffer_size); - - bool (*serialize_readings_topic)(reading_t* first_reading, size_t num_readings, const char* device_key, - char* buffer, size_t buffer_size); - - size_t (*serialize_configuration)(const char* device_key, char (*reference)[CONFIGURATION_REFERENCE_SIZE], - char (*value)[CONFIGURATION_VALUE_SIZE], size_t num_configuration_items, - outbound_message_t* outbound_message); - size_t (*deserialize_configuration_commands)(char* buffer, size_t buffer_size, - configuration_command_t* first_configuration_command, - size_t num_config_items); - - bool (*serialize_file_management_status)(const char* device_key, - file_management_packet_request_t* file_management_packet_request, - file_management_status_t* status, outbound_message_t* outbound_message); - bool (*deserialize_file_management_parameter)(char* buffer, size_t buffer_size, - file_management_parameter_t* parameter); - bool (*serialize_file_management_packet_request)(const char* device_key, - file_management_packet_request_t* file_management_packet_request, - outbound_message_t* outbound_message); - bool (*serialize_file_management_url_download_status)(const char* device_key, - file_management_parameter_t* file_management_parameter, - file_management_status_t* status, - outbound_message_t* outbound_message); - bool (*serialize_file_management_file_list)(const char* device_key, char* file_list, size_t file_list_items, - outbound_message_t* outbound_message); - - bool (*deserialize_firmware_update_parameter)(char* device_key, char* buffer, size_t buffer_size, - firmware_update_t* parameter); - bool (*serialize_firmware_update_status)(const char* device_key, firmware_update_t* firmware_update, - outbound_message_t* outbound_message); - bool (*serialize_firmware_update_version)(const char* device_key, char* firmware_update_version, - outbound_message_t* outbound_message); - - bool (*serialize_ping_keep_alive_message)(const char* device_key, outbound_message_t* outbound_message); - bool (*deserialize_pong_keep_alive_message)(char* buffer, size_t buffer_size, utc_command_t* utc); -} parser_t; - -void parser_init(parser_t* parser, parser_type_t parser_type); - -/**** Actuator command ****/ -size_t parser_deserialize_actuator_commands(parser_t* parser, char* topic, size_t topic_size, char* buffer, - size_t buffer_size, actuator_command_t* commands_buffer, - size_t commands_buffer_size); -/**** Actuator command ****/ - -/**** Reading ****/ -/* Note: Actuator status is considered reading, henece it's serialization is tied to funcions in this section */ -size_t parser_serialize_readings(parser_t* parser, reading_t* first_reading, size_t num_readings, char* buffer, - size_t buffer_size); - -bool parser_serialize_readings_topic(parser_t* parser, const char* device_key, reading_t* first_reading, - size_t num_readings, char* buffer, size_t buffer_size); -/**** Reading ****/ - -/**** Configuration ****/ -bool parser_serialize_configuration(parser_t* parser, const char* device_key, - char (*reference)[CONFIGURATION_REFERENCE_SIZE], - char (*value)[CONFIGURATION_VALUE_SIZE], size_t num_configuration_items, - outbound_message_t* outbound_message); - -size_t parser_deserialize_configuration_commands(parser_t* parser, char* buffer, size_t buffer_size, - configuration_command_t* first_configuration_command, - size_t num_configuration_commands); -/**** Configuration ****/ - -/**** File Management ****/ -bool parser_serialize_file_management_status(parser_t* parser, const char* device_key, - file_management_packet_request_t* file_management_packet_request, - file_management_status_t* status, outbound_message_t* outbound_message); - -bool parser_deserialize_file_management_parameter(parser_t* parser, char* buffer, size_t buffer_size, - file_management_parameter_t* parameter); - -bool parser_serialize_file_management_packet_request(parser_t* parser, const char* device_key, - file_management_packet_request_t* file_management_packet_request, - outbound_message_t* outbound_message); - -bool parser_serialize_file_management_url_download(parser_t* parser, const char* device_key, - file_management_parameter_t* parameter, - file_management_status_t* status, - outbound_message_t* outbound_message); - -bool parser_serialize_file_management_file_list(parser_t* parser, const char* device_key, char* file_list, - size_t file_list_items, outbound_message_t* outbound_message); -/**** File Management ****/ - -/**** Firmware Update ****/ -bool parse_deserialize_firmware_update_parameter(parser_t* parser, char* device_key, char* buffer, size_t buffer_size, - firmware_update_t* firmware_update_parameter); - -bool parse_serialize_firmware_update_status(parser_t* parser, const char* device_key, - firmware_update_t* firmware_update, outbound_message_t* outbound_message); - -bool parse_serialize_firmware_update_version(parser_t* parser, const char* device_key, char* firmware_update_version, - outbound_message_t* outbound_message); -/**** Firmware Update ****/ - - -/**** PING keep alive ****/ -bool parser_serialize_ping_keep_alive_message(parser_t* parser, const char* device_key, - outbound_message_t* outbound_message); -bool parser_deserialize_pong_keep_alive_message(parser_t* parser, char* buffer, size_t buffer_size, utc_command_t* utc); -/**** PING keep alive ****/ - -parser_type_t parser_get_type(parser_t* parser); -bool parser_is_initialized(parser_t* parser); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/sources/in_memory_persistence.c b/sources/persistence/in_memory_persistence.c old mode 100644 new mode 100755 similarity index 93% rename from sources/in_memory_persistence.c rename to sources/persistence/in_memory_persistence.c index e39cbd0..4719374 --- a/sources/in_memory_persistence.c +++ b/sources/persistence/in_memory_persistence.c @@ -15,9 +15,9 @@ */ #include "in_memory_persistence.h" -#include "circular_buffer.h" -#include "outbound_message.h" -#include "wolk_utils.h" +#include "model/outbound_message.h" +#include "utility/circular_buffer.h" +#include "utility/wolk_utils.h" #include #include diff --git a/sources/in_memory_persistence.h b/sources/persistence/in_memory_persistence.h old mode 100644 new mode 100755 similarity index 96% rename from sources/in_memory_persistence.h rename to sources/persistence/in_memory_persistence.h index a50d5ef..3b417ab --- a/sources/in_memory_persistence.h +++ b/sources/persistence/in_memory_persistence.h @@ -21,7 +21,7 @@ extern "C" { #endif -#include "outbound_message.h" +#include "model/outbound_message.h" #include #include diff --git a/sources/persistence.c b/sources/persistence/persistence.c old mode 100644 new mode 100755 similarity index 96% rename from sources/persistence.c rename to sources/persistence/persistence.c index a1136f4..e42ca86 --- a/sources/persistence.c +++ b/sources/persistence/persistence.c @@ -15,8 +15,8 @@ */ #include "persistence.h" -#include "outbound_message.h" -#include "wolk_utils.h" +#include "model/outbound_message.h" +#include "utility/wolk_utils.h" #include diff --git a/sources/persistence.h b/sources/persistence/persistence.h old mode 100644 new mode 100755 similarity index 98% rename from sources/persistence.h rename to sources/persistence/persistence.h index 529a8a0..521ab85 --- a/sources/persistence.h +++ b/sources/persistence/persistence.h @@ -17,7 +17,7 @@ #ifndef PERSISTENCE_H #define PERSISTENCE_H -#include "outbound_message.h" +#include "model/outbound_message.h" #include #include diff --git a/sources/protocol/json_parser.c b/sources/protocol/json_parser.c new file mode 100644 index 0000000..de737ed --- /dev/null +++ b/sources/protocol/json_parser.c @@ -0,0 +1,762 @@ +/* + * Copyright 2022 WolkAbout Technology s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "json_parser.h" +#include "model/file_management/file_management_packet_request.h" +#include "model/file_management/file_management_parameter.h" +#include "model/file_management/file_management_status.h" +#include "model/firmware_update.h" +#include "size_definitions.h" +#include "utility/base64.h" +#include "utility/jsmn.h" +#include "utility/wolk_utils.h" + +#include +#include +#include +#include +#include +#include + +#define JSON_TOKEN_SIZE FEEDS_MAX_NUMBER +#define UTC_MILLISECONDS_LENGTH 14 + +#define JSON_ARRAY_LEFT_BRACKET "[" +#define JSON_ARRAY_RIGHT_BRACKET "]" +#define JSON_ELEMENTS_SEPARATORS "[,]\"" + +const char JSON_P2D_TOPIC[TOPIC_DIRECTION_SIZE] = "p2d"; +const char JSON_D2P_TOPIC[TOPIC_DIRECTION_SIZE] = "d2p"; +const char JSON_FEED_REGISTRATION_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "feed_registration"; +const char JSON_FEED_REMOVAL_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "feed_removal"; +const char JSON_FEED_VALUES_MESSAGE_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "feed_values"; +const char JSON_PULL_FEEDS_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "pull_feed_values"; +const char JSON_ATTRIBUTE_REGISTRATION_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "attribute_registration"; +const char JSON_PARAMETERS_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "parameters"; +const char JSON_PULL_PARAMETERS_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "pull_parameters"; +const char JSON_SYNC_PARAMETERS_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "synchronize_parameters"; +const char JSON_SYNC_TIME_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "time"; +const char JSON_SYNC_DETAILS_SYNCHRONIZATION_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "details_synchronization"; +const char JSON_ERROR_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "error"; +const char JSON_DETAILS_SYNCHRONIZATION_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "details_synchronization"; + +const char JSON_FILE_MANAGEMENT_UPLOAD_INITIATE_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "file_upload_initiate"; +const char JSON_FILE_MANAGEMENT_FILE_UPLOAD_STATUS_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "file_upload_status"; +const char JSON_FILE_MANAGEMENT_FILE_UPLOAD_ABORT_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "file_upload_abort"; +const char JSON_FILE_MANAGEMENT_FILE_BINARY_REQUEST_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "file_binary_request"; +const char JSON_FILE_MANAGEMENT_FILE_BINARY_RESPONSE_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "file_binary_response"; +const char JSON_FILE_MANAGEMENT_URL_DOWNLOAD_INITIATE_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "file_url_download_initiate"; +const char JSON_FILE_MANAGEMENT_URL_DOWNLOAD_ABORT_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "file_url_download_abort"; +const char JSON_FILE_MANAGEMENT_URL_DOWNLOAD_STATUS_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "file_url_download_status"; +const char JSON_FILE_MANAGEMENT_FILE_LIST_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "file_list"; +const char JSON_FILE_MANAGEMENT_FILE_DELETE_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "file_delete"; +const char JSON_FILE_MANAGEMENT_FILE_PURGE_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "file_purge"; + +const char JSON_FIRMWARE_UPDATE_INSTALL_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "firmware_update_install"; +const char JSON_FIRMWARE_UPDATE_STATUS_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "firmware_update_status"; +const char JSON_FIRMWARE_UPDATE_ABORT_TOPIC[TOPIC_MESSAGE_TYPE_SIZE] = "firmware_update_abort"; + + +static bool json_token_str_equal(const char* json, jsmntok_t* tok, const char* s); +static const char* file_management_status_get_error_as_str(file_management_status_t* status); + + +static bool json_token_str_equal(const char* json, jsmntok_t* tok, const char* s) +{ + if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start + && strncmp(json + tok->start, s, (size_t)(tok->end - tok->start)) == 0) { + return true; + } + + return false; +} + +static const char* file_management_status_get_error_as_str(file_management_status_t* status) +{ + /* Sanity check */ + WOLK_ASSERT(status); + + switch (status->error) { + case FILE_MANAGEMENT_ERROR_NONE: + return "NONE"; + + case FILE_MANAGEMENT_ERROR_UNKNOWN: + return "UNKNOWN"; + + case FILE_MANAGEMENT_ERROR_TRANSFER_PROTOCOL_DISABLED: + return "TRANSFER_PROTOCOL_DISABLED"; + + case FILE_MANAGEMENT_ERROR_UNSUPPORTED_FILE_SIZE: + return "UNSUPPORTED_FILE_SIZE"; + + case FILE_MANAGEMENT_ERROR_MALFORMED_URL: + return "MALFORMED_URL"; + + case FILE_MANAGEMENT_ERROR_FILE_HASH_MISMATCH: + return "FILE_HASH_MISMATCH"; + + case FILE_MANAGEMENT_ERROR_FILE_SYSTEM: + return "FILE_SYSTEM_ERROR"; + + case FILE_MANAGEMENT_ERROR_RETRY_COUNT_EXCEEDED: + return "RETRY_COUNT_EXCEEDED"; + + default: + WOLK_ASSERT(false); + return ""; + } +} + +bool json_serialize_file_management_status(const char* device_key, + file_management_packet_request_t* file_management_packet_request, + file_management_status_t* status, outbound_message_t* outbound_message) +{ + /* Serialize topic */ + json_create_topic(JSON_D2P_TOPIC, device_key, JSON_FILE_MANAGEMENT_FILE_UPLOAD_STATUS_TOPIC, + outbound_message->topic); + + /* Check for errors*/ + char file_management_error[ITEM_NAME_SIZE] = {0}; + if (file_management_status_get_state(status) == FILE_MANAGEMENT_STATE_ERROR) { + if (snprintf(file_management_error, WOLK_ARRAY_LENGTH(file_management_error), "\"error\": \"%s\",", + file_management_status_get_error_as_str(status)) + >= (int)WOLK_ARRAY_LENGTH(file_management_error)) { + return false; + } + } + + /* Serialize payload */ + if (snprintf(outbound_message->payload, WOLK_ARRAY_LENGTH(outbound_message->payload), + "{\"name\": \"%s\",%s\"status\": \"%s\"}", + file_management_packet_request_get_file_name(file_management_packet_request), file_management_error, + file_management_status_as_str(status)) + >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { + return false; + } + + return true; +} + +bool json_deserialize_file_management_parameter(char* buffer, size_t buffer_size, + file_management_parameter_t* parameter) +{ + jsmn_parser parser = {0}; + jsmntok_t tokens[JSON_TOKEN_SIZE] = {0}; + jsmn_init(&parser); + const int parser_result = jsmn_parse(&parser, buffer, buffer_size, tokens, WOLK_ARRAY_LENGTH(tokens)); + + /* Received JSON must be valid, and top level element must be object */ + if (parser_result < 1 || tokens[0].type != JSMN_OBJECT || parser_result >= (int)WOLK_ARRAY_LENGTH(tokens)) { + return false; + } + + file_management_parameter_init(parameter); + + /* Obtain command type and value */ + char value_buffer[FEED_ELEMENT_SIZE] = ""; + + for (size_t i = 1; i < parser_result; i++) { + if (json_token_str_equal(buffer, &tokens[i], "name")) { + if (snprintf(value_buffer, WOLK_ARRAY_LENGTH(value_buffer), "%.*s", tokens[i + 1].end - tokens[i + 1].start, + buffer + tokens[i + 1].start) + >= (int)WOLK_ARRAY_LENGTH(value_buffer)) { + return false; + } + + if (strlen(value_buffer) > FILE_MANAGEMENT_FILE_NAME_SIZE) { + /* Leave file name array empty */ + return true; + } else { + file_management_parameter_set_filename(parameter, value_buffer); + i++; + } + } else if (json_token_str_equal(buffer, &tokens[i], "size")) { + if (snprintf(value_buffer, WOLK_ARRAY_LENGTH(value_buffer), "%.*s", tokens[i + 1].end - tokens[i + 1].start, + buffer + tokens[i + 1].start) + >= (int)WOLK_ARRAY_LENGTH(value_buffer)) { + return false; + } + + file_management_parameter_set_file_size(parameter, (size_t)atoi(value_buffer)); + i++; + } else if (json_token_str_equal(buffer, &tokens[i], "hash")) { + if (snprintf(value_buffer, WOLK_ARRAY_LENGTH(value_buffer), "%.*s", tokens[i + 1].end - tokens[i + 1].start, + buffer + tokens[i + 1].start) + >= (int)WOLK_ARRAY_LENGTH(value_buffer)) { + return false; + } + + if (strlen(value_buffer) > FILE_MANAGEMENT_HASH_SIZE) + return false; + strcpy((BYTE*)parameter->file_hash, value_buffer); // file MD5 checksum + i++; + } else { + return false; + } + } + return true; +} + +bool json_deserialize_url_download(char* buffer, size_t buffer_size, char* url_download) +{ + if (buffer_size > FILE_MANAGEMENT_URL_SIZE) + return false; + + // eliminate quotes by start copying from 2nd position and don't copying last two(" and \0) + if (buffer[0] == 34 && buffer[buffer_size - 1] == 34) // Decimal 34 is double quotes ascii value + { + strncpy(url_download, buffer + 1, buffer_size - 2); + return true; + } + + return false; +} + +size_t json_deserialize_file_delete(char* buffer, size_t buffer_size, file_list_t* file_list) +{ + size_t number_of_files_to_be_deleted = 0; + + char* files = strtok(buffer, JSON_ELEMENTS_SEPARATORS); + for (int i = 0; i < buffer_size; ++i) { + // end of the list + if (files == NULL) { + break; + } + // eliminate '[', ']' and ' ' + if (strstr(files, JSON_ARRAY_LEFT_BRACKET) == NULL && strstr(files, JSON_ARRAY_RIGHT_BRACKET) == NULL + && strcmp(files, " ") != 0) { + strncpy(file_list->file_name, files, strlen(files)); + file_list++; + number_of_files_to_be_deleted++; + } + + // take next element + files = strtok(NULL, JSON_ELEMENTS_SEPARATORS); + } + + return number_of_files_to_be_deleted; +} + +bool json_serialize_file_management_packet_request(const char* device_key, + file_management_packet_request_t* file_management_packet_request, + outbound_message_t* outbound_message) +{ + /* Serialize topic */ + json_create_topic(JSON_D2P_TOPIC, device_key, JSON_FILE_MANAGEMENT_FILE_BINARY_REQUEST_TOPIC, + outbound_message->topic); + + /* Serialize payload */ + if (snprintf(outbound_message->payload, WOLK_ARRAY_LENGTH(outbound_message->payload), + "{\"name\": \"%s\", \"chunkIndex\":%llu}", + file_management_packet_request_get_file_name(file_management_packet_request), + (unsigned long long int)file_management_packet_request_get_chunk_index(file_management_packet_request)) + >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { + return false; + } + + return true; +} + +bool json_serialize_file_management_url_download_status(const char* device_key, + file_management_parameter_t* file_management_parameter, + file_management_status_t* status, + outbound_message_t* outbound_message) +{ + /* Serialize topic */ + json_create_topic(JSON_D2P_TOPIC, device_key, JSON_FILE_MANAGEMENT_URL_DOWNLOAD_STATUS_TOPIC, + outbound_message->topic); + + /* Serialize payload */ + if (snprintf(outbound_message->payload, WOLK_ARRAY_LENGTH(outbound_message->payload), + "{\"fileUrl\":\"%s\",\"fileName\":\"%s\"", + file_management_parameter_get_file_url(file_management_parameter), + file_management_packet_request_get_file_name(file_management_parameter)) + >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { + return false; + } + + if (file_management_status_get_state(status) == FILE_MANAGEMENT_STATE_ERROR) { + if (file_management_status_get_error(status) >= 0) { + if (snprintf(outbound_message->payload + strlen(outbound_message->payload), + WOLK_ARRAY_LENGTH(outbound_message->payload), ",\"error\":\"%s\",\"status\":\"%s\"}", + file_management_status_get_error_as_str(status), file_management_status_as_str(status)) + >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { + return false; + } + } + } else { + if (snprintf(outbound_message->payload + strlen(outbound_message->payload), + WOLK_ARRAY_LENGTH(outbound_message->payload), ",\"status\": \"%s\"}", + file_management_status_as_str(status)) + >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { + return false; + } + } + + return true; +} + +bool json_serialize_file_management_file_list_update(const char* device_key, file_list_t* file_list, + size_t file_list_items, outbound_message_t* outbound_message) +{ + /* Serialize topic */ + json_create_topic(JSON_D2P_TOPIC, device_key, JSON_FILE_MANAGEMENT_FILE_LIST_TOPIC, outbound_message->topic); + + /* Serialize payload */ + strncpy(outbound_message->payload, JSON_ARRAY_LEFT_BRACKET, strlen(JSON_ARRAY_LEFT_BRACKET)); + for (size_t i = 0; i < file_list_items; i++) { + char file_hash[3] = {0}; // TODO: implement it, it's optional at the protocol + + if (snprintf(outbound_message->payload + strlen(outbound_message->payload), + WOLK_ARRAY_LENGTH(outbound_message->payload), "{\"name\":\"%s\",\"size\":%d,\"hash\":\"%s\"},", + (const char*)file_list->file_name, file_list->file_size, file_hash) + >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { + return false; + } + file_list++; + } + + file_list_items == 0 ? strncpy(outbound_message->payload + strlen(outbound_message->payload), + JSON_ARRAY_RIGHT_BRACKET, strlen(JSON_ARRAY_RIGHT_BRACKET)) + : strncpy(outbound_message->payload + strlen(outbound_message->payload) - 1, + JSON_ARRAY_RIGHT_BRACKET, strlen(JSON_ARRAY_RIGHT_BRACKET)); + + return true; +} + +bool json_deserialize_firmware_update_parameter(char* buffer, size_t buffer_size, firmware_update_t* parameter) +{ + char firmware_update_file_installation_name[FILE_MANAGEMENT_FILE_NAME_SIZE] = {0}; + firmware_update_parameter_init(parameter); + if (buffer_size > FILE_MANAGEMENT_FILE_NAME_SIZE) + return false; + + // eliminate quotes by start copying from 2nd position and don't copying last two(" and \0) + if (buffer[0] == 34 && buffer[buffer_size - 1] == 34) // Decimal 34 is double quotes ascii value + { + strncpy(firmware_update_file_installation_name, buffer + 1, buffer_size - 2); + firmware_update_parameter_set_filename(parameter, firmware_update_file_installation_name); + + return true; + } + + return false; +} + +bool json_serialize_firmware_update_status(const char* device_key, firmware_update_t* firmware_update, + outbound_message_t* outbound_message) +{ + /* Serialize topic */ + json_create_topic(JSON_D2P_TOPIC, device_key, JSON_FIRMWARE_UPDATE_STATUS_TOPIC, outbound_message->topic); + + /* Serialize payload */ + if (snprintf(outbound_message->payload, WOLK_ARRAY_LENGTH(outbound_message->payload), "{\"status\": \"%s\"}", + firmware_update_status_as_str(firmware_update)) + >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { + return false; + } + + if (firmware_update->error >= 0) { + if (snprintf(outbound_message->payload + strlen(outbound_message->payload) - 1, + WOLK_ARRAY_LENGTH(outbound_message->payload), ",\"error\":\"%s\"}", + firmware_update_error_as_str(firmware_update)) + >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) { + return false; + } + } + + return true; +} + +bool json_deserialize_time(char* buffer, size_t buffer_size, utc_command_t* utc_command) +{ + if (strlen(buffer) == 0) + return false; + + char* string_part; + uint64_t conversion_utc = strtoul(buffer, &string_part, 10); + if (conversion_utc == NULL) { + return false; + } + utc_command->utc = conversion_utc; + + return true; +} + +bool json_deserialize_details_synchronization(char* buffer, size_t buffer_size, feed_registration_t* feeds, + size_t* number_of_feeds, attribute_t* attributes, + size_t* number_of_attributes) +{ + jsmn_parser parser; + jsmntok_t tokens[JSON_TOKEN_SIZE]; + + jsmn_init(&parser); + int parser_result = jsmn_parse(&parser, buffer, buffer_size, tokens, WOLK_ARRAY_LENGTH(tokens)); + + /* Received JSON must be valid, and top level element must be array */ + if (parser_result < 1 || tokens[0].type != JSMN_OBJECT || parser_result >= (int)WOLK_ARRAY_LENGTH(tokens)) { + return false; + } + // OBJ*STR-ARRAY-STR-..-STR-STR-ARRAY-STR-..-STR + for (int i = 1; i < parser_result; ++i) { // at 1st position expects json object; 0 position is json array + if (tokens[i].type == JSMN_ARRAY) { + if (json_token_str_equal(buffer, &tokens[i - 1], "feeds")) { + for (int j = i; tokens[j + 1].type != JSMN_ARRAY; ++j) { // 1st str is value, 2nd is element name + if (tokens[j].type == JSMN_STRING) { + if (snprintf(feeds->name, WOLK_ARRAY_LENGTH(feeds->name), "%.*s", + tokens[j].end - tokens[j].start, buffer + tokens[j].start) + >= (int)WOLK_ARRAY_LENGTH(feeds->name)) { + return false; + } + *number_of_feeds += 1; + feeds++; + } + } + } else if (json_token_str_equal(buffer, &tokens[i - 1], "attributes")) { + for (int j = i; tokens[j + 1].type != JSMN_ARRAY; ++j) { // 1st str is value, 2nd is element name + if (tokens[j].type == JSMN_STRING) { + if (snprintf(attributes->name, WOLK_ARRAY_LENGTH(attributes->name), "%.*s", + tokens[j].end - tokens[j].start, buffer + tokens[j].start) + >= (int)WOLK_ARRAY_LENGTH(attributes->name)) { + return false; + } + *number_of_attributes += 1; + attributes++; + } + } + } else + return false; + } + } +} + +bool json_create_topic(char direction[TOPIC_DIRECTION_SIZE], const char device_key[DEVICE_KEY_SIZE], + char message_type[TOPIC_MESSAGE_TYPE_SIZE], char topic[TOPIC_SIZE]) +{ + topic[0] = '\0'; + strcat(topic, direction); + strcat(topic, "/"); + strcat(topic, device_key); + strcat(topic, "/"); + strcat(topic, message_type); + + return true; +} + +size_t json_deserialize_feeds_value_message(char* buffer, size_t buffer_size, feed_t* feeds_received) +{ + uint8_t number_of_deserialized_feeds = 0; + jsmn_parser parser; + jsmntok_t tokens[JSON_TOKEN_SIZE]; + + jsmn_init(&parser); + int parser_result = jsmn_parse(&parser, buffer, buffer_size, tokens, WOLK_ARRAY_LENGTH(tokens)); + + /* Received JSON must be valid, and top level element must be array */ + if (parser_result < 1 || tokens[0].type != JSMN_ARRAY || parser_result >= (int)WOLK_ARRAY_LENGTH(tokens)) { + return false; + } + + for (int i = 1; i < parser_result; ++i) { // at 1st position expects json object; 0 position is json array + if (tokens[i].type == JSMN_OBJECT) { + // object equals feed + for (int j = i + 1; tokens[j].type != JSMN_OBJECT; ++j) { // at 2nd position expects string + if (tokens[j].type == JSMN_STRING) { + // get timestamp + if (json_token_str_equal(buffer, &tokens[j], "timestamp")) { + char timestamp[UTC_MILLISECONDS_LENGTH] = ""; + + if (snprintf(timestamp, WOLK_ARRAY_LENGTH(timestamp), "%.*s", + tokens[j + 1].end - tokens[j + 1].start, buffer + tokens[j + 1].start) + >= (int)WOLK_ARRAY_LENGTH(timestamp)) { + return false; + } + char* string_part; + feed_set_utc(feeds_received, strtoul(timestamp, &string_part, 10)); + } else { + // get reference + if (snprintf(feeds_received->reference, WOLK_ARRAY_LENGTH(feeds_received->reference), "%.*s", + tokens[j].end - tokens[j].start, buffer + tokens[j].start) + >= (int)WOLK_ARRAY_LENGTH(feeds_received->reference)) { + return false; + } + // get value + if (snprintf(feeds_received->data, WOLK_ARRAY_LENGTH(feeds_received->data), "%.*s", + tokens[j + 1].end - tokens[j + 1].start, buffer + tokens[j + 1].start) + >= (int)WOLK_ARRAY_LENGTH(feeds_received->data)) { + return false; + } + } + } + } + // move to next feed + feeds_received++; + number_of_deserialized_feeds++; + } + } + return number_of_deserialized_feeds; +} + +size_t json_deserialize_parameter_message(char* buffer, size_t buffer_size, parameter_t* parameter_message) +{ + uint8_t number_of_deserialized_parameters = 0; + jsmn_parser parser; + jsmntok_t tokens[JSON_TOKEN_SIZE]; + + jsmn_init(&parser); + int parser_result = jsmn_parse(&parser, buffer, buffer_size, tokens, WOLK_ARRAY_LENGTH(tokens)); + + /* Received JSON must be valid, and top level element must be array */ + if (parser_result < 1 || tokens[0].type != JSMN_OBJECT || parser_result >= (int)WOLK_ARRAY_LENGTH(tokens)) { + return false; + } + // at 2nd position expects first json string; 1st position is json object + for (int i = 1; i < parser_result; i += 2) { + if (tokens[i].type == JSMN_STRING) { + // get name + if (snprintf(parameter_message->name, WOLK_ARRAY_LENGTH(parameter_message->name), "%.*s", + tokens[i].end - tokens[i].start, buffer + tokens[i].start) + >= (int)WOLK_ARRAY_LENGTH(parameter_message->name)) { + return false; + } + // get value + if (snprintf(parameter_message->value, WOLK_ARRAY_LENGTH(parameter_message->value), "%.*s", + tokens[i + 1].end - tokens[i + 1].start, buffer + tokens[i + 1].start) + >= (int)WOLK_ARRAY_LENGTH(parameter_message->value)) { + return false; + } + // move to next parameter + parameter_message++; + number_of_deserialized_parameters++; + } + } + + return number_of_deserialized_parameters; +} + +static bool serialize_feed(feed_t* feed, data_type_t type, size_t feed_element_size, char* buffer, size_t buffer_size) +{ + char data_buffer[PAYLOAD_SIZE] = ""; + + for (size_t i = 0; i < feed_element_size; ++i) { + strcat(data_buffer, feed->data[i]); + + if (i < feed_element_size - 1) + strcat(data_buffer, ","); + } + + if (feed_get_utc(feed) > 0 + && snprintf(buffer, buffer_size, "[{\"%s\":%s%s%s,\"timestamp\":%ld}]", feed->reference, + type == NUMERIC ? "" : "\"", data_buffer, type == NUMERIC ? "" : "\"", feed_get_utc(feed)) + >= (int)buffer_size) { + return false; + } else if (feed_get_utc(feed) == 0 + && snprintf(buffer, buffer_size, "[{\"%s\":%s%s%s}]", feed->reference, type == NUMERIC ? "" : "\"", + data_buffer, type == NUMERIC ? "" : "\"") + >= (int)buffer_size) { + return false; + } + + return true; +} + +static size_t serialize_feeds(feed_t* feeds, data_type_t type, size_t number_of_feeds, char* buffer, size_t buffer_size) +{ + WOLK_UNUSED(number_of_feeds); + + char data_buffer[PAYLOAD_SIZE] = ""; + strcat(buffer, JSON_ARRAY_LEFT_BRACKET); + + for (size_t i = 0; i < number_of_feeds; ++i) { + // when it consists of more feeds with the same reference it has to have utc + if (feed_get_utc(feeds) == 0) + return false; + + if (snprintf(data_buffer, buffer_size, "{\"%s\":%s%s%s,\"timestamp\":%ld}%s", feeds->reference, + type == NUMERIC ? "" : "\"", feeds->data[0], type == NUMERIC ? "" : "\"", feed_get_utc(feeds), + (number_of_feeds > 1 && i < (number_of_feeds - 1)) ? "," : "") + >= (int)buffer_size) + return false; + + strcat(buffer, data_buffer); + feeds++; + } + + strcat(buffer, JSON_ARRAY_RIGHT_BRACKET); + return true; +} + +size_t json_serialize_feeds(feed_t* feeds, data_type_t type, size_t number_of_feeds, size_t feed_element_size, + char* buffer, size_t buffer_size) +{ + /* Sanity check */ + WOLK_ASSERT(number_of_feeds > 0); + + if (number_of_feeds > 1) { + WOLK_UNUSED(feed_element_size); + return serialize_feeds(feeds, type, number_of_feeds, buffer, buffer_size); + } else { + return serialize_feed(feeds, type, feed_element_size, buffer, buffer_size) ? 1 : 0; + } +} +bool json_serialize_attribute(const char* device_key, attribute_t* attributes, size_t number_of_attributes, + outbound_message_t* outbound_message) +{ + char payload[PAYLOAD_SIZE] = ""; + + json_create_topic(JSON_D2P_TOPIC, device_key, JSON_ATTRIBUTE_REGISTRATION_TOPIC, outbound_message->topic); + + strncpy(outbound_message->payload, JSON_ARRAY_LEFT_BRACKET, 1); + for (int i = 0; i < number_of_attributes; ++i) { + if (sprintf(payload, "{\"name\": \"%s\", \"dataType\": \"%s\", \"value\": \"%s\"}%s", attributes->name, + attributes->data_type, attributes->value, + number_of_attributes > 1 && i < (number_of_attributes - 1) ? "," : "") + >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) + return false; + + if (strlen(payload) > (PAYLOAD_SIZE - strlen(outbound_message->payload))) + return false; + + strcat(outbound_message->payload, payload); + attributes++; + } + strcat(outbound_message->payload, JSON_ARRAY_RIGHT_BRACKET); + + return true; +} +bool json_serialize_parameter(const char* device_key, parameter_t* parameter, size_t number_of_parameters, + outbound_message_t* outbound_message) +{ + char payload[PAYLOAD_SIZE] = ""; + + json_create_topic(JSON_D2P_TOPIC, device_key, JSON_PARAMETERS_TOPIC, outbound_message->topic); + + strcat(outbound_message->payload, "{"); + for (int i = 0; i < number_of_parameters; ++i) { + if (sprintf(payload, "\"%s\": \"%s\"%s", parameter->name, parameter->value, + (number_of_parameters > 1 && i < (number_of_parameters - 1)) ? "," : "") + >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) + return false; + + if (strlen(payload) > (PAYLOAD_SIZE - strlen(outbound_message->payload))) + return false; + + strcat(outbound_message->payload, payload); + parameter++; + } + strcat(outbound_message->payload, "}"); + + return true; +} + +bool json_serialize_feed_registration(const char* device_key, feed_registration_t* feed, size_t number_of_feeds, + outbound_message_t* outbound_message) +{ + char payload[PAYLOAD_SIZE] = ""; + + json_create_topic(JSON_D2P_TOPIC, device_key, JSON_FEED_REGISTRATION_TOPIC, outbound_message->topic); + + strcat(outbound_message->payload, JSON_ARRAY_LEFT_BRACKET); + for (int i = 0; i < number_of_feeds; ++i) { + if (sprintf(payload, "{\"name\": \"%s\", \"type\": \"%s\", \"unitGuid\": \"%s\", \"reference\": \"%s\"}%s", + feed->name, feed_type_to_string(feed->feedType), feed->unit, feed->reference, + (number_of_feeds > 1 && i < (number_of_feeds - 1) ? "," : "")) + >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) + return false; + + if (strlen(payload) > (PAYLOAD_SIZE - strlen(outbound_message->payload))) + return false; + + strcat(outbound_message->payload, payload); + feed++; + } + strcat(outbound_message->payload, JSON_ARRAY_RIGHT_BRACKET); + + return true; +} +bool json_serialize_feed_removal(const char* device_key, feed_registration_t* feed, size_t number_of_feeds, + outbound_message_t* outbound_message) +{ + char payload[PAYLOAD_SIZE] = ""; + json_create_topic(JSON_D2P_TOPIC, device_key, JSON_FEED_REMOVAL_TOPIC, outbound_message->topic); + + strcat(outbound_message->payload, JSON_ARRAY_LEFT_BRACKET); + for (int i = 0; i < number_of_feeds; ++i) { + if (sprintf(payload, "\"%s\"%s", feed->name, (number_of_feeds > 1 && i < (number_of_feeds - 1) ? "," : "")) + >= (int)WOLK_ARRAY_LENGTH(outbound_message->payload)) + return false; + + if (strlen(payload) > (PAYLOAD_SIZE - strlen(outbound_message->payload))) + return false; + + strcat(outbound_message->payload, payload); + feed++; + } + strcat(outbound_message->payload, JSON_ARRAY_RIGHT_BRACKET); + + return true; +} +bool json_serialize_pull_feed_values(const char* device_key, outbound_message_t* outbound_message) +{ + json_create_topic(JSON_D2P_TOPIC, device_key, JSON_PULL_FEEDS_TOPIC, outbound_message->topic); + strncpy(outbound_message->payload, "", PAYLOAD_SIZE); + + return true; +} +bool json_serialize_pull_parameters(const char* device_key, outbound_message_t* outbound_message) +{ + json_create_topic(JSON_D2P_TOPIC, device_key, JSON_PULL_PARAMETERS_TOPIC, outbound_message->topic); + strncpy(outbound_message->payload, "", PAYLOAD_SIZE); + + return true; +} +bool json_serialize_sync_parameters(const char* device_key, parameter_t* parameters, size_t number_of_parameters, + outbound_message_t* outbound_message) +{ + json_create_topic(JSON_D2P_TOPIC, device_key, JSON_SYNC_PARAMETERS_TOPIC, outbound_message->topic); + + strcat(outbound_message->payload, JSON_ARRAY_LEFT_BRACKET); + for (int i = 0; i < number_of_parameters; ++i) { + strcat(outbound_message->payload, "\""); + if (strlen(parameters->name) > (PAYLOAD_SIZE - strlen(outbound_message->payload))) + return false; + strcat(outbound_message->payload, parameters->name); + strcat(outbound_message->payload, "\""); + + if (number_of_parameters > 1 && i < (number_of_parameters - 1)) + strcat(outbound_message->payload, ","); + + parameters++; + } + strcat(outbound_message->payload, JSON_ARRAY_RIGHT_BRACKET); + + return true; +} +bool json_serialize_sync_time(const char* device_key, outbound_message_t* outbound_message) +{ + json_create_topic(JSON_D2P_TOPIC, device_key, JSON_SYNC_TIME_TOPIC, outbound_message->topic); + strncpy(outbound_message->payload, "", PAYLOAD_SIZE); + + return true; +} + +bool json_serialize_sync_details_synchronization(const char* device_key, outbound_message_t* outbound_message) +{ + json_create_topic(JSON_D2P_TOPIC, device_key, JSON_SYNC_DETAILS_SYNCHRONIZATION_TOPIC, outbound_message->topic); + strncpy(outbound_message->payload, "", PAYLOAD_SIZE); + + return true; +} diff --git a/sources/protocol/json_parser.h b/sources/protocol/json_parser.h new file mode 100644 index 0000000..73bd2e1 --- /dev/null +++ b/sources/protocol/json_parser.h @@ -0,0 +1,129 @@ +/* + * Copyright 2022 WolkAbout Technology s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef JSON_PARSER_H +#define JSON_PARSER_H + +#include "model/attribute.h" +#include "model/feed.h" +#include "model/file_management/file_management.h" +#include "model/file_management/file_management_packet_request.h" +#include "model/file_management/file_management_parameter.h" +#include "model/file_management/file_management_status.h" +#include "model/firmware_update.h" +#include "model/outbound_message.h" +#include "model/parameter.h" +#include "model/utc_command.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +const char JSON_P2D_TOPIC[TOPIC_DIRECTION_SIZE]; +const char JSON_D2P_TOPIC[TOPIC_DIRECTION_SIZE]; +const char JSON_FEED_REGISTRATION_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_FEED_REMOVAL_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_FEED_VALUES_MESSAGE_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_PULL_FEEDS_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_ATTRIBUTE_REGISTRATION_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_PARAMETERS_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_PULL_PARAMETERS_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_SYNC_PARAMETERS_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_SYNC_TIME_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_ERROR_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_DETAILS_SYNCHRONIZATION_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; + +const char JSON_FILE_MANAGEMENT_UPLOAD_INITIATE_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_FILE_MANAGEMENT_FILE_UPLOAD_STATUS_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_FILE_MANAGEMENT_FILE_UPLOAD_ABORT_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_FILE_MANAGEMENT_FILE_BINARY_REQUEST_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_FILE_MANAGEMENT_FILE_BINARY_RESPONSE_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_FILE_MANAGEMENT_URL_DOWNLOAD_INITIATE_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_FILE_MANAGEMENT_URL_DOWNLOAD_ABORT_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_FILE_MANAGEMENT_URL_DOWNLOAD_STATUS_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_FILE_MANAGEMENT_FILE_LIST_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_FILE_MANAGEMENT_FILE_DELETE_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_FILE_MANAGEMENT_FILE_PURGE_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; + +const char JSON_FIRMWARE_UPDATE_INSTALL_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_FIRMWARE_UPDATE_STATUS_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; +const char JSON_FIRMWARE_UPDATE_ABORT_TOPIC[TOPIC_MESSAGE_TYPE_SIZE]; + +size_t json_serialize_feeds(feed_t* feeds, data_type_t type, size_t number_of_feeds, size_t feed_element_size, + char* buffer, size_t buffer_size); + +size_t json_deserialize_feeds_value_message(char* buffer, size_t buffer_size, feed_t* feeds_received); + +bool json_create_topic(char direction[TOPIC_DIRECTION_SIZE], const char device_key[DEVICE_KEY_SIZE], + char message_type[TOPIC_MESSAGE_TYPE_SIZE], char topic[TOPIC_SIZE]); + +bool json_serialize_feed_registration(const char* device_key, feed_registration_t* feed, size_t number_of_feeds, + outbound_message_t* outbound_message); +bool json_serialize_feed_removal(const char* device_key, feed_registration_t* feed, size_t number_of_feeds, + outbound_message_t* outbound_message); +bool json_serialize_pull_feed_values(const char* device_key, outbound_message_t* outbound_message); +bool json_serialize_parameter(const char* device_key, parameter_t* parameter, size_t number_of_parameters, + outbound_message_t* outbound_message); +bool json_serialize_pull_parameters(const char* device_key, outbound_message_t* outbound_message); +bool json_serialize_sync_parameters(const char* device_key, parameter_t* parameters, size_t number_of_parameters, + outbound_message_t* outbound_message); +size_t json_deserialize_parameter_message(char* buffer, size_t buffer_size, parameter_t* parameter_message); + +bool json_serialize_attribute(const char* device_key, attribute_t* attributes, size_t number_of_attributes, + outbound_message_t* outbound_message); +bool json_serialize_sync_time(const char* device_key, outbound_message_t* outbound_message); +bool json_serialize_sync_details_synchronization(const char* device_key, outbound_message_t* outbound_message); +bool json_deserialize_time(char* buffer, size_t buffer_size, utc_command_t* utc_command); +bool json_deserialize_details_synchronization(char* buffer, size_t buffer_size, feed_registration_t* feeds, + size_t* number_of_feeds, attribute_t* attributes, + size_t* number_of_attributes); + +bool json_serialize_file_management_status(const char* device_key, + file_management_packet_request_t* file_management_packet_request, + file_management_status_t* status, outbound_message_t* outbound_message); + +bool json_deserialize_file_management_parameter(char* buffer, size_t buffer_size, + file_management_parameter_t* parameter); + +bool json_deserialize_url_download(char* buffer, size_t buffer_size, char* url_download); + +size_t json_deserialize_file_delete(char* buffer, size_t buffer_size, file_list_t* file_list); + +bool json_serialize_file_management_packet_request(const char* device_key, + file_management_packet_request_t* file_management_packet_request, + outbound_message_t* outbound_message); + +bool json_serialize_file_management_url_download_status(const char* device_key, + file_management_parameter_t* file_management_parameter, + file_management_status_t* status, + outbound_message_t* outbound_message); +bool json_serialize_file_management_file_list_update(const char* device_key, file_list_t* file_list, + size_t file_list_items, outbound_message_t* outbound_message); + +bool json_deserialize_firmware_update_parameter(char* buffer, size_t buffer_size, firmware_update_t* parameter); +bool json_serialize_firmware_update_status(const char* device_key, firmware_update_t* firmware_update, + outbound_message_t* outbound_message); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sources/protocol/parser.c b/sources/protocol/parser.c new file mode 100644 index 0000000..46db147 --- /dev/null +++ b/sources/protocol/parser.c @@ -0,0 +1,287 @@ +/* + * Copyright 2022 WolkAbout Technology s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "protocol/parser.h" +#include "model/attribute.h" +#include "model/file_management/file_management_parameter.h" +#include "model/file_management/file_management_status.h" +#include "protocol/json_parser.h" +#include "utility/wolk_utils.h" + +#include +#include +#include + + +void parser_init(parser_t* parser) +{ + /* Sanity check */ + WOLK_ASSERT(parser); + + parser->is_initialized = true; + + parser->serialize_feeds = json_serialize_feeds; + + parser->serialize_file_management_status = json_serialize_file_management_status; + parser->deserialize_file_management_parameter = json_deserialize_file_management_parameter; + parser->deserialize_url_download = json_deserialize_url_download; + parser->deserialize_file_delete = json_deserialize_file_delete; + parser->serialize_file_management_packet_request = json_serialize_file_management_packet_request; + parser->serialize_file_management_url_download_status = json_serialize_file_management_url_download_status; + parser->serialize_file_management_file_list = json_serialize_file_management_file_list_update; + + parser->deserialize_firmware_update_parameter = json_deserialize_firmware_update_parameter; + parser->serialize_firmware_update_status = json_serialize_firmware_update_status; + + parser->deserialize_time = json_deserialize_time; + parser->deserialize_details_synchronization = json_deserialize_details_synchronization; + parser->deserialize_readings_value_message = json_deserialize_feeds_value_message; + parser->deserialize_parameter_message = json_deserialize_parameter_message; + + parser->create_topic = json_create_topic; + + parser->serialize_feed_registration = json_serialize_feed_registration; + parser->serialize_feed_removal = json_serialize_feed_removal; + parser->serialize_pull_feed_values = json_serialize_pull_feed_values; + parser->serialize_pull_parameters = json_serialize_pull_parameters; + parser->serialize_sync_parameters = json_serialize_sync_parameters; + parser->serialize_sync_time = json_serialize_sync_time; + parser->serialize_sync_details_synchronization = json_serialize_sync_details_synchronization; + parser->serialize_attribute = json_serialize_attribute; + parser->serialize_parameter = json_serialize_parameter; + + strncpy(parser->FILE_MANAGEMENT_UPLOAD_INITIATE_TOPIC, JSON_FILE_MANAGEMENT_UPLOAD_INITIATE_TOPIC, + TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->FILE_MANAGEMENT_BINARY_REQUEST_TOPIC, JSON_FILE_MANAGEMENT_FILE_BINARY_REQUEST_TOPIC, + TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->FILE_MANAGEMENT_BINARY_RESPONSE_TOPIC, JSON_FILE_MANAGEMENT_FILE_BINARY_RESPONSE_TOPIC, + TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->FILE_MANAGEMENT_UPLOAD_ABORT_TOPIC, JSON_FILE_MANAGEMENT_FILE_UPLOAD_ABORT_TOPIC, + TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->FILE_MANAGEMENT_URL_DOWNLOAD_INITIATE_TOPIC, JSON_FILE_MANAGEMENT_URL_DOWNLOAD_INITIATE_TOPIC, + TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->FILE_MANAGEMENT_URL_DOWNLOAD_ABORT_TOPIC, JSON_FILE_MANAGEMENT_URL_DOWNLOAD_ABORT_TOPIC, + TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->FILE_MANAGEMENT_FILE_LIST_TOPIC, JSON_FILE_MANAGEMENT_FILE_LIST_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->FILE_MANAGEMENT_FILE_DELETE_TOPIC, JSON_FILE_MANAGEMENT_FILE_DELETE_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->FILE_MANAGEMENT_FILE_PURGE_TOPIC, JSON_FILE_MANAGEMENT_FILE_PURGE_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->FIRMWARE_UPDATE_INSTALL_TOPIC, JSON_FIRMWARE_UPDATE_INSTALL_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->FIRMWARE_UPDATE_ABORT_TOPIC, JSON_FIRMWARE_UPDATE_ABORT_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->P2D_TOPIC, JSON_P2D_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->D2P_TOPIC, JSON_D2P_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->FEED_REGISTRATION_TOPIC, JSON_FEED_REGISTRATION_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->FEED_REMOVAL_TOPIC, JSON_FEED_REMOVAL_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->FEED_VALUES_MESSAGE_TOPIC, JSON_FEED_VALUES_MESSAGE_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->PULL_FEED_VALUES_TOPIC, JSON_PULL_FEEDS_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->ATTRIBUTE_REGISTRATION_TOPIC, JSON_ATTRIBUTE_REGISTRATION_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->PARAMETERS_TOPIC, JSON_PARAMETERS_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->PULL_PARAMETERS_TOPIC, JSON_PULL_PARAMETERS_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->SYNC_PARAMETERS_TOPIC, JSON_SYNC_PARAMETERS_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->SYNC_TIME_TOPIC, JSON_SYNC_TIME_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->ERROR_TOPIC, JSON_ERROR_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); + strncpy(parser->DETAILS_SYNCHRONIZATION_TOPIC, JSON_DETAILS_SYNCHRONIZATION_TOPIC, TOPIC_MESSAGE_TYPE_SIZE); +} + +size_t parser_serialize_feeds(parser_t* parser, feed_t* readings, data_type_t type, size_t num_readings, + size_t reading_element_size, char* buffer, size_t buffer_size) +{ + /* Sanity check */ + WOLK_ASSERT(parser); + WOLK_ASSERT(num_readings > 0); + WOLK_ASSERT(buffer_size >= PAYLOAD_SIZE); + + return parser->serialize_feeds(readings, type, num_readings, reading_element_size, buffer, buffer_size); +} + +bool parser_serialize_file_management_status(parser_t* parser, const char* device_key, + file_management_packet_request_t* file_management_packet_request, + file_management_status_t* status, outbound_message_t* outbound_message) +{ + /* Sanity check */ + WOLK_ASSERT(parser); + WOLK_ASSERT(device_key); + WOLK_ASSERT(status); + WOLK_ASSERT(outbound_message); + + return parser->serialize_file_management_status(device_key, file_management_packet_request, status, + outbound_message); +} + +bool parser_deserialize_file_management_parameter(parser_t* parser, char* buffer, size_t buffer_size, + file_management_parameter_t* parameter) +{ + /* Sanity check */ + WOLK_ASSERT(parser); + WOLK_ASSERT(buffer); + WOLK_ASSERT(parameter); + + return parser->deserialize_file_management_parameter(buffer, buffer_size, parameter); +} + +bool parser_deserialize_url_download(parser_t* parser, char* buffer, size_t buffer_size, char* url_download) +{ + /* Sanity check */ + WOLK_ASSERT(parser); + WOLK_ASSERT(buffer); + WOLK_ASSERT(url_download); + + return parser->deserialize_url_download(buffer, buffer_size, url_download); +} + +size_t parser_deserialize_file_delete(parser_t* parser, char* buffer, size_t buffer_size, file_list_t* file_list) +{ + /* Sanity check */ + WOLK_ASSERT(parser); + WOLK_ASSERT(buffer); + WOLK_ASSERT(parameter); + + return parser->deserialize_file_delete(buffer, buffer_size, file_list); +} + +bool parser_serialize_file_management_packet_request(parser_t* parser, const char* device_key, + file_management_packet_request_t* file_management_packet_request, + outbound_message_t* outbound_message) +{ + /* Sanity check */ + WOLK_ASSERT(parser); + WOLK_ASSERT(device_key); + WOLK_ASSERT(file_management_packet_request); + WOLK_ASSERT(outbound_message); + + return parser->serialize_file_management_packet_request(device_key, file_management_packet_request, + outbound_message); +} + +bool parser_serialize_file_management_url_download(parser_t* parser, const char* device_key, + file_management_parameter_t* file_management_parameter, + file_management_status_t* status, + outbound_message_t* outbound_message) +{ + /* Sanity check */ + WOLK_ASSERT(parser); + WOLK_ASSERT(device_key); + WOLK_ASSERT(file_management_parameter); + WOLK_ASSERT(status); + WOLK_ASSERT(outbound_message); + + return parser->serialize_file_management_url_download_status(device_key, file_management_parameter, status, + outbound_message); +} + +bool parser_serialize_file_management_file_list(parser_t* parser, const char* device_key, file_list_t* file_list, + size_t file_list_items, outbound_message_t* outbound_message) +{ + /* Sanity Check */ + WOLK_ASSERT(parser); + WOLK_ASSERT(device_key); + WOLK_ASSERT(file_list); + WOLK_ASSERT(file_list_items); + WOLK_ASSERT(outbound_message); + + return parser->serialize_file_management_file_list(device_key, file_list, file_list_items, outbound_message); +} + +bool parse_deserialize_firmware_update_parameter(parser_t* parser, char* buffer, size_t buffer_size, + firmware_update_t* firmware_update_parameter) +{ + WOLK_ASSERT(parser); + WOLK_ASSERT(buffer); + WOLK_ASSERT(buffer_size); + WOLK_ASSERT(firmware_update_parameter); + + return parser->deserialize_firmware_update_parameter(buffer, buffer_size, firmware_update_parameter); +} + +bool parse_serialize_firmware_update_status(parser_t* parser, const char* device_key, + firmware_update_t* firmware_update, outbound_message_t* outbound_message) +{ + /* Sanity Check */ + WOLK_ASSERT(parser); + WOLK_ASSERT(device_key); + WOLK_ASSERT(firmware_update); + WOLK_ASSERT(outbound_message); + + return parser->serialize_firmware_update_status(device_key, firmware_update, outbound_message); +} + +bool parser_deserialize_time(parser_t* parser, char* buffer, size_t buffer_size, utc_command_t* utc_command) +{ + return parser->deserialize_time(buffer, buffer_size, utc_command); +} + +bool parser_deserialize_details_synchronization(parser_t* parser, char* buffer, size_t buffer_size, + feed_registration_t* feeds, size_t* number_of_feeds, + attribute_t* attributes, size_t* number_of_attributes) +{ + return parser->deserialize_details_synchronization(buffer, buffer_size, feeds, number_of_feeds, attributes, + number_of_attributes); +} + +bool parser_create_topic(parser_t* parser, char* direction, char* device_key, char* message_type, char* topic) +{ + return parser->create_topic(direction, device_key, message_type, topic); +} +size_t parser_deserialize_feeds_message(parser_t* parser, char* buffer, size_t buffer_size, feed_t* readings_received) +{ + return parser->deserialize_readings_value_message(buffer, buffer_size, readings_received); +} +size_t parser_deserialize_parameter_message(parser_t* parser, char* buffer, size_t buffer_size, + parameter_t* parameter_message) +{ + return parser->deserialize_parameter_message(buffer, buffer_size, parameter_message); +} +bool parser_serialize_feed_registration(parser_t* parser, const char* device_key, feed_registration_t* feed, + size_t number_of_feeds, outbound_message_t* outbound_message) +{ + return parser->serialize_feed_registration(device_key, feed, number_of_feeds, outbound_message); +} +bool parser_serialize_feed_removal(parser_t* parser, const char* device_key, feed_registration_t* feed, + size_t number_of_feeds, outbound_message_t* outbound_message) +{ + return parser->serialize_feed_removal(device_key, feed, number_of_feeds, outbound_message); +} +bool parser_serialize_pull_feed_values(parser_t* parser, const char* device_key, outbound_message_t* outbound_message) +{ + return parser->serialize_pull_feed_values(device_key, outbound_message); +} +bool parser_serialize_pull_parameters(parser_t* parser, const char* device_key, outbound_message_t* outbound_message) +{ + return parser->serialize_pull_parameters(device_key, outbound_message); +} +bool parser_serialize_sync_parameters(parser_t* parser, const char* device_key, parameter_t* parameters, + size_t number_of_parameters, outbound_message_t* outbound_message) +{ + return parser->serialize_sync_parameters(device_key, parameters, number_of_parameters, outbound_message); +} +bool parser_serialize_sync_time(parser_t* parser, const char* device_key, outbound_message_t* outbound_message) +{ + return parser->serialize_sync_time(device_key, outbound_message); +} +bool parser_serialize_details_synchronization(parser_t* parser, const char* device_key, + outbound_message_t* outbound_message) +{ + return parser->serialize_sync_details_synchronization(device_key, outbound_message); +} +bool parser_serialize_attribute(parser_t* parser, const char* device_key, attribute_t* attributes, + size_t number_of_attributes, outbound_message_t* outbound_message) +{ + return parser->serialize_attribute(device_key, attributes, number_of_attributes, outbound_message); +} +bool parser_serialize_parameter(parser_t* parser, const char* device_key, parameter_t* parameter, + size_t number_of_parameters, outbound_message_t* outbound_message) +{ + return parser->serialize_parameter(device_key, parameter, number_of_parameters, outbound_message); +} diff --git a/sources/protocol/parser.h b/sources/protocol/parser.h new file mode 100644 index 0000000..d14890f --- /dev/null +++ b/sources/protocol/parser.h @@ -0,0 +1,203 @@ +/* + * Copyright 2022 WolkAbout Technology s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PARSER_H +#define PARSER_H + +#include "model/attribute.h" +#include "model/feed.h" +#include "model/file_management/file_management.h" +#include "model/file_management/file_management_packet_request.h" +#include "model/file_management/file_management_parameter.h" +#include "model/file_management/file_management_status.h" +#include "model/firmware_update.h" +#include "model/outbound_message.h" +#include "model/parameter.h" +#include "model/utc_command.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + bool is_initialized; + + char FILE_MANAGEMENT_UPLOAD_INITIATE_TOPIC[TOPIC_SIZE]; + char FILE_MANAGEMENT_BINARY_REQUEST_TOPIC[TOPIC_SIZE]; + char FILE_MANAGEMENT_BINARY_RESPONSE_TOPIC[TOPIC_SIZE]; + char FILE_MANAGEMENT_UPLOAD_ABORT_TOPIC[TOPIC_SIZE]; + + char FILE_MANAGEMENT_URL_DOWNLOAD_INITIATE_TOPIC[TOPIC_SIZE]; + char FILE_MANAGEMENT_URL_DOWNLOAD_ABORT_TOPIC[TOPIC_SIZE]; + + char FILE_MANAGEMENT_FILE_LIST_TOPIC[TOPIC_SIZE]; + char FILE_MANAGEMENT_FILE_DELETE_TOPIC[TOPIC_SIZE]; + char FILE_MANAGEMENT_FILE_PURGE_TOPIC[TOPIC_SIZE]; + + char FIRMWARE_UPDATE_INSTALL_TOPIC[TOPIC_SIZE]; + char FIRMWARE_UPDATE_ABORT_TOPIC[TOPIC_SIZE]; + + char P2D_TOPIC[TOPIC_SIZE]; + char D2P_TOPIC[TOPIC_SIZE]; + char FEED_REGISTRATION_TOPIC[TOPIC_SIZE]; + char FEED_REMOVAL_TOPIC[TOPIC_SIZE]; + char FEED_VALUES_MESSAGE_TOPIC[TOPIC_SIZE]; + char PULL_FEED_VALUES_TOPIC[TOPIC_SIZE]; + char ATTRIBUTE_REGISTRATION_TOPIC[TOPIC_SIZE]; + char PARAMETERS_TOPIC[TOPIC_SIZE]; + char PULL_PARAMETERS_TOPIC[TOPIC_SIZE]; + char SYNC_PARAMETERS_TOPIC[TOPIC_SIZE]; + char SYNC_TIME_TOPIC[TOPIC_SIZE]; + char ERROR_TOPIC[TOPIC_SIZE]; + char DETAILS_SYNCHRONIZATION_TOPIC[TOPIC_SIZE]; + + size_t (*serialize_feeds)(feed_t* readings, data_type_t type, size_t num_readings, size_t reading_element_size, + char* buffer, size_t buffer_size); + + bool (*serialize_file_management_status)(const char* device_key, + file_management_packet_request_t* file_management_packet_request, + file_management_status_t* status, outbound_message_t* outbound_message); + bool (*deserialize_file_management_parameter)(char* buffer, size_t buffer_size, + file_management_parameter_t* parameter); + bool (*deserialize_url_download)(char* buffer, size_t buffer_size, char* url_download); + size_t (*deserialize_file_delete)(char* buffer, size_t buffer_size, file_list_t* file_list); + bool (*serialize_file_management_packet_request)(const char* device_key, + file_management_packet_request_t* file_management_packet_request, + outbound_message_t* outbound_message); + bool (*serialize_file_management_url_download_status)(const char* device_key, + file_management_parameter_t* file_management_parameter, + file_management_status_t* status, + outbound_message_t* outbound_message); + bool (*serialize_file_management_file_list)(const char* device_key, file_list_t* file_list, size_t file_list_items, + outbound_message_t* outbound_message); + + bool (*deserialize_firmware_update_parameter)(char* buffer, size_t buffer_size, firmware_update_t* parameter); + bool (*serialize_firmware_update_status)(const char* device_key, firmware_update_t* firmware_update, + outbound_message_t* outbound_message); + + bool (*deserialize_time)(char* buffer, size_t buffer_size, utc_command_t* utc_command); + bool (*deserialize_details_synchronization)(char* buffer, size_t buffer_size, feed_registration_t* feeds, + size_t* number_of_feeds, attribute_t* attributes, + size_t* number_of_attributes); + + bool (*create_topic)(char direction[TOPIC_DIRECTION_SIZE], const char device_key[DEVICE_KEY_SIZE], + char message_type[TOPIC_MESSAGE_TYPE_SIZE], char topic[TOPIC_SIZE]); + size_t (*deserialize_readings_value_message)(char* buffer, size_t buffer_size, feed_t* readings_received); + size_t (*deserialize_parameter_message)(char* buffer, size_t buffer_size, parameter_t* parameter_message); + bool (*serialize_feed_registration)(const char* device_key, feed_registration_t* feed, size_t number_of_feeds, + outbound_message_t* outbound_message); + bool (*serialize_feed_removal)(const char* device_key, feed_registration_t* feed, size_t number_of_feeds, + outbound_message_t* outbound_message); + bool (*serialize_pull_feed_values)(const char* device_key, outbound_message_t* outbound_message); + bool (*serialize_pull_parameters)(const char* device_key, outbound_message_t* outbound_message); + bool (*serialize_sync_parameters)(const char* device_key, parameter_t* parameters, size_t number_of_parameters, + outbound_message_t* outbound_message); + bool (*serialize_sync_time)(const char* device_key, outbound_message_t* outbound_message); + bool (*serialize_sync_details_synchronization)(const char* device_key, outbound_message_t* outbound_message); + bool (*serialize_attribute)(const char* device_key, attribute_t* attributes, size_t number_of_attributes, + outbound_message_t* outbound_message); + bool (*serialize_parameter)(const char* device_key, parameter_t* parameter, size_t number_of_parameters, + outbound_message_t* outbound_message); + +} parser_t; + +void parser_init(parser_t* parser); + +/**** Feed ****/ +size_t parser_serialize_feeds(parser_t* parser, feed_t* readings, data_type_t type, size_t num_readings, + size_t reading_element_size, char* buffer, size_t buffer_size); +/**** Feed ****/ + +/**** File Management ****/ +bool parser_serialize_file_management_status(parser_t* parser, const char* device_key, + file_management_packet_request_t* file_management_packet_request, + file_management_status_t* status, outbound_message_t* outbound_message); + +bool parser_deserialize_file_management_parameter(parser_t* parser, char* buffer, size_t buffer_size, + file_management_parameter_t* parameter); + +bool parser_deserialize_url_download(parser_t* parser, char* buffer, size_t buffer_size, char* url_download); + +size_t parser_deserialize_file_delete(parser_t* parser, char* buffer, size_t buffer_size, file_list_t* file_list); + +bool parser_serialize_file_management_packet_request(parser_t* parser, const char* device_key, + file_management_packet_request_t* file_management_packet_request, + outbound_message_t* outbound_message); + +bool parser_serialize_file_management_url_download(parser_t* parser, const char* device_key, + file_management_parameter_t* parameter, + file_management_status_t* status, + outbound_message_t* outbound_message); + +bool parser_serialize_file_management_file_list(parser_t* parser, const char* device_key, file_list_t* file_list, + size_t file_list_items, outbound_message_t* outbound_message); +/**** File Management ****/ + +/**** Firmware Update ****/ +bool parse_deserialize_firmware_update_parameter(parser_t* parser, char* buffer, size_t buffer_size, + firmware_update_t* firmware_update_parameter); + +bool parse_serialize_firmware_update_status(parser_t* parser, const char* device_key, + firmware_update_t* firmware_update, outbound_message_t* outbound_message); + +/**** Firmware Update ****/ + +/**** Utility ****/ +bool parser_deserialize_time(parser_t* parser, char* buffer, size_t buffer_size, utc_command_t* utc_command); +bool parser_deserialize_details_synchronization(parser_t* parser, char* buffer, size_t buffer_size, + feed_registration_t* feeds, size_t* number_of_feeds, + attribute_t* attributes, size_t* number_of_attributes); + +bool parser_create_topic(parser_t* parser, char direction[TOPIC_DIRECTION_SIZE], char device_key[DEVICE_KEY_SIZE], + char message_type[TOPIC_MESSAGE_TYPE_SIZE], char topic[TOPIC_SIZE]); + +size_t parser_deserialize_feeds_message(parser_t* parser, char* buffer, size_t buffer_size, feed_t* readings_received); + +size_t parser_deserialize_parameter_message(parser_t* parser, char* buffer, size_t buffer_size, + parameter_t* parameter_message); + +bool parser_serialize_feed_registration(parser_t* parser, const char* device_key, feed_registration_t* feed, + size_t number_of_feeds, outbound_message_t* outbound_message); + +bool parser_serialize_feed_removal(parser_t* parser, const char* device_key, feed_registration_t* feed, + size_t number_of_feeds, outbound_message_t* outbound_message); +bool parser_serialize_pull_feed_values(parser_t* parser, const char* device_key, outbound_message_t* outbound_message); + +bool parser_serialize_pull_parameters(parser_t* parser, const char* device_key, outbound_message_t* outbound_message); + +bool parser_serialize_sync_parameters(parser_t* parser, const char* device_key, parameter_t* parameters, + size_t number_of_parameters, outbound_message_t* outbound_message); + +bool parser_serialize_sync_time(parser_t* parser, const char* device_key, outbound_message_t* outbound_message); +bool parser_serialize_details_synchronization(parser_t* parser, const char* device_key, + outbound_message_t* outbound_message); + +bool parser_serialize_attribute(parser_t* parser, const char* device_key, attribute_t* attributes, + size_t number_of_attributes, outbound_message_t* outbound_message); + +bool parser_serialize_parameter(parser_t* parser, const char* device_key, parameter_t* parameter, + size_t number_of_parameters, outbound_message_t* outbound_message); +/**** Utility ****/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/sources/reading.c b/sources/reading.c deleted file mode 100644 index 8692d7e..0000000 --- a/sources/reading.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2018 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "reading.h" -#include "manifest_item.h" -#include "wolk_utils.h" - -#include -#include -#include -#include -#include - -void reading_init(reading_t* reading, manifest_item_t* item) -{ - uint16_t i; - uint8_t reading_dimensions = (uint8_t)manifest_item_get_data_dimensions(item); - - memcpy(&reading->manifest_item, item, sizeof(reading->manifest_item)); - reading->actuator_status = ACTUATOR_STATE_READY; - reading->rtc = 0; - - for (i = 0; i < reading_dimensions; ++i) { - reading_set_data(reading, ""); - } -} - -void reading_clear(reading_t* reading) -{ - reading_init(reading, reading_get_manifest_item(reading)); -} - -void reading_clear_array(reading_t* first_reading, size_t readings_count) -{ - size_t i; - - reading_t* current_reading = first_reading; - for (i = 0; i < readings_count; ++i, ++current_reading) { - reading_clear(current_reading); - } -} - -void reading_set_data(reading_t* reading, const char* data) -{ - reading_set_data_at(reading, data, 0); -} - -char* reading_get_data(reading_t* reading) -{ - return reading_get_data_at(reading, 0); -} - -bool reading_get_delimited_data(reading_t* reading, char* buffer, size_t buffer_size) -{ - size_t i; - size_t data_dimensions = manifest_item_get_data_dimensions(reading_get_manifest_item(reading)); - char* data_delimiter = manifest_item_get_data_delimiter(reading_get_manifest_item(reading)); - - memset(buffer, '\0', buffer_size); - for (i = 0; i < data_dimensions; ++i) { - if (i != 0) { - size_t num_bytes_to_write = buffer_size - strlen(buffer); - if (snprintf(buffer + strlen(buffer), (int)num_bytes_to_write, "%s", data_delimiter) - >= (int)num_bytes_to_write) { - return false; - } - } - - size_t num_bytes_to_write = buffer_size - strlen(buffer); - if (snprintf(buffer + strlen(buffer), (int)num_bytes_to_write, "%s", reading_get_data_at(reading, i)) - >= (int)num_bytes_to_write) { - return false; - } - } - - return true; -} - -void reading_set_data_at(reading_t* reading, const char* data, size_t data_position) -{ - /* Sanity check */ - WOLK_ASSERT(strlen(data) < READING_SIZE); - WOLK_ASSERT(data_position < READING_DIMENSIONS); - - strcpy(reading->reading_data[data_position], data); -} - -char* reading_get_data_at(reading_t* reading, size_t data_position) -{ - /* Sanity check */ - WOLK_ASSERT(data_position < reading->manifest_item.data_dimensions); - - return reading->reading_data[data_position]; -} - -manifest_item_t* reading_get_manifest_item(reading_t* reading) -{ - return &reading->manifest_item; -} - -void reading_set_rtc(reading_t* reading, uint64_t rtc) -{ - reading->rtc = rtc; -} - -uint64_t reading_get_rtc(reading_t* reading) -{ - return reading->rtc; -} - -void reading_set_actuator_state(reading_t* reading, actuator_state_t actuator_status) -{ - /* Sanity check */ - WOLK_ASSERT(manifest_item_get_reading_type(reading_get_manifest_item(reading)) & READING_TYPE_ACTUATOR); - - reading->actuator_status = actuator_status; -} - -actuator_state_t reading_get_actuator_state(reading_t* reading) -{ - /* Sanity check */ - WOLK_ASSERT(manifest_item_get_reading_type(reading_get_manifest_item(reading)) & READING_TYPE_ACTUATOR); - - return reading->actuator_status; -} diff --git a/sources/reading.h b/sources/reading.h deleted file mode 100644 index 1353258..0000000 --- a/sources/reading.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2018 WolkAbout Technology s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef READING_H -#define READING_H - -#include "actuator_status.h" -#include "manifest_item.h" -#include "size_definitions.h" - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - manifest_item_t manifest_item; - - actuator_state_t actuator_status; - - char reading_data[READING_DIMENSIONS][READING_SIZE]; - - uint64_t rtc; -} reading_t; - -void reading_init(reading_t* reading, manifest_item_t* item); - -void reading_clear(reading_t* reading); -void reading_clear_array(reading_t* first_reading, size_t readings_count); - -void reading_set_data(reading_t* reading, const char* data); -char* reading_get_data(reading_t* reading); - -bool reading_get_delimited_data(reading_t* reading, char* buffer, size_t buffer_size); - -void reading_set_data_at(reading_t* reading, const char* data, size_t data_position); -char* reading_get_data_at(reading_t* reading, size_t data_position); - -manifest_item_t* reading_get_manifest_item(reading_t* reading); - -void reading_set_rtc(reading_t* reading, uint64_t rtc); -uint64_t reading_get_rtc(reading_t* reading); - -void reading_set_actuator_state(reading_t* reading, actuator_state_t actuator_status); -actuator_state_t reading_get_actuator_state(reading_t* reading); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/sources/size_definitions.h b/sources/size_definitions.h old mode 100644 new mode 100755 index 085ed2a..aa0d0d3 --- a/sources/size_definitions.h +++ b/sources/size_definitions.h @@ -1,5 +1,5 @@ /* - * Copyright 2018 WolkAbout Technology s.r.o. + * Copyright 2022 WolkAbout Technology s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,43 +23,46 @@ extern "C" { enum { /* Maximum size of MQTT packet in bytes */ - MQTT_PACKET_SIZE = 512, + MQTT_PACKET_SIZE = 2048, /* Maximum number of characters in device key string */ DEVICE_KEY_SIZE = 64, - /* Maximum number of characters in device password string */ DEVICE_PASSWORD_SIZE = 64, + /* Topic root path size */ + TOPIC_DIRECTION_SIZE = 4, + /* Topic branch size */ + TOPIC_MESSAGE_TYPE_SIZE = 64, /* Maximum number of characters in topic string */ - TOPIC_SIZE = 64 + DEVICE_KEY_SIZE, - /* Maximum number of bytes in payload string */ - PAYLOAD_SIZE = 448, + TOPIC_SIZE = TOPIC_DIRECTION_SIZE + DEVICE_KEY_SIZE + TOPIC_MESSAGE_TYPE_SIZE, - /* Maximum number of characters in reference string */ - MANIFEST_ITEM_REFERENCE_SIZE = 64, - /* Maximum number of characters in delimiter string */ - MANIFEST_ITEM_DATA_DELIMITER_SIZE = 3, + /* Maximum number of bytes in payload string */ + PAYLOAD_SIZE = 2048, - /* Maximum number of characters in reading value string */ - READING_SIZE = 128, - /* Maximum number of reading dimensions (Data size on DV-Tool) */ - READING_DIMENSIONS = 3, + /* Maximum number of characters in a single feed */ + FEED_ELEMENT_SIZE = 64, + /* Maximum number of feeds*/ + FEEDS_MAX_NUMBER = 32, - /* Maximum number of characters in command name */ - COMMAND_MAX_SIZE = 15, - /* Maximum number of characters in actuation value string */ - COMMAND_ARGUMENT_SIZE = READING_SIZE, + /* Maximum number of characters in reference string */ + REFERENCE_SIZE = 64, + /* Maximum number of characters in name string */ + ITEM_NAME_SIZE = 64, + /* Maximum number of characters in unit string */ + ITEM_UNIT_SIZE = 25, + /* Maximum number of characters in feed type string */ + ITEM_FEED_TYPE_SIZE = 5, + /* Maximum number of characters in type string */ + ITEM_DATA_TYPE_SIZE = 32, - /* Maximum number of characters in configuration item name string */ - CONFIGURATION_REFERENCE_SIZE = MANIFEST_ITEM_REFERENCE_SIZE, - /* Maximum number of characters in configuration item value string */ - CONFIGURATION_VALUE_SIZE = READING_SIZE, - /* Maximum number of configuration items for device */ - CONFIGURATION_ITEMS_SIZE = 3, + /* Maximum number of characters in parameter type string */ + PARAMETER_TYPE_SIZE = 32, + /* Maximum number of characters in parameter value */ + PARAMETER_VALUE_SIZE = FEED_ELEMENT_SIZE, - /* Parser internal buffer size, should be at least READING_SIZE big */ - PARSER_INTERNAL_BUFFER_SIZE = READING_SIZE, + /* Maximum number of characters in attribute value */ + ATTRIBUTE_VALUE_SIZE = FEED_ELEMENT_SIZE, /* Maximum number of files in list */ FILE_MANAGEMENT_FILE_LIST_SIZE = 32, @@ -69,9 +72,14 @@ enum { FILE_MANAGEMENT_URL_SIZE = 64, /* Size of hash used for file management file transfer (SHA-256) */ FILE_MANAGEMENT_HASH_SIZE = 32, + /* Size of the chunks read from file during verification phase. Don't change it */ + FILE_MANAGEMENT_VERIFICATION_CHUNK_SIZE = 1024, /* Maximum number of characters in firmware update version */ FIRMWARE_UPDATE_VERSION_SIZE = 16, + + /* Number of batches in which data will be published */ + PUBLISH_BATCH_SIZE = 50, }; #ifdef __cplusplus diff --git a/sources/types.c b/sources/types.c new file mode 100644 index 0000000..a61f179 --- /dev/null +++ b/sources/types.c @@ -0,0 +1,202 @@ +/* + * Copyright 2022 WolkAbout Technology s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "types.h" +#include "utility/wolk_utils.h" + +const char UNIT_NUMERIC[] = "NUMERIC"; +const char UNIT_BOOLEAN[] = "BOOLEAN"; +const char UNIT_PERCENT[] = "PERCENT"; +const char UNIT_DECIBEL[] = "DECIBEL"; +const char UNIT_LOCATION[] = "LOCATION"; +const char UNIT_TEXT[] = "TEXT"; +const char UNIT_METRES_PER_SQUARE_SECOND[] = "METRES_PER_SQUARE_SECOND"; +const char UNIT_G[] = "G"; +const char UNIT_MOLE[] = "MOLE"; +const char UNIT_ATOM[] = "ATOM"; +const char UNIT_RADIAN[] = "RADIAN"; +const char UNIT_REVOLUTION[] = "REVOLUTION"; +const char UNIT_DEGREE_ANGLE[] = "DEGREE_ANGLE"; +const char UNIT_MINUTE_ANGLE[] = "MINUTE_ANGLE"; +const char UNIT_SECOND_ANGLE[] = "SECOND_ANGLE"; +const char UNIT_CENTIRADIAN[] = "CENTIRADIAN"; +const char UNIT_GRADE[] = "GRADE"; +const char UNIT_SQUARE_METRE[] = "SQUARE_METRE"; +const char UNIT_ARE[] = "ARE"; +const char UNIT_HECTARE[] = "HECTARE"; +const char UNIT_KATAL[] = "KATAL"; +const char UNIT_BIT[] = "BIT"; +const char UNIT_BYTE[] = "BYTE"; +const char UNIT_SECOND[] = "SECOND"; +const char UNIT_MINUTE[] = "MINUTE"; +const char UNIT_HOUR[] = "HOUR"; +const char UNIT_DAY[] = "DAY"; +const char UNIT_WEEK[] = "WEEK"; +const char UNIT_YEAR[] = "YEAR"; +const char UNIT_MONTH[] = "MONTH"; +const char UNIT_DAY_SIDEREAL[] = "DAY_SIDEREAL"; +const char UNIT_YEAR_SIDEREAL[] = "YEAR_SIDEREAL"; +const char UNIT_YEAR_CALENDAR[] = "YEAR_CALENDAR"; +const char UNIT_POISE[] = "POISE"; +const char UNIT_FARAD[] = "FARAD"; +const char UNIT_COULOMB[] = "COULOMB"; +const char UNIT_E[] = "E"; +const char UNIT_FARADAY[] = "FARADAY"; +const char UNIT_FRANKLIN[] = "FRANKLIN"; +const char UNIT_SIEMENS[] = "SIEMENS"; +const char UNIT_AMPERE[] = "AMPERE"; +const char UNIT_GILBERT[] = "GILBERT"; +const char UNIT_HENRY[] = "HENRY"; +const char UNIT_VOLT[] = "VOLT"; +const char UNIT_CENTIVOLT[] = "CENTIVOLT"; +const char UNIT_MILLIVOLT[] = "MILLIVOLT"; +const char UNIT_OHM[] = "OHM"; +const char UNIT_JOULE[] = "JOULE"; +const char UNIT_ERG[] = "ERG"; +const char UNIT_ELECTRON_VOLT[] = "ELECTRON_VOLT"; +const char UNIT_NEWTON[] = "NEWTON"; +const char UNIT_DYNE[] = "DYNE"; +const char UNIT_KILOGRAM_FORCE[] = "KILOGRAM_FORCE"; +const char UNIT_POUND_FORCE[] = "POUND_FORCE"; +const char UNIT_HERTZ[] = "HERTZ"; +const char UNIT_MEGAHERTZ[] = "MEGAHERTZ"; +const char UNIT_GIGAHERTZ[] = "GIGAHERTZ"; +const char UNIT_LUX[] = "LUX"; +const char UNIT_LAMBERT[] = "LAMBERT"; +const char UNIT_STOKE[] = "STOKE"; +const char UNIT_METRE[] = "METRE"; +const char UNIT_KILOMETRE[] = "KILOMETRE"; +const char UNIT_CENTIMETRE[] = "CENTIMETRE"; +const char UNIT_MILLIMETRE[] = "MILLIMETRE"; +const char UNIT_FOOT[] = "FOOT"; +const char UNIT_FOOT_SURVEY_US[] = "FOOT_SURVEY_US"; +const char UNIT_YARD[] = "YARD"; +const char UNIT_INCH[] = "INCH"; +const char UNIT_MILE[] = "MILE"; +const char UNIT_NAUTICAL_MILE[] = "NAUTICAL_MILE"; +const char UNIT_ANGSTROM[] = "ANGSTROM"; +const char UNIT_ASTRONOMICAL_UNIT[] = "ASTRONOMICAL_UNIT"; +const char UNIT_LIGHT_YEAR[] = "LIGHT_YEAR"; +const char UNIT_PARSEC[] = "PARSEC"; +const char UNIT_POINT[] = "POINT"; +const char UNIT_PIXEL[] = "PIXEL"; +const char UNIT_LUMEN[] = "LUMEN"; +const char UNIT_CANDELA[] = "CANDELA"; +const char UNIT_WEBER[] = "WEBER"; +const char UNIT_MAXWELL[] = "MAXWELL"; +const char UNIT_TESLA[] = "TESLA"; +const char UNIT_GAUSS[] = "GAUSS"; +const char UNIT_KILOGRAM[] = "KILOGRAM"; +const char UNIT_GRAM[] = "GRAM"; +const char UNIT_ATOMIC_MASS[] = "ATOMIC_MASS"; +const char UNIT_ELECTRON_MASS[] = "ELECTRON_MASS"; +const char UNIT_POUND[] = "POUND"; +const char UNIT_OUNCE[] = "OUNCE"; +const char UNIT_TON_US[] = "TON_US"; +const char UNIT_TON_UK[] = "TON_UK"; +const char UNIT_METRIC_TON[] = "METRIC_TON"; +const char UNIT_WATT[] = "WATT"; +const char UNIT_HORSEPOWER[] = "HORSEPOWER"; +const char UNIT_PASCAL[] = "PASCAL"; +const char UNIT_HECTOPASCAL[] = "HECTOPASCAL"; +const char UNIT_ATMOSPHERE[] = "ATMOSPHERE"; +const char UNIT_BAR[] = "BAR"; +const char UNIT_MILLIBAR[] = "MILLIBAR"; +const char UNIT_MILLIMETER_OF_MERCURY[] = "MILLIMETER_OF_MERCURY"; +const char UNIT_INCH_OF_MERCURY[] = "INCH_OF_MERCURY"; +const char UNIT_GRAY[] = "GRAY"; +const char UNIT_RAD[] = "RAD"; +const char UNIT_SIEVERT[] = "SIEVERT"; +const char UNIT_REM[] = "REM"; +const char UNIT_BECQUEREL[] = "BECQUEREL"; +const char UNIT_CURIE[] = "CURIE"; +const char UNIT_RUTHERFORD[] = "RUTHERFORD"; +const char UNIT_ROENTGEN[] = "ROENTGEN"; +const char UNIT_STERADIAN[] = "STERADIAN"; +const char UNIT_SPHERE[] = "SPHERE"; +const char UNIT_KELVIN[] = "KELVIN"; +const char UNIT_CELSIUS[] = "CELSIUS"; +const char UNIT_RANKINE[] = "RANKINE"; +const char UNIT_FAHRENHEIT[] = "FAHRENHEIT"; +const char UNIT_METRES_PER_SECOND[] = "METRES_PER_SECOND"; +const char UNIT_MILES_PER_HOUR[] = "MILES_PER_HOUR"; +const char UNIT_KILOMETRES_PER_HOUR[] = "KILOMETRES_PER_HOUR"; +const char UNIT_KNOT[] = "KNOT"; +const char UNIT_MACH[] = "MACH"; +const char UNIT_C[] = "C"; +const char UNIT_CUBIC_METRE[] = "CUBIC_METRE"; +const char UNIT_LITRE[] = "LITRE"; +const char UNIT_DECILITRE[] = "DECILITRE"; +const char UNIT_MILLILITRE[] = "MILLILITRE"; +const char UNIT_CUBIC_INCH[] = "CUBIC_INCH"; +const char UNIT_GALLON_DRY_US[] = "GALLON_DRY_US"; +const char UNIT_GALLON_UK[] = "GALLON_UK"; +const char UNIT_OUNCE_LIQUID_UK[] = "OUNCE_LIQUID_UK"; +const char UNIT_UNKNOWN[] = "UNKNOWN"; + +const char** FEED_TYPE[] = {"IN", "IN_OUT"}; + +const char DATA_TYPE_STRING[] = "STRING"; +const char DATA_TYPE_NUMERIC[] = "NUMERIC"; +const char DATA_TYPE_BOOLEAN[] = "BOOLEAN"; +const char DATA_TYPE_HEXADECIMAL[] = "HEXADECIMAL"; +const char DATA_TYPE_LOCATION[] = "LOCATION"; +const char DATA_TYPE_ENUM[] = "ENUM"; +const char DATA_TYPE_VECTOR[] = "VECTOR"; + +const char PARAMETER_CONNECTIVITY_TYPE[] = "CONNECTIVITY_TYPE"; +const char PARAMETER_OUTBOUND_DATA_MODE[] = "OUTBOUND_DATA_MODE"; +const char PARAMETER_OUTBOUND_DATA_RETENTION_TIME[] = "OUTBOUND_DATA_RETENTION_TIME"; +const char PARAMETER_MAXIMUM_MESSAGE_SIZE[] = "MAXIMUM_MESSAGE_SIZE"; +const char PARAMETER_FILE_TRANSFER_PLATFORM_ENABLED[] = "FILE_TRANSFER_PLATFORM_ENABLED"; +const char PARAMETER_FILE_TRANSFER_URL_ENABLED[] = "FILE_TRANSFER_URL_ENABLED"; +const char PARAMETER_FIRMWARE_UPDATE_ENABLED[] = "FIRMWARE_UPDATE_ENABLED"; +const char PARAMETER_FIRMWARE_UPDATE_CHECK_TIME[] = "FIRMWARE_UPDATE_CHECK_TIME"; +const char PARAMETER_FIRMWARE_UPDATE_REPOSITORY[] = "FIRMWARE_UPDATE_REPOSITORY"; +const char PARAMETER_FIRMWARE_VERSION[] = "FIRMWARE_VERSION"; +const char PARAMETER_GATEWAY[] = "GATEWAY"; +const char PARAMETER_GATEWAY_PARENT[] = "GATEWAY_PARENT"; +const char PARAMETER_EXTERNAL_ID[] = "EXTERNAL_ID"; +const char PARAMETER_UNKNOWN[] = "UNKNOWN"; + +char* feed_type_to_string(feed_type_t feed_type) +{ + return FEED_TYPE[feed_type]; +} + +const char* file_management_status_as_str(file_management_status_t* status) +{ + /* Sanity check */ + WOLK_ASSERT(status); + + switch (status->state) { + case FILE_MANAGEMENT_STATE_FILE_TRANSFER: + return "FILE_TRANSFER"; + + case FILE_MANAGEMENT_STATE_FILE_READY: + return "FILE_READY"; + + case FILE_MANAGEMENT_STATE_ERROR: + return "ERROR"; + + case FILE_MANAGEMENT_STATE_ABORTED: + return "ABORTED"; + + default: + WOLK_ASSERT(false); + return ""; + } +} diff --git a/sources/types.h b/sources/types.h new file mode 100644 index 0000000..2db0e4b --- /dev/null +++ b/sources/types.h @@ -0,0 +1,225 @@ +/* + * Copyright 2022 WolkAbout Technology s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WOLK_TYPES_H +#define WOLK_TYPES_H + +#include "size_definitions.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const char UNIT_NUMERIC[ITEM_UNIT_SIZE]; +const char UNIT_BOOLEAN[ITEM_UNIT_SIZE]; +const char UNIT_PERCENT[ITEM_UNIT_SIZE]; +const char UNIT_DECIBEL[ITEM_UNIT_SIZE]; +const char UNIT_LOCATION[ITEM_UNIT_SIZE]; +const char UNIT_TEXT[ITEM_UNIT_SIZE]; +const char UNIT_METRES_PER_SQUARE_SECOND[ITEM_UNIT_SIZE]; +const char UNIT_G[ITEM_UNIT_SIZE]; +const char UNIT_MOLE[ITEM_UNIT_SIZE]; +const char UNIT_ATOM[ITEM_UNIT_SIZE]; +const char UNIT_RADIAN[ITEM_UNIT_SIZE]; +const char UNIT_REVOLUTION[ITEM_UNIT_SIZE]; +const char UNIT_DEGREE_ANGLE[ITEM_UNIT_SIZE]; +const char UNIT_MINUTE_ANGLE[ITEM_UNIT_SIZE]; +const char UNIT_SECOND_ANGLE[ITEM_UNIT_SIZE]; +const char UNIT_CENTIRADIAN[ITEM_UNIT_SIZE]; +const char UNIT_GRADE[ITEM_UNIT_SIZE]; +const char UNIT_SQUARE_METRE[ITEM_UNIT_SIZE]; +const char UNIT_ARE[ITEM_UNIT_SIZE]; +const char UNIT_HECTARE[ITEM_UNIT_SIZE]; +const char UNIT_KATAL[ITEM_UNIT_SIZE]; +const char UNIT_BIT[ITEM_UNIT_SIZE]; +const char UNIT_BYTE[ITEM_UNIT_SIZE]; +const char UNIT_SECOND[ITEM_UNIT_SIZE]; +const char UNIT_MINUTE[ITEM_UNIT_SIZE]; +const char UNIT_HOUR[ITEM_UNIT_SIZE]; +const char UNIT_DAY[ITEM_UNIT_SIZE]; +const char UNIT_WEEK[ITEM_UNIT_SIZE]; +const char UNIT_YEAR[ITEM_UNIT_SIZE]; +const char UNIT_MONTH[ITEM_UNIT_SIZE]; +const char UNIT_DAY_SIDEREAL[ITEM_UNIT_SIZE]; +const char UNIT_YEAR_SIDEREAL[ITEM_UNIT_SIZE]; +const char UNIT_YEAR_CALENDAR[ITEM_UNIT_SIZE]; +const char UNIT_POISE[ITEM_UNIT_SIZE]; +const char UNIT_FARAD[ITEM_UNIT_SIZE]; +const char UNIT_COULOMB[ITEM_UNIT_SIZE]; +const char UNIT_E[ITEM_UNIT_SIZE]; +const char UNIT_FARADAY[ITEM_UNIT_SIZE]; +const char UNIT_FRANKLIN[ITEM_UNIT_SIZE]; +const char UNIT_SIEMENS[ITEM_UNIT_SIZE]; +const char UNIT_AMPERE[ITEM_UNIT_SIZE]; +const char UNIT_GILBERT[ITEM_UNIT_SIZE]; +const char UNIT_HENRY[ITEM_UNIT_SIZE]; +const char UNIT_VOLT[ITEM_UNIT_SIZE]; +const char UNIT_CENTIVOLT[ITEM_UNIT_SIZE]; +const char UNIT_MILLIVOLT[ITEM_UNIT_SIZE]; +const char UNIT_OHM[ITEM_UNIT_SIZE]; +const char UNIT_JOULE[ITEM_UNIT_SIZE]; +const char UNIT_ERG[ITEM_UNIT_SIZE]; +const char UNIT_ELECTRON_VOLT[ITEM_UNIT_SIZE]; +const char UNIT_NEWTON[ITEM_UNIT_SIZE]; +const char UNIT_DYNE[ITEM_UNIT_SIZE]; +const char UNIT_KILOGRAM_FORCE[ITEM_UNIT_SIZE]; +const char UNIT_POUND_FORCE[ITEM_UNIT_SIZE]; +const char UNIT_HERTZ[ITEM_UNIT_SIZE]; +const char UNIT_MEGAHERTZ[ITEM_UNIT_SIZE]; +const char UNIT_GIGAHERTZ[ITEM_UNIT_SIZE]; +const char UNIT_LUX[ITEM_UNIT_SIZE]; +const char UNIT_LAMBERT[ITEM_UNIT_SIZE]; +const char UNIT_STOKE[ITEM_UNIT_SIZE]; +const char UNIT_METRE[ITEM_UNIT_SIZE]; +const char UNIT_KILOMETRE[ITEM_UNIT_SIZE]; +const char UNIT_CENTIMETRE[ITEM_UNIT_SIZE]; +const char UNIT_MILLIMETRE[ITEM_UNIT_SIZE]; +const char UNIT_FOOT[ITEM_UNIT_SIZE]; +const char UNIT_FOOT_SURVEY_US[ITEM_UNIT_SIZE]; +const char UNIT_YARD[ITEM_UNIT_SIZE]; +const char UNIT_INCH[ITEM_UNIT_SIZE]; +const char UNIT_MILE[ITEM_UNIT_SIZE]; +const char UNIT_NAUTICAL_MILE[ITEM_UNIT_SIZE]; +const char UNIT_ANGSTROM[ITEM_UNIT_SIZE]; +const char UNIT_ASTRONOMICAL_UNIT[ITEM_UNIT_SIZE]; +const char UNIT_LIGHT_YEAR[ITEM_UNIT_SIZE]; +const char UNIT_PARSEC[ITEM_UNIT_SIZE]; +const char UNIT_POINT[ITEM_UNIT_SIZE]; +const char UNIT_PIXEL[ITEM_UNIT_SIZE]; +const char UNIT_LUMEN[ITEM_UNIT_SIZE]; +const char UNIT_CANDELA[ITEM_UNIT_SIZE]; +const char UNIT_WEBER[ITEM_UNIT_SIZE]; +const char UNIT_MAXWELL[ITEM_UNIT_SIZE]; +const char UNIT_TESLA[ITEM_UNIT_SIZE]; +const char UNIT_GAUSS[ITEM_UNIT_SIZE]; +const char UNIT_KILOGRAM[ITEM_UNIT_SIZE]; +const char UNIT_GRAM[ITEM_UNIT_SIZE]; +const char UNIT_ATOMIC_MASS[ITEM_UNIT_SIZE]; +const char UNIT_ELECTRON_MASS[ITEM_UNIT_SIZE]; +const char UNIT_POUND[ITEM_UNIT_SIZE]; +const char UNIT_OUNCE[ITEM_UNIT_SIZE]; +const char UNIT_TON_US[ITEM_UNIT_SIZE]; +const char UNIT_TON_UK[ITEM_UNIT_SIZE]; +const char UNIT_METRIC_TON[ITEM_UNIT_SIZE]; +const char UNIT_WATT[ITEM_UNIT_SIZE]; +const char UNIT_HORSEPOWER[ITEM_UNIT_SIZE]; +const char UNIT_PASCAL[ITEM_UNIT_SIZE]; +const char UNIT_HECTOPASCAL[ITEM_UNIT_SIZE]; +const char UNIT_ATMOSPHERE[ITEM_UNIT_SIZE]; +const char UNIT_BAR[ITEM_UNIT_SIZE]; +const char UNIT_MILLIBAR[ITEM_UNIT_SIZE]; +const char UNIT_MILLIMETER_OF_MERCURY[ITEM_UNIT_SIZE]; +const char UNIT_INCH_OF_MERCURY[ITEM_UNIT_SIZE]; +const char UNIT_GRAY[ITEM_UNIT_SIZE]; +const char UNIT_RAD[ITEM_UNIT_SIZE]; +const char UNIT_SIEVERT[ITEM_UNIT_SIZE]; +const char UNIT_REM[ITEM_UNIT_SIZE]; +const char UNIT_BECQUEREL[ITEM_UNIT_SIZE]; +const char UNIT_CURIE[ITEM_UNIT_SIZE]; +const char UNIT_RUTHERFORD[ITEM_UNIT_SIZE]; +const char UNIT_ROENTGEN[ITEM_UNIT_SIZE]; +const char UNIT_STERADIAN[ITEM_UNIT_SIZE]; +const char UNIT_SPHERE[ITEM_UNIT_SIZE]; +const char UNIT_KELVIN[ITEM_UNIT_SIZE]; +const char UNIT_CELSIUS[ITEM_UNIT_SIZE]; +const char UNIT_RANKINE[ITEM_UNIT_SIZE]; +const char UNIT_FAHRENHEIT[ITEM_UNIT_SIZE]; +const char UNIT_METRES_PER_SECOND[ITEM_UNIT_SIZE]; +const char UNIT_MILES_PER_HOUR[ITEM_UNIT_SIZE]; +const char UNIT_KILOMETRES_PER_HOUR[ITEM_UNIT_SIZE]; +const char UNIT_KNOT[ITEM_UNIT_SIZE]; +const char UNIT_MACH[ITEM_UNIT_SIZE]; +const char UNIT_C[ITEM_UNIT_SIZE]; +const char UNIT_CUBIC_METRE[ITEM_UNIT_SIZE]; +const char UNIT_LITRE[ITEM_UNIT_SIZE]; +const char UNIT_DECILITRE[ITEM_UNIT_SIZE]; +const char UNIT_MILLILITRE[ITEM_UNIT_SIZE]; +const char UNIT_CUBIC_INCH[ITEM_UNIT_SIZE]; +const char UNIT_GALLON_DRY_US[ITEM_UNIT_SIZE]; +const char UNIT_GALLON_UK[ITEM_UNIT_SIZE]; +const char UNIT_OUNCE_LIQUID_UK[ITEM_UNIT_SIZE]; +const char UNIT_UNKNOWN[ITEM_UNIT_SIZE]; + +typedef enum { + IN, + IN_OUT, +} feed_type_t; + +char* feed_type_to_string(feed_type_t feed_type); + +const char** FEED_TYPE[ITEM_FEED_TYPE_SIZE]; + +typedef enum { NUMERIC = 0, BOOLEAN, STRING, HEX, LOCATION, ENUM, VECTOR } data_type_t; + +const char DATA_TYPE_STRING[ITEM_DATA_TYPE_SIZE]; +const char DATA_TYPE_NUMERIC[ITEM_DATA_TYPE_SIZE]; +const char DATA_TYPE_BOOLEAN[ITEM_DATA_TYPE_SIZE]; +const char DATA_TYPE_HEXADECIMAL[ITEM_DATA_TYPE_SIZE]; +const char DATA_TYPE_LOCATION[ITEM_DATA_TYPE_SIZE]; +const char DATA_TYPE_ENUM[ITEM_DATA_TYPE_SIZE]; +const char DATA_TYPE_VECTOR[ITEM_DATA_TYPE_SIZE]; + +typedef enum { + PUSH, + PULL, +} outbound_mode_t; + +const char PARAMETER_CONNECTIVITY_TYPE[PARAMETER_TYPE_SIZE]; +const char PARAMETER_OUTBOUND_DATA_MODE[PARAMETER_TYPE_SIZE]; +const char PARAMETER_OUTBOUND_DATA_RETENTION_TIME[PARAMETER_TYPE_SIZE]; +const char PARAMETER_MAXIMUM_MESSAGE_SIZE[PARAMETER_TYPE_SIZE]; +const char PARAMETER_FILE_TRANSFER_PLATFORM_ENABLED[PARAMETER_TYPE_SIZE]; +const char PARAMETER_FILE_TRANSFER_URL_ENABLED[PARAMETER_TYPE_SIZE]; +const char PARAMETER_FIRMWARE_UPDATE_ENABLED[PARAMETER_TYPE_SIZE]; +const char PARAMETER_FIRMWARE_UPDATE_CHECK_TIME[PARAMETER_TYPE_SIZE]; +const char PARAMETER_FIRMWARE_UPDATE_REPOSITORY[PARAMETER_TYPE_SIZE]; +const char PARAMETER_FIRMWARE_VERSION[PARAMETER_TYPE_SIZE]; +const char PARAMETER_GATEWAY[PARAMETER_TYPE_SIZE]; +const char PARAMETER_GATEWAY_PARENT[PARAMETER_TYPE_SIZE]; +const char PARAMETER_EXTERNAL_ID[PARAMETER_TYPE_SIZE]; +const char PARAMETER_UNKNOWN[PARAMETER_TYPE_SIZE]; + + +typedef enum { + FILE_MANAGEMENT_STATE_FILE_TRANSFER, + FILE_MANAGEMENT_STATE_FILE_READY, + FILE_MANAGEMENT_STATE_ERROR, + FILE_MANAGEMENT_STATE_ABORTED +} file_management_state_t; + +typedef enum { + FILE_MANAGEMENT_ERROR_NONE = -1, + FILE_MANAGEMENT_ERROR_UNKNOWN = 0, + FILE_MANAGEMENT_ERROR_TRANSFER_PROTOCOL_DISABLED = 1, + FILE_MANAGEMENT_ERROR_UNSUPPORTED_FILE_SIZE = 2, + FILE_MANAGEMENT_ERROR_MALFORMED_URL = 3, + FILE_MANAGEMENT_ERROR_FILE_HASH_MISMATCH = 4, + FILE_MANAGEMENT_ERROR_FILE_SYSTEM = 5, + FILE_MANAGEMENT_ERROR_RETRY_COUNT_EXCEEDED = 10 +} file_management_error_t; + +typedef struct { + file_management_state_t state; + file_management_error_t error; +} file_management_status_t; + +const char* file_management_status_as_str(file_management_status_t* status); + +#ifdef __cplusplus +} +#endif + +#endif // WOLK_TYPES_H diff --git a/sources/base64.c b/sources/utility/base64.c old mode 100644 new mode 100755 similarity index 100% rename from sources/base64.c rename to sources/utility/base64.c diff --git a/sources/base64.h b/sources/utility/base64.h old mode 100644 new mode 100755 similarity index 100% rename from sources/base64.h rename to sources/utility/base64.h diff --git a/sources/circular_buffer.c b/sources/utility/circular_buffer.c old mode 100644 new mode 100755 similarity index 99% rename from sources/circular_buffer.c rename to sources/utility/circular_buffer.c index 415b7f8..835cff3 --- a/sources/circular_buffer.c +++ b/sources/utility/circular_buffer.c @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "circular_buffer.h" +#include "utility/circular_buffer.h" #include #include diff --git a/sources/circular_buffer.h b/sources/utility/circular_buffer.h old mode 100644 new mode 100755 similarity index 100% rename from sources/circular_buffer.h rename to sources/utility/circular_buffer.h diff --git a/sources/jsmn.c b/sources/utility/jsmn.c old mode 100644 new mode 100755 similarity index 100% rename from sources/jsmn.c rename to sources/utility/jsmn.c diff --git a/sources/jsmn.h b/sources/utility/jsmn.h old mode 100644 new mode 100755 similarity index 100% rename from sources/jsmn.h rename to sources/utility/jsmn.h diff --git a/sources/utility/md5.c b/sources/utility/md5.c new file mode 100644 index 0000000..2f8b919 --- /dev/null +++ b/sources/utility/md5.c @@ -0,0 +1,198 @@ +/********************************************************************* +* Filename: md5.c +* Author: Brad Conte (brad AT bradconte.com) +* Copyright: +* Disclaimer: This code is presented "as is" without any guarantees. +* Details: Implementation of the MD5 hashing algorithm. + Algorithm specification can be found here: + * http://tools.ietf.org/html/rfc1321 + This implementation uses little endian byte order. +*********************************************************************/ + +/*************************** HEADER FILES ***************************/ +#include "md5.h" + +/****************************** MACROS ******************************/ +#define ROTLEFT(a, b) ((a << b) | (a >> (32 - b))) + +#define F(x, y, z) ((x & y) | (~x & z)) +#define G(x, y, z) ((x & z) | (y & ~z)) +#define H(x, y, z) (x ^ y ^ z) +#define I(x, y, z) (y ^ (x | ~z)) + +#define FF(a, b, c, d, m, s, t) \ + { \ + a += F(b, c, d) + m + t; \ + a = b + ROTLEFT(a, s); \ + } +#define GG(a, b, c, d, m, s, t) \ + { \ + a += G(b, c, d) + m + t; \ + a = b + ROTLEFT(a, s); \ + } +#define HH(a, b, c, d, m, s, t) \ + { \ + a += H(b, c, d) + m + t; \ + a = b + ROTLEFT(a, s); \ + } +#define II(a, b, c, d, m, s, t) \ + { \ + a += I(b, c, d) + m + t; \ + a = b + ROTLEFT(a, s); \ + } + +/*********************** FUNCTION DEFINITIONS ***********************/ +void md5_transform(MD5_CTX* ctx, const BYTE data[]) +{ + WORD a, b, c, d, m[16], i, j; + + // MD5 specifies big endian byte order, but this implementation assumes a little + // endian byte order CPU. Reverse all the bytes upon input, and re-reverse them + // on output (in md5_final()). + for (i = 0, j = 0; i < 16; ++i, j += 4) + m[i] = (data[j]) + (data[j + 1] << 8) + (data[j + 2] << 16) + (data[j + 3] << 24); + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + + FF(a, b, c, d, m[0], 7, 0xd76aa478); + FF(d, a, b, c, m[1], 12, 0xe8c7b756); + FF(c, d, a, b, m[2], 17, 0x242070db); + FF(b, c, d, a, m[3], 22, 0xc1bdceee); + FF(a, b, c, d, m[4], 7, 0xf57c0faf); + FF(d, a, b, c, m[5], 12, 0x4787c62a); + FF(c, d, a, b, m[6], 17, 0xa8304613); + FF(b, c, d, a, m[7], 22, 0xfd469501); + FF(a, b, c, d, m[8], 7, 0x698098d8); + FF(d, a, b, c, m[9], 12, 0x8b44f7af); + FF(c, d, a, b, m[10], 17, 0xffff5bb1); + FF(b, c, d, a, m[11], 22, 0x895cd7be); + FF(a, b, c, d, m[12], 7, 0x6b901122); + FF(d, a, b, c, m[13], 12, 0xfd987193); + FF(c, d, a, b, m[14], 17, 0xa679438e); + FF(b, c, d, a, m[15], 22, 0x49b40821); + + GG(a, b, c, d, m[1], 5, 0xf61e2562); + GG(d, a, b, c, m[6], 9, 0xc040b340); + GG(c, d, a, b, m[11], 14, 0x265e5a51); + GG(b, c, d, a, m[0], 20, 0xe9b6c7aa); + GG(a, b, c, d, m[5], 5, 0xd62f105d); + GG(d, a, b, c, m[10], 9, 0x02441453); + GG(c, d, a, b, m[15], 14, 0xd8a1e681); + GG(b, c, d, a, m[4], 20, 0xe7d3fbc8); + GG(a, b, c, d, m[9], 5, 0x21e1cde6); + GG(d, a, b, c, m[14], 9, 0xc33707d6); + GG(c, d, a, b, m[3], 14, 0xf4d50d87); + GG(b, c, d, a, m[8], 20, 0x455a14ed); + GG(a, b, c, d, m[13], 5, 0xa9e3e905); + GG(d, a, b, c, m[2], 9, 0xfcefa3f8); + GG(c, d, a, b, m[7], 14, 0x676f02d9); + GG(b, c, d, a, m[12], 20, 0x8d2a4c8a); + + HH(a, b, c, d, m[5], 4, 0xfffa3942); + HH(d, a, b, c, m[8], 11, 0x8771f681); + HH(c, d, a, b, m[11], 16, 0x6d9d6122); + HH(b, c, d, a, m[14], 23, 0xfde5380c); + HH(a, b, c, d, m[1], 4, 0xa4beea44); + HH(d, a, b, c, m[4], 11, 0x4bdecfa9); + HH(c, d, a, b, m[7], 16, 0xf6bb4b60); + HH(b, c, d, a, m[10], 23, 0xbebfbc70); + HH(a, b, c, d, m[13], 4, 0x289b7ec6); + HH(d, a, b, c, m[0], 11, 0xeaa127fa); + HH(c, d, a, b, m[3], 16, 0xd4ef3085); + HH(b, c, d, a, m[6], 23, 0x04881d05); + HH(a, b, c, d, m[9], 4, 0xd9d4d039); + HH(d, a, b, c, m[12], 11, 0xe6db99e5); + HH(c, d, a, b, m[15], 16, 0x1fa27cf8); + HH(b, c, d, a, m[2], 23, 0xc4ac5665); + + II(a, b, c, d, m[0], 6, 0xf4292244); + II(d, a, b, c, m[7], 10, 0x432aff97); + II(c, d, a, b, m[14], 15, 0xab9423a7); + II(b, c, d, a, m[5], 21, 0xfc93a039); + II(a, b, c, d, m[12], 6, 0x655b59c3); + II(d, a, b, c, m[3], 10, 0x8f0ccc92); + II(c, d, a, b, m[10], 15, 0xffeff47d); + II(b, c, d, a, m[1], 21, 0x85845dd1); + II(a, b, c, d, m[8], 6, 0x6fa87e4f); + II(d, a, b, c, m[15], 10, 0xfe2ce6e0); + II(c, d, a, b, m[6], 15, 0xa3014314); + II(b, c, d, a, m[13], 21, 0x4e0811a1); + II(a, b, c, d, m[4], 6, 0xf7537e82); + II(d, a, b, c, m[11], 10, 0xbd3af235); + II(c, d, a, b, m[2], 15, 0x2ad7d2bb); + II(b, c, d, a, m[9], 21, 0xeb86d391); + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; +} + +void md5_init(MD5_CTX* ctx) +{ + ctx->datalen = 0; + ctx->bitlen = 0; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +void md5_update(MD5_CTX* ctx, const BYTE data[], size_t len) +{ + size_t i; + + for (i = 0; i < len; ++i) { + ctx->data[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 64) { + md5_transform(ctx, ctx->data); + ctx->bitlen += 512; + ctx->datalen = 0; + } + } +} + +void md5_final(MD5_CTX* ctx, BYTE hash[]) +{ + size_t i; + + i = ctx->datalen; + + // Pad whatever data is left in the buffer. + if (ctx->datalen < 56) { + ctx->data[i++] = 0x80; + while (i < 56) + ctx->data[i++] = 0x00; + } else if (ctx->datalen >= 56) { + ctx->data[i++] = 0x80; + while (i < 64) + ctx->data[i++] = 0x00; + md5_transform(ctx, ctx->data); + memset(ctx->data, 0, 56); + } + + // Append to the padding the total message's length in bits and transform. + ctx->bitlen += ctx->datalen * 8; + ctx->data[56] = ctx->bitlen; + ctx->data[57] = ctx->bitlen >> 8; + ctx->data[58] = ctx->bitlen >> 16; + ctx->data[59] = ctx->bitlen >> 24; + ctx->data[60] = ctx->bitlen >> 32; + ctx->data[61] = ctx->bitlen >> 40; + ctx->data[62] = ctx->bitlen >> 48; + ctx->data[63] = ctx->bitlen >> 56; + md5_transform(ctx, ctx->data); + + // Since this implementation uses little endian byte ordering and MD uses big endian, + // reverse all the bytes when copying the final state to the output hash. + for (i = 0; i < 4; ++i) { + hash[i] = (ctx->state[0] >> (i * 8)) & 0x000000ff; + hash[i + 4] = (ctx->state[1] >> (i * 8)) & 0x000000ff; + hash[i + 8] = (ctx->state[2] >> (i * 8)) & 0x000000ff; + hash[i + 12] = (ctx->state[3] >> (i * 8)) & 0x000000ff; + } +} diff --git a/sources/utility/md5.h b/sources/utility/md5.h new file mode 100644 index 0000000..1bc8f67 --- /dev/null +++ b/sources/utility/md5.h @@ -0,0 +1,36 @@ +/********************************************************************* + * Filename: md5.h + * Author: Brad Conte (brad AT bradconte.com) + * Copyright: + * Disclaimer: This code is presented "as is" without any guarantees. + * Details: Defines the API for the corresponding MD5 implementation. + *********************************************************************/ + +#ifndef WOLKCONNECTOR_C_MD5_H +#define WOLKCONNECTOR_C_MD5_H + +/*************************** HEADER FILES ***************************/ +#include +#include +#include + +/****************************** MACROS ******************************/ +#define MD5_BLOCK_SIZE 32 // MD5 outputs a 32 byte digest +typedef unsigned char BYTE; // 8-bit byte +typedef unsigned int WORD; // 32-bit word, change to "long" for 16-bit machines + +/**************************** DATA TYPES ****************************/ + +typedef struct { + BYTE data[64]; + WORD datalen; + unsigned long long bitlen; + WORD state[4]; +} MD5_CTX; + +/*********************** FUNCTION DECLARATIONS **********************/ +void md5_init(MD5_CTX* ctx); +void md5_update(MD5_CTX* ctx, const BYTE data[], size_t len); +void md5_final(MD5_CTX* ctx, BYTE hash[]); + +#endif // WOLKCONNECTOR_C_MD5_H diff --git a/sources/sha256.c b/sources/utility/sha256.c old mode 100644 new mode 100755 similarity index 100% rename from sources/sha256.c rename to sources/utility/sha256.c diff --git a/sources/sha256.h b/sources/utility/sha256.h old mode 100644 new mode 100755 similarity index 100% rename from sources/sha256.h rename to sources/utility/sha256.h diff --git a/sources/wolk_utils.h b/sources/utility/wolk_utils.h old mode 100644 new mode 100755 similarity index 100% rename from sources/wolk_utils.h rename to sources/utility/wolk_utils.h diff --git a/sources/version.h b/sources/version.h new file mode 100644 index 0000000..a1a0189 --- /dev/null +++ b/sources/version.h @@ -0,0 +1,25 @@ +/* + * Copyright 2022 WolkAbout Technology s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef VERSION_H +#define VERSION_H + +/** + * @brief Library versioning + */ +enum { WOLK_VERSION_MAJOR = 5, WOLK_VERSION_MINOR = 0, WOLK_VERSION_PATCH = 0 }; + +#endif // VERSION_H diff --git a/sources/wolk_connector.c b/sources/wolk_connector.c index 80e119f..ec114fa 100644 --- a/sources/wolk_connector.c +++ b/sources/wolk_connector.c @@ -1,5 +1,5 @@ /* - * Copyright 2018 WolkAbout Technology s.r.o. + * Copyright 2022 WolkAbout Technology s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,16 +16,15 @@ #include "wolk_connector.h" #include "MQTTPacket.h" -#include "actuator_command.h" -#include "file_management.h" -#include "file_management_parameter.h" -#include "firmware_update.h" -#include "in_memory_persistence.h" -#include "outbound_message.h" -#include "outbound_message_factory.h" -#include "parser.h" -#include "persistence.h" -#include "wolk_utils.h" +#include "model/file_management/file_management.h" +#include "model/file_management/file_management_parameter.h" +#include "model/firmware_update.h" +#include "model/outbound_message.h" +#include "model/outbound_message_factory.h" +#include "persistence/in_memory_persistence.h" +#include "persistence/persistence.h" +#include "protocol/parser.h" +#include "utility/wolk_utils.h" #include #include @@ -33,54 +32,30 @@ #define MQTT_KEEP_ALIVE_INTERVAL 60 // Unit: s -#define PING_KEEP_ALIVE_INTERVAL (10 * 1000) // Unit: ms - -static const char* PONG_TOPIC = "pong/"; - -static const char* LASTWILL_TOPIC = "lastwill/"; -static char* LASTWILL_MESSAGE = "Gone offline"; - -static const char* ACTUATOR_COMMANDS_TOPIC = "p2d/actuator_set/d/"; - -static const char* CONFIGURATION_COMMANDS = "p2d/configuration_set/d/"; - -static const char* FILE_MANAGEMENT_UPLOAD_INITIATE_TOPIC = "p2d/file_upload_initiate/d/"; -static const char* FILE_MANAGEMENT_CHUNK_UPLOAD_TOPIC = "p2d/file_binary_response/d/"; -static const char* FILE_MANAGEMENT_UPLOAD_ABORT_TOPIC = "p2d/file_upload_abort/d/"; - -static const char* FILE_MANAGEMENT_URL_DOWNLOAD_INITIATE_TOPIC = "p2d/file_url_download_initiate/d/"; -static const char* FILE_MANAGEMENT_URL_DOWNLOAD_ABORT_TOPIC = "p2d/file_url_download_abort/d/"; - -static const char* FILE_MANAGEMENT_FILE_DELETE_TOPIC = "p2d/file_delete/d/"; -static const char* FILE_MANAGEMENT_FILE_PURGE_TOPIC = "p2d/file_purge/d/"; - -static const char* FIRMWARE_UPDATE_INSTALL_TOPIC = "p2d/firmware_update_install/d/"; -static const char* FIRMWARE_UPDATE_ABORT_TOPIC = "p2d/firmware_update_abort/d/"; - static WOLK_ERR_T mqtt_keep_alive(wolk_ctx_t* ctx, uint64_t tick); -static WOLK_ERR_T ping_keep_alive(wolk_ctx_t* ctx, uint64_t tick); static WOLK_ERR_T receive(wolk_ctx_t* ctx); static WOLK_ERR_T publish(wolk_ctx_t* ctx, outbound_message_t* outbound_message); static WOLK_ERR_T subscribe(wolk_ctx_t* ctx, const char* topic); -static void parser_init_parameters(wolk_ctx_t* ctx, protocol_t protocol); - static bool is_wolk_initialized(wolk_ctx_t* ctx); -static void handle_actuator_command(wolk_ctx_t* ctx, actuator_command_t* actuator_command); -static void handle_configuration_command(wolk_ctx_t* ctx, configuration_command_t* configuration_command); +static void handle_feeds(wolk_ctx_t* ctx, feed_t* feeds, size_t number_of_feeds); +static void handle_parameter_message(wolk_ctx_t* ctx, parameter_t* parameter_message, size_t number_of_parameters); static void handle_utc_command(wolk_ctx_t* ctx, utc_command_t* utc); +static void handle_details_synchronization_message(wolk_ctx_t* ctx, feed_registration_t* feeds, size_t number_of_feeds, + attribute_t* attributes, size_t number_of_attributes); +static void handle_error_message(wolk_ctx_t* ctx, char* error); static void handle_file_management_parameter(file_management_t* file_management, file_management_parameter_t* file_management_parameter); static void handle_file_management_packet(file_management_t* file_management, uint8_t* packet, size_t packet_size); -static void handle_file_management_abort(file_management_t* file_management); -static void handle_file_management_url_download(file_management_t* file_management, - file_management_parameter_t* parameter); -static void handle_file_management_file_delete(file_management_t* file_management, - file_management_parameter_t* parameter); +static void handle_file_management_abort(file_management_t* file_management, uint8_t* packet, size_t packet_size); +static void handle_file_management_url_download(file_management_t* file_management, char* url_download); +static void handle_file_management_file_list(file_management_t* file_management); +static void handle_file_management_file_delete(file_management_t* file_management, file_list_t* file_list, + size_t number_of_files); static void handle_file_management_file_purge(file_management_t* file_management); static void listener_file_management_on_status(file_management_t* file_management, file_management_status_t status); @@ -89,22 +64,21 @@ static void listener_file_management_on_packet_request(file_management_t* file_m static void listener_file_management_on_url_download_status(file_management_t* file_management, file_management_status_t status); -static void listener_file_management_on_file_list_status(file_management_t* file_management, char* file_list, +static void listener_file_management_on_file_list_status(file_management_t* file_management, file_list_t* file_list, size_t file_list_items); static void listener_firmware_update_on_status(firmware_update_t* firmware_update); -static void listener_firmware_update_on_version(firmware_update_t* firmware_update, char* firmware_update_version); static void listener_firmware_update_on_verification(firmware_update_t* firmware_update); static void handle_firmware_update_installation(firmware_update_t* firmware_update, firmware_update_t* parameter); static void handle_firmware_update_abort(firmware_update_t* firmware_update); +static WOLK_ERR_T subscribe_to(wolk_ctx_t* ctx, char message_type[TOPIC_MESSAGE_TYPE_SIZE]); -WOLK_ERR_T wolk_init(wolk_ctx_t* ctx, send_func_t snd_func, recv_func_t rcv_func, actuation_handler_t actuation_handler, - actuator_status_provider_t actuator_status_provider, configuration_handler_t configuration_handler, - configuration_provider_t configuration_provider, const char* device_key, - const char* device_password, protocol_t protocol, const char** actuator_references, - uint32_t num_actuator_references) +WOLK_ERR_T wolk_init(wolk_ctx_t* ctx, send_func_t snd_func, recv_func_t rcv_func, const char* device_key, + const char* device_password, outbound_mode_t outbound_mode, feed_handler_t feed_handler, + parameter_handler_t parameter_handler, + details_synchronization_handler_t details_synchronization_handler) { /* Sanity check */ WOLK_ASSERT(snd_func != NULL); @@ -116,18 +90,6 @@ WOLK_ERR_T wolk_init(wolk_ctx_t* ctx, send_func_t snd_func, recv_func_t rcv_func WOLK_ASSERT(strlen(device_key) < DEVICE_KEY_SIZE); WOLK_ASSERT(strlen(device_password) < DEVICE_PASSWORD_SIZE); - WOLK_ASSERT(protocol == PROTOCOL_WOLKABOUT); - - if (num_actuator_references > 0 && (actuation_handler == NULL || actuator_status_provider == NULL)) { - WOLK_ASSERT(false); - return W_TRUE; - } - - if ((configuration_handler != NULL && configuration_provider == NULL) - || (configuration_handler == NULL && configuration_provider != NULL)) { - WOLK_ASSERT(false); - return W_TRUE; - } /* Sanity check */ MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer; @@ -154,20 +116,14 @@ WOLK_ERR_T wolk_init(wolk_ctx_t* ctx, send_func_t snd_func, recv_func_t rcv_func ctx->connectData.username.cstring = &ctx->device_key[0]; ctx->connectData.password.cstring = &ctx->device_password[0]; - ctx->actuation_handler = actuation_handler; - ctx->actuator_status_provider = actuator_status_provider; - - ctx->configuration_handler = configuration_handler; - ctx->configuration_provider = configuration_provider; + ctx->feed_handler = feed_handler; + ctx->parameter_handler = parameter_handler; + ctx->details_synchronization_handler = details_synchronization_handler; - ctx->protocol = protocol; - parser_init_parameters(ctx, protocol); + ctx->outbound_mode = outbound_mode; - ctx->actuator_references = actuator_references; - ctx->num_actuator_references = num_actuator_references; + parser_init(&ctx->parser); - ctx->is_keep_ping_alive_enabled = true; - ctx->milliseconds_since_last_ping_keep_alive = PING_KEEP_ALIVE_INTERVAL; ctx->utc = 0; ctx->is_initialized = true; @@ -201,18 +157,21 @@ WOLK_ERR_T wolk_init_file_management( file_management_remove_file_t remove_file, file_management_purge_files_t purge_files) { if (chunk_size > (PAYLOAD_SIZE - 4 * FILE_MANAGEMENT_HASH_SIZE)) { - chunk_size = PAYLOAD_SIZE - 4 * FILE_MANAGEMENT_HASH_SIZE; + printf("Failed to accept defined chunk size. It is higher than payload size. See size_definition.h file!\n"); + return W_TRUE; } - file_management_init(&ctx->file_management, ctx->device_key, maximum_file_size, chunk_size, start, write_chunk, - read_chunk, abort, finalize, start_url_download, is_url_download_done, get_file_list, - remove_file, purge_files, ctx); + if (!file_management_init(ctx, &ctx->file_management, ctx->device_key, maximum_file_size, chunk_size, start, + write_chunk, read_chunk, abort, finalize, start_url_download, is_url_download_done, + get_file_list, remove_file, purge_files)) + return W_TRUE; file_management_set_on_status_listener(&ctx->file_management, listener_file_management_on_status); file_management_set_on_packet_request_listener(&ctx->file_management, listener_file_management_on_packet_request); file_management_set_on_url_download_status_listener(&ctx->file_management, listener_file_management_on_url_download_status); file_management_set_on_file_list_listener(&ctx->file_management, listener_file_management_on_file_list_status); + return W_FALSE; } @@ -220,37 +179,17 @@ WOLK_ERR_T wolk_init_firmware_update(wolk_ctx_t* ctx, firmware_update_start_inst firmware_update_is_installation_completed_t is_installation_completed, firmware_update_verification_store_t verification_store, firmware_update_verification_read_t verification_read, - firmware_update_get_version_t get_version, firmware_update_abort_t abort_installation) { firmware_update_init(&ctx->firmware_update, start_installation, is_installation_completed, verification_store, - verification_read, get_version, abort_installation, ctx); + verification_read, abort_installation, ctx); firmware_update_set_on_status_listener(&ctx->firmware_update, listener_firmware_update_on_status); - firmware_update_set_on_version_listener(&ctx->firmware_update, listener_firmware_update_on_version); firmware_update_set_on_verification_listener(&ctx->firmware_update, listener_firmware_update_on_verification); return W_FALSE; } -WOLK_ERR_T wolk_enable_ping_keep_alive(wolk_ctx_t* ctx) -{ - /* Sanity check */ - WOLK_ASSERT(ctx); - - ctx->is_keep_ping_alive_enabled = true; - return W_FALSE; -} - -WOLK_ERR_T wolk_disable_ping_keep_alive(wolk_ctx_t* ctx) -{ - /* Sanity check */ - WOLK_ASSERT(ctx); - - ctx->is_keep_ping_alive_enabled = false; - return W_FALSE; -} - WOLK_ERR_T wolk_connect(wolk_ctx_t* ctx) { /* Sanity check */ @@ -261,169 +200,43 @@ WOLK_ERR_T wolk_connect(wolk_ctx_t* ctx) char topic_buf[TOPIC_SIZE]; /* Setup and Connect to MQTT */ - char lastwill_topic[TOPIC_SIZE]; - MQTTString lastwill_topic_string = MQTTString_initializer; - MQTTString lastwill_message_string = MQTTString_initializer; - - memset(lastwill_topic, 0, TOPIC_SIZE); - strcpy(lastwill_topic, LASTWILL_TOPIC); - strcat(lastwill_topic, ctx->device_key); - - lastwill_topic_string.cstring = lastwill_topic; - lastwill_message_string.cstring = LASTWILL_MESSAGE; - - ctx->connectData.will.topicName = lastwill_topic_string; - ctx->connectData.will.message = lastwill_message_string; - ctx->connectData.willFlag = 1; int len = MQTTSerialize_connect((unsigned char*)buf, sizeof(buf), &ctx->connectData); if (transmission_buffer(ctx->sock, (unsigned char*)buf, len) == TRANSPORT_DONE) { return W_TRUE; } - /* Enable PING Keepalive */ - wolk_enable_ping_keep_alive(ctx); - - /* Subscribe to PONG */ - memset(topic_buf, '\0', sizeof(topic_buf)); - strcpy(&topic_buf[0], PONG_TOPIC); - strcat(&topic_buf[0], ctx->device_key); - - if (subscribe(ctx, topic_buf) != W_FALSE) { - return W_TRUE; - } - - /* Subscribe to ACTUATORS */ - for (i = 0; i < ctx->num_actuator_references; ++i) { - const char* reference = ctx->actuator_references[i]; - memset(topic_buf, '\0', sizeof(topic_buf)); - - strcpy(&topic_buf[0], ACTUATOR_COMMANDS_TOPIC); - strcat(&topic_buf[0], ctx->device_key); - strcat(&topic_buf[0], "/r/"); - strcat(&topic_buf[0], reference); - - if (subscribe(ctx, topic_buf) != W_FALSE) { - return W_TRUE; - } - } - - /* Subscribe to CONFIGURATION */ - memset(topic_buf, '\0', sizeof(topic_buf)); - strcpy(&topic_buf[0], CONFIGURATION_COMMANDS); - strcat(&topic_buf[0], ctx->device_key); - - if (subscribe(ctx, topic_buf) != W_FALSE) { - return W_TRUE; - } - - /* Subscribe to FILE MANAGEMENT */ - memset(topic_buf, '\0', sizeof(topic_buf)); - strcpy(&topic_buf[0], FILE_MANAGEMENT_UPLOAD_INITIATE_TOPIC); - strcat(&topic_buf[0], ctx->device_key); - - if (subscribe(ctx, topic_buf) != W_FALSE) { - return W_TRUE; - } - - memset(topic_buf, '\0', sizeof(topic_buf)); - strcpy(&topic_buf[0], FILE_MANAGEMENT_CHUNK_UPLOAD_TOPIC); - strcat(&topic_buf[0], ctx->device_key); - - if (subscribe(ctx, topic_buf) != W_FALSE) { - return W_TRUE; - } - - memset(topic_buf, '\0', sizeof(topic_buf)); - strcpy(&topic_buf[0], FILE_MANAGEMENT_UPLOAD_ABORT_TOPIC); - strcat(&topic_buf[0], ctx->device_key); - - if (subscribe(ctx, topic_buf) != W_FALSE) { - return W_TRUE; - } - - memset(topic_buf, '\0', sizeof(topic_buf)); - strcpy(&topic_buf[0], FILE_MANAGEMENT_URL_DOWNLOAD_INITIATE_TOPIC); - strcat(&topic_buf[0], ctx->device_key); - - if (subscribe(ctx, topic_buf) != W_FALSE) { - return W_TRUE; - } - - memset(topic_buf, '\0', sizeof(topic_buf)); - strcpy(&topic_buf[0], FILE_MANAGEMENT_URL_DOWNLOAD_ABORT_TOPIC); - strcat(&topic_buf[0], ctx->device_key); + /* Subscribe to topics */ + subscribe_to(ctx, ctx->parser.FEED_VALUES_MESSAGE_TOPIC); + subscribe_to(ctx, ctx->parser.PARAMETERS_TOPIC); + subscribe_to(ctx, ctx->parser.SYNC_TIME_TOPIC); + subscribe_to(ctx, ctx->parser.ERROR_TOPIC); + subscribe_to(ctx, ctx->parser.DETAILS_SYNCHRONIZATION_TOPIC); - if (subscribe(ctx, topic_buf) != W_FALSE) { - return W_TRUE; - } - - memset(topic_buf, '\0', sizeof(topic_buf)); - strcpy(&topic_buf[0], FILE_MANAGEMENT_FILE_DELETE_TOPIC); - strcat(&topic_buf[0], ctx->device_key); - - if (subscribe(ctx, topic_buf) != W_FALSE) { - return W_TRUE; - } + subscribe_to(ctx, ctx->parser.FILE_MANAGEMENT_UPLOAD_INITIATE_TOPIC); + subscribe_to(ctx, ctx->parser.FILE_MANAGEMENT_BINARY_RESPONSE_TOPIC); + subscribe_to(ctx, ctx->parser.FILE_MANAGEMENT_UPLOAD_ABORT_TOPIC); + subscribe_to(ctx, ctx->parser.FILE_MANAGEMENT_URL_DOWNLOAD_INITIATE_TOPIC); + subscribe_to(ctx, ctx->parser.FILE_MANAGEMENT_URL_DOWNLOAD_ABORT_TOPIC); + subscribe_to(ctx, ctx->parser.FILE_MANAGEMENT_FILE_LIST_TOPIC); + subscribe_to(ctx, ctx->parser.FILE_MANAGEMENT_FILE_DELETE_TOPIC); + subscribe_to(ctx, ctx->parser.FILE_MANAGEMENT_FILE_PURGE_TOPIC); - memset(topic_buf, '\0', sizeof(topic_buf)); - strcpy(&topic_buf[0], FILE_MANAGEMENT_FILE_PURGE_TOPIC); - strcat(&topic_buf[0], ctx->device_key); + subscribe_to(ctx, ctx->parser.FIRMWARE_UPDATE_INSTALL_TOPIC); + subscribe_to(ctx, ctx->parser.FIRMWARE_UPDATE_ABORT_TOPIC); if (subscribe(ctx, topic_buf) != W_FALSE) { return W_TRUE; } - /* Firmware Update */ - memset(topic_buf, '\0', sizeof(topic_buf)); - strcpy(&topic_buf[0], FIRMWARE_UPDATE_INSTALL_TOPIC); - strcat(&topic_buf[0], ctx->device_key); - - if (subscribe(ctx, topic_buf) != W_FALSE) { - return W_TRUE; - } - - memset(topic_buf, '\0', sizeof(topic_buf)); - strcpy(&topic_buf[0], FIRMWARE_UPDATE_ABORT_TOPIC); - strcat(&topic_buf[0], ctx->device_key); - - if (subscribe(ctx, topic_buf) != W_FALSE) { - return W_TRUE; - } - - /* Publish initial values */ - for (i = 0; i < ctx->num_actuator_references; ++i) { - const char* reference = ctx->actuator_references[i]; - - actuator_status_t actuator_status = ctx->actuator_status_provider(reference); - outbound_message_t outbound_message; - if (!outbound_message_make_from_actuator_status(&ctx->parser, ctx->device_key, &actuator_status, reference, - &outbound_message)) { - continue; - } - - if (publish(ctx, &outbound_message) != W_FALSE) { - persistence_push(&ctx->persistence, &outbound_message); - } - } - - configuration_command_t configuration_command; - configuration_command_init(&configuration_command, CONFIGURATION_COMMAND_TYPE_GET); - handle_configuration_command(ctx, &configuration_command); - - char file_list[FILE_MANAGEMENT_FILE_LIST_SIZE][FILE_MANAGEMENT_FILE_NAME_SIZE] = {0}; + file_list_t file_list[FILE_MANAGEMENT_FILE_LIST_SIZE] = {0}; if (ctx->file_management.has_valid_configuration) { - listener_file_management_on_file_list_status(&ctx->file_management, file_list, ctx->file_management.get_file_list(file_list)); } - char firmware_update_version[FIRMWARE_UPDATE_VERSION_SIZE] = {0}; if (ctx->firmware_update.is_initialized) { listener_firmware_update_on_verification(&ctx->firmware_update); - - ctx->firmware_update.get_version(firmware_update_version); - listener_firmware_update_on_version(&ctx->firmware_update, firmware_update_version); } return W_FALSE; @@ -434,33 +247,11 @@ WOLK_ERR_T wolk_disconnect(wolk_ctx_t* ctx) /* Sanity check */ WOLK_ASSERT(is_wolk_initialized(ctx)); - unsigned char buf[MQTT_PACKET_SIZE]; - memset(buf, 0, MQTT_PACKET_SIZE); - - /* lastwill message */ - MQTTString lastwill_topic_string = MQTTString_initializer; - MQTTString lastwill_message_string = MQTTString_initializer; - - char lastwill_topic[TOPIC_SIZE]; - memset(lastwill_topic, 0, TOPIC_SIZE); - strcpy(lastwill_topic, LASTWILL_TOPIC); - strcat(lastwill_topic, ctx->device_key); - - lastwill_topic_string.cstring = lastwill_topic; - lastwill_message_string.cstring = LASTWILL_MESSAGE; - - int len = - MQTTSerialize_publish(buf, MQTT_PACKET_SIZE, 0, 1, 0, 0, lastwill_topic_string, lastwill_message_string.cstring, - (int)strlen((const char*)lastwill_message_string.cstring)); - if (transmission_buffer(ctx->sock, (unsigned char*)buf, len) == TRANSPORT_DONE) { - return W_TRUE; - } - - memset(buf, 0, MQTT_PACKET_SIZE); + unsigned char buf[MQTT_PACKET_SIZE] = ""; /* disconnect message */ - len = MQTTSerialize_disconnect(buf, sizeof(buf)); - if (transmission_buffer(ctx->sock, buf, len) == TRANSPORT_DONE) { + int length = MQTTSerialize_disconnect(buf, sizeof(buf)); + if (transmission_buffer(ctx->sock, buf, length) == TRANSPORT_DONE) { return W_TRUE; } @@ -476,10 +267,6 @@ WOLK_ERR_T wolk_process(wolk_ctx_t* ctx, uint64_t tick) return W_TRUE; } - if (ping_keep_alive(ctx, tick) != W_FALSE) { - return W_TRUE; - } - if (receive(ctx) != W_FALSE) { return W_TRUE; } @@ -490,232 +277,287 @@ WOLK_ERR_T wolk_process(wolk_ctx_t* ctx, uint64_t tick) return W_FALSE; } -WOLK_ERR_T wolk_add_string_sensor_reading(wolk_ctx_t* ctx, const char* reference, const char* value, uint64_t utc_time) +WOLK_ERR_T wolk_init_feed(feed_registration_t* feed, char* name, const char* reference, const char* unit, + const feed_type_t feedType) +{ + feed_initialize_registration(feed, name, reference, unit, feedType); + + return W_FALSE; +} + +WOLK_ERR_T wolk_add_string_feed(wolk_ctx_t* ctx, const char* reference, wolk_string_feeds_t* feeds, + size_t number_of_feeds) { /* Sanity check */ WOLK_ASSERT(is_wolk_initialized(ctx)); + WOLK_ASSERT(is_wolk_initialized(reference)); + WOLK_ASSERT(is_wolk_initialized(feeds)); + WOLK_ASSERT(is_wolk_initialized(number_of_feeds)); + WOLK_ASSERT(number_of_feeds > FEEDS_MAX_NUMBER); + + feed_t feed; + feed_initialize(&feed, number_of_feeds, reference); + + for (size_t i = 0; i < number_of_feeds; ++i) { + if (feeds->utc_time < 1000000000000 && feeds->utc_time != 0) // Unit ms and zero is valid value + { + printf("Failed UTC attached to feed with reference %s. It has to be in ms!\n", reference); + return W_TRUE; + } - manifest_item_t string_sensor; - manifest_item_init(&string_sensor, reference, READING_TYPE_SENSOR, DATA_TYPE_STRING); + feed_set_data_at(&feed, feeds->value, i); + feed_set_utc(&feed, feeds->utc_time); - reading_t reading; - reading_init(&reading, &string_sensor); - reading_set_data(&reading, value); - reading_set_rtc(&reading, utc_time); + feeds++; + } - outbound_message_t outbound_message; - outbound_message_make_from_readings(&ctx->parser, ctx->device_key, &reading, 1, &outbound_message); + outbound_message_t outbound_message = {0}; + outbound_message_make_from_feeds(&ctx->parser, ctx->device_key, &feed, STRING, number_of_feeds, 1, + &outbound_message); return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; } -WOLK_ERR_T wolk_add_multi_value_string_sensor_reading(wolk_ctx_t* ctx, const char* reference, - const char (*values)[READING_SIZE], uint16_t values_size, - uint64_t utc_time) +WOLK_ERR_T wolk_add_numeric_feed(wolk_ctx_t* ctx, const char* reference, wolk_numeric_feeds_t* feeds, + size_t number_of_feeds) { /* Sanity check */ WOLK_ASSERT(is_wolk_initialized(ctx)); - WOLK_ASSERT(READING_DIMENSIONS > 1); + WOLK_ASSERT(is_wolk_initialized(reference)); + WOLK_ASSERT(is_wolk_initialized(feeds)); + WOLK_ASSERT(is_wolk_initialized(number_of_feeds)); + WOLK_ASSERT(number_of_feeds > FEEDS_MAX_NUMBER); + + char value_string[FEED_ELEMENT_SIZE] = ""; + feed_t feed; + feed_initialize(&feed, number_of_feeds, reference); + + for (size_t i = 0; i < number_of_feeds; ++i) { + if (feeds->utc_time < 1000000000000 && feeds->utc_time != 0) // Unit ms and zero is valid value + { + printf("Failed UTC attached to feed with reference %s. It has to be in ms!\n", reference); + return W_TRUE; + } - manifest_item_t string_sensor; - manifest_item_init(&string_sensor, reference, READING_TYPE_SENSOR, DATA_TYPE_STRING); - manifest_item_set_reading_dimensions_and_delimiter(&string_sensor, values_size, DATA_DELIMITER); + if (!snprintf(value_string, FEED_ELEMENT_SIZE, "%2f", feeds->value)) { + return W_TRUE; + } - reading_t reading; - reading_init(&reading, &string_sensor); - reading_set_rtc(&reading, utc_time); + feed_set_data_at(&feed, value_string, i); + feed_set_utc(&feed, feeds->utc_time); - for (uint32_t i = 0; i < values_size; ++i) { - reading_set_data_at(&reading, values[i], i); + feeds++; } - outbound_message_t outbound_message; - outbound_message_make_from_readings(&ctx->parser, ctx->device_key, &reading, 1, &outbound_message); + outbound_message_t outbound_message = {0}; + outbound_message_make_from_feeds(&ctx->parser, ctx->device_key, &feed, NUMERIC, number_of_feeds, 1, + &outbound_message); return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; } -WOLK_ERR_T wolk_add_numeric_sensor_reading(wolk_ctx_t* ctx, const char* reference, double value, uint64_t utc_time) +WOLK_ERR_T wolk_add_multi_value_numeric_feed(wolk_ctx_t* ctx, const char* reference, double* values, + uint16_t value_size, uint64_t utc_time) { /* Sanity check */ WOLK_ASSERT(is_wolk_initialized(ctx)); + WOLK_ASSERT(value_size > FEEDS_MAX_NUMBER); - manifest_item_t numeric_sensor; - manifest_item_init(&numeric_sensor, reference, READING_TYPE_SENSOR, DATA_TYPE_NUMERIC); - - char value_str[READING_SIZE]; - memset(value_str, 0, sizeof(value_str)); - if (!snprintf(value_str, READING_SIZE, "%f", value)) { + if (utc_time < 1000000000000 && utc_time != 0) // Unit ms and zero is valid value + { + printf("Failed UTC attached to feeds. It has to be in ms!\n"); return W_TRUE; } - reading_t reading; - reading_init(&reading, &numeric_sensor); - reading_set_data(&reading, value_str); - reading_set_rtc(&reading, utc_time); + feed_t feed; + feed_initialize(&feed, 1, reference); // one feed consisting of N numeric values + feed_set_utc(&feed, utc_time); - outbound_message_t outbound_message; - outbound_message_make_from_readings(&ctx->parser, ctx->device_key, &reading, 1, &outbound_message); + char value_string_representation[FEED_ELEMENT_SIZE] = ""; + for (size_t i = 0; i < value_size; ++i) { + if (!snprintf(value_string_representation, FEED_ELEMENT_SIZE, "%f", values[i])) { + return W_TRUE; + } + + feed_set_data_at(&feed, value_string_representation, i); + } + + outbound_message_t outbound_message = {0}; + outbound_message_make_from_feeds(&ctx->parser, ctx->device_key, &feed, VECTOR, 1, value_size, &outbound_message); return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; } -WOLK_ERR_T wolk_add_multi_value_numeric_sensor_reading(wolk_ctx_t* ctx, const char* reference, double* values, - uint16_t values_size, uint64_t utc_time) +WOLK_ERR_T wolk_add_bool_feeds(wolk_ctx_t* ctx, const char* reference, wolk_boolean_feeds_t* feeds, + size_t number_of_feeds) { /* Sanity check */ WOLK_ASSERT(is_wolk_initialized(ctx)); - WOLK_ASSERT(READING_DIMENSIONS > 1); - - manifest_item_t numeric_sensor; - manifest_item_init(&numeric_sensor, reference, READING_TYPE_SENSOR, DATA_TYPE_NUMERIC); - manifest_item_set_reading_dimensions_and_delimiter(&numeric_sensor, values_size, DATA_DELIMITER); - reading_t reading; - reading_init(&reading, &numeric_sensor); - reading_set_rtc(&reading, utc_time); + feed_t feed; + feed_initialize(&feed, number_of_feeds, reference); - for (uint32_t i = 0; i < values_size; ++i) { - char value_str[READING_SIZE]; - memset(value_str, 0, sizeof(value_str)); - if (!snprintf(value_str, READING_SIZE, "%f", values[i])) { + for (size_t i = 0; i < number_of_feeds; ++i) { + if (feeds->utc_time < 1000000000000 && feeds->utc_time != 0) // Unit ms and zero is valid value + { + printf("Failed UTC attached to feed with reference %s. It has to be in ms!\n", reference); return W_TRUE; } - reading_set_data_at(&reading, value_str, i); + feed_set_data_at(&feed, BOOL_TO_STR(feeds->value), i); + feed_set_utc(&feed, feeds->utc_time); + + feeds++; } - outbound_message_t outbound_message; - outbound_message_make_from_readings(&ctx->parser, ctx->device_key, &reading, 1, &outbound_message); + outbound_message_t outbound_message = {0}; + outbound_message_make_from_feeds(&ctx->parser, ctx->device_key, &feed, BOOLEAN, number_of_feeds, 1, + &outbound_message); return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; } -WOLK_ERR_T wolk_add_bool_sensor_reading(wolk_ctx_t* ctx, const char* reference, bool value, uint64_t utc_time) + +WOLK_ERR_T wolk_publish(wolk_ctx_t* ctx) { /* Sanity check */ WOLK_ASSERT(is_wolk_initialized(ctx)); - manifest_item_t bool_sensor; - manifest_item_init(&bool_sensor, reference, READING_TYPE_SENSOR, DATA_TYPE_BOOLEAN); + uint16_t i; + outbound_message_t outbound_message = {0}; + + for (i = 0; i < PUBLISH_BATCH_SIZE; ++i) { + if (persistence_is_empty(&ctx->persistence)) { + return W_FALSE; + } - reading_t reading; - reading_init(&reading, &bool_sensor); - reading_set_data(&reading, BOOL_TO_STR(value)); - reading_set_rtc(&reading, utc_time); + if (!persistence_peek(&ctx->persistence, &outbound_message)) { + continue; + } - outbound_message_t outbound_message; - outbound_message_make_from_readings(&ctx->parser, ctx->device_key, &reading, 1, &outbound_message); + if (publish(ctx, &outbound_message) != W_FALSE) { + return W_TRUE; + } + + persistence_pop(&ctx->persistence, &outbound_message); + } + + return W_FALSE; +} + +WOLK_ERR_T wolk_register_feed(wolk_ctx_t* ctx, feed_registration_t* feeds, size_t number_of_feeds) +{ + outbound_message_t outbound_message = {0}; + if (!outbound_message_feed_registration(&ctx->parser, ctx->device_key, feeds, number_of_feeds, &outbound_message)) + return W_TRUE; return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; } -WOLK_ERR_T wolk_add_multi_value_bool_sensor_reading(wolk_ctx_t* ctx, const char* reference, bool* values, - uint16_t values_size, uint64_t utc_time) +WOLK_ERR_T wolk_remove_feed(wolk_ctx_t* ctx, feed_registration_t* feeds, size_t number_of_feeds) { - /* Sanity check */ - WOLK_ASSERT(is_wolk_initialized(ctx)); - WOLK_ASSERT(READING_DIMENSIONS > 1); + outbound_message_t outbound_message = {0}; + if (!outbound_message_feed_removal(&ctx->parser, ctx->device_key, feeds, number_of_feeds, &outbound_message)) + return W_TRUE; - manifest_item_t string_sensor; - manifest_item_init(&string_sensor, reference, READING_TYPE_SENSOR, DATA_TYPE_STRING); - manifest_item_set_reading_dimensions_and_delimiter(&string_sensor, values_size, DATA_DELIMITER); + return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; +} - reading_t reading; - reading_init(&reading, &string_sensor); - reading_set_rtc(&reading, utc_time); +WOLK_ERR_T wolk_pull_feed_values(wolk_ctx_t* ctx) +{ + if (ctx->outbound_mode == PULL) { + outbound_message_t outbound_message = {0}; + outbound_message_pull_feed_values(&ctx->parser, ctx->device_key, &outbound_message); - for (uint32_t i = 0; i < values_size; ++i) { - reading_set_data_at(&reading, BOOL_TO_STR(values[i]), i); + return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; } - outbound_message_t outbound_message; - outbound_message_make_from_readings(&ctx->parser, ctx->device_key, &reading, 1, &outbound_message); - - return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; + return W_TRUE; } -WOLK_ERR_T wolk_add_alarm(wolk_ctx_t* ctx, const char* reference, bool state, uint64_t utc_time) +WOLK_ERR_T wolk_init_parameter(parameter_t* parameter, char* name, char* value) { - /* Sanity check */ - WOLK_ASSERT(is_wolk_initialized(ctx)); + parameter_init(parameter, name, value); - manifest_item_t alarm; - manifest_item_init(&alarm, reference, READING_TYPE_ALARM, DATA_TYPE_STRING); - - reading_t alarm_reading; - reading_init(&alarm_reading, &alarm); - reading_set_rtc(&alarm_reading, utc_time); - reading_set_data(&alarm_reading, (state == true ? "true" : "false")); + return W_FALSE; +} - outbound_message_t outbound_message; - outbound_message_make_from_readings(&ctx->parser, ctx->device_key, &alarm_reading, 1, &outbound_message); +WOLK_ERR_T wolk_set_value_parameter(parameter_t* parameter, char* value) +{ + parameter_set_value(parameter, value); - return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; + return W_FALSE; } -WOLK_ERR_T wolk_publish_actuator_status(wolk_ctx_t* ctx, const char* reference) +WOLK_ERR_T wolk_change_parameter(wolk_ctx_t* ctx, parameter_t* parameter, size_t number_of_parameters) { - /* Sanity check */ - WOLK_ASSERT(is_wolk_initialized(ctx)); + outbound_message_t outbound_message = {0}; + outbound_message_update_parameters(&ctx->parser, ctx->device_key, parameter, number_of_parameters, + &outbound_message); - if (ctx->actuator_status_provider != NULL) { - actuator_status_t actuator_status = ctx->actuator_status_provider(reference); + return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; +} - outbound_message_t outbound_message; - if (!outbound_message_make_from_actuator_status(&ctx->parser, ctx->device_key, &actuator_status, reference, - &outbound_message)) { - return W_TRUE; - } +WOLK_ERR_T wolk_pull_parameters(wolk_ctx_t* ctx) +{ + if (ctx->outbound_mode == PULL) { + outbound_message_t outbound_message = {0}; + outbound_message_pull_parameters(&ctx->parser, ctx->device_key, &outbound_message); - if (publish(ctx, &outbound_message) != W_FALSE) { - persistence_push(&ctx->persistence, &outbound_message); - } + return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; } - return W_FALSE; + return W_TRUE; } -WOLK_ERR_T wolk_publish(wolk_ctx_t* ctx) +WOLK_ERR_T wolk_sync_parameters(wolk_ctx_t* ctx, parameter_t* parameters, size_t number_of_parameters) { - /* Sanity check */ - WOLK_ASSERT(is_wolk_initialized(ctx)); + outbound_message_t outbound_message = {0}; + outbound_message_synchronize_parameters(&ctx->parser, ctx->device_key, parameters, number_of_parameters, + &outbound_message); + + return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; +} - uint8_t i; - uint16_t batch_size = 50; - outbound_message_t outbound_message; +WOLK_ERR_T wolk_sync_time_request(wolk_ctx_t* ctx) +{ + outbound_message_t outbound_message = {0}; + outbound_message_synchronize_time(&ctx->parser, ctx->device_key, &outbound_message); - for (i = 0; i < batch_size; ++i) { - if (persistence_is_empty(&ctx->persistence)) { - return W_FALSE; - } + return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; +} - if (!persistence_peek(&ctx->persistence, &outbound_message)) { - continue; - } +WOLK_ERR_T wolk_details_synchronization(wolk_ctx_t* ctx) +{ + outbound_message_t outbound_message = {0}; + outbound_message_details_synchronize(&ctx->parser, ctx->device_key, &outbound_message); - if (publish(ctx, &outbound_message) != W_FALSE) { - return W_TRUE; - } + return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; +} - persistence_pop(&ctx->persistence, &outbound_message); - } +WOLK_ERR_T wolk_init_attribute(wolk_attribute_t* attribute, char* name, char* data_type, char* value) +{ + attribute_init(attribute, name, data_type, value); return W_FALSE; } -uint64_t wolk_request_timestamp(wolk_ctx_t* ctx) +WOLK_ERR_T wolk_register_attribute(wolk_ctx_t* ctx, attribute_t* attributes, size_t number_of_attributes) { - return ctx->utc; + outbound_message_t outbound_message = {0}; + outbound_message_attribute_registration(&ctx->parser, ctx->device_key, attributes, number_of_attributes, + &outbound_message); + + return persistence_push(&ctx->persistence, &outbound_message) ? W_FALSE : W_TRUE; } -/* Local function definition */ +/* Local function definitions */ + static WOLK_ERR_T mqtt_keep_alive(wolk_ctx_t* ctx, uint64_t tick) { - unsigned char buf[MQTT_PACKET_SIZE]; - memset(buf, 0, MQTT_PACKET_SIZE); + unsigned char buf[MQTT_PACKET_SIZE] = ""; - if (ctx->connectData.keepAliveInterval < (MQTT_KEEP_ALIVE_INTERVAL * 1000)) { // Convert to Unit: ms + if (ctx->connectData.keepAliveInterval < (MQTT_KEEP_ALIVE_INTERVAL * 1000)) { // Convert to ms ctx->connectData.keepAliveInterval += tick; return W_FALSE; } @@ -743,27 +585,6 @@ static WOLK_ERR_T mqtt_keep_alive(wolk_ctx_t* ctx, uint64_t tick) } while (true); } -static WOLK_ERR_T ping_keep_alive(wolk_ctx_t* ctx, uint64_t tick) -{ - if (!ctx->is_keep_ping_alive_enabled) { - return W_FALSE; - } - - if (ctx->milliseconds_since_last_ping_keep_alive < PING_KEEP_ALIVE_INTERVAL) { - ctx->milliseconds_since_last_ping_keep_alive += tick; - return W_FALSE; - } - - outbound_message_t outbound_message; - outbound_message_make_from_keep_alive_message(&ctx->parser, ctx->device_key, &outbound_message); - if (publish(ctx, &outbound_message) != W_FALSE) { - return W_TRUE; - } - - ctx->milliseconds_since_last_ping_keep_alive = 0; - return W_FALSE; -} - static WOLK_ERR_T receive(wolk_ctx_t* ctx) { unsigned char mqtt_packet[MQTT_PACKET_SIZE]; @@ -775,9 +596,9 @@ static WOLK_ERR_T receive(wolk_ctx_t* ctx) unsigned char retained; unsigned short msgid; - MQTTString topic_mqtt_str; + MQTTString topic_mqtt_str = {0}; unsigned char* payload; - int payload_len; + int payload_len = 0; if (MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &topic_mqtt_str, &payload, &payload_len, mqtt_packet, mqtt_packet_len) @@ -787,72 +608,78 @@ static WOLK_ERR_T receive(wolk_ctx_t* ctx) WOLK_ASSERT(TOPIC_SIZE > topic_mqtt_str.lenstring.len); - char topic_str[TOPIC_SIZE]; - memset(&topic_str[0], '\0', TOPIC_SIZE); - strncpy(&topic_str[0], topic_mqtt_str.lenstring.data, topic_mqtt_str.lenstring.len); + char topic_str[TOPIC_SIZE] = ""; + strncpy(topic_str, topic_mqtt_str.lenstring.data, topic_mqtt_str.lenstring.len); - if (strstr(topic_str, PONG_TOPIC)) { + if (strstr(topic_str, ctx->parser.FEED_VALUES_MESSAGE_TOPIC) != NULL) { + feed_t feeds_received[FEED_ELEMENT_SIZE]; + const size_t number_of_deserialized_feeds = + parser_deserialize_feeds_message(&ctx->parser, (char*)payload, (size_t)payload_len, &feeds_received); + if (number_of_deserialized_feeds != 0) { + handle_feeds(ctx, &feeds_received, number_of_deserialized_feeds); + } + } else if (strstr(topic_str, ctx->parser.PARAMETERS_TOPIC)) { + parameter_t parameter_message[FEED_ELEMENT_SIZE]; + const size_t number_of_deserialized_parameters = parser_deserialize_parameter_message( + &ctx->parser, (char*)payload, (size_t)payload_len, ¶meter_message); + if (number_of_deserialized_parameters != 0) { + handle_parameter_message(ctx, ¶meter_message, number_of_deserialized_parameters); + } + } else if (strstr(topic_str, ctx->parser.SYNC_TIME_TOPIC)) { utc_command_t utc_command; - const size_t response = parser_deserialize_pong_keep_alive_message(&ctx->parser, (char*)payload, - (size_t)payload_len, &utc_command); - if (response != 0) { + const size_t num_deserialized_commands = + parser_deserialize_time(&ctx->parser, (char*)payload, (size_t)payload_len, &utc_command); + if (num_deserialized_commands != 0) { handle_utc_command(ctx, &utc_command); } - } else if (strstr(topic_str, ACTUATOR_COMMANDS_TOPIC) != NULL) { - actuator_command_t actuator_command; - const size_t num_deserialized_commands = parser_deserialize_actuator_commands( - &ctx->parser, topic_str, strlen(topic_str), (char*)payload, (size_t)payload_len, &actuator_command, 1); - if (num_deserialized_commands != 0) { - handle_actuator_command(ctx, &actuator_command); + } else if (strstr(topic_str, ctx->parser.ERROR_TOPIC)) { + if (payload_len != 0) { + handle_error_message(ctx, &payload); } - } else if (strstr(topic_str, CONFIGURATION_COMMANDS)) { - configuration_command_t configuration_command; - const size_t num_deserialized_commands = parser_deserialize_configuration_commands( - &ctx->parser, (char*)payload, (size_t)payload_len, &configuration_command, 1); - if (num_deserialized_commands != 0) { - handle_configuration_command(ctx, &configuration_command); + } else if (strstr(topic_str, ctx->parser.DETAILS_SYNCHRONIZATION_TOPIC)) { + feed_registration_t feeds[FEED_ELEMENT_SIZE]; + attribute_t attributes[FEED_ELEMENT_SIZE]; + size_t number_of_feeds = 0; + size_t number_of_attributes = 0; + + if (parser_deserialize_details_synchronization(&ctx->parser, (char*)payload, (size_t)payload_len, feeds, + &number_of_feeds, attributes, &number_of_attributes)) { + handle_details_synchronization_message(ctx, feeds, number_of_feeds, attributes, number_of_attributes); } - } else if (strstr(topic_str, FILE_MANAGEMENT_UPLOAD_INITIATE_TOPIC)) { + } else if (strstr(topic_str, ctx->parser.FILE_MANAGEMENT_UPLOAD_INITIATE_TOPIC)) { file_management_parameter_t file_management_parameter; const size_t num_deserialized_parameter = parser_deserialize_file_management_parameter( &ctx->parser, (char*)payload, (size_t)payload_len, &file_management_parameter); if (num_deserialized_parameter != 0) { handle_file_management_parameter(&ctx->file_management, &file_management_parameter); } - } else if (strstr(topic_str, FILE_MANAGEMENT_CHUNK_UPLOAD_TOPIC)) { + } else if (strstr(topic_str, ctx->parser.FILE_MANAGEMENT_BINARY_RESPONSE_TOPIC)) { handle_file_management_packet(&ctx->file_management, (uint8_t*)payload, (size_t)payload_len); - } else if ((strstr(topic_str, FILE_MANAGEMENT_UPLOAD_ABORT_TOPIC)) - || (strstr(topic_str, FILE_MANAGEMENT_URL_DOWNLOAD_ABORT_TOPIC))) { - file_management_parameter_t file_management_parameter; - const size_t num_deserialized_parameter = parser_deserialize_file_management_parameter( - &ctx->parser, (char*)payload, (size_t)payload_len, &file_management_parameter); - if (num_deserialized_parameter != 0) { - handle_file_management_abort(&ctx->file_management); + } else if ((strstr(topic_str, ctx->parser.FILE_MANAGEMENT_UPLOAD_ABORT_TOPIC)) + || (strstr(topic_str, ctx->parser.FILE_MANAGEMENT_URL_DOWNLOAD_ABORT_TOPIC))) { + handle_file_management_abort(&ctx->file_management, (uint8_t*)payload, (size_t)payload_len); + } else if (strstr(topic_str, ctx->parser.FILE_MANAGEMENT_URL_DOWNLOAD_INITIATE_TOPIC)) { + char url_download[FILE_MANAGEMENT_URL_SIZE] = {0}; + if (parser_deserialize_url_download(&ctx->parser, (char*)payload, (size_t)payload_len, url_download)) + handle_file_management_url_download(&ctx->file_management, url_download); + } else if (strstr(topic_str, ctx->parser.FILE_MANAGEMENT_FILE_LIST_TOPIC)) { + handle_file_management_file_list(&ctx->file_management); + } else if (strstr(topic_str, ctx->parser.FILE_MANAGEMENT_FILE_DELETE_TOPIC)) { + file_list_t file_list[FILE_MANAGEMENT_FILE_LIST_SIZE]; + const size_t number_deserialized = + parser_deserialize_file_delete(&ctx->parser, (char*)payload, (size_t)payload_len, file_list); + if (number_deserialized) { + handle_file_management_file_delete(&ctx->file_management, file_list, number_deserialized); } - } else if (strstr(topic_str, FILE_MANAGEMENT_URL_DOWNLOAD_INITIATE_TOPIC)) { - file_management_parameter_t file_management_parameter; - const size_t num_deserialized = parser_deserialize_file_management_parameter( - &ctx->parser, (char*)payload, (size_t)payload_len, &file_management_parameter); - if (num_deserialized != 0) { - handle_file_management_url_download(&ctx->file_management, &file_management_parameter); - } - } else if (strstr(topic_str, FILE_MANAGEMENT_FILE_DELETE_TOPIC)) { - file_management_parameter_t file_management_parameter; - const size_t num_deserialized = parser_deserialize_file_management_parameter( - &ctx->parser, (char*)payload, (size_t)payload_len, &file_management_parameter); - if (num_deserialized != 0) { - handle_file_management_file_delete(&ctx->file_management, &file_management_parameter); - } - } else if (strstr(topic_str, FILE_MANAGEMENT_FILE_PURGE_TOPIC)) { + } else if (strstr(topic_str, ctx->parser.FILE_MANAGEMENT_FILE_PURGE_TOPIC)) { handle_file_management_file_purge(&ctx->file_management); - } else if (strstr(topic_str, FIRMWARE_UPDATE_INSTALL_TOPIC)) { + } else if (strstr(topic_str, ctx->parser.FIRMWARE_UPDATE_INSTALL_TOPIC)) { firmware_update_t firmware_update_parameter; - const size_t num_deserialized = parse_deserialize_firmware_update_parameter( - &ctx->parser, (char*)ctx->device_key, (char*)payload, (size_t)payload_len, &firmware_update_parameter); - if (num_deserialized != 0) { + if (parse_deserialize_firmware_update_parameter(&ctx->parser, (char*)payload, (size_t)payload_len, + &firmware_update_parameter)) { handle_firmware_update_installation(&ctx->firmware_update, &firmware_update_parameter); } - } else if (strstr(topic_str, FIRMWARE_UPDATE_ABORT_TOPIC)) { + } else if (strstr(topic_str, ctx->parser.FIRMWARE_UPDATE_ABORT_TOPIC)) { handle_firmware_update_abort(&ctx->firmware_update); } } @@ -862,16 +689,14 @@ static WOLK_ERR_T receive(wolk_ctx_t* ctx) static WOLK_ERR_T publish(wolk_ctx_t* ctx, outbound_message_t* outbound_message) { - int len; - unsigned char buf[MQTT_PACKET_SIZE]; - memset(buf, 0, MQTT_PACKET_SIZE); + unsigned char buf[MQTT_PACKET_SIZE] = ""; MQTTString mqtt_topic = MQTTString_initializer; mqtt_topic.cstring = outbound_message_get_topic(outbound_message); unsigned char* payload = (unsigned char*)outbound_message_get_payload(outbound_message); - len = MQTTSerialize_publish(buf, MQTT_PACKET_SIZE, 0, 0, 0, 0, mqtt_topic, payload, - (int)strlen((const char*)payload)); + int len = MQTTSerialize_publish(buf, MQTT_PACKET_SIZE, 0, 0, 0, 0, mqtt_topic, payload, + (int)strlen((const char*)payload)); transmission_buffer_nb_start(ctx->sock, buf, len); do { @@ -895,8 +720,7 @@ static WOLK_ERR_T publish(wolk_ctx_t* ctx, outbound_message_t* outbound_message) static WOLK_ERR_T subscribe(wolk_ctx_t* ctx, const char* topic) { - unsigned char buf[MQTT_PACKET_SIZE]; - memset(buf, 0, MQTT_PACKET_SIZE); + unsigned char buf[MQTT_PACKET_SIZE] = ""; int req_qos = 0; @@ -925,19 +749,6 @@ static WOLK_ERR_T subscribe(wolk_ctx_t* ctx, const char* topic) } while (true); } -static void parser_init_parameters(wolk_ctx_t* ctx, protocol_t protocol) -{ - switch (protocol) { - case PROTOCOL_WOLKABOUT: - parser_init(&ctx->parser, PARSER_TYPE_WOLKABOUT); - break; - - default: - /* Sanity check */ - WOLK_ASSERT(false); - } -} - static bool is_wolk_initialized(wolk_ctx_t* ctx) { /* Sanity Check */ @@ -946,79 +757,23 @@ static bool is_wolk_initialized(wolk_ctx_t* ctx) return ctx->is_initialized && persistence_is_initialized(&ctx->persistence); } -static void handle_actuator_command(wolk_ctx_t* ctx, actuator_command_t* actuator_command) +static void handle_feeds(wolk_ctx_t* ctx, feed_t* feeds, size_t number_of_feeds) { - const char* reference = actuator_command_get_reference(actuator_command); - const char* value = actuator_command_get_value(actuator_command); - - switch (actuator_command_get_type(actuator_command)) { - case ACTUATOR_COMMAND_TYPE_SET: - if (ctx->actuation_handler != NULL) { - ctx->actuation_handler(reference, value); - } - - /* Fallthrough */ - /* break; */ - - case ACTUATOR_COMMAND_TYPE_STATUS: - if (ctx->actuator_status_provider != NULL) { - actuator_status_t actuator_status = ctx->actuator_status_provider(reference); - - outbound_message_t outbound_message; - if (!outbound_message_make_from_actuator_status(&ctx->parser, ctx->device_key, &actuator_status, reference, - &outbound_message)) { - return; - } - - if (publish(ctx, &outbound_message) != W_FALSE) { - persistence_push(&ctx->persistence, &outbound_message); - } - } - break; + /* Sanity Check */ + WOLK_ASSERT(ctx); - case ACTUATOR_COMMAND_TYPE_UNKNOWN: - break; + if (ctx->feed_handler != NULL) { + ctx->feed_handler(feeds, number_of_feeds); } } -static void handle_configuration_command(wolk_ctx_t* ctx, configuration_command_t* configuration_command) +static void handle_parameter_message(wolk_ctx_t* ctx, parameter_t* parameter_message, size_t number_of_parameters) { - switch (configuration_command_get_type(configuration_command)) { - case CONFIGURATION_COMMAND_TYPE_SET: - if (ctx->configuration_handler != NULL) { - ctx->configuration_handler(configuration_command_get_references(configuration_command), - configuration_command_get_values(configuration_command), - configuration_command_get_number_of_items(configuration_command)); - } - - /* Fallthrough */ - /* break; */ - - case CONFIGURATION_COMMAND_TYPE_GET: - if (ctx->configuration_provider != NULL) { - char references[CONFIGURATION_ITEMS_SIZE][CONFIGURATION_REFERENCE_SIZE]; - char values[CONFIGURATION_ITEMS_SIZE][CONFIGURATION_VALUE_SIZE]; - - const size_t num_configuration_items = - ctx->configuration_provider(&references[0], &values[0], CONFIGURATION_ITEMS_SIZE); - if (num_configuration_items == 0) { - return; - } - - outbound_message_t outbound_message; - if (!outbound_message_make_from_configuration(&ctx->parser, ctx->device_key, references, values, - num_configuration_items, &outbound_message)) { - return; - } - - if (publish(ctx, &outbound_message) != W_FALSE) { - persistence_push(&ctx->persistence, &outbound_message); - } - } - break; + /* Sanity Check */ + WOLK_ASSERT(ctx); - case CONFIGURATION_COMMAND_TYPE_UNKNOWN: - break; + if (ctx->parameter_handler != NULL) { + ctx->parameter_handler(parameter_message, number_of_parameters); } } @@ -1031,6 +786,23 @@ static void handle_utc_command(wolk_ctx_t* ctx, utc_command_t* utc) ctx->utc = utc_command_get(utc); } +static void handle_details_synchronization_message(wolk_ctx_t* ctx, feed_registration_t* feeds, size_t number_of_feeds, + attribute_t* attributes, size_t number_of_attributes) +{ + /* Sanity Check */ + WOLK_ASSERT(ctx); + + if (ctx->details_synchronization_handler != NULL) { + ctx->details_synchronization_handler(feeds, number_of_feeds, attributes, number_of_attributes); + } +} + +static void handle_error_message(wolk_ctx_t* ctx, char* error) +{ + WOLK_UNUSED(ctx); + WOLK_UNUSED(error); +} + static void handle_file_management_parameter(file_management_t* file_management, file_management_parameter_t* file_management_parameter) { @@ -1050,32 +822,39 @@ static void handle_file_management_packet(file_management_t* file_management, ui file_management_handle_packet(file_management, packet, packet_size); } -static void handle_file_management_abort(file_management_t* file_management) +static void handle_file_management_abort(file_management_t* file_management, uint8_t* packet, size_t packet_size) { /* Sanity check */ WOLK_ASSERT(file_management); - file_management_handle_abort(file_management); + file_management_handle_abort(file_management, packet, packet_size); } -static void handle_file_management_url_download(file_management_t* file_management, - file_management_parameter_t* parameter) +static void handle_file_management_url_download(file_management_t* file_management, char* url_download) { /* Sanity check */ WOLK_ASSERT(file_management); WOLK_ASSERT(parameter); - file_management_handle_url_download(file_management, parameter); + file_management_handle_url_download(file_management, url_download); +} + +static void handle_file_management_file_list(file_management_t* file_management) +{ + /* Sanity Check*/ + WOLK_ASSERT(file_management); + + file_management_handle_file_list(file_management); } -static void handle_file_management_file_delete(file_management_t* file_management, - file_management_parameter_t* parameter) +static void handle_file_management_file_delete(file_management_t* file_management, file_list_t* file_list, + size_t number_of_files) { /* Sanity Check*/ WOLK_ASSERT(file_management); WOLK_ASSERT(parameter); - file_management_handle_file_delete(file_management, parameter); + file_management_handle_file_delete(file_management, file_list, number_of_files); } static void handle_file_management_file_purge(file_management_t* file_management) @@ -1093,7 +872,7 @@ static void listener_file_management_on_status(file_management_t* file_managemen WOLK_ASSERT(status); wolk_ctx_t* wolk_ctx = (wolk_ctx_t*)file_management->wolk_ctx; - outbound_message_t outbound_message; + outbound_message_t outbound_message = {0}; outbound_message_make_from_file_management_status(&wolk_ctx->parser, wolk_ctx->device_key, file_management->file_name, &status, &outbound_message); @@ -1109,7 +888,7 @@ static void listener_file_management_on_packet_request(file_management_t* file_m wolk_ctx_t* wolk_ctx = (wolk_ctx_t*)file_management->wolk_ctx; - outbound_message_t outbound_message; + outbound_message_t outbound_message = {0}; outbound_message_make_from_file_management_packet_request(&wolk_ctx->parser, wolk_ctx->device_key, &request, &outbound_message); @@ -1124,7 +903,7 @@ static void listener_file_management_on_url_download_status(file_management_t* f WOLK_ASSERT(status); wolk_ctx_t* wolk_ctx = (wolk_ctx_t*)file_management->wolk_ctx; - outbound_message_t outbound_message; + outbound_message_t outbound_message = {0}; file_management_parameter_t file_management_parameter; file_management_parameter_set_file_url(&file_management_parameter, file_management->file_url); @@ -1136,7 +915,7 @@ static void listener_file_management_on_url_download_status(file_management_t* f publish(wolk_ctx, &outbound_message); } -static void listener_file_management_on_file_list_status(file_management_t* file_management, char* file_list, +static void listener_file_management_on_file_list_status(file_management_t* file_management, file_list_t* file_list, size_t file_list_items) { /* Sanity check */ @@ -1145,7 +924,7 @@ static void listener_file_management_on_file_list_status(file_management_t* file WOLK_ASSERT(file_list_items); wolk_ctx_t* wolk_ctx = (wolk_ctx_t*)file_management->wolk_ctx; - outbound_message_t outbound_message; + outbound_message_t outbound_message = {0}; outbound_message_make_from_file_management_file_list(&wolk_ctx->parser, wolk_ctx->device_key, file_list, file_list_items, &outbound_message); @@ -1160,7 +939,7 @@ static void listener_firmware_update_on_status(firmware_update_t* firmware_updat WOLK_ASSERT(status); wolk_ctx_t* wolk_ctx = (wolk_ctx_t*)firmware_update->wolk_ctx; - outbound_message_t outbound_message; + outbound_message_t outbound_message = {0}; outbound_message_make_from_firmware_update_status(&wolk_ctx->parser, wolk_ctx->device_key, firmware_update, &outbound_message); @@ -1168,21 +947,6 @@ static void listener_firmware_update_on_status(firmware_update_t* firmware_updat publish(wolk_ctx, &outbound_message); } -static void listener_firmware_update_on_version(firmware_update_t* firmware_update, char* firmware_update_version) -{ - /* Sanity check */ - WOLK_ASSERT(firmware_update); - WOLK_ASSERT(firmware_update_version); - - wolk_ctx_t* wolk_ctx = (wolk_ctx_t*)firmware_update->wolk_ctx; - outbound_message_t outbound_message; - - outbound_message_make_from_firmware_update_version(&wolk_ctx->parser, wolk_ctx->device_key, firmware_update_version, - &outbound_message); - - publish(wolk_ctx, &outbound_message); -} - static void listener_firmware_update_on_verification(firmware_update_t* firmware_update) { /* Sanity Check */ @@ -1207,3 +971,13 @@ static void handle_firmware_update_abort(firmware_update_t* firmware_update) firmware_update_handle_abort(firmware_update); } + +static WOLK_ERR_T subscribe_to(wolk_ctx_t* ctx, char message_type[TOPIC_MESSAGE_TYPE_SIZE]) +{ + char topic[TOPIC_SIZE] = ""; + parser_create_topic(&ctx->parser, ctx->parser.P2D_TOPIC, ctx->device_key, message_type, topic); + if (subscribe(ctx, topic) != W_FALSE) { + return W_TRUE; + } + return W_FALSE; +} diff --git a/sources/wolk_connector.h b/sources/wolk_connector.h index cd94d2f..5fd326e 100644 --- a/sources/wolk_connector.h +++ b/sources/wolk_connector.h @@ -1,5 +1,5 @@ /* - * Copyright 2018 WolkAbout Technology s.r.o. + * Copyright 2022 WolkAbout Technology s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ */ /** - * @file WolkConn.h + * @file wolkconnector.h * * WolkConnect C * @@ -28,26 +28,19 @@ extern "C" { #endif #include "MQTTPacket.h" -#include "actuator_status.h" -#include "data_transmission.h" -#include "file_management.h" -#include "parser.h" -#include "persistence.h" +#include "connectivity/data_transmission.h" +#include "model/attribute.h" +#include "model/feed.h" +#include "model/file_management/file_management.h" +#include "model/utc_command.h" +#include "persistence/persistence.h" +#include "protocol/parser.h" #include "size_definitions.h" -#include "utc_command.h" +#include "types.h" #include #include -/** - * @brief Library versioning - */ -enum { WOLK_VERSION_MAJOR = 4, WOLK_VERSION_MINOR = 0, WOLK_VERSION_PATCH = 2 }; - -/** - * @brief Supported protocols, WolkConnect libararies currently support only PROTOCOL_WOLKABOUT - */ -typedef enum { PROTOCOL_WOLKABOUT = 0 } protocol_t; /** * @brief WOLK_ERR_T Boolean used for error handling in WolkConnect-C library @@ -60,50 +53,72 @@ typedef unsigned char WOLK_ERR_T; typedef unsigned char WOLK_BOOL_T; enum WOLK_BOOL_T_values { W_FALSE = 0, W_TRUE = 1 }; +/** + * @brief WolkAbout IoT Platform numeric feed type. + */ +typedef struct wolk_numeric_feeds_t { + double value; + uint64_t utc_time; +} wolk_numeric_feeds_t; + +/** + * @brief WolkAbout IoT Platform string feed type. + */ +typedef struct wolk_string_feeds_t { + char* value; + uint64_t utc_time; +} wolk_string_feeds_t; + +/** + * @brief WolkAbout IoT Platform boolean feed type. + */ +typedef struct wolk_boolean_feeds_t { + bool value; + uint64_t utc_time; +} wolk_boolean_feeds_t; + +typedef feed_t wolk_feed_t; +typedef feed_registration_t wolk_feed_registration_t; +typedef parameter_t wolk_parameter_t; +typedef attribute_t wolk_attribute_t; + /** * @brief Callback declaration for writting bytes to socket */ typedef int (*send_func_t)(unsigned char* bytes, unsigned int num_bytes); /** - * @brief Callback declaration for reading bytes from socket + * @brief Callback declaration for bytes from socket */ typedef int (*recv_func_t)(unsigned char* bytes, unsigned int num_bytes); /** - * @brief Declaration of actuator handler. - * Actuator reference and value are the pairs of data on the same place in own arrays. - * - * @param reference actuator references defined in manifest on WolkAbout IoT Platform. - * @param value value received from WolkAbout IoT Platform. - */ -typedef void (*actuation_handler_t)(const char* reference, const char* value); -/** - * @brief Declaration of actuator status + * @brief Declaration of feed value handler. * - * @param reference actuator references define in manifest on WolkAbout IoT Platform + * @param feeds feeds received as name:value pairs from WolkAbout IoT Platform. + * @param number_of_feeds number fo received feeds. */ -typedef actuator_status_t (*actuator_status_provider_t)(const char* reference); +typedef void (*feed_handler_t)(wolk_feed_t* feeds, size_t number_of_feeds); /** - * @brief Declaration of configuration handler. - * Configuration reference and value are the pairs of data on the same place in own arrays. + * @brief Declaration of parameter handler. * - * @param reference actuator references define in manifest on WolkAbout IoT Platform - * @param value actuator values received from WolkAbout IoT Platform. - * @param num_configuration_items number of used configuration parameters + * @param parameter_message Parameters received as name:value pairs from WolkAbout IoT Platform. + * @param number_of_parameters number of received parameters */ -typedef void (*configuration_handler_t)(char (*reference)[CONFIGURATION_REFERENCE_SIZE], - char (*value)[CONFIGURATION_VALUE_SIZE], size_t num_configuration_items); +typedef void (*parameter_handler_t)(wolk_parameter_t* parameter_message, size_t number_of_parameters); + /** - * @brief Declaration of configuration provider + * @brief Declaration of details synchronization handler. It will be called as a response on the + * wolk_details_synchronization() call. It will give list of the all feeds and attributes from the platform. * - * @param reference configuration references define in manifest on WolkAbout IoT Platform - * @param value configuration values received from WolkAbout IoT Platform - * @param num_configuration_items number of used configuration parameters + * @param parameter_message Parameters received as name:value pairs from WolkAbout IoT Platform. + * @param number_of_parameters number of received parameters */ -typedef size_t (*configuration_provider_t)(char (*reference)[CONFIGURATION_REFERENCE_SIZE], - char (*value)[CONFIGURATION_VALUE_SIZE], size_t max_num_configuration_items); +typedef void (*details_synchronization_handler_t)(wolk_feed_registration_t* feeds, size_t number_of_received_feeds, + wolk_attribute_t* attributes, size_t number_of_received_attributes); + + /** * @brief WolkAbout IoT Platform connector context. * Most of the parameters are used to initialize WolkConnect library forwarding to wolk_init(). @@ -114,22 +129,26 @@ typedef struct wolk_ctx { MQTTTransport mqtt_transport; transmission_io_functions_t iof; - actuation_handler_t actuation_handler; /**< Callback for handling received actuation from WolkAbout IoT Platform. - @see actuation_handler_t*/ - actuator_status_provider_t actuator_status_provider; /**< Callback for providing the current actuator status to - WolkAbout IoT Platform. @see actuator_status_provider_t*/ + outbound_mode_t outbound_mode; + + feed_handler_t feed_handler; /**< Callback for handling incoming feeds from WolkAbout IoT Platform. + @see feed_handler_t*/ + + parameter_handler_t parameter_handler; /**< Callback for handling received configuration from WolkAbout IoT + Platform. @see parameter_handler_t*/ - configuration_handler_t configuration_handler; /**< Callback for handling received configuration from WolkAbout IoT - Platform. @see configuration_handler_t*/ - configuration_provider_t configuration_provider; /**< Callback for providing the current configuration status to - WolkAbout IoT Platform. @see configuration_provider_t*/ + details_synchronization_handler_t details_synchronization_handler; /**< Callback for handling received details +configuration from WolkAbout IoT Platform. @see attribute_handler_t*/ - char device_key[DEVICE_KEY_SIZE]; /**< Authentication parameters for WolkAbout IoT Platform. Obtained as a result + char device_key[DEVICE_KEY_SIZE]; /**< Authentication parameters for WolkAbout IoT Platform. Obtained as a + * + * result of device creation on the platform.*/ char device_password[DEVICE_PASSWORD_SIZE]; /**< Authentication parameters for WolkAbout IoT Platform. Obtained as - a result of device creation on the platform.*/ + a + + result of device creation on the platform.*/ - protocol_t protocol; /**< Used protocol for communication with WolkAbout IoT Platform. @see protocol_t*/ parser_t parser; persistence_t persistence; @@ -138,11 +157,6 @@ typedef struct wolk_ctx { firmware_update_t firmware_update; - const char** actuator_references; - uint32_t num_actuator_references; - - bool is_keep_ping_alive_enabled; - uint32_t milliseconds_since_last_ping_keep_alive; uint64_t utc; bool is_initialized; @@ -156,30 +170,23 @@ typedef struct wolk_ctx { * @param snd_func Callback function that handles outgoing traffic * @param rcv_func Callback function that handles incoming traffic * - * @param actuation_handler function pointer to 'actuation_handler_t' implementation - * @param actuator_status_provider function pointer to 'actuator_status_provider_t' implementation - * - * @param configuration_handler function pointer to 'configuration_handler_t' implementation - * @param configuration_provider function pointer to 'configuration_provider_t' implementation - * * @param device_key Device key provided by WolkAbout IoT Platform upon device * creation * @param password Device password provided by WolkAbout IoT Platform device * upon device creation - * @param protocol Protocol specified for device * - * @param actuator_references Array of strings containing references of - * actuators that device possess - * @param num_actuator_references Number of actuator references contained in - * actuator_references + * @param feed_handler function pointer to 'feed_handler_t' implementation + * + * @param parameter_handler function pointer to 'parameter_handler_t' implementation + * + * @param details_synchronization_handler function pointer to 'details_synchronization_handler_t' implementation * * @return Error code */ -WOLK_ERR_T wolk_init(wolk_ctx_t* ctx, send_func_t snd_func, recv_func_t rcv_func, actuation_handler_t actuation_handler, - actuator_status_provider_t actuator_status_provider, configuration_handler_t configuration_handler, - configuration_provider_t configuration_provider, const char* device_key, - const char* device_password, protocol_t protocol, const char** actuator_references, - uint32_t num_actuator_references); +WOLK_ERR_T wolk_init(wolk_ctx_t* ctx, send_func_t snd_func, recv_func_t rcv_func, const char* device_key, + const char* device_password, outbound_mode_t outbound_mode, feed_handler_t feed_handler, + parameter_handler_t parameter_handler, + details_synchronization_handler_t details_synchronization_handler); /** * @brief Initializes persistence mechanism with in-memory implementation @@ -198,7 +205,8 @@ WOLK_ERR_T wolk_init_in_memory_persistence(wolk_ctx_t* ctx, void* storage, uint3 * @brief Initializes persistence mechanism with custom implementation * * @param ctx Context - * @param push Function pointer to 'push' implemenation + * @param push Function pointer to 'push' implementation + * @param peek Function pointer to 'peek' implementation * @param pop Function pointer to 'pop' implementation * @param is_empty Function pointer to 'is empty' implementation * @@ -215,7 +223,8 @@ WOLK_ERR_T wolk_init_custom_persistence(wolk_ctx_t* ctx, persistence_push_t push * * @param ctx Context * @param maximum_file_size Maximum acceptable size of file, in bytes - * @param chunk_size file is transferred in chunks of size 'chunk_size' + * @param chunk_size file is transferred in chunks of size 'chunk_size'. Unit is Kbytes defined during device creation + * on the platform as "Maximum message size" Connectivity property * @param start Function pointer to 'file_management_start' implementation * @param write_chunk Function pointer to 'file_management_write_chunk' implementation * @param read_chunk Function pointer to 'file_management_read_chunk' implementation @@ -242,7 +251,6 @@ WOLK_ERR_T wolk_init_file_management( * @param function pointer to 'is_installation_completed' implementation * @param function pointer to 'verification_store' implementation * @param function pointer to 'verification_read' implementation - * @param function pointer to 'get_version' implementation * @param function pointer to 'abort_installation' implementation * * @return Error code @@ -251,186 +259,259 @@ WOLK_ERR_T wolk_init_firmware_update(wolk_ctx_t* ctx, firmware_update_start_inst firmware_update_is_installation_completed_t is_installation_completed, firmware_update_verification_store_t verification_store, firmware_update_verification_read_t verification_read, - firmware_update_get_version_t get_version, firmware_update_abort_t abort_installation); /** - * @brief Enable internal ping keep alive mechanism. - * By default it is enable. + * @brief Connect to WolkAbout IoT Platform + * + * Prior to connecting, following must be performed: + * 1. Context must be initialized via wolk_init(wolk_ctx_t* ctx, send_func_t snd_func, recv_func_t rcv_func, const + * char* device_key, const char* device_password, outbound_mode_t outbound_mode, feed_handler_t feed_handler, + * parameter_handler_t parameter_handler, details_synchronization_handler_t details_synchronization_handler) + * 2. Persistence must be initialized using + * wolk_init_in_memory_persistence(wolk_ctx_t* ctx, void* storage, uint32_t size, bool wrap) or + * wolk_init_custom_persistence(wolk_ctx_t* ctx, persistence_push_t push, persistence_peek_t peek, + * persistence_pop_t pop, persistence_is_empty_t is_empty) * * @param ctx Context * * @return Error code */ -WOLK_ERR_T wolk_enable_ping_keep_alive(wolk_ctx_t* ctx); +WOLK_ERR_T wolk_connect(wolk_ctx_t* ctx); /** - * @brief Disables internal ping keep alive mechanism + * @brief Disconnect from WolkAbout IoT Platform * * @param ctx Context * * @return Error code */ -WOLK_ERR_T wolk_disable_ping_keep_alive(wolk_ctx_t* ctx); +WOLK_ERR_T wolk_disconnect(wolk_ctx_t* ctx); /** - * @brief Connect to WolkAbout IoT Platform - * - * Prior to connecting, following must be performed: - * 1. Context must be initialized via wolk_init(wolk_ctx_t* ctx, send_func - * snd_func, recv_func rcv_func, const char *device_key, const char *password, - * protocol_t protocol) - * 2. Persistence must be initialized using - * wolk_initialize_in_memory_persistence(wolk_ctx_t *ctx, void* storage, - * uint16_t num_elements, bool wrap) or - * wolk_initialize_custom_persistence(wolk_ctx_t *ctx, - * persistence_push_t push, - * persistence_pop_t pop, persistence_is_empty_t is_empty, persistence_size_t - * size) + * @brief Must be called periodically to keep alive connection to WolkAbout IoT + * platform, obtain and perform incoming traffic * * @param ctx Context + * @param tick Period at which wolk_process is called * * @return Error code */ -WOLK_ERR_T wolk_connect(wolk_ctx_t* ctx); +WOLK_ERR_T wolk_process(wolk_ctx_t* ctx, uint64_t tick); /** - * @brief Disconnect from WolkAbout IoT Platform + * @brief Initialized feed + * + * @param feed Where it's data will be stored + * @param name Feed name + * @param reference Reference define on the WolkAbout IoT platform. This is mandatory filed to map feed. + * @param unit Feed's unit, use one of the defined in the type.h file + * @param feedType Can be IN or IN_OUT + * @return + */ +WOLK_ERR_T wolk_init_feed(feed_registration_t* feed, char* name, const char* reference, const char* unit, + const feed_type_t feedType); + +/** @brief Add string feed + * + * @param ctx Context + * @param reference Feed reference + * @param feeds Feed values, one or more values organized as value:utc pairs. Value is char pointer. Utc time has to + * be in milliseconds. + * @param number_of_feeds Number of feeds that is captured + * + * @return Error code + */ +WOLK_ERR_T wolk_add_string_feed(wolk_ctx_t* ctx, const char* reference, wolk_string_feeds_t* feeds, + size_t number_of_feeds); + +/** + * @brief Add numeric feeds * * @param ctx Context + * @param reference Feed reference + * @param feeds Feed values, one or more values organized as value:utc pairs. Value is double. Utc time has to be in + * milliseconds. + * @param number_of_feeds Number of feeds that is captured * * @return Error code */ -WOLK_ERR_T wolk_disconnect(wolk_ctx_t* ctx); +WOLK_ERR_T wolk_add_numeric_feed(wolk_ctx_t* ctx, const char* reference, wolk_numeric_feeds_t* feeds, + size_t number_of_feeds); /** - * @brief Must be called periodically to keep alive connection to WolkAbout IoT - * platform, obtain and perform actuation requests + * @brief Add multi-value numeric feed. For feeds that has more than one numeric number associated as value, like + * location is. Max number of numeric values is define with FEEDS_MAX_NUMBER from size_definition * * @param ctx Context - * @param tick Period at which wolk_process is called + * @param reference Feed reference + * @param values Feed values + * @param value_size Number of numeric values limited by FEEDS_MAX_NUMBER + * @param utc_time UTC time of feed value acquisition [miliseconds] * * @return Error code */ -WOLK_ERR_T wolk_process(wolk_ctx_t* ctx, uint64_t tick); +WOLK_ERR_T wolk_add_multi_value_numeric_feed(wolk_ctx_t* ctx, const char* reference, double* values, + uint16_t value_size, uint64_t utc_time); -/** @brief Add string reading +/** + * @brief Add bool feed * - * @param ctx Context - * @param reference Sensor reference - * @param value Sensor value - * @param utc_time UTC time of sensor value acquisition [seconds] + * @param ctx Context + * @param reference Feed reference + * @param feeds Feed values, one or more values organized as value:utc pairs. Value is boolean. Utc time has to be in + * milliseconds. + * @param number_of_feeds Number of feeds that is captured * - * @return Error code + * @return Error code */ -WOLK_ERR_T wolk_add_string_sensor_reading(wolk_ctx_t* ctx, const char* reference, const char* value, uint64_t utc_time); +WOLK_ERR_T wolk_add_bool_feeds(wolk_ctx_t* ctx, const char* reference, wolk_boolean_feeds_t* feeds, + size_t number_of_feeds); -/** @brief Add multi-value string reading +/** + * @brief Publish all accumulated data from persistence. It can be any data(feeds, attributed or parameters) added after + * last publish. * - * @param ctx Context - * @param reference Sensor reference - * @param values Sensor values - * @param values_size Number of sensor dimensions - * @param utc_time UTC time of sensor value acquisition [seconds] + * @param ctx Context * - * @return Error code + * @return Error code + */ +WOLK_ERR_T wolk_publish(wolk_ctx_t* ctx); + +/** + * @brief Initialized attribute + * + * @param attribute Destination attribute + * @param name String name that will be associated with the attribute + * @param data_type String value that will be associated with the attribute name + * @param value String value that will be associated with the attribute name */ -WOLK_ERR_T wolk_add_multi_value_string_sensor_reading(wolk_ctx_t* ctx, const char* reference, - const char (*values)[READING_SIZE], uint16_t values_size, - uint64_t utc_time); +WOLK_ERR_T wolk_init_attribute(wolk_attribute_t* attribute, char* name, char* data_type, char* value); /** - * @brief Add numeric reading + * @brief Register and update attribute. The attribute name must be unique per device. All attributes created by a + * device are always required and read-only. If an attribute with the given name already exists, the value will be + * updated. * * @param ctx Context - * @param reference Sensor reference - * @param value Sensor value - * @param utc_time UTC time of sensor value acquisition [seconds] + * @param attributes Attribute description consists of name, data type and value. + * @param number_of_attributes Number of attributes that is captured * * @return Error code */ -WOLK_ERR_T wolk_add_numeric_sensor_reading(wolk_ctx_t* ctx, const char* reference, double value, uint64_t utc_time); +WOLK_ERR_T wolk_register_attribute(wolk_ctx_t* ctx, wolk_attribute_t* attributes, size_t number_of_attributes); /** - * @brief Add multi-value numeric reading + * @brief Register feeds. If feed already exist error will be raised at the error channel. If bulk registration is + * request one error feed is enough to block registration. * * @param ctx Context - * @param reference Sensor reference - * @param values Sensor values - * @param values_size Number of sensor dimensions - * @param utc_time UTC time of sensor value acquisition [seconds] + * @param feeds List of feeds that will be register. The feed name and reference must be unique per device, it's user + * responsibility. + * @param number_of_feeds Number of feeds presented into feeds list * * @return Error code */ -WOLK_ERR_T wolk_add_multi_value_numeric_sensor_reading(wolk_ctx_t* ctx, const char* reference, double* values, - uint16_t values_size, uint64_t utc_time); +WOLK_ERR_T wolk_register_feed(wolk_ctx_t* ctx, feed_registration_t* feeds, size_t number_of_feeds); /** - * @brief Add bool reading + * @brief Remove feeds. * * @param ctx Context - * @param reference Sensor reference - * @param value Sensor value - * @param utc_time UTC time of sensor value acquisition [seconds] + * @param feeds A list of feed references to be removed. If there is no feed with a specified reference, the reference + * will be ignored and nothing will happen + * @param number_of_feeds Number of feeds presented into feeds list * * @return Error code */ -WOLK_ERR_T wolk_add_bool_sensor_reading(wolk_ctx_t* ctx, const char* reference, bool value, uint64_t utc_time); +WOLK_ERR_T wolk_remove_feed(wolk_ctx_t* ctx, feed_registration_t* feeds, size_t number_of_feeds); /** - * @brief Add multi-value bool reading + * @brief This will notify the platform that the device is ready to receive all feed values that were queued on the + * platform for it. Relevant when the device specified PULL mode. * * @param ctx Context - * @param reference Sensor reference - * @param values Sensor values - * @param values_size Number of sensor dimensions - * @param utc_time UTC time of sensor value acquisition [seconds] * * @return Error code */ -WOLK_ERR_T wolk_add_multi_value_bool_sensor_reading(wolk_ctx_t* ctx, const char* reference, bool* values, - uint16_t values_size, uint64_t utc_time); +WOLK_ERR_T wolk_pull_feed_values(wolk_ctx_t* ctx); + +/** + * @brief Initialized parameter + * + * @param parameter Where it's data will be stored + * @param name parameter name, one of the define at types.h or custom + * @param value parameter value + * + * @return Error code + */ +WOLK_ERR_T wolk_init_parameter(parameter_t* parameter, char* name, char* value); /** - * @brief Add alarm + * @brief Set parameter value + * + * @param parameter Where it's data will be stored + * @param value parameter value + * @return + */ +WOLK_ERR_T wolk_set_value_parameter(parameter_t* parameter, char* value); + +/** + * @brief Change existing parameters on the WolkAbout IoT Platform. + * Updating parameters this way can lead to a misconfigured connection which might prevent further updates. Update + * connectivity parameters responsibly! * * @param ctx Context - * @param reference Alarm reference - * @param message Alarm message - * @param utc_time UTC time when alarm was risen [seconds] + * @param parameters List of parameters + * @param number_of_parameters Number of parameters that is captured * * @return Error code */ -WOLK_ERR_T wolk_add_alarm(wolk_ctx_t* ctx, const char* reference, bool state, uint64_t utc_time); +WOLK_ERR_T wolk_change_parameter(wolk_ctx_t* ctx, parameter_t* parameter, size_t number_of_parameters); /** - * @brief Obtains actuator status via actuator_status_provider_t and publishes - * it. If actuator status can not be published, it is persisted. + * @brief Sending a message to this topic will notify the platform that the device is ready to receive all parameter + * updates that were queued on the platform for that device. Relevant when the device specified PULL outbound data type. * * @param ctx Context - * @param reference Actuator reference + * @param parameters List of parameters + * @param number_of_parameters Number of parameters that is captured * * @return Error code */ -WOLK_ERR_T wolk_publish_actuator_status(wolk_ctx_t* ctx, const char* reference); +WOLK_ERR_T wolk_pull_parameters(wolk_ctx_t* ctx); /** - * @brief Publish accumulated sensor readings, and alarms + * @brief A request from the device to the WolkAbout IoT platform for the current values of particular device + * parameters. The payload should contain a list of parameter names that will be contained in the response with it's + * values. * * @param ctx Context + * @param parameters List of parameters + * @param number_of_parameters Number of parameters that is captured * * @return Error code */ -WOLK_ERR_T wolk_publish(wolk_ctx_t* ctx); +WOLK_ERR_T wolk_sync_parameters(wolk_ctx_t* ctx, parameter_t* parameters, size_t number_of_parameters); /** - * @brief Get last received UTC from platform + * @brief This is request for getting WolkAbout IoT Platform's timestamp define as UTC in milliseconds. It will lead to + * updating ctx->utc to received value. * * @param ctx Context * - * @return UTC in miliseconds + * @return Error code */ -uint64_t wolk_request_timestamp(wolk_ctx_t* ctx); +WOLK_ERR_T wolk_sync_time_request(wolk_ctx_t* ctx); + +/** + * @brief Requesting list of the feeds and attributes from the WolkAbout IoT platform + * + * @param ctx Context + * @return Error code + */ +WOLK_ERR_T wolk_details_synchronization(wolk_ctx_t* ctx); + #ifdef __cplusplus } diff --git a/tests/project.yml b/tests/project.yml index 6f41466..b2074cc 100644 --- a/tests/project.yml +++ b/tests/project.yml @@ -13,7 +13,7 @@ # :release_build: TRUE :test_file_prefix: test_ :which_ceedling: gem - :ceedling_version: 0.30.0 + :ceedling_version: 0.31.1 :default_tasks: - test:all @@ -34,10 +34,8 @@ - +:test/** - -:test/support :source: - - ../sources/** - ../dependencies/pahomqttembeddedc/MQTTPacket/src/** - - src/** - - ../examples/full_feature_set/** + - ../sources/** :support: - test/support :libraries: [] diff --git a/tests/src/reading.c b/tests/src/reading.c deleted file mode 100644 index 381d2f6..0000000 --- a/tests/src/reading.c +++ /dev/null @@ -1 +0,0 @@ -#include "reading.h" diff --git a/tests/src/reading.h b/tests/src/reading.h deleted file mode 100644 index 160f58c..0000000 --- a/tests/src/reading.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef READING_H -#define READING_H - - -#endif // READING_H diff --git a/tests/src/readings.c b/tests/src/readings.c deleted file mode 100644 index f833954..0000000 --- a/tests/src/readings.c +++ /dev/null @@ -1 +0,0 @@ -#include "readings.h" diff --git a/tests/src/readings.h b/tests/src/readings.h deleted file mode 100644 index 43a7686..0000000 --- a/tests/src/readings.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef READINGS_H -#define READINGS_H - - -#endif // READINGS_H diff --git a/tests/src/wolk_connector.c b/tests/src/wolk_connector.c deleted file mode 100644 index 3e6eb7b..0000000 --- a/tests/src/wolk_connector.c +++ /dev/null @@ -1 +0,0 @@ -#include "wolk_connector.h" diff --git a/tests/src/wolk_connector.h b/tests/src/wolk_connector.h deleted file mode 100644 index 428d31d..0000000 --- a/tests/src/wolk_connector.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef WOLK_CONNECTOR_H -#define WOLK_CONNECTOR_H - - -#endif // WOLK_CONNECTOR_H diff --git a/tests/test/test_actuator_command.c b/tests/test/test_actuator_command.c deleted file mode 100644 index 025c513..0000000 --- a/tests/test/test_actuator_command.c +++ /dev/null @@ -1,71 +0,0 @@ -#include "unity.h" -#include "string.h" - -#include "actuator_command.h" - -void setUp(void) -{ -} - -void tearDown(void) -{ -} - -void test_actuator_command_actuator_command_init(void) -{ - actuator_command_t command; - char reference[MANIFEST_ITEM_REFERENCE_SIZE]; - char argument[PAYLOAD_SIZE]; - - strncpy(reference, "reference", strlen("reference")); - strncpy(argument, "off", strlen("off")); - - actuator_command_init(&command, ACTUATOR_COMMAND_TYPE_SET, reference, argument); - TEST_ASSERT_EQUAL_INT(ACTUATOR_COMMAND_TYPE_SET, command.type); - TEST_ASSERT_EQUAL_STRING(reference, command.reference); - TEST_ASSERT_EQUAL_STRING(argument, command.argument); -} - -void test_actuator_actuator_command_get_type(void) -{ - actuator_command_t command; - - actuator_command_init(&command, ACTUATOR_COMMAND_TYPE_STATUS, "", ""); - - TEST_ASSERT_EQUAL_INT(ACTUATOR_COMMAND_TYPE_STATUS, actuator_command_get_type(&command)); -} - -void test_actuator_actuator_command_get_reference(void) -{ - actuator_command_t command; - char reference[MANIFEST_ITEM_REFERENCE_SIZE]; - - strncpy(reference, "reference", strlen("reference")); - actuator_command_init(&command, ACTUATOR_COMMAND_TYPE_STATUS, reference, ""); - - TEST_ASSERT_EQUAL_STRING(reference, actuator_command_get_reference(&command)); -} - -void test_actuator_actuator_command_set_reference(void) -{ - actuator_command_t command; - char reference[MANIFEST_ITEM_REFERENCE_SIZE]; - - actuator_command_init(&command, ACTUATOR_COMMAND_TYPE_STATUS, "", ""); - - strncpy(reference, "reference", strlen("reference")); - - actuator_command_set_reference(&command, reference); - TEST_ASSERT_EQUAL_STRING(reference, actuator_command_get_reference(&command)); -} - -void test_actuator_actuator_command_get_value(void) -{ - actuator_command_t command; - char argument[PAYLOAD_SIZE]; - - strncpy(argument, "32.1", strlen("32.1")); - actuator_command_init(&command, ACTUATOR_COMMAND_TYPE_STATUS, "", argument); - - TEST_ASSERT_EQUAL_STRING(argument, actuator_command_get_value(&command)); -} diff --git a/tests/test/test_actuator_status.c b/tests/test/test_actuator_status.c deleted file mode 100644 index 3784018..0000000 --- a/tests/test/test_actuator_status.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "unity.h" -#include "string.h" - -#include "actuator_status.h" - -void setUp(void) -{ -} - -void tearDown(void) -{ -} - -void test_actuator_status_actuator_status_init(void) -{ - actuator_status_t actuator_status; - char value[PAYLOAD_SIZE]; - - strncpy(value, "0", strlen("0")); - actuator_status_init(&actuator_status, value, ACTUATOR_STATE_READY); - - TEST_ASSERT_EQUAL_INT(ACTUATOR_STATE_READY, actuator_status.state); - TEST_ASSERT_EQUAL_STRING(value, actuator_status.value); -} diff --git a/tests/test/test_json_parser.c b/tests/test/test_json_parser.c index 3d0e4ef..adb120d 100644 --- a/tests/test/test_json_parser.c +++ b/tests/test/test_json_parser.c @@ -1,34 +1,40 @@ +#ifdef TEST + #include "unity.h" -#include "json_parser.h" -#include "actuator_command.h" -#include "base64.h" -#include "file_management_parameter.h" -#include "file_management_packet_request.h" -#include "file_management_status.h" -#include "jsmn.h" -#include "reading.h" +#include "MQTTPacket.h" #include "size_definitions.h" -#include "wolk_utils.h" -#include "firmware_update.h" - -#include "manifest_item.h" -#include "outbound_message.h" -#include "configuration_command.h" - #include "string.h" +#include "types.h" +//#include "wolk_connector.h" + +#include "model/attribute.h" +#include "model/feed.h" +#include "model/file_management/file_management.h" +#include "model/file_management/file_management_packet.h" +#include "model/file_management/file_management_packet_request.h" +#include "model/file_management/file_management_parameter.h" +#include "model/file_management/file_management_status.h" +#include "model/firmware_update.h" +#include "model/outbound_message.h" +#include "model/outbound_message_factory.h" +#include "model/utc_command.h" +#include "connectivity/data_transmission.h" -reading_t first_reading; +#include "persistence/in_memory_persistence.h" +#include "persistence/persistence.h" -static const char* UNIT_TEST_READINGS_TOPIC = "d2p/sensor_reading/d/"; -static const char* UNIT_TEST_EVENTS_TOPIC = "d2p/events/d/"; +#include "protocol/json_parser.h" +#include "protocol/parser.h" -static const char* UNIT_TEST_ACTUATOR_SET_TOPIC = "p2d/actuator_set/d/"; -static const char* UNIT_TEST_ACTUATOR_STATUS_TOPIC = "d2p/actuator_status/d/"; +#include "utility/base64.h" +#include "utility/circular_buffer.h" +#include "utility/jsmn.h" +#include "utility/md5.h" +#include "utility/sha256.h" +#include "utility/wolk_utils.h" -static const char* UNIT_TEST_CONFIGURATION_SET = "p2d/configuration_set/d/"; -static const char* UNIT_TEST_CONFIGURATION_GET = "d2p/configuration_get/d/"; void setUp(void) { @@ -38,200 +44,157 @@ void tearDown(void) { } -void test_json_parser_json_serialize_readings_sensor(void) + +void test_json_parser_json_serialize_feed_all_types(void) { - char buffer[PAYLOAD_SIZE]; - uint64_t rtc = 1591621716; - manifest_item_t string_sensor; + feed_t first_feed; + char buffer[PAYLOAD_SIZE] = ""; + uint64_t utc = 1646815080000; // in milliseconds /* Data type String */ - manifest_item_init(&string_sensor, "reference", READING_TYPE_SENSOR, DATA_TYPE_STRING); - manifest_item_set_reading_dimensions_and_delimiter(&string_sensor, 1, DATA_DELIMITER); - - reading_init(&first_reading, &string_sensor); - reading_set_data_at(&first_reading, "TEST SENSOR", 0); - reading_set_rtc(&first_reading, rtc); + feed_initialize(&first_feed, 1, "FS"); + feed_set_data_at(&first_feed, "FEED STRING", 0); + feed_set_utc(&first_feed, utc); - TEST_ASSERT_TRUE(json_serialize_readings(&first_reading, 1, buffer, sizeof(buffer))); - TEST_ASSERT_EQUAL_STRING("{\"utc\":1591621716,\"data\":\"TEST SENSOR\"}", buffer); + TEST_ASSERT_TRUE(json_serialize_feeds(&first_feed, STRING, 1, 1, buffer, sizeof(buffer))); + TEST_ASSERT_EQUAL_STRING("[{\"FS\":\"FEED STRING\",\"timestamp\":1646815080000}]", buffer); /* Data type Numeric */ - manifest_item_init(&string_sensor, "reference", READING_TYPE_SENSOR, DATA_TYPE_NUMERIC); - - reading_init(&first_reading, &string_sensor); - reading_set_data_at(&first_reading, "32.1", 0); - reading_set_rtc(&first_reading, rtc); + feed_initialize(&first_feed, 1, "FN"); + feed_set_data_at(&first_feed, "32.1", 0); + feed_set_utc(&first_feed, utc); - TEST_ASSERT_TRUE(json_serialize_readings(&first_reading, 1, buffer, sizeof(buffer))); - TEST_ASSERT_EQUAL_STRING("{\"utc\":1591621716,\"data\":\"32.1\"}", buffer); + TEST_ASSERT_TRUE(json_serialize_feeds(&first_feed, NUMERIC, 1, 1, buffer, sizeof(buffer))); + TEST_ASSERT_EQUAL_STRING("[{\"FN\":32.1,\"timestamp\":1646815080000}]", buffer); /* Data type Boolean */ - manifest_item_init(&string_sensor, "reference", READING_TYPE_SENSOR, DATA_TYPE_BOOLEAN); + feed_initialize(&first_feed, 1, "FB"); + feed_set_data_at(&first_feed, "true", 0); + feed_set_utc(&first_feed, utc); - reading_init(&first_reading, &string_sensor); - reading_set_data_at(&first_reading, "ON", 0); - reading_set_rtc(&first_reading, rtc); - - TEST_ASSERT_TRUE(json_serialize_readings(&first_reading, 1, buffer, sizeof(buffer))); - TEST_ASSERT_EQUAL_STRING("{\"utc\":1591621716,\"data\":\"ON\"}", buffer); + TEST_ASSERT_TRUE(json_serialize_feeds(&first_feed, BOOLEAN, 1, 1, buffer, sizeof(buffer))); + TEST_ASSERT_EQUAL_STRING("[{\"FB\":\"true\",\"timestamp\":1646815080000}]", buffer); } -void test_json_parser_json_serialize_readings_actuator(void) +void test_json_parser_json_serialize_feeds_all_types_different_timestamp(void) { - char buffer[PAYLOAD_SIZE]; - manifest_item_t string_sensor; + feed_t first_feed[3]; + char buffer[PAYLOAD_SIZE] = ""; + uint64_t utc = 1646815080000; // in milliseconds /* Data type String */ - manifest_item_init(&string_sensor, "reference", READING_TYPE_ACTUATOR, DATA_TYPE_STRING); - - reading_init(&first_reading, &string_sensor); - reading_set_data_at(&first_reading, "TEST ACTUATOR", 0); - - TEST_ASSERT_TRUE(json_serialize_readings(&first_reading, 1, buffer, sizeof(buffer))); - TEST_ASSERT_EQUAL_STRING("{\"status\":\"READY\",\"value\":\"TEST ACTUATOR\"}", buffer); - + feed_initialize(&first_feed[0], 1, "FS"); + feed_set_data_at(&first_feed[0], "STRING1", 0); + feed_set_utc(&first_feed[0], utc); + feed_initialize(&first_feed[1], 1, "FS"); + feed_set_data_at(&first_feed[1], "STRING2", 0); + feed_set_utc(&first_feed[1], utc + 100); + + TEST_ASSERT_TRUE(json_serialize_feeds(&first_feed, STRING, 2, 1, buffer, sizeof(buffer))); + TEST_ASSERT_EQUAL_STRING( + "[{\"FS\":\"STRING1\",\"timestamp\":1646815080000},{\"FS\":\"STRING2\",\"timestamp\":1646815080100}]", buffer); + + memset(buffer, '\0', PAYLOAD_SIZE); /* Data type Numeric */ - manifest_item_init(&string_sensor, "reference", READING_TYPE_ACTUATOR, DATA_TYPE_NUMERIC); + feed_initialize(&first_feed[0], 1, "FN"); + feed_set_data_at(&first_feed[0], "3", 0); + feed_set_utc(&first_feed[0], utc); - reading_init(&first_reading, &string_sensor); - reading_set_data_at(&first_reading, "32.1", 0); + feed_initialize(&first_feed[1], 1, "FN"); + feed_set_data_at(&first_feed[1], "32", 0); + feed_set_utc(&first_feed[1], utc + 100); - TEST_ASSERT_TRUE(json_serialize_readings(&first_reading, 1, buffer, sizeof(buffer))); - TEST_ASSERT_EQUAL_STRING("{\"status\":\"READY\",\"value\":\"32.1\"}", buffer); + feed_initialize(&first_feed[2], 1, "FN"); + feed_set_data_at(&first_feed[2], "32.1", 0); + feed_set_utc(&first_feed[2], utc + 200); - TEST_ASSERT_EQUAL_STRING("{\"status\":\"READY\",\"value\":\"32.1\"}", buffer); + TEST_ASSERT_TRUE(json_serialize_feeds(&first_feed, NUMERIC, 3, 1, buffer, sizeof(buffer))); + TEST_ASSERT_EQUAL_STRING( + "[{\"FN\":3,\"timestamp\":1646815080000},{\"FN\":32,\"timestamp\":1646815080100},{\"FN\":32.1,\"timestamp\":1646815080200}]", + buffer); + memset(buffer, '\0', PAYLOAD_SIZE); /* Data type Boolean */ - manifest_item_init(&string_sensor, "reference", READING_TYPE_ACTUATOR, DATA_TYPE_BOOLEAN); + feed_initialize(&first_feed[0], 1, "FB"); + feed_set_data_at(&first_feed[0], "true", 0); + feed_set_utc(&first_feed[0], utc); - reading_init(&first_reading, &string_sensor); - reading_set_data_at(&first_reading, "ON", 0); + feed_initialize(&first_feed[1], 1, "FB"); + feed_set_data_at(&first_feed[1], "false", 0); + feed_set_utc(&first_feed[1], utc + 100); - TEST_ASSERT_TRUE(json_serialize_readings(&first_reading, 1, buffer, sizeof(buffer))); - TEST_ASSERT_EQUAL_STRING("{\"status\":\"READY\",\"value\":\"ON\"}", buffer); + TEST_ASSERT_TRUE(json_serialize_feeds(&first_feed, BOOLEAN, 2, 1, buffer, sizeof(buffer))); + TEST_ASSERT_EQUAL_STRING( + "[{\"FB\":\"true\",\"timestamp\":1646815080000},{\"FB\":\"false\",\"timestamp\":1646815080100}]", buffer); } -void test_json_parser_json_serialize_readings_alarm(void) +void test_json_parser_json_serialize_feed_multivalue(void) { - char buffer[PAYLOAD_SIZE]; - uint64_t rtc = 1591621716; - manifest_item_t string_sensor; + feed_t first_feed; + char buffer[PAYLOAD_SIZE] = ""; + uint64_t utc = 1646815080000; // in milliseconds /* Data type String */ - manifest_item_init(&string_sensor, "reference", READING_TYPE_ALARM, DATA_TYPE_STRING); - - reading_init(&first_reading, &string_sensor); - reading_set_data_at(&first_reading, "ON", 0); - reading_set_rtc(&first_reading, rtc); - - TEST_ASSERT_TRUE(json_serialize_readings(&first_reading, 1, buffer, sizeof(buffer))); - TEST_ASSERT_EQUAL_STRING("{\"utc\":1591621716,\"data\":\"ON\"}", buffer); -} + feed_initialize(&first_feed, 3, "FS"); + feed_set_data_at(&first_feed, "STRING1", 0); + feed_set_data_at(&first_feed, "STRING2", 1); + feed_set_data_at(&first_feed, "STRING3", 2); + feed_set_utc(&first_feed, utc); -void test_json_parser_json_deserialize_actuator_commands(void) -{ - char topic[TOPIC_SIZE]; - char payload[PAYLOAD_SIZE]; - int payload_len = 0; - actuator_command_t actuator_command; - - strncpy(topic, UNIT_TEST_ACTUATOR_SET_TOPIC, strlen(UNIT_TEST_ACTUATOR_SET_TOPIC)); - strcat(topic, "/r/reference"); - strncpy(payload, "{\"value\":\"321.1\"}", strlen("{\"value\":\"321.1\"}")+1); - payload_len = strlen(payload); - - TEST_ASSERT_EQUAL_INT(1, json_deserialize_actuator_commands(topic, strlen(topic), payload, (size_t)payload_len, &actuator_command, 1)); - TEST_ASSERT_EQUAL_STRING("321.1", actuator_command.argument); -} - -void test_json_json_serialize_readings_topic(void) -{ - char device_key[DEVICE_KEY_SIZE]; - char buffer[PAYLOAD_SIZE]; - char topic[TOPIC_SIZE]; - char reference[MANIFEST_ITEM_REFERENCE_SIZE] = {"reference"}; - manifest_item_t string_sensor; + TEST_ASSERT_TRUE(json_serialize_feeds(&first_feed, STRING, 1, 3, buffer, sizeof(buffer))); + TEST_ASSERT_EQUAL_STRING("[{\"FS\":\"STRING1,STRING2,STRING3\",\"timestamp\":1646815080000}]", buffer); - /* Data type String */ - manifest_item_init(&string_sensor, reference, READING_TYPE_SENSOR, DATA_TYPE_STRING); - manifest_item_set_reading_dimensions_and_delimiter(&string_sensor, 1, DATA_DELIMITER); - - reading_init(&first_reading, &string_sensor); - reading_set_data_at(&first_reading, "TEST SENSOR", 0); + memset(buffer, '\0', PAYLOAD_SIZE); + /* Data type Numeric */ + feed_initialize(&first_feed, 3, "FN"); + feed_set_data_at(&first_feed, "3", 0); + feed_set_data_at(&first_feed, "32", 1); + feed_set_data_at(&first_feed, "32.1", 2); + feed_set_utc(&first_feed, utc); - strncpy(device_key, "some_device_key", strlen("some_device_key")); + TEST_ASSERT_TRUE(json_serialize_feeds(&first_feed, NUMERIC, 1, 3, buffer, sizeof(buffer))); + TEST_ASSERT_EQUAL_STRING("[{\"FN\":3,32,32.1,\"timestamp\":1646815080000}]", buffer); - strncpy(topic, UNIT_TEST_READINGS_TOPIC, strlen(UNIT_TEST_READINGS_TOPIC)+1); - strcat(topic, device_key); - strcat(topic, "/r/"); - strcat(topic, reference); + memset(buffer, '\0', PAYLOAD_SIZE); + /* Data type Boolean */ + feed_initialize(&first_feed, 2, "FB"); + feed_set_data_at(&first_feed, "true", 0); + feed_set_data_at(&first_feed, "false", 1); + feed_set_utc(&first_feed, utc); - TEST_ASSERT_TRUE(json_serialize_readings_topic(&first_reading, 1, device_key, buffer, PAYLOAD_SIZE)); - TEST_ASSERT_EQUAL_STRING(topic, buffer); + TEST_ASSERT_TRUE(json_serialize_feeds(&first_feed, BOOLEAN, 1, 2, buffer, sizeof(buffer))); + TEST_ASSERT_EQUAL_STRING("[{\"FB\":\"true,false\",\"timestamp\":1646815080000}]", buffer); } -void test_json_parser_json_serialize_configuration_single_item(void) +void test_json_deserialize_file_delete(void) { - char device_key[DEVICE_KEY_SIZE] = {"some_device_key"}; - char references[CONFIGURATION_ITEMS_SIZE][CONFIGURATION_REFERENCE_SIZE] = {"reference"}; - char values[CONFIGURATION_ITEMS_SIZE][CONFIGURATION_VALUE_SIZE] = {"string"}; - char topic[TOPIC_SIZE]; - int8_t num_configuration_items = 1; - outbound_message_t outbound_message; - - strncpy(topic, UNIT_TEST_CONFIGURATION_GET, strlen(UNIT_TEST_CONFIGURATION_GET)+1); - strcat(topic, device_key); - - TEST_ASSERT_TRUE(json_serialize_configuration(device_key, references, values, num_configuration_items, &outbound_message)); - TEST_ASSERT_EQUAL_STRING(topic, outbound_message.topic); - TEST_ASSERT_EQUAL_STRING("{\"values\":{\"reference\":\"string\"}}", outbound_message.payload); + char received_payload[100]; + strcpy(received_payload, "[\"My file\", \"My other file\", \"firmware_1.0.0.firmware\"]"); + size_t buffer_size = 40; + file_list_t file_list[10]; + + TEST_ASSERT_EQUAL_INT(3, json_deserialize_file_delete((char*)received_payload, buffer_size, file_list)); + TEST_ASSERT_EQUAL_STRING("My file", file_list[0].file_name); + TEST_ASSERT_EQUAL_STRING("My other file", file_list[1].file_name); + TEST_ASSERT_EQUAL_STRING("firmware_1.0.0.firmware", file_list[2].file_name); } -void test_json_parser_json_serialize_configuration_multi_item(void) +void test_json_deserialize_url_download(void) { - char device_key[DEVICE_KEY_SIZE] = {"some_device_key"}; - char references[CONFIGURATION_ITEMS_SIZE][CONFIGURATION_REFERENCE_SIZE] = {"reference1", "reference2", "referenceN"}; - char values[CONFIGURATION_ITEMS_SIZE][CONFIGURATION_VALUE_SIZE] = {"string1", "string2", "stringN"}; - char topic[TOPIC_SIZE]; - int8_t num_configuration_items = 3; - outbound_message_t outbound_message; - - strncpy(topic, UNIT_TEST_CONFIGURATION_GET, strlen(UNIT_TEST_CONFIGURATION_GET)+1); - strcat(topic, device_key); - - TEST_ASSERT_TRUE(json_serialize_configuration(device_key, references, values, num_configuration_items, &outbound_message)); - TEST_ASSERT_EQUAL_STRING(topic, outbound_message.topic); - TEST_ASSERT_EQUAL_STRING("{\"values\":{\"reference1\":\"string1\",\"reference2\":\"string2\",\"referenceN\":\"stringN\"}}", outbound_message.payload); + char* buffer = "\"https://www.modbusdriver.com/downloads/modpoll.tgz\""; + char url_download[100] = {0}; + + TEST_ASSERT_TRUE(json_deserialize_url_download(buffer, strlen(buffer), url_download)); + TEST_ASSERT_EQUAL_STRING("https://www.modbusdriver.com/downloads/modpoll.tgz", url_download); + + TEST_ASSERT_FALSE(json_deserialize_url_download("https://www.modbusdriver.com/downloads/modpoll.tgz\"", + strlen("https://www.modbusdriver.com/downloads/modpoll.tgz\""), + url_download)); + TEST_ASSERT_FALSE(json_deserialize_url_download("\"https://www.modbusdriver.com/downloads/modpoll.tgz\"", + strlen("\"https://www.modbusdriver.com/downloads/modpoll.tgz"), + url_download)); + TEST_ASSERT_FALSE(json_deserialize_url_download("", 0, url_download)); } -void test_json_parser_json_deserialize_configuration_command_single(void) -{ - char buffer[PAYLOAD_SIZE]; - configuration_command_t current_config_command; - int8_t num_deserialized_config_items = 1; - - int8_t buffer_size = strlen("{\"EF\":\"T,H,P,ACL\"}")+1; - strncpy(buffer, "{\"EF\":\"T,H,P,ACL\"}", buffer_size); - TEST_ASSERT_EQUAL_INT(num_deserialized_config_items, json_deserialize_configuration_command(buffer, buffer_size, ¤t_config_command, num_deserialized_config_items)); - TEST_ASSERT_EQUAL_STRING("EF", current_config_command.reference); - TEST_ASSERT_EQUAL_INT(CONFIGURATION_COMMAND_TYPE_SET, current_config_command.type); - TEST_ASSERT_EQUAL_STRING("T,H,P,ACL", current_config_command.value[0]); -} - -void test_json_parser_json_deserialize_configuration_command_multi(void) -{ - char buffer[PAYLOAD_SIZE]; - configuration_command_t current_config_command; - int8_t num_deserialized_config_items = 3; - - int8_t buffer_size = strlen("{\"EF\":\"T,H,P,ACL\",\"HB\":\"5\",\"LL\":\"debug\"}")+1; - strncpy(buffer, "{\"EF\":\"T,H,P,ACL\",\"HB\":\"5\",\"LL\":\"debug\"}", buffer_size); - - TEST_ASSERT_EQUAL_INT(num_deserialized_config_items, json_deserialize_configuration_command(buffer, buffer_size, ¤t_config_command, num_deserialized_config_items)); - TEST_ASSERT_EQUAL_STRING("EF", current_config_command.reference); - TEST_ASSERT_EQUAL_INT(CONFIGURATION_COMMAND_TYPE_SET, current_config_command.type); - TEST_ASSERT_EQUAL_STRING("T,H,P,ACL", current_config_command.value[0]); - TEST_ASSERT_EQUAL_STRING("5", current_config_command.value[1]); - TEST_ASSERT_EQUAL_STRING("debug", current_config_command.value[2]); -} +#endif // TEST diff --git a/tests/test/test_reading.c b/tests/test/test_reading.c deleted file mode 100644 index e6bd944..0000000 --- a/tests/test/test_reading.c +++ /dev/null @@ -1,159 +0,0 @@ -#include "unity.h" - -#include "reading.h" -#include "manifest_item.h" -#include "actuator_status.h" - - -reading_t reading; - -void setUp(void) -{ -} - -void tearDown(void) -{ -} - -void test_reading_readings_init(void) -{ - manifest_item_t string_sensor; - manifest_item_init(&string_sensor, "T", READING_TYPE_SENSOR, DATA_TYPE_STRING); - - reading_init(&reading, &string_sensor); - - TEST_ASSERT_EQUAL_INT(reading.actuator_status, ACTUATOR_STATE_READY); - TEST_ASSERT_EQUAL_INT(reading.manifest_item.reading_type, READING_TYPE_SENSOR); - TEST_ASSERT_EQUAL_INT(reading.manifest_item.data_type, DATA_TYPE_STRING); - TEST_ASSERT_EQUAL_STRING("T", reading.manifest_item.reference); - - reading_clear(&reading); - TEST_ASSERT_EQUAL_STRING("", reading.reading_data); -} - -void test_reading_readings_clear() -{ - manifest_item_t string_sensor; - manifest_item_init(&string_sensor, "reference", READING_TYPE_SENSOR, DATA_TYPE_STRING); - - reading_init(&reading, &string_sensor); - reading_set_data(&reading, "TEST READINGS"); - TEST_ASSERT_EQUAL_STRING("TEST READINGS", reading.reading_data); - - reading_clear(&reading); - - TEST_ASSERT_EQUAL_INT(ACTUATOR_STATE_READY, reading.actuator_status); - TEST_ASSERT_EQUAL_INT(0, reading.rtc); - TEST_ASSERT_EQUAL_STRING("", reading.reading_data); -} - -void test_reading_reading_set_data(void) -{ - manifest_item_t string_sensor; - manifest_item_init(&string_sensor, "reference", READING_TYPE_SENSOR, DATA_TYPE_STRING); - - reading_init(&reading, &string_sensor); - reading_set_data(&reading, "TEST READINGS"); - - TEST_ASSERT_EQUAL_STRING("TEST READINGS", reading.reading_data); - - reading_clear(&reading); - TEST_ASSERT_EQUAL_STRING("", reading.reading_data); -} - -void test_reading_reading_get_delimited_data(void) -{ - char data_buffer[PARSER_INTERNAL_BUFFER_SIZE]; - int8_t values_size = 2; - manifest_item_t string_sensor; - manifest_item_init(&string_sensor, "reference", READING_TYPE_SENSOR, DATA_TYPE_STRING); - manifest_item_set_reading_dimensions_and_delimiter(&string_sensor, values_size, DATA_DELIMITER); - - reading_init(&reading, &string_sensor); - reading_set_rtc(&reading, 1591621716); - - for (uint32_t i = 0; i < values_size; ++i) { - reading_set_data_at(&reading, "TEST READINGS", i); - } - - TEST_ASSERT(reading_get_delimited_data(&reading, data_buffer, PARSER_INTERNAL_BUFFER_SIZE)); - - reading_clear(&reading); - TEST_ASSERT_EQUAL_STRING("", reading.reading_data); -} - -void test_reading_reading_set_data_at(void) -{ - reading_set_data_at(&reading, "TEST READING", 0); - - TEST_ASSERT_EQUAL_STRING("TEST READING", reading.reading_data); - - reading_clear(&reading); - TEST_ASSERT_EQUAL_STRING("", reading.reading_data); -} - -void test_reading_reading_get_data_at(void) -{ - manifest_item_t string_sensor; - manifest_item_init(&string_sensor, "reference", READING_TYPE_SENSOR, DATA_TYPE_STRING); - - reading_init(&reading, &string_sensor); - reading_set_data_at(&reading, "TEST READINGS", 0); - - TEST_ASSERT_EQUAL_STRING("TEST READINGS", reading_get_data_at(&reading, 0)); - - reading_clear(&reading); - TEST_ASSERT_EQUAL_STRING("", reading.reading_data); -} - -void test_reading_reading_get_manifest_item(void) -{ - manifest_item_t string_sensor; - manifest_item_init(&string_sensor, "reference", READING_TYPE_SENSOR, DATA_TYPE_NUMERIC); - manifest_item_set_reading_dimensions_and_delimiter(&string_sensor, 1, DATA_DELIMITER); - - reading_init(&reading, &string_sensor); - reading_set_data_at(&reading, "TEST READINGS", 0); - - TEST_ASSERT_EQUAL_STRING("reference", reading_get_manifest_item(&reading)->reference); - TEST_ASSERT_EQUAL_INT(READING_TYPE_SENSOR, reading_get_manifest_item(&reading)->reading_type); - TEST_ASSERT_EQUAL_INT(DATA_TYPE_NUMERIC, reading_get_manifest_item(&reading)->data_type); - TEST_ASSERT_EQUAL_INT(1, reading_get_manifest_item(&reading)->data_dimensions); - TEST_ASSERT_EQUAL_STRING(DATA_DELIMITER, reading_get_manifest_item(&reading)->data_delimiter); -} - -void test_reading_set_rtc(void) -{ - uint64_t rtc = 1591621716; - reading_set_rtc(&reading, rtc); - - TEST_ASSERT_EQUAL_INT64(rtc, reading.rtc); -} - -void test_reading_reading_get_rtc(void) -{ - uint64_t rtc = 1591621716; - reading_set_rtc(&reading, rtc); - - TEST_ASSERT_EQUAL_INT64(rtc, reading_get_rtc(&reading)); -} - -void test_reading_reading_set_actuator_state(void) -{ - reading_set_actuator_state(&reading, ACTUATOR_STATE_READY); - - TEST_ASSERT_EQUAL_INT(ACTUATOR_STATE_READY, reading.actuator_status); - - reading_clear(&reading); - TEST_ASSERT_EQUAL_STRING("", reading.reading_data); -} - -void test_reading_reading_get_actuator_state(void) -{ - reading_set_actuator_state(&reading, ACTUATOR_STATE_BUSY); - - TEST_ASSERT_EQUAL_INT(ACTUATOR_STATE_BUSY, reading_get_actuator_state(&reading)); - - reading_clear(&reading); - TEST_ASSERT_EQUAL_STRING("", reading.reading_data); -} diff --git a/tests/test/test_wolk_connector.c b/tests/test/test_wolk_connector.c deleted file mode 100644 index d29cf12..0000000 --- a/tests/test/test_wolk_connector.c +++ /dev/null @@ -1,361 +0,0 @@ -#include "unity.h" - -#include -#include -#include - -TEST_FILE("MQTTSerializePublish.c") -TEST_FILE("MQTTConnectClient.c") -TEST_FILE("MQTTDeserializePublish.c") -TEST_FILE("MQTTSubscribeClient.c") - -#include "wolk_connector.h" -#include "wolk_utils.h" - -#include "MQTTPacket.h" - -#include "sha256.h" -#include "base64.h" -#include "data_transmission.h" -#include "size_definitions.h" -#include "parser.h" -#include "json_parser.h" -#include "jsmn.h" -#include "manifest_item.h" -#include "circular_buffer.h" -#include "outbound_message.h" -#include "outbound_message_factory.h" - -#include "reading.h" -#include "actuator_command.h" -#include "actuator_status.h" -#include "configuration_command.h" -#include "utc_command.h" - -#include "persistence.h" -#include "in_memory_persistence.h" - -#include "file_management.h" -#include "file_management_packet.h" -#include "file_management_parameter.h" -#include "file_management_status.h" -#include "file_management_packet_request.h" -#include "file_management_implementation.h" - -#include "firmware_update.h" - - -void setUp(void) -{ -} - -void tearDown(void) -{ -} - -void test_wolk_connector_wolk_init_simple(void) -{ - wolk_ctx_t wolk; - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_init(&wolk, NULL, NULL, NULL, ACTUATOR_STATE_READY, NULL, NULL, "device_key", "device_password", PROTOCOL_WOLKABOUT, NULL, 0)); - - TEST_ASSERT_EQUAL_INT(NULL, wolk.actuation_handler); - TEST_ASSERT_EQUAL_INT(ACTUATOR_STATE_READY, wolk.actuator_status_provider); - TEST_ASSERT_EQUAL_INT(NULL, wolk.configuration_handler); - TEST_ASSERT_EQUAL_INT(NULL, wolk.configuration_provider); - TEST_ASSERT_EQUAL_STRING("device_key", wolk.device_key); - TEST_ASSERT_EQUAL_STRING("device_password", wolk.device_password); - TEST_ASSERT_EQUAL_INT(PROTOCOL_WOLKABOUT, wolk.protocol); - TEST_ASSERT_EQUAL_INT(NULL, wolk.actuator_references); - TEST_ASSERT_EQUAL_INT(ACTUATOR_STATE_READY, wolk.num_actuator_references); -} - -void test_wolk_connector_wolk_init_ffs(void) -{ - wolk_ctx_t wolk; - int send_buffer(unsigned char* buffer, unsigned int len){return 1;} - int receive_buffer(unsigned char* buffer, unsigned int max_bytes){return 1;} - void actuation_handler(const char* reference, const char* value){} - actuator_status_t actuator_status_provider(const char* reference){ - actuator_status_t actuator_status; - actuator_status_init(&actuator_status, "1", ACTUATOR_STATE_READY); - return actuator_status; - } - void configuration_handler(char (*reference)[CONFIGURATION_REFERENCE_SIZE], char (*value)[CONFIGURATION_VALUE_SIZE], size_t num_configuration_items){} - size_t configuration_provider(char (*reference)[CONFIGURATION_REFERENCE_SIZE], char (*value)[CONFIGURATION_VALUE_SIZE], size_t max_num_configuration_items){return CONFIGURATION_ITEMS_SIZE;} - static const char* actuator_references[] = {"SW"}; - static const uint32_t num_actuator_references = 1; - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_init(&wolk, send_buffer, receive_buffer, actuation_handler, actuator_status_provider, configuration_handler, configuration_provider, "device_key", "device_password", PROTOCOL_WOLKABOUT, actuator_references, num_actuator_references)); - - TEST_ASSERT_EQUAL_INT(actuation_handler, wolk.actuation_handler); - TEST_ASSERT_EQUAL_INT(actuator_status_provider, wolk.actuator_status_provider); - TEST_ASSERT_EQUAL_INT(configuration_handler, wolk.configuration_handler); - TEST_ASSERT_EQUAL_INT(configuration_provider, wolk.configuration_provider); - TEST_ASSERT_EQUAL_STRING("device_key", wolk.device_key); - TEST_ASSERT_EQUAL_STRING("device_password", wolk.device_password); - TEST_ASSERT_EQUAL_INT(PROTOCOL_WOLKABOUT, wolk.protocol); - TEST_ASSERT_EQUAL_INT(actuator_references, wolk.actuator_references); - TEST_ASSERT_EQUAL_INT(num_actuator_references, wolk.num_actuator_references); -} - -void test_wolk_connector_wolk_connect(void) -{ - wolk_ctx_t wolk; - int send_buffer(unsigned char* buffer, unsigned int len){return 1;} - int receive_buffer(unsigned char* buffer, unsigned int max_bytes){return 1;} - void actuation_handler(const char* reference, const char* value){} - actuator_status_t actuator_status_provider(const char* reference){ - actuator_status_t actuator_status; - actuator_status_init(&actuator_status, "1", ACTUATOR_STATE_READY); - return actuator_status; - } - void configuration_handler(char (*reference)[CONFIGURATION_REFERENCE_SIZE], char (*value)[CONFIGURATION_VALUE_SIZE], size_t num_configuration_items){} - size_t configuration_provider(char (*reference)[CONFIGURATION_REFERENCE_SIZE], char (*value)[CONFIGURATION_VALUE_SIZE], size_t max_num_configuration_items){return CONFIGURATION_ITEMS_SIZE;} - static const char* actuator_references[] = {"SW"}; - static const uint32_t num_actuator_references = 1; - bool file_management_start(const char* file_name, size_t file_size){}; - bool file_management_chunk_write(uint8_t* data, size_t data_size){}; - size_t file_management_chunk_read(size_t index, uint8_t* data, size_t data_size){}; - void file_management_abort(void){}; - void file_management_finalize(void){}; - bool file_management_start_url_download(const char* url){}; - bool file_management_is_url_download_done(bool* success){}; - int8_t file_management_get_file_list(char* file_list){return 0;}; - bool file_management_remove_file(const char* file_name){}; - bool file_management_purge_files(void){}; - bool firmware_update_start_installation(const char* file_name){}; - bool firmware_update_is_installation_completed(bool* success){}; - bool firmware_update_verification_store(uint8_t parameter){}; - uint8_t firmware_update_verification_read(void){}; - bool firmware_update_get_version(const char* version){}; - bool firmware_update_abort_installation(void){}; - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_init(&wolk, send_buffer, receive_buffer, actuation_handler, actuator_status_provider, configuration_handler, configuration_provider, "device_key", "device_password", PROTOCOL_WOLKABOUT, actuator_references, num_actuator_references)); - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_init_file_management(&wolk, 128 * 1024 * 1024, 500, file_management_start, file_management_chunk_write, file_management_chunk_read, file_management_abort, file_management_finalize, file_management_start_url_download, file_management_is_url_download_done, file_management_get_file_list, file_management_remove_file, file_management_purge_files)); - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_init_firmware_update(&wolk, firmware_update_start_installation, firmware_update_is_installation_completed, firmware_update_verification_store, firmware_update_verification_read, firmware_update_get_version, firmware_update_abort_installation)); - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_connect(&wolk)); -} - -void test_wolk_connector_wolk_disconnect(void) -{ - wolk_ctx_t wolk; - int send_buffer(unsigned char* buffer, unsigned int len){return 1;} - int receive_buffer(unsigned char* buffer, unsigned int max_bytes){return 1;} - void actuation_handler(const char* reference, const char* value){} - actuator_status_t actuator_status_provider(const char* reference){ - actuator_status_t actuator_status; - actuator_status_init(&actuator_status, "1", ACTUATOR_STATE_READY); - return actuator_status; - } - void configuration_handler(char (*reference)[CONFIGURATION_REFERENCE_SIZE], char (*value)[CONFIGURATION_VALUE_SIZE], size_t num_configuration_items){} - size_t configuration_provider(char (*reference)[CONFIGURATION_REFERENCE_SIZE], char (*value)[CONFIGURATION_VALUE_SIZE], size_t max_num_configuration_items){return CONFIGURATION_ITEMS_SIZE;} - static const char* actuator_references[] = {"SW"}; - static const uint32_t num_actuator_references = 1; - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_init(&wolk, send_buffer, receive_buffer, actuation_handler, actuator_status_provider, configuration_handler, configuration_provider, "device_key", "device_password", PROTOCOL_WOLKABOUT, actuator_references, num_actuator_references)); - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_disconnect(&wolk)); -} - -void test_wolk_connector_wolk_process(void) -{ - wolk_ctx_t wolk; - int send_buffer(unsigned char* buffer, unsigned int len){return 1;} - int receive_buffer(unsigned char* buffer, unsigned int max_bytes){return 1;} - void actuation_handler(const char* reference, const char* value){} - actuator_status_t actuator_status_provider(const char* reference){ - actuator_status_t actuator_status; - actuator_status_init(&actuator_status, "1", ACTUATOR_STATE_READY); - return actuator_status; - } - void configuration_handler(char (*reference)[CONFIGURATION_REFERENCE_SIZE], char (*value)[CONFIGURATION_VALUE_SIZE], size_t num_configuration_items){} - size_t configuration_provider(char (*reference)[CONFIGURATION_REFERENCE_SIZE], char (*value)[CONFIGURATION_VALUE_SIZE], size_t max_num_configuration_items){return CONFIGURATION_ITEMS_SIZE;} - static const char* actuator_references[] = {"SW"}; - static const uint32_t num_actuator_references = 1; - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_init(&wolk, send_buffer, receive_buffer, actuation_handler, actuator_status_provider, configuration_handler, configuration_provider, "device_key", "device_password", PROTOCOL_WOLKABOUT, actuator_references, num_actuator_references)); - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_process(&wolk, 5)); -} - -void test_wolk_connector_wolk_add_string_sensor_reading(void) -{ - wolk_ctx_t wolk; - char reference[MANIFEST_ITEM_REFERENCE_SIZE]; - char value[READING_SIZE]; - uint64_t utc_time = 1592574949; - uint8_t persistence_storage[1024 * 1024]; - static outbound_message_t outbound_message; - - strncpy(reference, "reference", strlen("reference")); - strncpy(value, "string", strlen("string")); - - wolk_init(&wolk, NULL, NULL, NULL, ACTUATOR_STATE_READY, NULL, NULL, "device_key", "device_password", PROTOCOL_WOLKABOUT, NULL, 0); - wolk_init_in_memory_persistence(&wolk, persistence_storage, sizeof(persistence_storage), false); - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_add_string_sensor_reading(&wolk, reference, value, utc_time)); - TEST_ASSERT_TRUE(persistence_pop(&wolk.persistence, &outbound_message)); - TEST_ASSERT_EQUAL_STRING("{\"utc\":1592574949,\"data\":\"string\"}", outbound_message.payload); -} - -void test_wolkconnector_wolk_add_multi_value_string_sensor_reading(void) -{ - wolk_ctx_t wolk; - char reference[MANIFEST_ITEM_REFERENCE_SIZE]; - char value[READING_DIMENSIONS][READING_SIZE]; - uint64_t utc_time = 1592574949; - uint8_t persistence_storage[1024 * 1024]; - static outbound_message_t outbound_message; - - strncpy(reference, "reference", strlen("reference")); - for (int i = 0; i < READING_DIMENSIONS; ++i) { - strncpy(value[i], "string", strlen("string")); - } - - wolk_init(&wolk, NULL, NULL, NULL, ACTUATOR_STATE_READY, NULL, NULL, "device_key", "device_password", PROTOCOL_WOLKABOUT, NULL, 0); - wolk_init_in_memory_persistence(&wolk, persistence_storage, sizeof(persistence_storage), false); - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_add_multi_value_string_sensor_reading(&wolk, reference, value, READING_DIMENSIONS, utc_time)); - TEST_ASSERT_TRUE(persistence_pop(&wolk.persistence, &outbound_message)); - TEST_ASSERT_EQUAL_STRING("{\"utc\":1592574949,\"data\":\"string,string,string\"}", outbound_message.payload); -} - -void test_wolk_connector_wolk_add_numeric_sensor_reading(void) -{ - wolk_ctx_t wolk; - char reference[MANIFEST_ITEM_REFERENCE_SIZE]; - double value = 32.1; - uint64_t utc_time = 1592574949; - uint8_t persistence_storage[1024 * 1024]; - static outbound_message_t outbound_message; - - strncpy(reference, "reference", strlen("reference")); - - wolk_init(&wolk, NULL, NULL, NULL, ACTUATOR_STATE_READY, NULL, NULL, "device_key", "device_password", PROTOCOL_WOLKABOUT, NULL, 0); - wolk_init_in_memory_persistence(&wolk, persistence_storage, sizeof(persistence_storage), false); - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_add_numeric_sensor_reading(&wolk, reference, value, utc_time)); - TEST_ASSERT_TRUE(persistence_pop(&wolk.persistence, &outbound_message)); - TEST_ASSERT_EQUAL_STRING("{\"utc\":1592574949,\"data\":\"32.100000\"}", outbound_message.payload); -} - -void test_wolk_connector_wolk_add_multi_value_numeric_sensor_reading(void) -{ - wolk_ctx_t wolk; - char reference[MANIFEST_ITEM_REFERENCE_SIZE]; - double value[READING_SIZE]; - uint64_t utc_time = 1592574949; - uint8_t persistence_storage[1024 * 1024]; - static outbound_message_t outbound_message; - - strncpy(reference, "reference", strlen("reference")); - for (int i = 0; i < READING_DIMENSIONS; ++i) { - value[i] = i; - } - - wolk_init(&wolk, NULL, NULL, NULL, ACTUATOR_STATE_READY, NULL, NULL, "device_key", "device_password", PROTOCOL_WOLKABOUT, NULL, 0); - wolk_init_in_memory_persistence(&wolk, persistence_storage, sizeof(persistence_storage), false); - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_add_multi_value_numeric_sensor_reading(&wolk, reference, value, READING_DIMENSIONS, utc_time)); - TEST_ASSERT_TRUE(persistence_pop(&wolk.persistence, &outbound_message)); - TEST_ASSERT_EQUAL_STRING("{\"utc\":1592574949,\"data\":\"0.000000,1.000000,2.000000\"}", outbound_message.payload); -} - -void test_wolk_connector_wolk_add_bool_sensor_reading(void) -{ - wolk_ctx_t wolk; - char reference[MANIFEST_ITEM_REFERENCE_SIZE]; - bool value = 1; - uint64_t utc_time = 1592574949; - uint8_t persistence_storage[1024 * 1024]; - static outbound_message_t outbound_message; - - strncpy(reference, "reference", strlen("reference")); - - wolk_init(&wolk, NULL, NULL, NULL, ACTUATOR_STATE_READY, NULL, NULL, "device_key", "device_password", PROTOCOL_WOLKABOUT, NULL, 0); - wolk_init_in_memory_persistence(&wolk, persistence_storage, sizeof(persistence_storage), false); - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_add_bool_sensor_reading(&wolk, reference, value, utc_time)); - TEST_ASSERT_TRUE(persistence_pop(&wolk.persistence, &outbound_message)); - TEST_ASSERT_EQUAL_STRING("{\"utc\":1592574949,\"data\":\"true\"}", outbound_message.payload); -} - -void test_wolk_connector_wolk_add_multi_value_bool_sensor_reading(void) -{ - wolk_ctx_t wolk; - char reference[MANIFEST_ITEM_REFERENCE_SIZE]; - bool value[READING_SIZE]; - uint64_t utc_time = 1592574949; - uint8_t persistence_storage[1024 * 1024]; - static outbound_message_t outbound_message; - - strncpy(reference, "reference", strlen("reference")); - for (int i = 0; i < READING_DIMENSIONS; ++i) { - value[i] = true; - } - - wolk_init(&wolk, NULL, NULL, NULL, ACTUATOR_STATE_READY, NULL, NULL, "device_key", "device_password", PROTOCOL_WOLKABOUT, NULL, 0); - wolk_init_in_memory_persistence(&wolk, persistence_storage, sizeof(persistence_storage), false); - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_add_multi_value_bool_sensor_reading(&wolk, reference, value, READING_DIMENSIONS, utc_time)); - TEST_ASSERT_TRUE(persistence_pop(&wolk.persistence, &outbound_message)); - TEST_ASSERT_EQUAL_STRING("{\"utc\":1592574949,\"data\":\"true,true,true\"}", outbound_message.payload); -} - -void test_wolk_connector_wolk_add_alarm(void) -{ - wolk_ctx_t wolk; - char reference[MANIFEST_ITEM_REFERENCE_SIZE]; - bool value; - uint64_t utc_time = 1592574949; - uint8_t persistence_storage[1024 * 1024]; - static outbound_message_t outbound_message; - - strncpy(reference, "reference", strlen("reference")); - value = false; - - wolk_init(&wolk, NULL, NULL, NULL, ACTUATOR_STATE_READY, NULL, NULL, "device_key", "device_password", PROTOCOL_WOLKABOUT, NULL, 0); - wolk_init_in_memory_persistence(&wolk, persistence_storage, sizeof(persistence_storage), false); - - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_add_alarm(&wolk, reference, value, utc_time)); - TEST_ASSERT_TRUE(persistence_pop(&wolk.persistence, &outbound_message)); - TEST_ASSERT_EQUAL_STRING("{\"utc\":1592574949,\"data\":\"false\"}", outbound_message.payload); -} - -void test_wolkconnector_wolk_publish_actuator_status(void) -{ - wolk_ctx_t wolk; - int send_buffer(unsigned char* buffer, unsigned int len){return 1;} - int receive_buffer(unsigned char* buffer, unsigned int max_bytes){return 1;} - static const char* actuator_references[] = {"SW"}; - static const uint32_t num_actuator_references = 1; - void actuation_handler(const char* reference, const char* value){} - actuator_status_t actuator_status_provider(const char* reference){ - actuator_status_t actuator_status; - actuator_status_init(&actuator_status, "1", ACTUATOR_STATE_READY); - return actuator_status; - } - - wolk_init(&wolk, send_buffer, receive_buffer, actuation_handler, actuator_status_provider, NULL, NULL, "device_key", "device_password", PROTOCOL_WOLKABOUT, actuator_references, num_actuator_references); - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_publish_actuator_status(&wolk, actuator_references[0])); -} - -void test_wolkconnector_wolk_publish(void) -{ - wolk_ctx_t wolk; - int send_buffer(unsigned char* buffer, unsigned int len){return 1;} - int receive_buffer(unsigned char* buffer, unsigned int max_bytes){return 1;} - uint8_t persistence_storage[1024 * 1024]; - static outbound_message_t outbound_message; - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_init(&wolk, send_buffer, receive_buffer, NULL, NULL, NULL, NULL, "device_key", "device_password", PROTOCOL_WOLKABOUT, NULL, 0)); - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_init_in_memory_persistence(&wolk, persistence_storage, sizeof(persistence_storage), false)); - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_connect(&wolk)); - - TEST_ASSERT_EQUAL_INT(W_FALSE, wolk_publish(&wolk)); -}