diff --git a/.clang-format b/.clang-format new file mode 100755 index 0000000..112d905 --- /dev/null +++ b/.clang-format @@ -0,0 +1,30 @@ +--- +BasedOnStyle: Microsoft +Language: Cpp + +# code format + +UseTab: Never +IndentWidth: 4 +TabWidth: 4 +ColumnLimit: 80 +AccessModifierOffset: -4 +NamespaceIndentation: All +FixNamespaceComments: false +BreakBeforeBraces: Linux + +# for more conf, you can ref: https://clang.llvm.org/docs/ClangFormatStyleOptions.html + +AllowShortIfStatementsOnASingleLine: false + +AllowShortLoopsOnASingleLine: false + +AllowShortBlocksOnASingleLine: false + +IndentCaseLabels: true + +SortIncludes: false + +AlignConsecutiveMacros: AcrossEmptyLines + +AlignConsecutiveAssignments: Consecutive diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml new file mode 100755 index 0000000..289a881 --- /dev/null +++ b/.github/workflows/cmake-multi-platform.yml @@ -0,0 +1,78 @@ +# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform. +# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml +name: CMake on multiple platforms + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. + fail-fast: false + + # Set up a matrix to run the following 3 configurations: + # 1. + # 2. + # 3. + # + # To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list. + matrix: + os: [ubuntu-latest, windows-latest] + build_type: [Release] + c_compiler: [gcc, clang, cl] + include: + - os: windows-latest + c_compiler: cl + cpp_compiler: cl + - os: ubuntu-latest + c_compiler: gcc + cpp_compiler: g++ + - os: ubuntu-latest + c_compiler: clang + cpp_compiler: clang++ + exclude: + - os: windows-latest + c_compiler: gcc + - os: windows-latest + c_compiler: clang + - os: ubuntu-latest + c_compiler: cl + + steps: + - uses: actions/checkout@v3 + + - name: update submodules + run: git submodule update --init --recursive + + - name: Set reusable strings + # Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file. + id: strings + shell: bash + run: | + echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: > + cmake -B ${{ steps.strings.outputs.build-output-dir }} + -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} + -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -S ${{ github.workspace }} + + - name: Build + # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). + run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} + + - name: Test + working-directory: ${{ steps.strings.outputs.build-output-dir }} + # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest --build-config ${{ matrix.build_type }} diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..117f721 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vscode +build +*.code-workspace +ULib Workspace Start.bat diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..3099a90 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.12) + +project(ULib) + +include_directories(${CMAKE_CURRENT_LIST_DIR}/) + +if(CMAKE_C_COMPILER_ID MATCHES "MSVC") + # add_compile_definitions(/w35045) + add_compile_options(/wd5045) +endif() + +# SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) +add_subdirectory(src/) + +if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) + include(CTest) +endif() +if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND BUILD_TESTING) + add_subdirectory(test) +endif() diff --git a/Licence b/Licence new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/Licence @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100755 index 0000000..3ba3317 --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# ULib +This repository has some common business layer implementations, that implement in the form of a module usage. + +You can use these modules via `#include`, there is a macro like `XXX_DEBUG` in all modules, and you can enable debugging logging via `#define XXX_DEBUG 1`. + ++ Modules: + + [uconfig](#uconfig) + + [uprotocol](#uprotocol) + +**WARNING**: That modules are not thread safe, and you should not use them in a multi-threaded environment or you must add mutexes. + +## uconfig +This config manager for embedded system +### Usage +1. Implement your config interface file(uconfig_if.c and uconfig_if.h) +2. Your need include uconfig header`#include "uconfig.h"` +3. First you must call `uconfig_init()`, this function will load config + ++ File example: + + Refer header: [./test/test_uconfig_if.h](./test/test_uconfig_if.h) + + Refer source: [./test/test_uconfig_if.c](./test/test_uconfig_if.c) + +## uprotocol +This easy protocol for point to point communication, look like RPC protocol, is application layer protocol + +1. Each request must response +2. The next request can only be sent after the response is received +2. Each request is independent of the other + +> Timeout feature need user implementation + +### Usage + +1. Implement your transport interface file(uprotocol_if.c and uprotocol_if.h) +2. Your need include uconfig header`#include "uprotocol.h"` +3. Use `uptl_send` function to send request, and `uptl_process` function to handle request + ++ File example: + + Refer header: [./test/test_uprotocol_if.h](./test/test_uprotocol_if.h) + + Refer source: [./test/test_uprotocol_if.c](./test/test_uprotocol_if.c) + +TODO: Secure feature, for macro switch, predefine cmd handler + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100755 index 0000000..be25dcc --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.12) + +set(SOURCE_FILE_ALL + ${CMAKE_CURRENT_LIST_DIR}/ULib.c + ${CMAKE_CURRENT_LIST_DIR}/uconfig/uconfig.c + ${CMAKE_CURRENT_LIST_DIR}/uprotocol/uprotocol.c +) + +set(HEADER_FILE_ALL + ${CMAKE_CURRENT_LIST_DIR}/ + ${CMAKE_CURRENT_LIST_DIR}/uconfig/ + ${CMAKE_CURRENT_LIST_DIR}/uprotocol/ +) + +add_library(ULib OBJECT) +target_sources(ULib PRIVATE ${SOURCE_FILE_ALL}) +target_include_directories(ULib PUBLIC ${HEADER_FILE_ALL}/) + diff --git a/src/ULib.c b/src/ULib.c new file mode 100755 index 0000000..7e7dbf9 --- /dev/null +++ b/src/ULib.c @@ -0,0 +1,13 @@ +/** + * @file ULib.c + * @author vhex (visual86n@outlook.com) + * @brief This file include some util functions. + * @version 0.1 + * @date 2023-12-30 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include "ULib.h" diff --git a/src/ULib.h b/src/ULib.h new file mode 100755 index 0000000..43599fb --- /dev/null +++ b/src/ULib.h @@ -0,0 +1,52 @@ +/** + * @file ULib.h + * @author vhex (visual86n@outlook.com) + * @brief + * @version 0.1 + * @date 2023-12-30 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef __ULIB_H +#define __ULIB_H + +#include +#include +#include + +#include "uconfig/uconfig.h" +#include "uprotocol/uprotocol.h" + +#define ULIB_SWAP(a, b) \ + do { \ + *(a) ^= *(b); \ + *(b) ^= *(a); \ + *(a) ^= *(b); \ + } while (0); + +#define ULIB_MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define ULIB_MAX(a, b) ((a) > (b) ? (a) : (b)) + +#define ULIB_U16_TO_U8ARR(x) (((x) >> 0x08) & 0xFF), \ + (((x) >> 0x00) & 0xFF) + +#define ULIB_U32_TO_U8ARR(x) (((x) >> 0x18) & 0xFF), \ + (((x) >> 0x10) & 0xFF), \ + (((x) >> 0x08) & 0xFF), \ + (((x) >> 0x00) & 0xFF) + +#define ULIB_ARRAY_MAX(list_name) (sizeof(list_name) / sizeof(list_name[0])) + +#if defined __GNUC__ +#define PACK(__Declaration__) __Declaration__ __attribute__((__packed__)) +#elif defined _MSC_VER +#define PACK(__Declaration__) __pragma(pack(push, 1)) __Declaration__ __pragma(pack(pop)) +#elif defined __ARMCC_VERSION +#define PACK(__Declaration__) __packed __Declaration__ +#endif + +#endif diff --git a/src/uconfig/uconfig.c b/src/uconfig/uconfig.c new file mode 100755 index 0000000..ad773d8 --- /dev/null +++ b/src/uconfig/uconfig.c @@ -0,0 +1,198 @@ +/** + * @file uconfig.c + * @author vhex (visual86n@outlook.com) + * @brief This is util config source file. + * @version 0.1 + * @date 2023-12-30 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include "stdio.h" +#include "string.h" +#include "stddef.h" + +#include "uconfig.h" +#include "uconfig_if.h" + +// ------------------------------------------------------------------------ +// External Variables +// ------------------------------------------------------------------------ +extern const struct uconfig_inst __ext_uconfig_inst_dflt; +extern struct uconfig_inst __ext_uconfig_inst; +extern const uint8_t __ext_uconfig_field_map[]; +extern const uint8_t __ext_uconfig_field_map_max; +extern const uint8_t __ext_uconfig_inst_max; + +// ------------------------------------------------------------------------ +// Private Variables +// ------------------------------------------------------------------------ + +// ------------------------------------------------------------------------ +// Private Macro +// ------------------------------------------------------------------------ + +#define UCONFIG_FIELD_SIZE(field) \ + ((uint32_t)(__ext_uconfig_field_map[field + 1] - \ + __ext_uconfig_field_map[field])) + +#define UCONFIG_FIELD_IDX(field) \ + (((uint8_t *)(&__ext_uconfig_inst)) + __ext_uconfig_field_map[field]) + +// ------------------------------------------------------------------------ +// Public Functions +// ------------------------------------------------------------------------ + +/** + * @brief Read data from a specific field in the configuration. + * + * This function reads the data from the specified field in the configuration + * and stores it in the provided data buffer. + * + * @param field The index of the field to read from. + * @param data Pointer to the buffer where the data will be stored. + * @param size The size of the data to be read. + * + * @return int uconfig error code + * + * @retval UCONFIG_SUCCESS: if the operation was successful + * @retval UCONFIG_ERROR_INVALID_FIELD: if the field index is invalid + * @retval UCONFIG_ERROR_SIZE_MISMATCH: if the size does not match the expected + * size for the field. + */ +int uconfig_read(const uint32_t field, uint8_t *data, const uint32_t size) +{ + // Check if field index is valid + if (field >= __ext_uconfig_field_map_max) { + return UCONFIG_ERROR_INVALID_FIELD; + } + + // Check if size matches expected size for the field + if (size != UCONFIG_FIELD_SIZE(field)) { + return UCONFIG_ERROR_SIZE_MISMATCH; + } + + // Read from memory and store in data buffer + memcpy(data, UCONFIG_FIELD_IDX(field), size); + + UCONFIG_LOG("UCONFIG Read: "); + UCONFIG_FIELD_PRINT(field, data, size); + + return UCONFIG_SUCCESS; +} + +/** + * @brief Writes configuration data to memory and persistent storage. + * + * This function writes the specified configuration data to both memory and + * persistent storage. The field and size parameters determine the specific + * configuration data to be written. + * + * @param field The field identifier for the configuration data to be written. + * @param data Pointer to the configuration data to be written. + * @param size Size of the configuration data to be written. + * + * @return int uconfig error code + * + * @retval UCONFIG_SUCCESS: if the write operation is successful + * @retval UCONFIG_ERROR_INVALID_FIELD: if the field identifier is invalid, + * @retval UCONFIG_ERROR_SIZE_MISMATCH: if the size of the data does not match + * the expected size for the specified field. + * + * @retval Other: interface return error + */ +int uconfig_write(const uint32_t field, const uint8_t *data, + const uint32_t size) +{ + // Check if field identifier is valid + if (field >= __ext_uconfig_field_map_max) { + return UCONFIG_ERROR_INVALID_FIELD; + } + + // Check if size matches the expected size for the specified field + if (size != UCONFIG_FIELD_SIZE(field)) { + return UCONFIG_ERROR_SIZE_MISMATCH; + } + + UCONFIG_LOG("UCONFIG Write: "); + UCONFIG_FIELD_PRINT(field, data, size); + + // Write the configuration data to persistent storage + uint32_t ret = uconfig_if_write(field, data, size); + if (ret != UCONFIG_SUCCESS) { + return ret; + } + + // Write the configuration data to memory + memcpy(UCONFIG_FIELD_IDX(field), data, size); + + return UCONFIG_SUCCESS; +} + +/** + * @brief Restores the uconfig instance to default values. + * + * This function copies the default uconfig instance to the current instance, + * and then writes the values from the current instance to their respective + * positions in the default instance. + * + * @return int uconfig error code + * + * @retval UCONFIG_SUCCESS: The restoration was successful. + * @retval Other: If an error occurred during the restoration process. + */ +int uconfig_restore(void) +{ + memcpy(&__ext_uconfig_inst, &__ext_uconfig_inst_dflt, + __ext_uconfig_inst_max); + + for (uint32_t i = 0; i < __ext_uconfig_field_map_max; i++) { + uint32_t ret = + uconfig_write(i, UCONFIG_FIELD_IDX(i), UCONFIG_FIELD_SIZE(i)); + if (ret != UCONFIG_SUCCESS) { + return ret; + } + } + + return UCONFIG_SUCCESS; +} + +/** + * @brief Initializes and read the uconfig module. + * + * @return int uconfig error code + * + * @retval UCONFIG_SUCCESS: Initialization successful. + * @retval Other: Initialization failed. + */ +int uconfig_init(void) +{ + uint32_t ret = uconfig_if_init(); + if (ret != UCONFIG_SUCCESS) { + return ret; + } + + for (uint32_t i = 0; i < __ext_uconfig_field_map_max; i++) { + uint32_t ret = + uconfig_if_read(i, UCONFIG_FIELD_IDX(i), UCONFIG_FIELD_SIZE(i)); + if (ret != UCONFIG_SUCCESS) { + return ret; + } + + UCONFIG_FIELD_PRINT(i, UCONFIG_FIELD_IDX(i), UCONFIG_FIELD_SIZE(i)); + } + + return UCONFIG_SUCCESS; +} + +/** + * @brief Deinitializes the uconfig module. + * + * @return int From uconfig_if_deinit error code + */ +int uconfig_deinit(void) +{ + return uconfig_if_deinit(); +} diff --git a/src/uconfig/uconfig.h b/src/uconfig/uconfig.h new file mode 100755 index 0000000..e8fc170 --- /dev/null +++ b/src/uconfig/uconfig.h @@ -0,0 +1,60 @@ +/** + * @file uconfig.h + * @author vhex (visual86n@outlook.com) + * @brief This is util config header file. + * @version 0.1 + * @date 2023-12-30 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef __UCONFIG_H +#define __UCONFIG_H + +#include +#include + +#define UCONFIG_DEBUG 0 + +#if UCONFIG_DEBUG == 1 +/* Enable debug */ +#define UCONFIG_PARAM_ASSERT(exp) \ + if (!(exp)) { \ + while (1) \ + ; \ + } +#define UCONFIG_LOG(fmt, ...) printf(fmt, ##__VA_ARGS__) +#define UCONFIG_FIELD_PRINT(field, val, sz) \ + do { \ + printf("Field [%d]: ", field); \ + for (unsigned int idx = 0; idx < sz; idx++) \ + printf("0x%02X ", *((val) + idx)); \ + printf("\n"); \ + } while (0) + +#else +/* Disable debug */ +#define UCONFIG_PARAM_ASSERT(exp) +#define UCONFIG_LOG(fmt, ...) +#define UCONFIG_FIELD_PRINT(field, val, sz) +#endif + +enum uconfig_ret { + UCONFIG_SUCCESS = 0, + UCONFIG_ERROR_INVALID_FIELD, + UCONFIG_ERROR_SIZE_MISMATCH, +}; + +int uconfig_read(const uint32_t field, uint8_t *data, const uint32_t size); + +int uconfig_write(const uint32_t field, const uint8_t *data, const uint32_t size); + +int uconfig_restore(void); + +int uconfig_init(void); + +int uconfig_deinit(void); + +#endif diff --git a/src/uconfig/uconfig_if.c b/src/uconfig/uconfig_if.c new file mode 100755 index 0000000..f0cd2b1 --- /dev/null +++ b/src/uconfig/uconfig_if.c @@ -0,0 +1,155 @@ +/** + * @file uconfig_if.c + * @author vhex (visual86n@outlook.com) + * @brief This file is uconfig user interface source file. + * @version 0.1 + * @date 2024-01-04 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include + +#include "uconfig_if.h" +#include "ULib.h" + +PACK(struct uconfig_inst { + // ------------------------------------------------------------------------ + // User Implement Start + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // User Implement End + // ------------------------------------------------------------------------ + + uint32_t magic; +}); + +const struct uconfig_inst __ext_uconfig_inst_dflt = { + // ------------------------------------------------------------------------ + // User Implement Start + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // User Implement End + // ------------------------------------------------------------------------ + + .magic = 0x11223344, +}; +struct uconfig_inst __ext_uconfig_inst = {0}; +const uint8_t __ext_uconfig_field_map[] = { + // ------------------------------------------------------------------------ + // User Implement Start + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // User Implement End + // ------------------------------------------------------------------------ + + offsetof(struct uconfig_inst, magic), + sizeof(struct uconfig_inst), +}; +const uint8_t __ext_uconfig_field_map_max = sizeof(__ext_uconfig_field_map) - 1; +const uint8_t __ext_uconfig_inst_max = sizeof(struct uconfig_inst); + +// ------------------------------------------------------------------------ +// User Implementation +// ------------------------------------------------------------------------ +/** + * @brief Initialize the user configuration interface. + * + * @return int: The status code of the initialization. + * + * @retval UCONFIG_IF_SUCCESS: Initialization success + * @retval Other: Initialization failure + */ +int uconfig_if_init(void) +{ + // ------------------------------------------------------------------------ + // User Implement Start + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // User Implement End + // ------------------------------------------------------------------------ + + return UCONFIG_IF_SUCCESS; +} + +/** + * @brief Deinitialize the user configuration interface. + * + * @return int: The status code of the Deinitialization. + * + * @retval UCONFIG_IF_SUCCESS: Deinitialization success + * @retval Other: Denitialization failure + */ +int uconfig_if_deinit(void) +{ + // ------------------------------------------------------------------------ + // User Implement Start + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // User Implement End + // ------------------------------------------------------------------------ + + return UCONFIG_IF_SUCCESS; +} + +/** + * @brief Read data from persistent storage + * + * @note This function need user implement + * + * @param field The field to be read + * @param data Pointer to the data buffer + * @param size Size of the data buffer + * + * @return int: uconfig error code + * + * @retval UCONFIG_IF_SUCCESS: if the data was successfully written + * @retval Other: interface return error + */ +int uconfig_if_read(const uint32_t field, uint8_t *data, const uint32_t size) +{ + // ------------------------------------------------------------------------ + // User Implement Start + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // User Implement End + // ------------------------------------------------------------------------ + + return UCONFIG_IF_SUCCESS; +} + +/** + * @brief Write data from persistent storage + * + * @note This function need user implement + * + * @param field The field to write data to + * @param data Pointer to the data to be written + * @param size Size of the data + * + * @return int: uconfig error code + * + * @retval UCONFIG_IF_SUCCESS: if the data was successfully written + * @retval Other: interface return error + */ +int uconfig_if_write(const uint32_t field, const uint8_t *data, + const uint32_t size) +{ + // ------------------------------------------------------------------------ + // User Implement Start + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // User Implement End + // ------------------------------------------------------------------------ + + return UCONFIG_IF_SUCCESS; +} diff --git a/src/uconfig/uconfig_if.h b/src/uconfig/uconfig_if.h new file mode 100755 index 0000000..3f90acc --- /dev/null +++ b/src/uconfig/uconfig_if.h @@ -0,0 +1,32 @@ +/** + * @file uconfig_if.h + * @author vhex (visual86n@outlook.com) + * @brief This file is uconfig user interface header file. + * @version 0.1 + * @date 2024-01-04 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef __UCONFIG_IF_H +#define __UCONFIG_IF_H + +#include +#include + +enum uconfig_if_ret { + UCONFIG_IF_SUCCESS = 0, +}; + +int uconfig_if_init(void); + +int uconfig_if_deinit(void); + +int uconfig_if_read(const uint32_t field, uint8_t *data, const uint32_t size); + +int uconfig_if_write(const uint32_t field, const uint8_t *data, + const uint32_t size); + +#endif diff --git a/src/uprotocol/uprotocol.c b/src/uprotocol/uprotocol.c new file mode 100755 index 0000000..09d9e12 --- /dev/null +++ b/src/uprotocol/uprotocol.c @@ -0,0 +1,148 @@ +/** + * @file uprotocol.c + * @author vhex (visual86n@outlook.com) + * @brief This file is uprotocol source file. + * @version 0.1 + * @date 2024-01-04 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include "stdio.h" +#include "string.h" + +#include "uprotocol.h" +#include "uprotocol_if.h" + +// ------------------------------------------------------------------------ +// External Variables +// ------------------------------------------------------------------------ +extern struct uptl_cmd_handler __ext_cmd_hdl_list[]; +extern uint32_t __ext_cmd_hdl_list_len; + +// ------------------------------------------------------------------------ +// Private Variables +// ------------------------------------------------------------------------ +static uint8_t __uptl_static_buf[UPROTOCOL_STATIC_BUF_SIZE]; + +// ------------------------------------------------------------------------ +// Private Macro +// ------------------------------------------------------------------------ + +// ------------------------------------------------------------------------ +// Private Functions +// ------------------------------------------------------------------------ + +static uint32_t __uptl_cmd_hdl_match(const struct uptl_frame *frame, + const uint32_t payload_len) +{ + for (uint32_t i = 0; i < __ext_cmd_hdl_list_len; i++) { + // match cmd code + if (__ext_cmd_hdl_list[i].cmd != frame->cmd) { + continue; + } + // check type + if (__ext_cmd_hdl_list[i].type != frame->type) { + continue; + } + // check segment + if (__ext_cmd_hdl_list[i].can_segment != 1) { + if (frame->is_segment == 1) { + return UPTL_ERROR_CMD_HDL_SEGMENT; + } + } + + UPROTOCOL_LOG("UPTL[%u], cmd: %d, type: %d, len: %d\n", i, + __ext_cmd_hdl_list[i].cmd, __ext_cmd_hdl_list[i].type, + payload_len); + // all prerequisite match + return __ext_cmd_hdl_list[i].handler(frame->payload, payload_len); + } + + return UPTL_ERROR_CMD_HDL_NOT_FOUND; +} + +// ------------------------------------------------------------------------ +// Public Functions +// ------------------------------------------------------------------------ + +/** + * @brief Sends an UPTL protocol frame. + * + * This function sends an UPTL protocol frame with the given frame type, + * command, and data. The length of the data determines the size of the payload. + * + * @param type The frame type. + * @param cmd The command for the frame. + * @param data The data to be sent. + * @param len The length of the data. + * + * @return int uprotocol error code. + * + * @retval UPTL_SUCCESS: Send success + */ +int uptl_send(const enum uptl_frame_type type, const uint8_t cmd, + const uint8_t *data, uint32_t len) +{ + struct uptl_frame *frame = (struct uptl_frame *)__uptl_static_buf; + const uint32_t frame_head_size = sizeof(struct uptl_frame); + uint32_t frame_payload_size = 0; + const uint32_t payload_size_max = + UPROTOCOL_STATIC_BUF_SIZE - frame_head_size; + + while (len > 0) { + /* function recursion global variable `__uptl_static_buf` may be + * modified.*/ + frame->cmd = cmd; + frame->type = type; + if (len > payload_size_max) { + frame->is_segment = 1; + frame_payload_size = payload_size_max; + len -= payload_size_max; + } else { + frame->is_segment = 0; + frame_payload_size = len; + len = 0; + } + + memcpy(frame->payload, data, frame_payload_size); + + const uint32_t ret = uptl_if_send((const uint8_t *)frame, + frame_head_size + frame_payload_size); + if (ret != UPTL_SUCCESS) { + return ret; + } + + data += frame_payload_size; + } + + return UPTL_SUCCESS; +} + +/** + * @brief Process the UPTL frame + * + * This function processes the UPTL (uprotocol) frame received. + * It performs various checks and operations based on the contents of the frame. + * + * @param data Pointer to the UPTL frame data + * @param len Length of the UPTL frame data + * @return int The return value depends on the processing result + * + * @retval UPTL_SUCCESS if the frame is processed successfully + * @retval UPTL_ERROR_FRAME_LEN if the frame length is invalid + * @retval UPTL_ERROR_FRAME_SEQ if the frame sequence is invalid + */ +int uptl_process(const uint8_t *data, uint32_t len) +{ + if (len < sizeof(struct uptl_frame)) { + return UPTL_ERROR_FRAME_LEN; + } + + const struct uptl_frame *frame = (const struct uptl_frame *)data; + const uint32_t payload_len = len - sizeof(struct uptl_frame); + + return __uptl_cmd_hdl_match(frame, payload_len); +} diff --git a/src/uprotocol/uprotocol.h b/src/uprotocol/uprotocol.h new file mode 100755 index 0000000..92ea232 --- /dev/null +++ b/src/uprotocol/uprotocol.h @@ -0,0 +1,86 @@ +/** + * @file uprotocol.h + * @author vhex (visual86n@outlook.com) + * @brief This file is uprotocol header file. + * @version 0.1 + * @date 2023-12-30 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef __UPROTOCOL_H +#define __UPROTOCOL_H + +#include +#include + +#define UPROTOCOL_STATIC_BUF_SIZE 1024 + +#if UPROTOCOL_STATIC_BUF_SIZE < 1 +#error "UPROTOCOL_STATIC_BUF_SIZE must be greater than 1" +#endif + +#define UPROTOCOL_DEBUG 0 + +#if UPROTOCOL_DEBUG == 1 +/* Enable debug */ +#define UPROTOCOL_PARAM_ASSERT(exp) \ + if (!(exp)) { \ + while (1) \ + ; \ + } +#define UPROTOCOL_LOG(fmt, ...) printf(fmt, ##__VA_ARGS__) +#define UPROTOCOL_FIELD_PRINT(field, val, sz) \ + do { \ + printf("Field [%d]: ", field); \ + for (unsigned int idx = 0; idx < sz; idx++) \ + printf("0x%02X ", *((val) + idx)); \ + printf("\n"); \ + } while (0) + +#else +/* Disable debug */ +#define UPROTOCOL_PARAM_ASSERT(exp) +#define UPROTOCOL_LOG(fmt, ...) +#define UPROTOCOL_FIELD_PRINT(field, val, sz) +#endif + +typedef uint32_t (*cmd_handler)(const uint8_t *data, const uint32_t len); + +struct uptl_cmd_handler { + uint8_t can_segment : 1; // acceptance segment 0: cannot , 1: can + uint8_t type : 2; // 0: request, 1: response + uint8_t cmd : 5; // limit 31 + cmd_handler handler; // cmd handle function pointer +}; + +struct uptl_frame { + uint8_t is_segment : 1; // 0: is end, 1: followed by data + uint8_t type : 2; // 0: request, 1: response + uint8_t cmd : 5; // cmd code + uint8_t payload[]; // params or data +}; + +enum uptl_frame_type { + UPTL_FRAME_REQUEST = 0, + UPTL_FRAME_RESPONSE, +}; + +enum uptl_ret { + UPTL_SUCCESS = 0, + UPTL_ERROR_FRAME_LEN, + UPTL_ERROR_FRAME_SEQ, + UPTL_ERROR_CMD_HDL_SEGMENT, + UPTL_ERROR_CMD_HDL_NOT_FOUND, + // handle error + UPTL_ERROR_INVAILD_PARAM, + UPTL_ERROR_INTERNAL, +}; + +int uptl_send(const enum uptl_frame_type type, const uint8_t cmd, const uint8_t *data, uint32_t len); + +int uptl_process(const uint8_t *data, uint32_t len); + +#endif diff --git a/src/uprotocol/uprotocol_if.c b/src/uprotocol/uprotocol_if.c new file mode 100755 index 0000000..694badb --- /dev/null +++ b/src/uprotocol/uprotocol_if.c @@ -0,0 +1,65 @@ +/** + * @file uprotocol_if.c + * @author vhex (visual86n@outlook.com) + * @brief This file is uprotocol user interface source file. + * @version 0.1 + * @date 2024-01-08 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include "uprotocol_if.h" +#include "ULib.h" + +// just example implement +static uint32_t __example_cmd_handler(const uint8_t *data, const uint32_t len) +{ + uint8_t resp[2] = {0x11, 0x22}; + uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 2); + + return UPTL_SUCCESS; +} + +struct uptl_cmd_handler __ext_cmd_hdl_list[] = { + // example implement + { + .cmd = 0x00, + .type = UPTL_FRAME_REQUEST, + .can_segment = 1, + .handler = __example_cmd_handler, + }, + // ------------------------------------------------------------------------ + // User Implement Start + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // User Implement End + // ------------------------------------------------------------------------ + +}; +int __ext_cmd_hdl_list_len = sizeof(__ext_cmd_hdl_list); + +/** + * @brief Uprotocol send data interface + * + * @param data Buffer of data to be sent + * @param len Length of data to be sent + * + * @return Uprotocol error code + * @retval UCONFIG_IF_SUCCESS: Initialization success + * @retval Other: send failure + */ +int uptl_if_send(const uint8_t *data, const uint32_t len) +{ + // ------------------------------------------------------------------------ + // User Implement Start + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // User Implement End + // ------------------------------------------------------------------------ + + return UPTL_SUCCESS; +} diff --git a/src/uprotocol/uprotocol_if.h b/src/uprotocol/uprotocol_if.h new file mode 100755 index 0000000..efdab10 --- /dev/null +++ b/src/uprotocol/uprotocol_if.h @@ -0,0 +1,21 @@ +/** + * @file uprotocol_if.h + * @author vhex (visual86n@outlook.com) + * @brief This file is uprotocol user interface header file. + * @version 0.1 + * @date 2024-01-08 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef __UPROTOCOL_IF_H +#define __UPROTOCOL_IF_H + +#include +#include + +int uptl_if_send(const uint8_t *data, const uint32_t len); + +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100755 index 0000000..f476c66 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.12) +project(ULibTest) + +# Add unity double suport +add_compile_definitions(UNITY_INCLUDE_CONFIG_H) + +include_directories(${CMAKE_CURRENT_LIST_DIR}) + +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/Unity) + +add_executable(ULibTest test.c test_uconfig_if.c test_uprotocol_if.c) + +target_link_libraries(ULibTest ULib unity) + +add_test(ULibTest ULibTest) diff --git a/test/Unity b/test/Unity index 1d28a99..860062d 160000 --- a/test/Unity +++ b/test/Unity @@ -1 +1 @@ -Subproject commit 1d28a9981207fa03be19018f60b23d5dca53cabc +Subproject commit 860062d51b2e8a75d150337b63ca2a472840d13c diff --git a/test/test.c b/test/test.c new file mode 100755 index 0000000..dd23235 --- /dev/null +++ b/test/test.c @@ -0,0 +1,351 @@ +/** + * @file test.c + * @author vhex (visual86n@outlook.com) + * @brief + * @version 0.1 + * @date 2023-12-30 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include + +#include + +#include "ULib.h" + +/* Is run before every test, put unit init calls here. */ +void setUp(void) +{ +} + +/* Is run after every test, put unit clean-up calls here. */ +void tearDown(void) +{ +} + +void test_uconfig(void) +{ + extern bool f1; + extern uint8_t f2; + extern uint16_t f3; + extern uint32_t f4; + extern uint64_t f5; + extern float f6; + extern double f7; + extern char f8[6]; + extern uint32_t magic; + + bool t_f1; + uint8_t t_f2; + uint16_t t_f3; + uint32_t t_f4; + uint64_t t_f5; + float t_f6; + double t_f7; + char t_f8[6]; + uint32_t t_magic; + + // --------------------------------------------------------------------------------------- + // Initialization and Read Test + // --------------------------------------------------------------------------------------- + TEST_ASSERT_EQUAL_UINT32(uconfig_init(), UCONFIG_SUCCESS); + + /* Test read all types */ + TEST_ASSERT_EQUAL_UINT32(uconfig_read(0, (uint8_t *)&t_f1, sizeof(t_f1)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(1, (uint8_t *)&t_f2, sizeof(t_f2)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(2, (uint8_t *)&t_f3, sizeof(t_f3)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(3, (uint8_t *)&t_f4, sizeof(t_f4)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(4, (uint8_t *)&t_f5, sizeof(t_f5)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(5, (uint8_t *)&t_f6, sizeof(t_f6)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(6, (uint8_t *)&t_f7, sizeof(t_f7)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(7, (uint8_t *)t_f8, sizeof(t_f8)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32( + uconfig_read(8, (uint8_t *)&t_magic, sizeof(t_magic)), UCONFIG_SUCCESS); + + /* Check all read values */ + TEST_ASSERT_EQUAL_UINT32(t_f1, f1); + TEST_ASSERT_EQUAL_UINT8(t_f2, f2); + TEST_ASSERT_EQUAL_UINT16(t_f3, f3); + TEST_ASSERT_EQUAL_UINT32(t_f4, f4); + TEST_ASSERT_EQUAL_UINT64(t_f5, f5); + TEST_ASSERT_EQUAL_FLOAT(t_f6, f6); + TEST_ASSERT_EQUAL_DOUBLE(t_f7, f7); + TEST_ASSERT_EQUAL_CHAR_ARRAY(t_f8, f8, sizeof(t_f8)); + TEST_ASSERT_EQUAL_UINT32(t_magic, magic); + + // --------------------------------------------------------------------------------------- + // Write Test + // --------------------------------------------------------------------------------------- + + /* Test write all types */ + t_f1 = true; + t_f2 = 0x33; + t_f3 = 0x1122; + t_f4 = 0x11223344; + t_f5 = 0x1122334455667788; + t_f6 = 36.32768F; + t_f7 = 999999.123456789; + t_f8[0] = '!'; + t_f8[1] = '@'; + t_f8[2] = '#'; + t_f8[3] = '$'; + t_f8[4] = '%'; + t_f8[5] = '^'; + t_magic; + + TEST_ASSERT_EQUAL_UINT32(uconfig_write(0, (uint8_t *)&t_f1, sizeof(t_f1)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_write(1, (uint8_t *)&t_f2, sizeof(t_f2)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_write(2, (uint8_t *)&t_f3, sizeof(t_f3)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_write(3, (uint8_t *)&t_f4, sizeof(t_f4)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_write(4, (uint8_t *)&t_f5, sizeof(t_f5)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_write(5, (uint8_t *)&t_f6, sizeof(t_f6)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_write(6, (uint8_t *)&t_f7, sizeof(t_f7)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_write(7, (uint8_t *)t_f8, sizeof(t_f8)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32( + uconfig_write(8, (uint8_t *)&t_magic, sizeof(t_magic)), + UCONFIG_SUCCESS); + + /* Check all read values */ + TEST_ASSERT_EQUAL_UINT32(t_f1, f1); + TEST_ASSERT_EQUAL_UINT8(t_f2, f2); + TEST_ASSERT_EQUAL_UINT16(t_f3, f3); + TEST_ASSERT_EQUAL_UINT32(t_f4, f4); + TEST_ASSERT_EQUAL_UINT64(t_f5, f5); + TEST_ASSERT_EQUAL_FLOAT(t_f6, f6); + TEST_ASSERT_EQUAL_DOUBLE(t_f7, f7); + TEST_ASSERT_EQUAL_CHAR_ARRAY(t_f8, f8, sizeof(t_f8)); + TEST_ASSERT_EQUAL_UINT32(t_magic, magic); + + // --------------------------------------------------------------------------------------- + // Reread Test + // --------------------------------------------------------------------------------------- + /* NOTO: Only last test is pass this test is pass */ + /* Test read all types */ + TEST_ASSERT_EQUAL_UINT32(uconfig_read(0, (uint8_t *)&t_f1, sizeof(t_f1)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(1, (uint8_t *)&t_f2, sizeof(t_f2)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(2, (uint8_t *)&t_f3, sizeof(t_f3)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(3, (uint8_t *)&t_f4, sizeof(t_f4)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(4, (uint8_t *)&t_f5, sizeof(t_f5)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(5, (uint8_t *)&t_f6, sizeof(t_f6)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(6, (uint8_t *)&t_f7, sizeof(t_f7)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(7, (uint8_t *)t_f8, sizeof(t_f8)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32( + uconfig_read(8, (uint8_t *)&t_magic, sizeof(t_magic)), UCONFIG_SUCCESS); + + /* Check all read values */ + TEST_ASSERT_EQUAL_UINT32(t_f1, f1); + TEST_ASSERT_EQUAL_UINT8(t_f2, f2); + TEST_ASSERT_EQUAL_UINT16(t_f3, f3); + TEST_ASSERT_EQUAL_UINT32(t_f4, f4); + TEST_ASSERT_EQUAL_UINT64(t_f5, f5); + TEST_ASSERT_EQUAL_FLOAT(t_f6, f6); + TEST_ASSERT_EQUAL_DOUBLE(t_f7, f7); + TEST_ASSERT_EQUAL_CHAR_ARRAY(t_f8, f8, sizeof(t_f8)); + TEST_ASSERT_EQUAL_UINT32(t_magic, magic); + + // --------------------------------------------------------------------------------------- + // Reinit Test + // --------------------------------------------------------------------------------------- + + t_f1 = true; + t_f2 = 0xAA; + t_f3 = 0xAA55; + t_f4 = 0x11223344; + t_f5 = 0x1122334455667788; + t_f6 = 3.141592653589793F; + t_f7 = 1.333333333333333; + t_f8[0] = 'a'; + t_f8[1] = 'b'; + t_f8[2] = 'c'; + t_f8[3] = 'd'; + t_f8[4] = 'e'; + t_f8[5] = 'f'; + t_magic = 0x11223344; + + TEST_ASSERT_EQUAL(uconfig_init(), UCONFIG_SUCCESS); + + /* Test read all types */ + TEST_ASSERT_EQUAL_UINT32(uconfig_read(0, (uint8_t *)&t_f1, sizeof(t_f1)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(1, (uint8_t *)&t_f2, sizeof(t_f2)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(2, (uint8_t *)&t_f3, sizeof(t_f3)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(3, (uint8_t *)&t_f4, sizeof(t_f4)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(4, (uint8_t *)&t_f5, sizeof(t_f5)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(5, (uint8_t *)&t_f6, sizeof(t_f6)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(6, (uint8_t *)&t_f7, sizeof(t_f7)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(7, (uint8_t *)t_f8, sizeof(t_f8)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32( + uconfig_read(8, (uint8_t *)&t_magic, sizeof(t_magic)), UCONFIG_SUCCESS); + + /* Check all read values */ + TEST_ASSERT_EQUAL_UINT32(t_f1, f1); + TEST_ASSERT_EQUAL_UINT8(t_f2, f2); + TEST_ASSERT_EQUAL_UINT16(t_f3, f3); + TEST_ASSERT_EQUAL_UINT32(t_f4, f4); + TEST_ASSERT_EQUAL_UINT64(t_f5, f5); + TEST_ASSERT_EQUAL_FLOAT(t_f6, f6); + TEST_ASSERT_EQUAL_DOUBLE(t_f7, f7); + TEST_ASSERT_EQUAL_CHAR_ARRAY(t_f8, f8, sizeof(t_f8)); + TEST_ASSERT_EQUAL_UINT32(t_magic, magic); + + // --------------------------------------------------------------------------------------- + // Restore Test + // --------------------------------------------------------------------------------------- + TEST_ASSERT_EQUAL(uconfig_restore(), UCONFIG_SUCCESS); + + /* Test read all types */ + TEST_ASSERT_EQUAL_UINT32(uconfig_read(0, (uint8_t *)&t_f1, sizeof(t_f1)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(1, (uint8_t *)&t_f2, sizeof(t_f2)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(2, (uint8_t *)&t_f3, sizeof(t_f3)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(3, (uint8_t *)&t_f4, sizeof(t_f4)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(4, (uint8_t *)&t_f5, sizeof(t_f5)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(5, (uint8_t *)&t_f6, sizeof(t_f6)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(6, (uint8_t *)&t_f7, sizeof(t_f7)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32(uconfig_read(7, (uint8_t *)t_f8, sizeof(t_f8)), + UCONFIG_SUCCESS); + TEST_ASSERT_EQUAL_UINT32( + uconfig_read(8, (uint8_t *)&t_magic, sizeof(t_magic)), UCONFIG_SUCCESS); + + /* Check all read values */ + TEST_ASSERT_EQUAL_UINT32(t_f1, f1); + TEST_ASSERT_EQUAL_UINT8(t_f2, f2); + TEST_ASSERT_EQUAL_UINT16(t_f3, f3); + TEST_ASSERT_EQUAL_UINT32(t_f4, f4); + TEST_ASSERT_EQUAL_UINT64(t_f5, f5); + TEST_ASSERT_EQUAL_FLOAT(t_f6, f6); + TEST_ASSERT_EQUAL_DOUBLE(t_f7, f7); + TEST_ASSERT_EQUAL_CHAR_ARRAY(t_f8, f8, sizeof(t_f8)); + TEST_ASSERT_EQUAL_UINT32(t_magic, magic); +} + +void test_uprotocol(void) +{ + uint32_t ret = UPTL_SUCCESS; + + uint8_t test_0x00_tmpl[18]; + + // 0x00 used variable + uint8_t test_0x00_p1 = 0x55; + uint16_t test_0x00_p2 = 0x1122; + uint32_t test_0x00_p3 = 0x11223344; + uint64_t test_0x00_p4 = 0x1122334455667788; + float test_0x00_p5 = 3.14159f; + double test_0x00_p6 = 1.777777777; + bool test_0x00_p7 = false; + char test_0x00_p8[16] = "123456789abcdef"; + + uint8_t test_send_0x01_buf[8192] = {0}; + uint8_t test_send_0x02_buf[8192] = {0}; + + for (size_t i = 0; i < 8192; i++) { + test_send_0x02_buf[i] = 255 - (i % 256); + } + + // test 0x00 read + for (size_t i = 1; i < 9; i++) { + test_0x00_tmpl[0] = i % 256; + ret = uptl_send(UPTL_FRAME_REQUEST, 0x00, test_0x00_tmpl, 1); + TEST_ASSERT_EQUAL_UINT32(ret, UPTL_SUCCESS); + } + + // test 0x00 write + test_0x00_tmpl[0] = 1; + memcpy(test_0x00_tmpl + 1, &test_0x00_p1, 1); + ret = uptl_send(UPTL_FRAME_REQUEST, 0x00, test_0x00_tmpl, 2); + TEST_ASSERT_EQUAL_UINT32(ret, UPTL_SUCCESS); + + test_0x00_tmpl[0] = 2; + memcpy(test_0x00_tmpl + 1, &test_0x00_p2, 2); + ret = uptl_send(UPTL_FRAME_REQUEST, 0x00, test_0x00_tmpl, 3); + TEST_ASSERT_EQUAL_UINT32(ret, UPTL_SUCCESS); + + test_0x00_tmpl[0] = 3; + memcpy(test_0x00_tmpl + 1, &test_0x00_p3, 4); + ret = uptl_send(UPTL_FRAME_REQUEST, 0x00, test_0x00_tmpl, 5); + TEST_ASSERT_EQUAL_UINT32(ret, UPTL_SUCCESS); + + test_0x00_tmpl[0] = 4; + memcpy(test_0x00_tmpl + 1, &test_0x00_p4, 8); + ret = uptl_send(UPTL_FRAME_REQUEST, 0x00, test_0x00_tmpl, 9); + TEST_ASSERT_EQUAL_UINT32(ret, UPTL_SUCCESS); + + test_0x00_tmpl[0] = 5; + memcpy(test_0x00_tmpl + 1, &test_0x00_p5, 4); + ret = uptl_send(UPTL_FRAME_REQUEST, 0x00, test_0x00_tmpl, 5); + TEST_ASSERT_EQUAL_UINT32(ret, UPTL_SUCCESS); + + test_0x00_tmpl[0] = 6; + memcpy(test_0x00_tmpl + 1, &test_0x00_p6, 8); + ret = uptl_send(UPTL_FRAME_REQUEST, 0x00, test_0x00_tmpl, 9); + TEST_ASSERT_EQUAL_UINT32(ret, UPTL_SUCCESS); + + test_0x00_tmpl[0] = 7; + memcpy(test_0x00_tmpl + 1, &test_0x00_p7, sizeof(bool)); + ret = uptl_send(UPTL_FRAME_REQUEST, 0x00, test_0x00_tmpl, sizeof(bool)); + TEST_ASSERT_EQUAL_UINT32(ret, UPTL_SUCCESS); + + test_0x00_tmpl[0] = 8; + memcpy(test_0x00_tmpl + 1, test_0x00_p8, 16); + ret = uptl_send(UPTL_FRAME_REQUEST, 0x00, test_0x00_tmpl, 17); + TEST_ASSERT_EQUAL_UINT32(ret, UPTL_SUCCESS); + + // test 0x01 + for (size_t i = 0; i < 8192; i++) { + test_send_0x01_buf[i] = 255 - (i % 256); + } + ret = uptl_send(UPTL_FRAME_REQUEST, 0x01, test_send_0x01_buf, 8192); + TEST_ASSERT_EQUAL_UINT32(ret, UPTL_SUCCESS); + + // test 0x02 + ret = uptl_send(UPTL_FRAME_REQUEST, 0x02, NULL, 0); + TEST_ASSERT_EQUAL_UINT32(ret, UPTL_SUCCESS); +} + +int main(void) +{ + UNITY_BEGIN(); + RUN_TEST(test_uconfig); + RUN_TEST(test_uprotocol); + return UNITY_END(); +} diff --git a/test/test_uconfig_if.c b/test/test_uconfig_if.c new file mode 100755 index 0000000..97758e8 --- /dev/null +++ b/test/test_uconfig_if.c @@ -0,0 +1,208 @@ +/** + * @file uconfig_if.c + * @author vhex (visual86n@outlook.com) + * @brief This file is uconfig user interface source file. + * @version 0.1 + * @date 2024-01-04 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include +#include + +#include "test_uconfig_if.h" + +PACK(struct uconfig_inst { + // ----Instance declaration---- + // -------User Implement------- + bool f1; + uint8_t f2; + uint16_t f3; + uint32_t f4; + uint64_t f5; + float f6; + double f7; + char f8[6]; + // ---------------------------- + uint32_t magic; +}); + +bool f1 = false; +uint8_t f2 = 0x55; +uint16_t f3 = 0x1234; +uint32_t f4 = 0x12345678; +uint64_t f5 = 0x123456789ABCDEF0; +float f6 = 6.283185307179586F; +double f7 = 1.777777777777777; +char f8[6] = {'1', '2', '3', '4', '5', '6'}; +uint32_t magic; + +const struct uconfig_inst __ext_uconfig_inst_dflt = { + // -------Default Value-------- + // -------User Implement------- + .f1 = true, + .f2 = 0xAA, + .f3 = 0xAA55, + .f4 = 0x11223344, + .f5 = 0x1122334455667788, + .f6 = 3.141592653589793F, + .f7 = 1.333333333333333, + .f8 = {'a', 'b', 'c', 'd', 'e', 'f'}, + // ---------------------------- + .magic = 0x11223344, +}; +struct uconfig_inst __ext_uconfig_inst = {0}; +const uint8_t __ext_uconfig_field_map[] = { + // -------Field offset--------- + // -------User Implement------- + offsetof(struct uconfig_inst, f1), + offsetof(struct uconfig_inst, f2), + offsetof(struct uconfig_inst, f3), + offsetof(struct uconfig_inst, f4), + offsetof(struct uconfig_inst, f5), + offsetof(struct uconfig_inst, f6), + offsetof(struct uconfig_inst, f7), + offsetof(struct uconfig_inst, f8), + // ---------------------------- + offsetof(struct uconfig_inst, magic), + sizeof(struct uconfig_inst), +}; +const uint8_t __ext_uconfig_field_map_max = sizeof(__ext_uconfig_field_map) - 1; +const uint8_t __ext_uconfig_inst_max = sizeof(struct uconfig_inst); + +// ------------------------------------------------------------------------ +// User Implementation +// ------------------------------------------------------------------------ +/** + * @brief Initialize the user configuration interface. + * + * @details This function initializes the user configuration interface. + * + * @return int: The status code of the initialization. + * + * @retval UCONFIG_IF_SUCCESS: Initialization success + * @retval Other: Initialization failure + */ +int uconfig_if_init(void) +{ + // ---------------Initialize--------------- + // -------------User Implement------------- + + // ---------------------------------------- + return UCONFIG_IF_SUCCESS; +} + +/** + * @brief Read data from persistent storage + * + * @note This function need user implement + * + * @param field The field to be read + * @param data Pointer to the data buffer + * @param size Size of the data buffer + * + * @return int: uconfig error code + * + * @retval UCONFIG_IF_SUCCESS: if the data was successfully written + * @retval Other: interface return error + */ +int uconfig_if_read(const uint32_t field, uint8_t *data, const uint32_t size) +{ + // --------------Read data from persistent storage------------- + // ----------------------User Implement------------------------ + switch (field) { + case 0: + memcpy(data, &f1, size); + break; + case 1: + memcpy(data, &f2, size); + break; + case 2: + memcpy(data, &f3, size); + break; + case 3: + memcpy(data, &f4, size); + break; + case 4: + memcpy(data, &f5, size); + break; + case 5: + memcpy(data, &f6, size); + break; + case 6: + memcpy(data, &f7, size); + break; + case 7: + memcpy(data, f8, size); + break; + case 8: + memcpy(data, &magic, size); + break; + default: + // no such field + return 1; + } + // ------------------------------------------------------------ + + return UCONFIG_IF_SUCCESS; +} + +/** + * @brief Write data from persistent storage + * + * @note This function need user implement + * + * @param field The field to write data to + * @param data Pointer to the data to be written + * @param size Size of the data + * + * @return int: uconfig error code + * + * @retval UCONFIG_IF_SUCCESS: if the data was successfully written + * @retval Other: interface return error + */ +int uconfig_if_write(const uint32_t field, const uint8_t *data, + const uint32_t size) +{ + // --------------Write data from persistent storage------------- + // ----------------------User Implement------------------------ + switch (field) { + case 0: + memcpy(&f1, data, size); + break; + case 1: + memcpy(&f2, data, size); + break; + case 2: + memcpy(&f3, data, size); + break; + case 3: + memcpy(&f4, data, size); + break; + case 4: + memcpy(&f5, data, size); + break; + case 5: + memcpy(&f6, data, size); + break; + case 6: + memcpy(&f7, data, size); + break; + case 7: + memcpy(f8, data, size); + break; + + case 8: + memcpy(&magic, data, size); + break; + + default: + return 1; + } + // ------------------------------------------------------------ + + return UCONFIG_IF_SUCCESS; +} diff --git a/test/test_uconfig_if.h b/test/test_uconfig_if.h new file mode 100755 index 0000000..7228c65 --- /dev/null +++ b/test/test_uconfig_if.h @@ -0,0 +1,31 @@ +/** + * @file test_uconfig_if.h + * @author vhex (visual86n@outlook.com) + * @brief This file is uconfig user interface header file. + * @version 0.1 + * @date 2024-01-04 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef __TEST_UCONFIG_IF_H +#define __TEST_UCONFIG_IF_H + +#include +#include + +#include "ULib.h" + +enum uconfig_if_ret { + UCONFIG_IF_SUCCESS = 0, +}; + +int uconfig_if_init(void); + +int uconfig_if_read(const uint32_t field, uint8_t *data, const uint32_t size); + +int uconfig_if_write(const uint32_t field, const uint8_t *data, const uint32_t size); + +#endif diff --git a/test/test_uprotocol_if.c b/test/test_uprotocol_if.c new file mode 100755 index 0000000..c8f1f3c --- /dev/null +++ b/test/test_uprotocol_if.c @@ -0,0 +1,379 @@ +/** + * @file uprotocol_if.c + * @author vhex (visual86n@outlook.com) + * @brief This file is uprotocol user interface source file. + * @version 0.1 + * @date 2024-01-08 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#include + +#include "uprotocol_if.h" +#include "ULib.h" + +#define UPTL_VERIFY_FAIL 0x8001 + +uint8_t test_buf[8192] = {0x55}; + +uint8_t test_0x01_buf[8192] = {0xAA}; +uint32_t test_0x01_idx = 0; + +uint8_t test_0x02_buf[8192] = {0xEE}; +uint32_t test_0x02_idx = 0; + +// 0x00 used variable +uint8_t test_0x00_p1 = 0xAA; +uint16_t test_0x00_p2 = 0x2211; +uint32_t test_0x00_p3 = 0x44332211; +uint64_t test_0x00_p4 = 0x8877665544332211; +float test_0x00_p5 = 1.333333333f; +double test_0x00_p6 = 2.14444444444; +bool test_0x00_p7 = true; +char test_0x00_p8[16] = "123456789abcdef"; + +static uint32_t test_0x00_req(const uint8_t *data, const uint32_t len) +{ + // data read + if (len == 1) { + // read + switch (data[0]) { + case 1: { + uint8_t resp[2]; + resp[0] = 1; + memcpy(resp + 1, &test_0x00_p1, 1); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 2); + return ret; + } + case 2: { + uint8_t resp[3]; + resp[0] = 2; + memcpy(resp + 1, &test_0x00_p2, 2); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 3); + return ret; + } + case 3: { + uint8_t resp[5]; + resp[0] = 3; + memcpy(resp + 1, &test_0x00_p3, 4); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 5); + return ret; + } + case 4: { + uint8_t resp[9]; + resp[0] = 4; + memcpy(resp + 1, &test_0x00_p4, 8); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 9); + return ret; + } + case 5: { + uint8_t resp[5]; + resp[0] = 5; + memcpy(resp + 1, &test_0x00_p5, 4); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 5); + return ret; + } + case 6: { + uint8_t resp[9]; + resp[0] = 6; + memcpy(resp + 1, &test_0x00_p6, 8); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 9); + return ret; + } + case 7: { + uint8_t resp[1 + sizeof(bool)]; + resp[0] = 7; + memcpy(resp + 1, &test_0x00_p7, sizeof(bool)); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, + sizeof(bool) + 1); + return ret; + } + case 8: { + uint8_t resp[17]; + resp[0] = 8; + memcpy(resp + 1, &test_0x00_p8, 16); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 17); + return ret; + } + default: + return UPTL_ERROR_INVAILD_PARAM; + } + } else if (len > 1) { + // write + switch (data[0]) { + case 1: { + if (len != 2) { + return UPTL_ERROR_INVAILD_PARAM; + } + memcpy(&test_0x00_p1, data + 1, 1); + uint8_t resp[2]; + resp[0] = 1; + memcpy(resp + 1, &test_0x00_p1, 1); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 2); + return ret; + } + case 2: { + if (len != 3) { + return UPTL_ERROR_INVAILD_PARAM; + } + memcpy(&test_0x00_p2, data + 1, 2); + uint8_t resp[3]; + resp[0] = 2; + memcpy(resp + 1, &test_0x00_p2, 2); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 3); + return ret; + } + case 3: { + if (len != 5) { + return UPTL_ERROR_INVAILD_PARAM; + } + memcpy(&test_0x00_p3, data + 1, 4); + uint8_t resp[5]; + resp[0] = 3; + memcpy(resp + 1, &test_0x00_p3, 4); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 5); + return ret; + } + case 4: { + if (len != 9) { + return UPTL_ERROR_INVAILD_PARAM; + } + memcpy(&test_0x00_p4, data + 1, 8); + uint8_t resp[9]; + resp[0] = 4; + memcpy(resp + 1, &test_0x00_p4, 8); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 9); + return ret; + } + case 5: { + if (len != 5) { + return UPTL_ERROR_INVAILD_PARAM; + } + memcpy(&test_0x00_p5, data + 1, 4); + uint8_t resp[5]; + resp[0] = 5; + memcpy(resp + 1, &test_0x00_p5, 4); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 5); + return ret; + } + case 6: { + if (len != 9) { + return UPTL_ERROR_INVAILD_PARAM; + } + memcpy(&test_0x00_p6, data + 1, 8); + uint8_t resp[9]; + resp[0] = 6; + memcpy(resp + 1, &test_0x00_p6, 8); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 9); + return ret; + } + case 7: { + if (len != 2) { + return UPTL_ERROR_INVAILD_PARAM; + } + memcpy(&test_0x00_p7, data + 1, 1); + uint8_t resp[1 + sizeof(bool)]; + resp[0] = 7; + memcpy(resp + 1, &test_0x00_p7, sizeof(bool)); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, + sizeof(bool) + 1); + return ret; + } + case 8: { + if (len != 17) { + return UPTL_ERROR_INVAILD_PARAM; + } + memcpy(test_0x00_p8, data + 1, 16); + uint8_t resp[17]; + resp[0] = 8; + memcpy(resp + 1, &test_0x00_p8, 16); + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x00, resp, 17); + return ret; + } + default: + return UPTL_ERROR_INVAILD_PARAM; + } + } else { + return UPTL_ERROR_INVAILD_PARAM; + } + + return UPTL_SUCCESS; +} + +static uint32_t test_0x00_resp(const uint8_t *data, const uint32_t len) +{ + // check + if (len > 1) { + switch (data[0]) { + case 1: + if (memcmp(data + 1, &test_0x00_p1, 1) == 0) { + return UPTL_SUCCESS; + } + return UPTL_VERIFY_FAIL; + case 2: + if (memcmp(data + 1, &test_0x00_p2, 2) == 0) { + return UPTL_SUCCESS; + } + return UPTL_VERIFY_FAIL; + case 3: + if (memcmp(data + 1, &test_0x00_p3, 4) == 0) { + return UPTL_SUCCESS; + } + return UPTL_VERIFY_FAIL; + case 4: + if (memcmp(data + 1, &test_0x00_p4, 8) == 0) { + return UPTL_SUCCESS; + } + return UPTL_VERIFY_FAIL; + case 5: + if (memcmp(data + 1, &test_0x00_p5, 4) == 0) { + return UPTL_SUCCESS; + } + return UPTL_VERIFY_FAIL; + case 6: + if (memcmp(data + 1, &test_0x00_p6, 8) == 0) { + return UPTL_SUCCESS; + } + return UPTL_VERIFY_FAIL; + case 7: + if (memcmp(data + 1, &test_0x00_p7, sizeof(bool)) == 0) { + return UPTL_SUCCESS; + } + return UPTL_VERIFY_FAIL; + case 8: + if (memcmp(data + 1, &test_0x00_p8, 16) == 0) { + return UPTL_SUCCESS; + } + return UPTL_VERIFY_FAIL; + default: + return UPTL_VERIFY_FAIL; + } + } else { + return UPTL_VERIFY_FAIL; + } + + return UPTL_SUCCESS; +} + +static uint32_t test_0x01_req(const uint8_t *data, const uint32_t len) +{ + if (test_0x01_idx + len > 8192) { + return UPTL_ERROR_INVAILD_PARAM; + } + // write + memcpy(test_0x01_buf + test_0x01_idx, data, len); + test_0x01_idx += len; + uint32_t resp_len = test_0x01_idx; + uint32_t ret = + uptl_send(UPTL_FRAME_RESPONSE, 0x01, (uint8_t *)&resp_len, 4); + return ret; +} + +static uint32_t test_0x01_resp(const uint8_t *data, const uint32_t len) +{ + if (len != 4) { + return UPTL_VERIFY_FAIL; + } + uint32_t resp_len; + memcpy(&resp_len, data, 4); + if (resp_len != test_0x01_idx) { + return UPTL_VERIFY_FAIL; + } + // check data + for (size_t i = 0; i < len; i++) { + if (test_0x01_buf[i] != 255 - (i % 256)) { + return UPTL_VERIFY_FAIL; + } + } + + return UPTL_SUCCESS; +} + +static uint32_t test_0x02_req(const uint8_t *data, const uint32_t len) +{ + for (size_t i = 0; i < 8192; i++) { + test_0x02_buf[i] = i % 256; + } + uint32_t ret = uptl_send(UPTL_FRAME_RESPONSE, 0x02, test_0x02_buf, 8192); + return ret; +} + +static uint32_t test_0x02_resp(const uint8_t *data, const uint32_t len) +{ + if (test_0x01_idx + len > 8192) { + return UPTL_VERIFY_FAIL; + } + + for (size_t i = test_0x02_idx; i < test_0x02_idx + len; i++) { + if (test_0x02_buf[i] != i) { + return UPTL_VERIFY_FAIL; + } + } + + test_0x02_idx += len; + + return UPTL_SUCCESS; +} + +struct uptl_cmd_handler __ext_cmd_hdl_list[] = { + // example implement + // { + // .cmd = 0x00, + // .type = UPTL_FRAME_REQUEST, + // .can_segment = 1, + // .handler = NULL, + // }, + // ------CMD Handler List------ + // -------User Implement------- + { + .cmd = 0x00, + .type = UPTL_FRAME_REQUEST, + .can_segment = 0, + .handler = test_0x00_req, + }, + { + .cmd = 0x00, + .type = UPTL_FRAME_RESPONSE, + .can_segment = 0, + .handler = test_0x00_resp, + }, + { + .cmd = 0x01, + .type = UPTL_FRAME_REQUEST, + .can_segment = 1, + .handler = test_0x01_req, + }, + { + .cmd = 0x01, + .type = UPTL_FRAME_RESPONSE, + .can_segment = 1, + .handler = test_0x01_resp, + }, + { + .cmd = 0x02, + .type = UPTL_FRAME_REQUEST, + .can_segment = 0, + .handler = test_0x02_req, + }, + { + .cmd = 0x02, + .type = UPTL_FRAME_RESPONSE, + .can_segment = 1, + .handler = test_0x02_resp, + }, + // ---------------------------- +}; +uint32_t __ext_cmd_hdl_list_len = sizeof(__ext_cmd_hdl_list); + +int uptl_if_send(const uint8_t *data, const uint32_t len) +{ + // ------UPTL Send Interface------ + // --------User Implement--------- + memcpy(test_buf, data, len); + return uptl_process(test_buf, len); + // ------------------------------- + // return UPTL_SUCCESS; +} diff --git a/test/test_uprotocol_if.h b/test/test_uprotocol_if.h new file mode 100755 index 0000000..af4dec2 --- /dev/null +++ b/test/test_uprotocol_if.h @@ -0,0 +1,21 @@ +/** + * @file uprotocol_if.h + * @author vhex (visual86n@outlook.com) + * @brief This file is uprotocol user interface header file. + * @version 0.1 + * @date 2024-01-08 + * + * SPDX-FileCopyrightText: Copyright (c) 2024 + * SPDX-License-Identifier: Apache-2.0 + * + */ + +#ifndef __UPROTOCOL_IF_H +#define __UPROTOCOL_IF_H + +#include +#include + +int uptl_if_send(const uint8_t *data, const uint32_t len); + +#endif diff --git a/test/unity_config.h b/test/unity_config.h new file mode 100755 index 0000000..2de47d5 --- /dev/null +++ b/test/unity_config.h @@ -0,0 +1,244 @@ +/* Unity Configuration + * As of May 11th, 2016 at ThrowTheSwitch/Unity commit 837c529 + * Update: December 29th, 2016 + * See Also: Unity/docs/UnityConfigurationGuide.pdf + * + * Unity is designed to run on almost anything that is targeted by a C compiler. + * It would be awesome if this could be done with zero configuration. While + * there are some targets that come close to this dream, it is sadly not + * universal. It is likely that you are going to need at least a couple of the + * configuration options described in this document. + * + * All of Unity's configuration options are `#defines`. Most of these are simple + * definitions. A couple are macros with arguments. They live inside the + * unity_internals.h header file. We don't necessarily recommend opening that + * file unless you really need to. That file is proof that a cross-platform + * library is challenging to build. From a more positive perspective, it is also + * proof that a great deal of complexity can be centralized primarily to one + * place in order to provide a more consistent and simple experience elsewhere. + * + * Using These Options + * It doesn't matter if you're using a target-specific compiler and a simulator + * or a native compiler. In either case, you've got a couple choices for + * configuring these options: + * + * 1. Because these options are specified via C defines, you can pass most of + * these options to your compiler through command line compiler flags. Even + * if you're using an embedded target that forces you to use their + * overbearing IDE for all configuration, there will be a place somewhere in + * your project to configure defines for your compiler. + * 2. You can create a custom `unity_config.h` configuration file (present in + * your toolchain's search paths). In this file, you will list definitions + * and macros specific to your target. All you must do is define + * `UNITY_INCLUDE_CONFIG_H` and Unity will rely on `unity_config.h` for any + * further definitions it may need. + */ + +#ifndef UNITY_CONFIG_H +#define UNITY_CONFIG_H + +/* ************************* AUTOMATIC INTEGER TYPES *************************** + * C's concept of an integer varies from target to target. The C Standard has + * rules about the `int` matching the register size of the target + * microprocessor. It has rules about the `int` and how its size relates to + * other integer types. An `int` on one target might be 16 bits while on another + * target it might be 64. There are more specific types in compilers compliant + * with C99 or later, but that's certainly not every compiler you are likely to + * encounter. Therefore, Unity has a number of features for helping to adjust + * itself to match your required integer sizes. It starts off by trying to do it + * automatically. + **************************************************************************** */ + +/* The first attempt to guess your types is to check `limits.h`. Some compilers + * that don't support `stdint.h` could include `limits.h`. If you don't + * want Unity to check this file, define this to make it skip the inclusion. + * Unity looks at UINT_MAX & ULONG_MAX, which were available since C89. + */ +/* #define UNITY_EXCLUDE_LIMITS_H */ + +/* The second thing that Unity does to guess your types is check `stdint.h`. + * This file defines `UINTPTR_MAX`, since C99, that Unity can make use of to + * learn about your system. It's possible you don't want it to do this or it's + * possible that your system doesn't support `stdint.h`. If that's the case, + * you're going to want to define this. That way, Unity will know to skip the + * inclusion of this file and you won't be left with a compiler error. + */ +/* #define UNITY_EXCLUDE_STDINT_H */ + +/* ********************** MANUAL INTEGER TYPE DEFINITION *********************** + * If you've disabled all of the automatic options above, you're going to have + * to do the configuration yourself. There are just a handful of defines that + * you are going to specify if you don't like the defaults. + **************************************************************************** */ + + /* Define this to be the number of bits an `int` takes up on your system. The + * default, if not auto-detected, is 32 bits. + * + * Example: + */ +/* #define UNITY_INT_WIDTH 16 */ + +/* Define this to be the number of bits a `long` takes up on your system. The + * default, if not autodetected, is 32 bits. This is used to figure out what + * kind of 64-bit support your system can handle. Does it need to specify a + * `long` or a `long long` to get a 64-bit value. On 16-bit systems, this option + * is going to be ignored. + * + * Example: + */ +/* #define UNITY_LONG_WIDTH 16 */ + +/* Define this to be the number of bits a pointer takes up on your system. The + * default, if not autodetected, is 32-bits. If you're getting ugly compiler + * warnings about casting from pointers, this is the one to look at. + * + * Example: + */ +/* #define UNITY_POINTER_WIDTH 64 */ + +/* Unity will automatically include 64-bit support if it auto-detects it, or if + * your `int`, `long`, or pointer widths are greater than 32-bits. Define this + * to enable 64-bit support if none of the other options already did it for you. + * There can be a significant size and speed impact to enabling 64-bit support + * on small targets, so don't define it if you don't need it. + */ +/* #define UNITY_INCLUDE_64 */ + + +/* *************************** FLOATING POINT TYPES **************************** + * In the embedded world, it's not uncommon for targets to have no support for + * floating point operations at all or to have support that is limited to only + * single precision. We are able to guess integer sizes on the fly because + * integers are always available in at least one size. Floating point, on the + * other hand, is sometimes not available at all. Trying to include `float.h` on + * these platforms would result in an error. This leaves manual configuration as + * the only option. + **************************************************************************** */ + + /* By default, Unity guesses that you will want single precision floating point + * support, but not double precision. It's easy to change either of these using + * the include and exclude options here. You may include neither, just float, + * or both, as suits your needs. + */ +/* #define UNITY_EXCLUDE_FLOAT */ +#define UNITY_INCLUDE_DOUBLE +/* #define UNITY_EXCLUDE_DOUBLE */ + +/* For features that are enabled, the following floating point options also + * become available. + */ + +/* Unity aims for as small of a footprint as possible and avoids most standard + * library calls (some embedded platforms don't have a standard library!). + * Because of this, its routines for printing integer values are minimalist and + * hand-coded. To keep Unity universal, though, we eventually chose to develop + * our own floating point print routines. Still, the display of floating point + * values during a failure are optional. By default, Unity will print the + * actual results of floating point assertion failures. So a failed assertion + * will produce a message like "Expected 4.0 Was 4.25". If you would like less + * verbose failure messages for floating point assertions, use this option to + * give a failure message `"Values Not Within Delta"` and trim the binary size. + */ +/* #define UNITY_EXCLUDE_FLOAT_PRINT */ + +/* If enabled, Unity assumes you want your `FLOAT` asserts to compare standard C + * floats. If your compiler supports a specialty floating point type, you can + * always override this behavior by using this definition. + * + * Example: + */ +/* #define UNITY_FLOAT_TYPE float16_t */ + +/* If enabled, Unity assumes you want your `DOUBLE` asserts to compare standard + * C doubles. If you would like to change this, you can specify something else + * by using this option. For example, defining `UNITY_DOUBLE_TYPE` to `long + * double` could enable gargantuan floating point types on your 64-bit processor + * instead of the standard `double`. + * + * Example: + */ +/* #define UNITY_DOUBLE_TYPE long double */ + +/* If you look up `UNITY_ASSERT_EQUAL_FLOAT` and `UNITY_ASSERT_EQUAL_DOUBLE` as + * documented in the Unity Assertion Guide, you will learn that they are not + * really asserting that two values are equal but rather that two values are + * "close enough" to equal. "Close enough" is controlled by these precision + * configuration options. If you are working with 32-bit floats and/or 64-bit + * doubles (the normal on most processors), you should have no need to change + * these options. They are both set to give you approximately 1 significant bit + * in either direction. The float precision is 0.00001 while the double is + * 10^-12. For further details on how this works, see the appendix of the Unity + * Assertion Guide. + * + * Example: + */ +/* #define UNITY_FLOAT_PRECISION 0.001f */ +/* #define UNITY_DOUBLE_PRECISION 0.001f */ + + +/* *************************** MISCELLANEOUS *********************************** + * Miscellaneous configuration options for Unity + **************************************************************************** */ + +/* Unity uses the stddef.h header included in the C standard library for the + * "NULL" macro. Define this in order to disable the include of stddef.h. If you + * do this, you have to make sure to provide your own "NULL" definition. + */ +/* #define UNITY_EXCLUDE_STDDEF_H */ + +/* Define this to enable the unity formatted print macro: + * "TEST_PRINTF" + */ +/* #define UNITY_INCLUDE_PRINT_FORMATTED */ + + +/* *************************** TOOLSET CUSTOMIZATION *************************** + * In addition to the options listed above, there are a number of other options + * which will come in handy to customize Unity's behavior for your specific + * toolchain. It is possible that you may not need to touch any of these but + * certain platforms, particularly those running in simulators, may need to jump + * through extra hoops to operate properly. These macros will help in those + * situations. + **************************************************************************** */ + +/* By default, Unity prints its results to `stdout` as it runs. This works + * perfectly fine in most situations where you are using a native compiler for + * testing. It works on some simulators as well so long as they have `stdout` + * routed back to the command line. There are times, however, where the + * simulator will lack support for dumping results or you will want to route + * results elsewhere for other reasons. In these cases, you should define the + * `UNITY_OUTPUT_CHAR` macro. This macro accepts a single character at a time + * (as an `int`, since this is the parameter type of the standard C `putchar` + * function most commonly used). You may replace this with whatever function + * call you like. + * + * Example: + * Say you are forced to run your test suite on an embedded processor with no + * `stdout` option. You decide to route your test result output to a custom + * serial `RS232_putc()` function you wrote like thus: + */ +/* #define UNITY_OUTPUT_CHAR(a) RS232_putc(a) */ +/* #define UNITY_OUTPUT_CHAR_HEADER_DECLARATION RS232_putc(int) */ +/* #define UNITY_OUTPUT_FLUSH() RS232_flush() */ +/* #define UNITY_OUTPUT_FLUSH_HEADER_DECLARATION RS232_flush(void) */ +/* #define UNITY_OUTPUT_START() RS232_config(115200,1,8,0) */ +/* #define UNITY_OUTPUT_COMPLETE() RS232_close() */ + +/* Some compilers require a custom attribute to be assigned to pointers, like + * `near` or `far`. In these cases, you can give Unity a safe default for these + * by defining this option with the attribute you would like. + * + * Example: + */ +/* #define UNITY_PTR_ATTRIBUTE __attribute__((far)) */ +/* #define UNITY_PTR_ATTRIBUTE near */ + +/* Print execution time of each test when executed in verbose mode + * + * Example: + * + * TEST - PASS (10 ms) + */ +/* #define UNITY_INCLUDE_EXEC_TIME */ + +#endif /* UNITY_CONFIG_H */