diff --git a/.github/workflows/chsm_crf_ci.yml b/.github/workflows/chsm_crf_ci.yml new file mode 100644 index 00000000..67b8f40d --- /dev/null +++ b/.github/workflows/chsm_crf_ci.yml @@ -0,0 +1,42 @@ +name: chsm_crf_ci + +on: + push: + branches: [feature/multi_lang_sm_gen, feature/fix_test_runs, master, main ] + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. + # You can convert this to a matrix build if you need cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + submodules: recursive + + - name: List out the directory + run: tree ${{ github.workspace }} + + - name: Check cmake version + run: cmake --version + + - 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 ${{github.workspace}}/build -S ${{github.workspace}} -DCHSM_BUILD_TESTS=ON + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build -t crf + + - name: Test + working-directory: ${{github.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: | + cmake --build . -t crf_test + ctest -VV -R crf_test + diff --git a/.github/workflows/chsm_modules_ci.yml b/.github/workflows/chsm_modules_ci.yml new file mode 100644 index 00000000..4dbd6bf6 --- /dev/null +++ b/.github/workflows/chsm_modules_ci.yml @@ -0,0 +1,47 @@ +name: chsm_modules_ci + +on: + push: + branches: [ feature/multi_lang_sm_gen, feature/fix_test_runs, master, main ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + submodules: recursive + + - name: List out the directory + run: tree ${{ github.workspace }} + + - name: Check cmake version + run: cmake --version + + - name: Init the submodules + run: git submodule init + + - name: Update submodules + run: git submodule update --recursive + + - name: Install Graphviz + # You may pin to the exact commit or the version. + # uses: tlylt/install-graphviz@b2201200d85f06f0189cb74d9b69208504cf12cd + uses: tlylt/install-graphviz@v1.0.0 + + - name: Configure CMake + run: cmake -B ${{github.workspace}}/build -S ${{github.workspace}} -DCHSM_BUILD_TESTS=ON + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build -t all + + - name: Test + working-directory: ${{github.workspace}}/build + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: | + ctest + diff --git a/.github/workflows/docs_pages.yml b/.github/workflows/docs_pages.yml new file mode 100644 index 00000000..d758127e --- /dev/null +++ b/.github/workflows/docs_pages.yml @@ -0,0 +1,43 @@ +name: Build and Deploy Documentation + +on: + push: + branches: + - feature/multi_lang_sm_gen + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install Sphinx m2r sphinxcontrib-plantuml sphinx-rtd-dark-mode sphinxcontrib-datatemplates sphinxcontrib-drawio + + - name: Install Draw.io + run: | + sudo apt-get update + sudo apt install snapd + sudo snap install drawio + + - name: Build documentation + run: | + cd docs/doc_gen + make html + ls -lah + tree + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: docs/doc_gen/build/html diff --git a/.gitignore b/.gitignore index 6ac009e7..dbb9cc8f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,14 @@ -/.vscode/ /**/__pycache__/ /**/build/* !/**/build/.keep #dependencies -**/deps/** \ No newline at end of file +**/unity/**build-mingw-test/ +build-mingw-test/ + +build-mingw/ + +.vscode/settings.json + +docs/sphinx/_build/ +docs/typst/*.pdf diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..d8e376c5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,11 @@ +[submodule "languages/c/cmake_utils"] + path = languages/c/cmake_utils + url = https://github.com/xsession/cmake_utils.git +[submodule "languages/c/unity"] + path = languages/c/unity + url = https://github.com/xsession/Unity.git +[submodule "languages/c/examples/menu_structure"] + url = https://github.com/xsession/menu_structure.git +[submodule "docs/modules"] + path = docs/modules + url = https://github.com/xsession/chsm-docs.git \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..3d5a356b --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,102 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "i2c_master_test_debug", + "type": "cppdbg", + "request": "launch", + // "preLaunchTask": "build_i2c_master_test", + "program": "${workspaceFolder}/languages/c/build-mingw-test/bin/i2c_master_test.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${fileDirname}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "miDebuggerPath": "C:/MinGW/bin/gdb.exe", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Set Disassembly Flavor to Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + }, + { + "description": "Display numbers in hex", + "text": "set output-radix 16", + "ignoreFailures": true + } + ] + }, + { + "name": "lm73_test_debug", + "type": "cppdbg", + "request": "launch", + // "preLaunchTask": "build_lm73_test", + "program": "${workspaceFolder}/languages/c/build-mingw-test/bin/lm73_test.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${fileDirname}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "miDebuggerPath": "C:/MinGW/bin/gdb.exe", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Set Disassembly Flavor to Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + }, + { + "description": "Display numbers in hex", + "text": "set output-radix 16", + "ignoreFailures": true + } + ] + }, + { + "name": "sht30_test_debug", + "type": "cppdbg", + "request": "launch", + // "preLaunchTask": "build_sht30_test", + "program": "${workspaceFolder}/languages/c/build-mingw-test/bin/sht30_test.exe", + "args": [], + "stopAtEntry": false, + "cwd": "${fileDirname}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "miDebuggerPath": "C:/MinGW/bin/gdb.exe", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Set Disassembly Flavor to Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + }, + { + "description": "Display numbers in hex", + "text": "set output-radix 16", + "ignoreFailures": true + } + ] + }, + + ] +} diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 1bdbd5f2..00000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,89 +0,0 @@ -cmake_minimum_required(VERSION 3.19) - -project(crf - VERSION 1.0.0 - LANGUAGES C) - -list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/utils") - -add_library(crf - crf/src/cbits.c - crf/src/chsm.c - crf/src/cpool.c - crf/src/cqueue.c - crf/src/crf.c - crf/src/cvalue.c - ) - -add_library(${PROJECT_NAME}::framework ALIAS ${PROJECT_NAME}) - -target_compile_definitions(crf PRIVATE - NDEBUG -) - -# Includes --------------------------------------------------------------------- - -include(GNUInstallDirs) -include(CMakePackageConfigHelpers) - - -target_include_directories(${PROJECT_NAME} - PUBLIC - $ - $ - $ -) - -set(${PROJECT_NAME}_PUBLIC_HEADERS - crf/inc/atomic_ops.h - crf/inc/cbits.h - crf/inc/cevent.h - crf/inc/chsm.h - crf/inc/cpool.h - crf/inc/cqueue.h - crf/inc/crf.h - crf/inc/cvalue.h - -) - -set_target_properties(${PROJECT_NAME} - PROPERTIES - C_STANDARD 99 - C_STANDARD_REQUIRED ON - C_EXTENSIONS OFF - PUBLIC_HEADER "${${PROJECT_NAME}_PUBLIC_HEADERS}" - EXPORT_NAME framework -) - -# Install ------------------------------------------------------------------------ - -write_basic_package_version_file(${PROJECT_NAME}ConfigVersion.cmake - VERSION ${PROJECT_VERSION} - COMPATIBILITY SameMajorVersion -) - -## Target installation -install(TARGETS ${PROJECT_NAME} - EXPORT ${PROJECT_NAME}Targets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} - COMPONENT library -) - -## Target's cmake files: targets export -install(EXPORT ${PROJECT_NAME}Targets - NAMESPACE ${PROJECT_NAME}:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} -) - -## Target's cmake files: config and version config for find_package() -install(FILES ${PROJECT_NAME}Config.cmake - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} -) - -include(diagnostic) -set(debug on) -# set(autodetect_toolchain on) -diagnostic(crf) \ No newline at end of file diff --git a/README.md b/README.md index a009127c..4ae5addb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +[![Actions Status](https://github.com/xsession/chsm/workflows/chsm_crf_ci/badge.svg)](https://github.com/xsession/chsm/actions) +[![Actions Status](https://github.com/xsession/chsm/workflows/chsm_modules_ci/badge.svg)](https://github.com/xsession/chsm/actions) + # CHSM - Hierarchical State Machine (HSM) Framework for C :warning: **Experimental code, expect breaking changes.** @@ -49,7 +52,25 @@ Cloning: `git clone https://github.com/ThrowTheSwitch/Unity.git` 1. Clone the repo 2. Checkout the **master** branch 3. Navigate into the **chsm** folder, open a command prompt and run this command: - **python3 cgen/chsm_backend.py** +**python3 cgen/chsm_backend.py** The result should be a new window with a simple state machine already in it. + +## Compile modules + +### To run one individual test, build and run it +``` +cd build +cmake --build . -t lm73_test; ctest -VV -R lm73_test +``` +### Build and run all tests with one command +``` +cd build +cmake --build . -t ; ctest -VV -R +``` +### To listout all target +``` +cd build +make help +``` \ No newline at end of file diff --git a/cgen/hsm/__init__.py b/cgen/hsm/__init__.py deleted file mode 100644 index 4687f3f3..00000000 --- a/cgen/hsm/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .sm import StateMachine \ No newline at end of file diff --git a/chsm_start.bat b/chsm_start.bat new file mode 100644 index 00000000..903903aa --- /dev/null +++ b/chsm_start.bat @@ -0,0 +1,11 @@ +@echo off + +set python_path=%PYTHON_PATH% + +if exist "%PYTHON_PATH%" ( + echo Environment variable PYTHON_PATH exists! + echo %python_path% + %python_path%\python.exe .\gui\chsm_backend.py +) else ( + echo Environment variable PYTHON_PATH doesen't exists please create it! +) \ No newline at end of file diff --git a/cmake/compilers/toolchain-ti-armcl.cmake b/cmake/compilers/toolchain-ti-armcl.cmake deleted file mode 100644 index bcc5b4f0..00000000 --- a/cmake/compilers/toolchain-ti-armcl.cmake +++ /dev/null @@ -1,100 +0,0 @@ -cmake_minimum_required(VERSION 3.18 FATAL_ERROR) - -# set target system -set(CMAKE_SYSTEM_NAME Generic) -set(CMAKE_SYSTEM_VERSION 1) -set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) - -if(MINGW OR CYGWIN OR WIN32) - set(UTIL_SEARCH_CMD where) -elseif(UNIX OR APPLE) - set(UTIL_SEARCH_CMD which) -endif() - -set(toolchain_name "armcl") -set(CMAKE_C_COMPILER_ID ${toolchain_name}) - -if(autodetect_toolchain) - find_program(toolchain ${toolchain_name}) - if(toolchain) - execute_process( - COMMAND ${UTIL_SEARCH_CMD} ${toolchain_name} - OUTPUT_VARIABLE BINUTILS_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process(COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --blue --bold "Find tolchain as ${BINUTILS_PATH}") - get_filename_component(TOOLCHAIN_DIR ${BINUTILS_PATH} DIRECTORY) - message(STATUS "TOOLCHAIN_DIR: -> ${TOOLCHAIN_DIR}") - get_filename_component(PARENT_TOOLCHAIN_DIR ${TOOLCHAIN_DIR} DIRECTORY) - message(STATUS "PARENT_TOOLCHAIN_DIR: -> ${PARENT_TOOLCHAIN_DIR}") - else() - execute_process(COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red --bold " Didn't find toolchain! - It's possible you forget to add it to the system PATH variable.") - message(FATAL_ERROR "") - endif() -else() - set(TOOLCHAIN_DIR "C:/ti/ccs1020/ccs/tools/compiler/ti-cgt-arm_20.2.5.LTS/bin") - find_program(toolchain NAMES ${toolchain_name} PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) - if(toolchain) - execute_process(COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --blue --bold "Find tolchain as ${TOOLCHAIN_DIR}") - message(STATUS "TOOLCHAIN_DIR: -> ${TOOLCHAIN_DIR}") - get_filename_component(PARENT_TOOLCHAIN_DIR ${TOOLCHAIN_DIR} DIRECTORY) - message(STATUS "PARENT_TOOLCHAIN_DIR: -> ${PARENT_TOOLCHAIN_DIR}") - else() - execute_process(COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red --bold " Didn't find toolchain! - It's possible you forget to add it to the system PATH variable.") - message(FATAL_ERROR "") - endif() -endif() - -set(CMAKE_FIND_ROOT_PATH "${TOOLCHAIN_DIR}") -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - -# toolchain paths -find_program(TI_GCC NAMES armcl PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TI_CXX NAMES armcl PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TI_AS NAMES armcl PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TI_AR NAMES armar PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TI_OBJCOPY NAMES armofd PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TI_OBJDUMP NAMES armhex PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TI_SIZE NAMES armsize PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TI_LD NAMES armcl PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) - -# set executables settings -set(CMAKE_C_COMPILER ${TI_GCC}) -set(CMAKE_CXX_COMPILER ${TI_CXX}) -set(AS ${TI_AS}) -set(AR ${TI_AR}) -set(OBJCOPY ${TI_OBJCOPY}) -set(OBJDUMP ${TI_OBJDUMP}) -set(SIZE ${TI_SIZE}) -set(LD ${TI_LD}) - -add_definitions( - -DOD_EXTENSION - -DFPGA_PWM - -D_RADIUS_INTERFACE_ACTIVE - -DNODEBUG - -DBOARD_EL_24_02_03 - -D_FLASH - -DFPGA_TEST) - -set(CMAKE_C_STANDARD_COMPUTED_DEFAULT 99) - -add_compile_options( - -mv7M3 - --code_state=16 - -me - -O2 - --c99 - --gcc - --diag_warning=225 - --diag_wrap=off - --display_error_number - --gen_func_subsections=on - --abi=eabi - --ual ) - - include_directories("${TOOLCHAIN_DIR}/../include") \ No newline at end of file diff --git a/cmake/compilers/toolchain-ti-cl2000.cmake b/cmake/compilers/toolchain-ti-cl2000.cmake deleted file mode 100644 index 9ced13f8..00000000 --- a/cmake/compilers/toolchain-ti-cl2000.cmake +++ /dev/null @@ -1,108 +0,0 @@ -cmake_minimum_required(VERSION 3.18 FATAL_ERROR) - -# set target system -set(CMAKE_SYSTEM_NAME Generic) -set(CMAKE_SYSTEM_VERSION 1) -set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) - -set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES 1) -set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_LIBRARIES 1) -set(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1) -set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1) -set(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1) -set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1) -set(CMAKE_C_RESPONSE_FILE_LINK_FLAG "@") -set(CMAKE_CXX_RESPONSE_FILE_LINK_FLAG "@") - -if(MINGW OR CYGWIN OR WIN32) - set(UTIL_SEARCH_CMD where) -elseif(UNIX OR APPLE) - set(UTIL_SEARCH_CMD which) -endif() - -set(toolchain_name "cl2000") -set(CMAKE_C_COMPILER_ID ${toolchain_name}) - -if(autodetect_toolchain) - find_program(toolchain ${toolchain_name}) - if(toolchain) - execute_process( - COMMAND ${UTIL_SEARCH_CMD} ${toolchain_name} - OUTPUT_VARIABLE BINUTILS_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process(COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --blue --bold "Find tolchain as ${BINUTILS_PATH}") - get_filename_component(TOOLCHAIN_DIR ${BINUTILS_PATH} DIRECTORY) - message(STATUS "TOOLCHAIN_DIR: -> ${TOOLCHAIN_DIR}") - get_filename_component(PARENT_TOOLCHAIN_DIR ${TOOLCHAIN_DIR} DIRECTORY) - message(STATUS "PARENT_TOOLCHAIN_DIR: -> ${PARENT_TOOLCHAIN_DIR}") - else() - execute_process(COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red --bold " Didn't find toolchain! - It's possible you forget to add it to the system PATH variable.") - message(FATAL_ERROR "") - endif() -else() - set(TOOLCHAIN_DIR "C:/ti/ccs1020/ccs/tools/compiler/ti-cgt-c2000_20.2.5.LTS/bin") - find_program(toolchain NAMES ${toolchain_name} PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) - if(toolchain) - execute_process(COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --blue --bold "Find tolchain as ${TOOLCHAIN_DIR}") - message(STATUS "TOOLCHAIN_DIR: -> ${TOOLCHAIN_DIR}") - get_filename_component(PARENT_TOOLCHAIN_DIR ${TOOLCHAIN_DIR} DIRECTORY) - message(STATUS "PARENT_TOOLCHAIN_DIR: -> ${PARENT_TOOLCHAIN_DIR}") - else() - execute_process(COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red --bold " Didn't find toolchain! - It's possible you forget to add it to the system PATH variable.") - message(FATAL_ERROR "") - endif() -endif() - -set(CMAKE_FIND_ROOT_PATH "${TOOLCHAIN_DIR}") # path/bin -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - -# toolchain paths -find_program(TI_GCC NAMES cl2000 PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TI_CXX NAMES cl2000 PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TI_AS NAMES cl2000 PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TI_AR NAMES ar2000 PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TI_OBJCOPY NAMES ofd2000 PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TI_OBJDUMP NAMES hex2000 PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -# find_program(TI_SIZE NAMES size2000 PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TI_LD NAMES cl2000 PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) - -# set executables settings -set(CMAKE_C_COMPILER ${TI_GCC}) -set(CMAKE_CXX_COMPILER ${TI_CXX}) -set(AS ${TI_AS}) -set(AR ${TI_AR}) -set(OBJCOPY ${TI_OBJCOPY}) -set(OBJDUMP ${TI_OBJDUMP}) -# set(SIZE ${TI_SIZE}) -set(LD ${TI_LD}) - -add_definitions( - -D_INLINE - -DNO_PROFILING - -DFPGA_PWM - -DFPGA_TEST - # -D__TMS320C2000__ - # -D__TMS320C28X__ - # -D__TMS320C28XX__ - # -D__TMS320C28XX_CLA__ - -DBOARD_EL_24_02_03) - -add_compile_options( - -v28 - -ml - -mt - --float_support=fpu32 - --vcu_support=vcu0 - -O2 - --c99 - --diag_warning=225 - --diag_wrap=off - --display_error_number - --abi=coffabi ) - -include_directories("${TOOLCHAIN_DIR}/../include") \ No newline at end of file diff --git a/cmake/compilers/toolchain-xc16.cmake b/cmake/compilers/toolchain-xc16.cmake deleted file mode 100644 index c87666ed..00000000 --- a/cmake/compilers/toolchain-xc16.cmake +++ /dev/null @@ -1,88 +0,0 @@ -cmake_minimum_required(VERSION 3.18 FATAL_ERROR) - -# set target system -set(CMAKE_SYSTEM_NAME dsPIC33) -set(CMAKE_SYSTEM_VERSION 1) -set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) - -if(MINGW OR CYGWIN OR WIN32) - set(UTIL_SEARCH_CMD where) -elseif(UNIX OR APPLE) - set(UTIL_SEARCH_CMD which) -endif() - -set(MCU_MODEL 33FJ128MC802 CACHE STRING "MCU model number set.") - -set(toolchain_name "xc16") -set(toolchain_prefix ${toolchain_name}) -set(CMAKE_C_COMPILER_ID ${toolchain_name}) - -find_program(toolchain ${toolchain_name}-gcc) -if(toolchain) - execute_process( - COMMAND ${UTIL_SEARCH_CMD} ${toolchain_name}-gcc - OUTPUT_VARIABLE BINUTILS_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process(COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --blue --bold "Find tolchain as ${BINUTILS_PATH}") -else() - execute_process(COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red --bold " Didn't find toolchain! - It's possible you forget to add it to the system PATH variable.") - message(FATAL_ERROR "") -endif() - -get_filename_component(TOOLCHAIN_DIR ${BINUTILS_PATH} DIRECTORY) -message(STATUS "TOOLCHAIN_DIR: -> ${TOOLCHAIN_DIR}") -get_filename_component(PARENT_TOOLCHAIN_DIR ${TOOLCHAIN_DIR} DIRECTORY) -message(STATUS "PARENT_TOOLCHAIN_DIR: -> ${PARENT_TOOLCHAIN_DIR}") - -set(CMAKE_FIND_ROOT_PATH "${TOOLCHAIN_DIR}") -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - -# toolchain paths -find_program(TOOLCHAIN_GCC NAMES ${toolchain_prefix}-gcc PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TOOLCHAIN_CXX NAMES ${toolchain_prefix}-gcc PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TOOLCHAIN_AS NAMES ${toolchain_prefix}-as PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TOOLCHAIN_AR NAMES ${toolchain_prefix}-ar PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TOOLCHAIN_OBJCOPY NAMES ${toolchain_prefix}-objcopy PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TOOLCHAIN_OBJDUMP NAMES ${toolchain_prefix}-objdump PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TOOLCHAIN_SIZE NAMES ${toolchain_prefix}-bin2hex PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) -find_program(TOOLCHAIN_LD NAMES ${toolchain_prefix}-ld PATHS ${TOOLCHAIN_DIR} NO_DEFAULT_PATH) - -# set executables settings -set(CMAKE_C_COMPILER ${TOOLCHAIN_GCC}) -set(CMAKE_CXX_COMPILER ${TOOLCHAIN_CXX}) -set(AS ${TOOLCHAIN_AS}) -set(AR ${TOOLCHAIN_AR}) -set(OBJCOPY ${TOOLCHAIN_OBJCOPY}) -set(OBJDUMP ${TOOLCHAIN_OBJDUMP}) -set(SIZE ${TOOLCHAIN_SIZE}) -set(LD ${TOOLCHAIN_LD}) - -# set the default C standard manually this is required by `Compiler/Gnu-C` -set(CMAKE_C_STANDARD_COMPUTED_DEFAULT 99) - -add_definitions( - # -DdsPIC33FJ128MC802 - # -DdsPIC33F - # -D__dsPIC33F__ - # -D__dsPIC33FJ128MC802__ -) - -add_compile_options( - -c - -mcpu=${MCU_MODEL} - -O0 - -omf=elf - -g - -mlarge-code - -mlarge-data - -mno-eds-warn - -no-legacy-libc - -MMD - -MF - -msmart-io=1 - -Wall - -msfr-warn=off) diff --git a/cmake/utils/Fetch_unity.cmake b/cmake/utils/Fetch_unity.cmake deleted file mode 100644 index 67c1ab2e..00000000 --- a/cmake/utils/Fetch_unity.cmake +++ /dev/null @@ -1,28 +0,0 @@ -include(FetchContent) - -set(FETCHCONTENT_QUIET OFF) - -get_filename_component(DIR ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) -get_filename_component(MODULE_NAME ${DIR} NAME) -message("MODULE_NAME: -> ${MODULE_NAME}") - -if(MODULE_NAME STREQUAL "crf") - FetchContent_Declare( - Unity - GIT_REPOSITORY https://github.com/ThrowTheSwitch/Unity.git - GIT_TAG origin/master - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../deps/unity - ) -else() - FetchContent_Declare( - Unity - GIT_REPOSITORY https://github.com/ThrowTheSwitch/Unity.git - GIT_TAG origin/master - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../deps/unity - ) -endif() - -set(UNITY_EXTENSION_FIXTURE ON CACHE INTERNAL "Set UNITY_EXTENSION_FIXTURE CACHE INTERNAL.") -set(UNITY_EXTENSION_MEMORY ON CACHE INTERNAL "Set UNITY_EXTENSION_MEMORY CACHE INTERNAL.") - -FetchContent_MakeAvailable( Unity ) diff --git a/cmake/utils/code_refactor.cmake b/cmake/utils/code_refactor.cmake deleted file mode 100644 index 7c425ac7..00000000 --- a/cmake/utils/code_refactor.cmake +++ /dev/null @@ -1,73 +0,0 @@ - -include(color_print) - -function(get_target_sources target_name locations) - get_target_property(target_sources ${target_name} SOURCE_DIR ) - set(include_dir "${target_sources}/inc" ) - set(source_dir "${target_sources}/src" ) - string(APPEND locations_ "${include_dir} " "${source_dir} " ) - set(${locations} ${locations_} PARENT_SCOPE) -endfunction() - - -##################### CLANG_FORMAT ###################### - -function(scan_source_dirs target_name resource_files) - get_target_property(target_sources ${target_name} SOURCE_DIR ) - file( - GLOB_RECURSE - SOURCE_FILES - CONFIGURE_DEPENDS - "${target_sources}/*.[cChH]") - set(${resource_files} ${SOURCE_FILES} PARENT_SCOPE) -endfunction() - -function(clang_format target_name) - scan_source_dirs(${target_name} res_files) - find_program(CLANG_FORMAT "clang-format") - if(CLANG_FORMAT) - color_print(blue "Format clang-format the ${target_name} .c/.h source files.") - execute_process( - # COMMAND clang-format -i -style=file ${res_files} - COMMAND clang-format -style=file ${res_files} - ) - else() - color_print(red "Can't find clang-format command.") - endif() -endfunction() - - -##################### CLANG_TIDY ###################### - -function(clang_tidy target_name) - scan_source_dirs(${target_name} res_files) - find_program(CLANG_TIDY "clang-tidy") - if(CLANG_TIDY) - color_print(yellow "Analize clang-tidy the ${target_name} .c/.h source files.") - execute_process( - COMMAND clang-tidy ${res_files} ) - else() - color_print(red "Can't find clang-format command.") - endif() -endfunction() - - -##################### CMAKE_FORMAT ###################### - -function(cmake_format) - file( - GLOB_RECURSE - ALL_CMAKE_FILES - CONFIGURE_DEPENDS - # "cmake/*.cmake" - "src/**/CMakeLists.txt") - find_program(CMAKE_FORMAT "cmake-format") - if(CMAKE_FORMAT) - color_print(pink "Format cmake-format the CMake files!") - execute_process( - # COMMAND cmake-format.exe -i ${ALL_CMAKE_FILES} - COMMAND cmake-format.exe -i ${ALL_CMAKE_FILES} ) - else() - color_print(red "Can't find cmake-format command.") - endif() -endfunction() diff --git a/cmake/utils/color_print.cmake b/cmake/utils/color_print.cmake deleted file mode 100644 index 7980e06f..00000000 --- a/cmake/utils/color_print.cmake +++ /dev/null @@ -1,7 +0,0 @@ - -# color is given like normal, black, red, green, yellow, blue, magenta, cyan, white -function(color_print color msg) -execute_process(COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --${color} --bold ${msg}) -endfunction() - -# color_print(cyan "Hi is there anyone?") diff --git a/cmake/utils/diagnostic.cmake b/cmake/utils/diagnostic.cmake deleted file mode 100644 index e4ca72bc..00000000 --- a/cmake/utils/diagnostic.cmake +++ /dev/null @@ -1,28 +0,0 @@ -include(color_print) -include(code_refactor) - -macro(diagnostic) - get_filename_component(libname ${CMAKE_CURRENT_SOURCE_DIR} NAME) - if(NOT TARGET ${libname}) - set(libname ${ARGN}) - else() - if(code_format) - clang_format(${libname}) - endif() - endif() - - if(debug) - color_print(cyan "--> ${libname}: ") - get_target_property(list ${libname} INCLUDE_DIRECTORIES) - message(STATUS "${libname} target INCLUDE_DIRECTORIES list: -> ${list}") - get_target_property(list ${libname} COMPILE_DEFINITIONS ) - message(STATUS "${libname} target COMPILE_DEFINITIONS list: -> ${list}") - get_target_property(list ${libname} LINK_LIBRARIES) - message(STATUS "${libname} target LINK_LIBRARIES list: -> ${list}") - get_target_property(list ${libname} COMPILE_OPTIONS) - message(STATUS "${libname} target COMPILE_OPTIONS list: -> ${list}") - else() - color_print(cyan "--> ${libname}: ") - endif() -endmacro() - diff --git a/cmake/utils/graphviz.cmake b/cmake/utils/graphviz.cmake deleted file mode 100644 index f748b7c0..00000000 --- a/cmake/utils/graphviz.cmake +++ /dev/null @@ -1,8 +0,0 @@ - -add_custom_target(graphviz ALL - COMMAND ${CMAKE_COMMAND} -E make_directory graphviz - COMMAND ${CMAKE_COMMAND} "--graphviz=graphviz/project_dependency.dot" . - COMMAND dot -Tpng graphviz/project_dependency.dot -o graphviz/project_dependency.png - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - COMMENT "Graphviz generated dependency map in ${CMAKE_BINARY_DIR}/graphviz/project_dependency.png" -) diff --git a/crf/inc/cevent.h b/crf/inc/cevent.h deleted file mode 100644 index 7a4fb455..00000000 --- a/crf/inc/cevent.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef INC_CEVENT_H_ -#define INC_CEVENT_H_ - -#include - -/** cevent - Base class for events - * - * Fields: - * sig: Event signal. - * gc_info: Used internally by CRF to keep track of the reference count - * on the event, and also to identify the event pool that - * handles the physical memory used by the event. - */ - -#ifndef SIGNAL_T -#define SIGNAL_T uint16_t -#endif - -typedef SIGNAL_T signal_t; - -typedef struct gc_info_tst -{ - uint16_t ref_cnt: 12; - uint16_t pool_id: 4; -} gc_info_tst; - -#define CEVENT_INVALID_POOL 0 - -typedef struct cevent_tst -{ - signal_t sig; - gc_info_tst gc_info; -} cevent_tst; - -#define CRF_SIGNAL_CLASS_MOD_INTERNAL 1 -#define CRF_SIGNAL_CLASS_START 2 -#define CRF_SIGNAL_CLASS_SIZE 256 - -#define SIGNAL_FROM_CLASS(CLASS) (CLASS * CRF_SIGNAL_CLASS_SIZE) - -static inline void cevent_ref_cnt_inc(const cevent_tst *e_pst) -{ - if (CEVENT_INVALID_POOL != e_pst->gc_info.pool_id) - { - ((cevent_tst *)e_pst)->gc_info.ref_cnt++; - } -} - -static inline void cevent_ref_cnt_dec(const cevent_tst *e_pst) -{ - if (CEVENT_INVALID_POOL != e_pst->gc_info.pool_id) - { - ((cevent_tst *)e_pst)->gc_info.ref_cnt--; - } -} - -#endif /* INC_CEVENT_H_ */ diff --git a/crf/inc/chsm.h b/crf/inc/chsm.h deleted file mode 100644 index c9ee0bca..00000000 --- a/crf/inc/chsm.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * hsm.h - * - * Created on: 2019. jan. 25. - * Author: jszeman - */ - -#ifndef INC_CHSM_H_ -#define INC_CHSM_H_ - -#include - -#include "cevent.h" -#include "cqueue.h" - -#define CHSM_MAX_NESTING_LEVEL 8 - -typedef enum -{ - C_SIG_NONE, - C_SIG_INIT, -} chsm_signals_ten; - -typedef enum -{ - C_RES_HANDLED, - C_RES_TRANS, - C_RES_PARENT, - C_RES_IGNORED, - C_RES_GUARDS, -} chsm_result_ten; - -typedef struct chsm_st chsm_tst; -typedef struct chsm_call_ctx_st chsm_call_ctx_tst; - -/* - * This is the type for functions the generated state machine will call. - */ -typedef void (*chsm_user_func_tpft)(chsm_tst *self, const cevent_tst *e_pst); - -/* - * This is the type for functions that implement state behaviour. Used only internally by - * the CRF library. - * Return: - * C_RES_HANDLED: The event was handled by the state or one of its ancestors - * C_RES_IGNORED: The event was ignored since there was no event hander defined for it - * in the state or any of its ancestors - * C_RES_TRANS: The event was handled and resulted in a state transition - * handler function to its parent state, and return a pointer for its own exit function. - * Params: - * self: Pointer to the state machine. - * e_pst: Pointer to the event to be handled. - * ctx_pst: Pointer to a call context that stores some information about the states involved - * in the event processing. - */ -typedef chsm_result_ten (*chsm_state_tpft)(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); - -/* - * Call context structure - * A pointer to such a structure will be passed to state handler functions. - * In case a state handler wants its parent to handle an event, it should write - * the pointer to the exit function in *exit_pft, then increase it. - * If the parent state handler executes a state transition, it should call the functions from - * the exit_stack_apft array to properly exit the currently active state. - */ -struct chsm_call_ctx_st -{ - chsm_user_func_tpft exit_stack_apft[CHSM_MAX_NESTING_LEVEL]; - chsm_user_func_tpft *exit_ppft; - chsm_state_tpft start_pft; -}; - -/* - * State machine - */ -struct chsm_st -{ - cqueue_tst event_q_st; - cqueue_tst defer_q_st; - - chsm_state_tpft state_handler_pft; - - /** send - * This function should be implemented by the application. - * - * Params: - * self: Pointer to the state machine instance - * e_pst: Pointer to the event to be sent - * Expected operation: - * The function should post the event to all state machines - * that need it for their operation. - * - * The state machine implementation shall call this function, when an - * event was created and need to be sent to the other parts of the system. - * This function should distribute the event to all queues in the application - * that may need it by calling their put method. - */ - void (*send)(chsm_tst *self, const cevent_tst *e_pst); - - /** next - * If a state machine has embedded state machine(s), the next pointers - * shall be used to link them into list, so the framework can step - * throgh them. - */ - chsm_tst* next; -}; - -void chsm_ctor(chsm_tst *self, chsm_state_tpft init_state_pft, - const cevent_tst **events, uint16_t event_q_len, uint16_t defer_q_len); -void chsm_init(chsm_tst *self); -void chsm_dispatch(chsm_tst *self, const cevent_tst *e_pst); -void chsm_defer(chsm_tst *self, const cevent_tst *e_pst); -void chsm_recall(chsm_tst *self, const cevent_tst *e_pst); - -void chsm_exit_children(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); - -extern const cevent_tst chsm_init_event_st; - -static inline chsm_result_ten chsm_handle_in_parent(chsm_tst *self, chsm_call_ctx_tst *ctx_pst, - chsm_state_tpft parent, void *exit_func, bool guards_only_b) -{ - self->state_handler_pft = parent; - if (exit_func) - { - *(ctx_pst->exit_ppft) = (chsm_user_func_tpft)exit_func; - ctx_pst->exit_ppft++; - } - - if (guards_only_b) - { - return C_RES_GUARDS; - } - - return C_RES_PARENT; -} - -static inline chsm_result_ten chsm_transition(chsm_tst *self, chsm_state_tpft target) -{ - self->state_handler_pft = target; - - return C_RES_TRANS; -} - -static inline chsm_result_ten chsm_ignored(chsm_tst *self) -{ - return C_RES_IGNORED; -} - -static inline chsm_result_ten chsm_handled(chsm_tst *self) -{ - return C_RES_HANDLED; -} - -#endif /* INC_CHSM_H_ */ diff --git a/crf/inc/cpool.h b/crf/inc/cpool.h deleted file mode 100644 index 1fd39ad8..00000000 --- a/crf/inc/cpool.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * event_pool.h - * - * Created on: 2019. jan. 25. - * Author: jszeman - */ - -#ifndef INC_CPOOL_H_ -#define INC_CPOOL_H_ - -#include -#include -#include "cevent.h" -#include "atomic_ops.h" -#include - -#if (CHAR_BIT == 16) - #ifndef COMMON_TYPES_H_ - typedef unsigned char uint8_t; - typedef char int8_t; - #endif -#endif -#if (CHAR_BIT == 8) -typedef unsigned char uint8; -#endif - -typedef struct cpool_tst cpool_tst; - -struct cpool_tst -{ - uint8_t *pool; // Pointer to a user allocated buffer - uint16_t esize; // Unit size of events in the pool - uint16_t ecnt; // Max number of events in the pool - atomic_uint16_t head; // Offset of the first free block - - void* (*new)(cpool_tst *self); - bool (*gc)(cpool_tst *self, const cevent_tst *e); -}; - -void cpool_init(cpool_tst *self, uint8_t *buff, uint16_t event_size, uint16_t event_count); - -#endif /* INC_CPOOL_H_ */ diff --git a/crf/inc/cqueue.h b/crf/inc/cqueue.h deleted file mode 100644 index ea131a28..00000000 --- a/crf/inc/cqueue.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * event_queue.h - * - * Created on: 2019. jan. 26. - * Author: jszeman - */ - -#ifndef INC_CQUEUE_H -#define INC_CQUEUE_H - -#include -#include -#include "cevent.h" -#include "atomic_ops.h" - -/* - * Thread safe multi-producer single consumer event queue - * - * The application should only ever need to call the put method directly - * to place events into the queue. Calling this function from interrupts - * and other threads is safe. - * All the other methods sould only be called from the main thread. - */ - -typedef struct cqueue_tst cqueue_tst; - -struct cqueue_tst -{ - int32_t (*put)(cqueue_tst *self, const cevent_tst *e_cpst); - int32_t (*put_left)(cqueue_tst *self, const cevent_tst *e_cpst); - const cevent_tst* (*get)(cqueue_tst *self); - const cevent_tst* (*get_right)(cqueue_tst *self); - - const cevent_tst **events; - uint16_t max; - atomic_uint16_t head; - atomic_uint16_t tail; - uint16_t mask; - uint32_t fault_cnt; -}; - -int32_t cqueue_init(cqueue_tst *self, const cevent_tst **events, uint16_t max_event_count); - -#endif /* INC_CQUEUE_H */ diff --git a/crf/inc/crf.h b/crf/inc/crf.h deleted file mode 100644 index 1d68da86..00000000 --- a/crf/inc/crf.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * cr.h - * - * Created on: 2019. jan. 31. - * Author: jszeman - * - * C Active Object System - */ - -#ifndef INC_CRF_H_ -#define INC_CRF_H_ - -#include -#include - -#include "cevent.h" -#include "cpool.h" -#include "cqueue.h" -#include "chsm.h" - -#define CRF_MAX_POOL_COUNT 4 - -typedef struct crf_tst crf_tst; - -struct crf_tst -{ - void* (*new_event)(crf_tst *self, uint32_t size, signal_t sig); - void (*publish)(crf_tst *self, const cevent_tst* e); - void (*post)(crf_tst *self, cevent_tst* e, cqueue_tst *q); - bool (*step)(crf_tst *self); - void (*gc)(crf_tst *self, const cevent_tst* e); - - - chsm_tst **chsm_ap; //< Pointer to the array of objects in the application - cpool_tst *pool_ast; //< Pointer to an array of memory pools. - uint16_t pool_cnt_u16; -}; - -bool crf_init(crf_tst *self , chsm_tst **chsm_ap, cpool_tst *pool_ast, uint16_t pool_cnt); - -#define TYPEOF(SIGNAL) SIGNAL##_TYPE - -#define CRF_NEW_EVENT(event_type, sig) crf.new_event(&crf, sizeof(event_type), sig) -#define CRF_NEW(SIGNAL) CRF_NEW_EVENT(TYPEOF(SIGNAL), SIGNAL) -#define CRF_POST(event_ptr, queue_ptr) crf.post(&crf, (cevent_tst *)event_ptr, (cqueue_tst *)(queue_ptr)) -#define CRF_POST_TO_SELF(event_ptr) ((cqueue_tst *)(self))->put_left((cqueue_tst *)(self), event_ptr) -#define CRF_STEP() crf.step(&crf) -#define CRF_EMIT(event_ptr) ((chsm_tst *)self)->send((chsm_tst *)self, (const cevent_tst *)event_ptr) -#define CRF_GC(event_ptr) crf.gc(&crf, (cevent_tst *)event_ptr) -#define CRF_SEND_FUNC(hsm_pst) ((chsm_tst *)hsm_pst)->send -#define CRF_SIG_VAR(SIGNAL, VAR, E_PST) TYPEOF(SIGNAL)* VAR = (TYPEOF(SIGNAL)*)E_PST -#define CRF_SET_SEND_FUNC(hsm_pst, func) CRF_SEND_FUNC(hsm_pst) = (void (*)(chsm_tst *, const cevent_tst *))func - -extern crf_tst crf; - -#endif /* INC_CRF_H_ */ diff --git a/crf/src/chsm.c b/crf/src/chsm.c deleted file mode 100644 index fd45763b..00000000 --- a/crf/src/chsm.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * hsm.c - * - * Created on: 2019. jan. 25. - * Author: jszeman - */ -#include -#include -#include -#include - - -const cevent_tst chsm_init_event_st = {.sig=C_SIG_INIT, .gc_info={0}}; -const cevent_tst chsm_none_event_st = {.sig=C_SIG_NONE, .gc_info={0}}; - -static void send(chsm_tst *self, const cevent_tst *e_pst) -{ - -} - -void chsm_ctor(chsm_tst *self, chsm_state_tpft init_state_pft, const cevent_tst **events, uint16_t event_q_len, uint16_t defer_q_len) -{ - assert(NULL != self); - assert(NULL != init_state_pft); - - self->send = send; - self->next = NULL; - self->state_handler_pft = init_state_pft; - cqueue_init(&self->event_q_st, events, event_q_len); - cqueue_init(&self->defer_q_st, events+event_q_len, defer_q_len); -} - -void chsm_init(chsm_tst *self) -{ - assert(NULL != self); - - chsm_dispatch(self, &chsm_init_event_st); -} - - -void chsm_defer(chsm_tst *self, const cevent_tst *e_pst) -{ - self->defer_q_st.put(&self->defer_q_st, (cevent_tst *)e_pst); -} - -void chsm_recall(chsm_tst *self, const cevent_tst *e_pst) -{ - const cevent_tst *ev_pst; - - while(ev_pst = self->defer_q_st.get_right(&self->defer_q_st)) - { - self->event_q_st.put_left(&self->event_q_st, (cevent_tst *)ev_pst); - } -} - -void chsm_exit_children(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - chsm_user_func_tpft *exit_ppft; - - exit_ppft = ctx_pst->exit_stack_apft; - - for (int i=0; istate_handler_pft; - - for (int i=0; istate_handler_pft(self, e_pst, &ctx_st); - - switch(result_en) - { - case C_RES_HANDLED: - case C_RES_IGNORED: - /* In these cases the event was handled in an ancestor so we have to - * restore the original state then finish the event processing. - */ - self->state_handler_pft = ctx_st.start_pft; - return; - - case C_RES_TRANS: - /* The event resulted in a transition. Don't need to do anything else. */ - return; - - case C_RES_PARENT: - /* The event was not handled by the current state, so it changed the - * state pointer to its parent. This means that we need to call - * the new state handler with the same event. - */ - break; - - case C_RES_GUARDS: - /* The event was handled without transitioning into a new state, - * so the original event shall not be handled in the parents, but - * we still want to run all the guards. - */ - e_pst = &chsm_none_event_st; - break; - } - } - - //TODO: error handling for nesting overflow -} diff --git a/crf/src/cqueue.c b/crf/src/cqueue.c deleted file mode 100644 index f29885f8..00000000 --- a/crf/src/cqueue.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * event_queue.c - * - * Created on: 2019. jan. 26. - * Author: jszeman - */ - -#include -#include -#include -#include -#include -#include "atomic_ops.h" - - -/* Thread safety analysis: - * - * 1. - * Interrupt here will not cause any problem. If no space left, it will - * simply restore the state the previous line left. If there is more space - * left then self->head will be increased by one, but this won't affect the - * rest of the code in this function. - * - * 2. - * Only cqueue_put should be called from interrupt and this function will - * not modify self->tail and self->max so this line only depends on the result - * of the fetch operation. - * - * 3. - * If an interrupt happens here it will fail since at this point we know that - * there is no more space in the queue. This means self->head will not be - * changed. - * - * 4. - * The function is about to return, so an interrupt here will not cause any - * problem. - * - * 5. - * Same as 1. - */ - -static int32_t cqueue_put(cqueue_tst *self, const cevent_tst *e) -{ - uint16_t head; - - assert(NULL != self); - - if (0 == self->max) return -1; - - head = atomic_fetch_add_u16(&self->head, 1); - - // 1. - - if (head - self->tail >= self->max) // 2. - { - // 3. - self->head = head; - // 4. - - self->fault_cnt++; - - return -1; - } - - cevent_ref_cnt_inc(e); - - // 5. - self->events[head & self->mask] = e; - - return 0; -} - -static int32_t cqueue_put_left(cqueue_tst *self, const cevent_tst *e_pst) -{ - assert(NULL != self); - - if (0 == self->max) return -1; - - if ((uint16_t)(self->head - self->tail) >= self->max) - { - self->fault_cnt++; - - return -1; - } - - self->tail--; - - cevent_ref_cnt_inc(e_pst); - - self->events[self->tail & self->mask] = e_pst; - - return 0; -} - -static const cevent_tst *cqueue_get(cqueue_tst *self) -{ - const cevent_tst *e; - - assert(NULL != self); - - if (0 == self->max) return NULL; - - if (self->head == self->tail) - { - return NULL; - } - - e = self->events[self->tail & self->mask]; - self->tail++; - - cevent_ref_cnt_dec(e); - return e; -} - -static const cevent_tst *cqueue_get_right(cqueue_tst *self) -{ - const cevent_tst *e; - - assert(NULL != self); - - if (0 == self->max) return NULL; - - if (self->head == self->tail) - { - return NULL; - } - - self->head--; - e = self->events[self->head & self->mask]; - - cevent_ref_cnt_dec(e); - return e; -} - -int32_t cqueue_init(cqueue_tst *self, const cevent_tst **events, uint16_t max_event_count) -{ - assert(NULL != self); - assert(NULL != events); - - self->events = events; - self->max = max_event_count; - self->head = 0; - self->tail = 0; - self->mask = max_event_count-1; - - self->fault_cnt = 0; - - self->put = cqueue_put; - self->put_left = cqueue_put_left; - self->get = cqueue_get; - self->get_right = cqueue_get_right; - -#if 0 // just to test orthogonality - self->put_left = cqueue_put; - self->put = cqueue_put_left; - self->get_right = cqueue_get; - self->get = cqueue_get_right; -#endif - - return 0; -} diff --git a/crf/test/CMakeLists.txt b/crf/test/CMakeLists.txt deleted file mode 100644 index 6d653739..00000000 --- a/crf/test/CMakeLists.txt +++ /dev/null @@ -1,71 +0,0 @@ -cmake_minimum_required(VERSION 3.19) - -project(CrfTest - LANGUAGES C) - -include(GNUInstallDirs) - -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}) - -list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../../cmake/utils") - -message(STATUS "Using toolchain file: ${CMAKE_TOOLCHAIN_FILE}.") - -include(Fetch_unity) - -add_executable(crf_test - tsrc/main.c - tsrc/cpool_test.c - tsrc/cqueue_test.c - tsrc/chsm_test.c - tsrc/crf_test.c - tsrc/cbits_test.c - tsrc/cvalue_test.c - tsrc/chsm_test_functions.c - tsrc/chsm_test_machine.c - tsrc/chsm_test_machine2.c - tsrc/chsm_test_machine3.c - tsrc/chsm_test_machine4.c - tsrc/bus_driver.c - tsrc/bus_driver_functions.c - tsrc/dev_driver.c - tsrc/dev_driver_functions.c - tsrc/atomic_functions.c - ../src/chsm.c - ../src/cvalue.c - ../src/cpool.c - ../src/cqueue.c - ../src/crf.c - ../src/cbits.c - ) - -target_include_directories(crf_test PRIVATE - tinc - ../inc - ) - - -target_compile_options(crf_test PRIVATE - -Wall - -Wextra - -pedantic - # -Werror - ) - -target_compile_definitions(crf_test PRIVATE - NDEBUG) - -target_link_options(crf_test PRIVATE - -Wl,-Map=${PROJECT_BINARY_DIR}/bin/${PROJECT_NAME}.map -) - -target_link_libraries(crf_test - unity - ) - -include(diagnostic) -set(debug on) -set(autodetect off) -diagnostic(crf_test) diff --git a/crf/test/tinc/bus_driver_functions.h b/crf/test/tinc/bus_driver_functions.h deleted file mode 100644 index b7ecd35d..00000000 --- a/crf/test/tinc/bus_driver_functions.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef BUS_DRIVER_FUNCTIONS_H -#define BUS_DRIVER_FUNCTIONS_H - -/*Generated with CHSM v0.0.0 at 2020.07.26 07.12.40*/ - -#include "bus_driver.h" -#include "chsm.h" -#include "cevent.h" -#include - -void emit_event(bus_driver_tst *self, const cevent_tst *e_pst); -void send_data(bus_driver_tst *self, const cevent_tst *e_pst); - - -#endif diff --git a/crf/test/tinc/chsm_test_functions2.h b/crf/test/tinc/chsm_test_functions2.h deleted file mode 100644 index 0e1192fe..00000000 --- a/crf/test/tinc/chsm_test_functions2.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef CHSM_TEST_FUNCTIONS2_H -#define CHSM_TEST_FUNCTIONS2_H - -/*Generated with CHSM v0.0.0 at 2021.05.12 21.17.52*/ - -#include "chsm_test_machine.h" -#include "chsm.h" -#include "cevent.h" -#include - - -void d_func(chsm_tst *self, const cevent_tst *e_pst); - -/*S11 entry function comment*/ -void s11_entry(chsm_tst *self, const cevent_tst *e_pst); - -void s11_exit(chsm_tst *self, const cevent_tst *e_pst); - -void s11_init(chsm_tst *self, const cevent_tst *e_pst); - -/*S1 entry function comment.*/ -void s1_entry(chsm_tst *self, const cevent_tst *e_pst); - -void s1_exit(chsm_tst *self, const cevent_tst *e_pst); - -void s1_func(chsm_tst *self, const cevent_tst *e_pst); - -void s1_init(chsm_tst *self, const cevent_tst *e_pst); - -void s211_entry(chsm_tst *self, const cevent_tst *e_pst); - -void s211_id(chsm_tst *self, const cevent_tst *e_pst); - -void s211_init(chsm_tst *self, const cevent_tst *e_pst); - -void s21_entry(chsm_tst *self, const cevent_tst *e_pst); - -void s21_exit(chsm_tst *self, const cevent_tst *e_pst); - -void s21_init(chsm_tst *self, const cevent_tst *e_pst); - -void s2_entry(chsm_tst *self, const cevent_tst *e_pst); - -void s2_exit(chsm_tst *self, const cevent_tst *e_pst); - -void s2_init(chsm_tst *self, const cevent_tst *e_pst); - -void s3_k_func(chsm_tst *self, const cevent_tst *e_pst); - -void s3_l_func(chsm_tst *self, const cevent_tst *e_pst); - -void s4_id(chsm_tst *self, const cevent_tst *e_pst); - -void s_entry(chsm_tst *self, const cevent_tst *e_pst); - -void s_exit(chsm_tst *self, const cevent_tst *e_pst); - -void s_init(chsm_tst *self, const cevent_tst *e_pst); - - -bool cond(chsm_tst *self, const cevent_tst *e_pst); - -bool j_guard(chsm_tst *self, const cevent_tst *e_pst); - -bool s1_guard(chsm_tst *self, const cevent_tst *e_pst); - -typedef enum chsm_test_machine_state_id_ten -{ - S = 0, - S1 = 1, - S11 = 2, - S2 = 3, - S21 = 4, - S211 = 5, - S3 = 6, - S4 = 7, -} chsm_test_machine_state_id_ten; - - -/* -Signals: - A - B - C - D - E - F Comment for F - G Comment for G - H - ID - J - K - L -*/ - -/* -Other function notes: - -k_guard: - Parametric guard comment. - -s11_func: - -s11_g1: - -s11_g2: - -s11_g_guard1: - Comment for the s11_g_guard1 func. - - Multiple lines. - -s11_g_guard2: - -s11_guard: - -s11_id: - -s211_exit: -*/ -#endif diff --git a/crf/test/tinc/dev_driver_functions.h b/crf/test/tinc/dev_driver_functions.h deleted file mode 100644 index 84f361ca..00000000 --- a/crf/test/tinc/dev_driver_functions.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef DEV_DRIVER_FUNCTIONS_H -#define DEV_DRIVER_FUNCTIONS_H - -/*Generated with CHSM v0.0.0 at 2020.07.29 06.46.58*/ - -#include "dev_driver.h" -#include "chsm.h" -#include "cevent.h" -#include - -void cancel_request(dev_driver_tst *self, const cevent_tst *e_pst); -void dev_drv_init(dev_driver_tst *self, const cevent_tst *e_pst); -void inc_timer(dev_driver_tst *self, const cevent_tst *e_pst); -void insert_data(dev_driver_tst *self, const cevent_tst *e_pst); -void send_read_request(dev_driver_tst *self, const cevent_tst *e_pst); -void send_write_request(dev_driver_tst *self, const cevent_tst *e_pst); -void start_timer(dev_driver_tst *self, const cevent_tst *e_pst); - -bool response_complete(dev_driver_tst *self, const cevent_tst *e_pst); -bool timeout(dev_driver_tst *self, const cevent_tst *e_pst); - -#endif diff --git a/crf/test/tsrc/cbits_test.c b/crf/test/tsrc/cbits_test.c deleted file mode 100644 index 5cfceccb..00000000 --- a/crf/test/tsrc/cbits_test.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * canopen_test.c - * - * Created on: 2019. jan. 25. - * Author: jszeman - */ - -#include -#include -#include -#include -#include -#include "unity_fixture.h" -#include "crf.h" -#include "cbits.h" - -TEST_GROUP(cb); - -cevent_tst active_events_ast[32]; -cevent_tst inactive_events_ast[32]; - -uint32_t active_bits_u32; -uint32_t inactive_bits_u32; -void *last_user_param_pv; - -cbits_tst cb_st; - -#define TEST_POINTER (void *)0x12345678 - -void send(void *user_param_pv, const cevent_tst *e_pst) -{ - last_user_param_pv = user_param_pv; - - if (e_pst->sig & 0x100) - { - active_bits_u32 |= (1UL << e_pst->sig); - } - else if (e_pst->sig & 0x200) - { - inactive_bits_u32 |= (1UL << (e_pst->sig & 0xff)); - } -} - -TEST_SETUP(cb) -{ - bool res_b; - - active_bits_u32 = 0; - inactive_bits_u32 = 0; - last_user_param_pv = NULL; - - for (int i=0; i<32; i++) - { - active_events_ast[i] = (cevent_tst){.sig = i | 0x100}; - inactive_events_ast[i] = (cevent_tst){.sig = i | 0x200}; - } - - cb_st = (cbits_tst){ - .config = { - .active_events_pst = active_events_ast, - .inactive_events_pst = inactive_events_ast, - .user_param_pv = TEST_POINTER, - .send_pft = send - } - }; - - res_b = cbits_init(&cb_st, 0); - TEST_ASSERT(res_b); - TEST_ASSERT(cb_st.set_data); -} - -TEST_TEAR_DOWN(cb) -{ -} - -/** - * Make a rising edge on bit 0 and check that the send function was called with - * the proper event. - */ -TEST(cb, init_without_send) -{ - bool res_b; - - cb_st.config.send_pft = NULL; - res_b = cbits_init(&cb_st, 0); - - TEST_ASSERT_FALSE(res_b); -} - -/** - * Make a rising edge on bit 0 and check that the send function was called with - * the proper event. - */ -TEST(cb, set_bit_0) -{ - cb_st.set_data(&cb_st, 1); - - TEST_ASSERT_EQUAL_HEX32(1, active_bits_u32); - TEST_ASSERT_EQUAL_HEX32(TEST_POINTER, last_user_param_pv); -} - -/** - * Make a rising and falling edge on bit 0 and check that the send function was - * called with the proper events. - */ -TEST(cb, set_clr_bit_0) -{ - cb_st.set_data(&cb_st, 1); - cb_st.set_data(&cb_st, 0); - - TEST_ASSERT_EQUAL_HEX32(1, active_bits_u32); - TEST_ASSERT_EQUAL_HEX32(1, inactive_bits_u32); -} - -/** - * Make a rising edge on bit 0 and 1 then check that the send function was called with - * the proper events. - */ -TEST(cb, set_bit_01) -{ - cb_st.set_data(&cb_st, 3); - - TEST_ASSERT_EQUAL_HEX32(3, active_bits_u32); -} - -/** - * Make a rising edge on bit 0 and 1 then check that the send function was called with - * the proper events. - */ -TEST(cb, set_bit_0_15) -{ - cb_st.set_data(&cb_st, 1 | (1 << 15)); - - TEST_ASSERT_EQUAL_HEX32(1 | (1 << 15), active_bits_u32); -} - -/** - * Check effect of setting two bits, then clearning only one - */ -TEST(cb, set_2_clr_1) -{ - cb_st.set_data(&cb_st, 1); - cb_st.set_data(&cb_st, 3); - cb_st.set_data(&cb_st, 2); - - TEST_ASSERT_EQUAL_HEX32(3, active_bits_u32); - TEST_ASSERT_EQUAL_HEX32(1, inactive_bits_u32); -} - -/** - * Check that events with sig == 0 are not sent - */ -TEST(cb, check_0_signal_not_sent) -{ - active_events_ast[0] = (cevent_tst){.sig = 0}; - - cb_st.set_data(&cb_st, 1); - - TEST_ASSERT_EQUAL_HEX32(0, active_bits_u32); -} - -/** - * Check that the module works without active_sig pointer. - */ -TEST(cb, no_active_events) -{ - cb_st.config.active_events_pst = NULL; - - cb_st.set_data(&cb_st, 1); - cb_st.set_data(&cb_st, 0); - - TEST_ASSERT_EQUAL_HEX32(0, active_bits_u32); - TEST_ASSERT_EQUAL_HEX32(1, inactive_bits_u32); -} - -/** - * Check that the module works without inactive_sig pointer. - */ -TEST(cb, no_inactive_events) -{ - cb_st.config.inactive_events_pst = NULL; - - cb_st.set_data(&cb_st, 1); - cb_st.set_data(&cb_st, 0); - - TEST_ASSERT_EQUAL_HEX32(1, active_bits_u32); - TEST_ASSERT_EQUAL_HEX32(0, inactive_bits_u32); -} - -TEST_GROUP_RUNNER(cb) -{ - RUN_TEST_CASE(cb, set_bit_0); - RUN_TEST_CASE(cb, init_without_send); - RUN_TEST_CASE(cb, set_clr_bit_0); - RUN_TEST_CASE(cb, set_bit_01); - RUN_TEST_CASE(cb, set_bit_0_15); - RUN_TEST_CASE(cb, set_2_clr_1); - RUN_TEST_CASE(cb, check_0_signal_not_sent); - RUN_TEST_CASE(cb, no_active_events); - RUN_TEST_CASE(cb, no_inactive_events); - //RUN_TEST_CASE(cb, init); - //RUN_TEST_CASE(cb, init); -} diff --git a/crf/test/tsrc/chsm_test_machine2.c b/crf/test/tsrc/chsm_test_machine2.c deleted file mode 100644 index 8c1cfb9c..00000000 --- a/crf/test/tsrc/chsm_test_machine2.c +++ /dev/null @@ -1,63 +0,0 @@ - -#include "chsm_test_machine.h" -#include "chsm.h" -#include "cevent.h" - -#include "chsm_test_functions.h" - -#include - -/* - * State machine 2 - */ - -static chsm_result_ten s(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); -static chsm_result_ten s1(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); - -chsm_result_ten __top__2(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - //printf("%d -> %s\n", e_pst->sig, __func__); - switch(e_pst->sig) - { - case C_SIG_INIT: - s_entry((test_hsm_tst *)self, e_pst); - s_init((test_hsm_tst *)self, e_pst); - s1_entry((test_hsm_tst *)self, e_pst); - s1_init((test_hsm_tst *)self, e_pst); - return chsm_transition(self, s1); - } - - return chsm_ignored(self); -} - -chsm_result_ten s(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - //printf("%d -> %s\n", e_pst->sig, __func__); - switch(e_pst->sig) - { - case TEST_SIG1: - s_sig1_handler((test_hsm_tst *)self, e_pst); - return chsm_handled(self); - - default: - break; - } - - return chsm_handle_in_parent(self, ctx_pst, __top__2, NULL, false); -} - -chsm_result_ten s1(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - //printf("%d -> %s\n", e_pst->sig, __func__); - switch(e_pst->sig) - { - case TEST_SIG2: - s_sig2_handler((test_hsm_tst *)self, e_pst); - return chsm_handled(self); - - default: - break; - } - - return chsm_handle_in_parent(self, ctx_pst, s, NULL, false); -} diff --git a/crf/test/tsrc/chsm_test_machine3.c b/crf/test/tsrc/chsm_test_machine3.c deleted file mode 100644 index 75e5ea73..00000000 --- a/crf/test/tsrc/chsm_test_machine3.c +++ /dev/null @@ -1,83 +0,0 @@ - -#include "chsm_test_machine.h" -#include "chsm.h" -#include "cevent.h" - -#include "chsm_test_functions.h" - -#include - -/* - * State machine 3 - */ - -static chsm_result_ten s(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); -static chsm_result_ten s1(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); -static chsm_result_ten s2(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); - -chsm_result_ten __top__3(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - //printf("%d -> %s\n", e_pst->sig, __func__); - switch(e_pst->sig) - { - case C_SIG_INIT: - s_entry((test_hsm_tst *)self, e_pst); - s_init((test_hsm_tst *)self, e_pst); - s1_entry((test_hsm_tst *)self, e_pst); - s1_init((test_hsm_tst *)self, e_pst); - return chsm_transition(self, s1); - } - - return chsm_ignored(self); -} - -chsm_result_ten s(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - //printf("%d -> %s\n", e_pst->sig, __func__); - switch(e_pst->sig) - { - case TEST_SIG1: - s_sig1_handler((test_hsm_tst *)self, e_pst); - chsm_exit_children(self, e_pst, ctx_pst); - s2_entry((test_hsm_tst *)self, e_pst); - s2_init((test_hsm_tst *)self, e_pst); - return chsm_transition(self, s2); - - default: - break; - } - - return chsm_handle_in_parent(self, ctx_pst, __top__3, NULL, false); -} - -chsm_result_ten s1(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - //printf("%d -> %s\n", e_pst->sig, __func__); - switch(e_pst->sig) - { - case TEST_SIG2: - s_sig2_handler((test_hsm_tst *)self, e_pst); - return chsm_handled(self); - - default: - break; - } - - return chsm_handle_in_parent(self, ctx_pst, s, s1_exit, false); -} - -chsm_result_ten s2(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - //printf("%d -> %s\n", e_pst->sig, __func__); - switch(e_pst->sig) - { - case TEST_SIG3: - s_sig3_handler((test_hsm_tst *)self, e_pst); - return chsm_handled(self); - - default: - break; - } - - return chsm_handle_in_parent(self, ctx_pst, s, NULL, false); -} diff --git a/crf/test/tsrc/chsm_test_machine4.c b/crf/test/tsrc/chsm_test_machine4.c deleted file mode 100644 index 7415e9db..00000000 --- a/crf/test/tsrc/chsm_test_machine4.c +++ /dev/null @@ -1,384 +0,0 @@ -/*Generated with CHSM v0.0.0 at 2021.05.12 21.17.52*/ -#include "cevent.h" -#include "chsm.h" -#include "chsm_test_machine.h" -#include "chsm_test_functions2.h" - - -static chsm_result_ten s4(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); -static chsm_result_ten s3(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); -static chsm_result_ten s211(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); -static chsm_result_ten s21(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); -static chsm_result_ten s2(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); -static chsm_result_ten s11(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); -static chsm_result_ten s1(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); -static chsm_result_ten s(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); - -static chsm_result_ten s(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - bool guards_only_b=true; - switch(e_pst->sig) - { - case TEST_SIG_E: - chsm_exit_children(self, e_pst, ctx_pst); - s1_entry(self, e_pst); - s11_entry(self, e_pst); - s11_init(self, e_pst); - return chsm_transition(self, s11); - - case TEST_SIG_J: - chsm_exit_children(self, e_pst, ctx_pst); - chsm_recall(self, e_pst); - return chsm_transition(self, s3); - - default: - guards_only_b = false; - } - - return chsm_handle_in_parent(self, ctx_pst, __top__4, s_exit, guards_only_b); -} - -static chsm_result_ten s1(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - bool guards_only_b=true; - switch(e_pst->sig) - { - case TEST_SIG_ID: - s1_func(self, e_pst); - break; - - case TEST_SIG_C: - chsm_exit_children(self, e_pst, ctx_pst); - s1_exit(self, e_pst); - s2_entry(self, e_pst); - s2_init(self, e_pst); - s21_entry(self, e_pst); - s21_init(self, e_pst); - s211_entry(self, e_pst); - s211_init(self, e_pst); - return chsm_transition(self, s211); - - case TEST_SIG_F: - chsm_exit_children(self, e_pst, ctx_pst); - s1_exit(self, e_pst); - s2_entry(self, e_pst); - s21_entry(self, e_pst); - s211_entry(self, e_pst); - s211_init(self, e_pst); - return chsm_transition(self, s211); - - case TEST_SIG_B: - chsm_exit_children(self, e_pst, ctx_pst); - s11_entry(self, e_pst); - s11_init(self, e_pst); - return chsm_transition(self, s11); - - case TEST_SIG_A: - chsm_exit_children(self, e_pst, ctx_pst); - s1_exit(self, e_pst); - s1_entry(self, e_pst); - s1_init(self, e_pst); - s11_entry(self, e_pst); - s11_init(self, e_pst); - return chsm_transition(self, s11); - - default: - guards_only_b = false; - } - - if(s1_guard(self, e_pst)) - { - s1_func(self, e_pst); - } - - if(j_guard(self, e_pst)) - { - chsm_exit_children(self, e_pst, ctx_pst); - s1_exit(self, e_pst); - s2_entry(self, e_pst); - s2_init(self, e_pst); - s21_entry(self, e_pst); - s21_init(self, e_pst); - s211_entry(self, e_pst); - s211_init(self, e_pst); - return chsm_transition(self, s211); - } - - return chsm_handle_in_parent(self, ctx_pst, s, s1_exit, guards_only_b); -} - -static chsm_result_ten s11(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - bool guards_only_b=true; - switch(e_pst->sig) - { - case TEST_SIG_ID: - s11_id(self, e_pst, 8); - break; - - case TEST_SIG_G: - if(s11_g_guard1(self, e_pst, 1)) - { - s11_g1(self, e_pst, 2); - } - if(s11_g_guard2(self, e_pst, 4)) - { - chsm_exit_children(self, e_pst, ctx_pst); - s11_g2(self, e_pst, 3); - s11_exit(self, e_pst); - s1_exit(self, e_pst); - s2_entry(self, e_pst); - s21_entry(self, e_pst); - s211_entry(self, e_pst); - s211_init(self, e_pst); - return chsm_transition(self, s211); - } - break; - - case TEST_SIG_K: - chsm_defer(self, e_pst); - break; - - case TEST_SIG_L: - chsm_defer(self, e_pst); - break; - - case TEST_SIG_D: - if(cond(self, e_pst)) - { - chsm_exit_children(self, e_pst, ctx_pst); - d_func(self, e_pst); - s11_exit(self, e_pst); - s1_init(self, e_pst); - s11_entry(self, e_pst); - s11_init(self, e_pst); - return chsm_transition(self, s11); - } - break; - - case TEST_SIG_H: - chsm_exit_children(self, e_pst, ctx_pst); - s11_exit(self, e_pst); - s1_exit(self, e_pst); - s_init(self, e_pst); - s1_entry(self, e_pst); - s1_init(self, e_pst); - s11_entry(self, e_pst); - s11_init(self, e_pst); - return chsm_transition(self, s11); - - default: - guards_only_b = false; - } - - if(s11_guard(self, e_pst, 6)) - { - s11_func(self, e_pst, 7); - } - - if(k_guard(self, e_pst, 5)) - { - chsm_exit_children(self, e_pst, ctx_pst); - s11_exit(self, e_pst); - s1_exit(self, e_pst); - s2_entry(self, e_pst); - s2_init(self, e_pst); - s21_entry(self, e_pst); - s21_init(self, e_pst); - s211_entry(self, e_pst); - s211_init(self, e_pst); - return chsm_transition(self, s211); - } - - return chsm_handle_in_parent(self, ctx_pst, s1, s11_exit, guards_only_b); -} - -static chsm_result_ten s2(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - bool guards_only_b=true; - switch(e_pst->sig) - { - case TEST_SIG_C: - chsm_exit_children(self, e_pst, ctx_pst); - s2_exit(self, e_pst); - s1_entry(self, e_pst); - s1_init(self, e_pst); - s11_entry(self, e_pst); - s11_init(self, e_pst); - return chsm_transition(self, s11); - - case TEST_SIG_F: - chsm_exit_children(self, e_pst, ctx_pst); - s2_exit(self, e_pst); - s1_entry(self, e_pst); - s11_entry(self, e_pst); - s11_init(self, e_pst); - return chsm_transition(self, s11); - - default: - guards_only_b = false; - } - - return chsm_handle_in_parent(self, ctx_pst, s, s2_exit, guards_only_b); -} - -static chsm_result_ten s21(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - bool guards_only_b=true; - switch(e_pst->sig) - { - case TEST_SIG_G: - chsm_exit_children(self, e_pst, ctx_pst); - s21_exit(self, e_pst); - s2_exit(self, e_pst); - s1_entry(self, e_pst); - s1_init(self, e_pst); - s11_entry(self, e_pst); - s11_init(self, e_pst); - return chsm_transition(self, s11); - - case TEST_SIG_B: - chsm_exit_children(self, e_pst, ctx_pst); - s211_entry(self, e_pst); - s211_init(self, e_pst); - return chsm_transition(self, s211); - - case TEST_SIG_A: - chsm_exit_children(self, e_pst, ctx_pst); - s21_exit(self, e_pst); - s21_entry(self, e_pst); - s21_init(self, e_pst); - s211_entry(self, e_pst); - s211_init(self, e_pst); - return chsm_transition(self, s211); - - default: - guards_only_b = false; - } - - return chsm_handle_in_parent(self, ctx_pst, s2, s21_exit, guards_only_b); -} - -static void s211_exit_func_wrapper(chsm_tst *self, const cevent_tst *e_pst) -{ - s211_exit(self, e_pst, 6); -} - -static chsm_result_ten s211(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - bool guards_only_b=true; - switch(e_pst->sig) - { - case TEST_SIG_ID: - s211_id(self, e_pst); - break; - - case TEST_SIG_H: - chsm_exit_children(self, e_pst, ctx_pst); - s211_exit(self, e_pst, 6); - s21_exit(self, e_pst); - s2_exit(self, e_pst); - s_init(self, e_pst); - s1_entry(self, e_pst); - s1_init(self, e_pst); - s11_entry(self, e_pst); - s11_init(self, e_pst); - return chsm_transition(self, s11); - - case TEST_SIG_D: - chsm_exit_children(self, e_pst, ctx_pst); - s211_exit(self, e_pst, 6); - s21_init(self, e_pst); - s211_entry(self, e_pst); - s211_init(self, e_pst); - return chsm_transition(self, s211); - - default: - guards_only_b = false; - } - - return chsm_handle_in_parent(self, ctx_pst, s21, s211_exit_func_wrapper, guards_only_b); -} - -static chsm_result_ten s3(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - bool guards_only_b=true; - switch(e_pst->sig) - { - case TEST_SIG_K: - s3_k_func(self, e_pst); - break; - - case TEST_SIG_L: - s3_l_func(self, e_pst); - break; - - case TEST_SIG_J: - chsm_exit_children(self, e_pst, ctx_pst); - s_init(self, e_pst); - s1_entry(self, e_pst); - s1_init(self, e_pst); - s11_entry(self, e_pst); - s11_init(self, e_pst); - return chsm_transition(self, s11); - - case TEST_SIG_G: - if(s11_g_guard2(self, e_pst, 4)) - { - chsm_exit_children(self, e_pst, ctx_pst); - s11_g2(self, e_pst, 3); - return chsm_transition(self, s4); - } - if(s11_g_guard1(self, e_pst, 1)) - { - chsm_exit_children(self, e_pst, ctx_pst); - s11_g1(self, e_pst, 2); - return chsm_transition(self, s4); - } - break; - - default: - guards_only_b = false; - } - - - return chsm_handle_in_parent(self, ctx_pst, s, NULL, guards_only_b); -} - -static chsm_result_ten s4(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - bool guards_only_b=true; - switch(e_pst->sig) - { - case TEST_SIG_ID: - s4_id(self, e_pst); - break; - - default: - guards_only_b = false; - } - - return chsm_handle_in_parent(self, ctx_pst, s, NULL, guards_only_b); -} - -chsm_result_ten __top__4(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - bool guards_only_b=true; - switch(e_pst->sig) - { - case C_SIG_INIT: - chsm_exit_children(self, e_pst, ctx_pst); - s_entry(self, e_pst); - s_init(self, e_pst); - s1_entry(self, e_pst); - s1_init(self, e_pst); - s11_entry(self, e_pst); - s11_init(self, e_pst); - return chsm_transition(self, s11); - - default: - guards_only_b = false; - } - - return chsm_ignored(self); -} diff --git a/crf/test/tsrc/dev_driver.c b/crf/test/tsrc/dev_driver.c deleted file mode 100644 index e48afea8..00000000 --- a/crf/test/tsrc/dev_driver.c +++ /dev/null @@ -1,82 +0,0 @@ -/*Generated with CHSM v0.0.0 at 2020.07.29 06.46.58*/ - -#include "cevent.h" -#include "chsm.h" -#include "dev_driver.h" -#include "dev_driver_functions.h" - - -static chsm_result_ten wait_response(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); -static chsm_result_ten idle(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst); - -static chsm_result_ten idle(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - switch(e_pst->sig) - { - case TEST_SIG_READ: - chsm_exit_children(self, e_pst, ctx_pst); - send_read_request((dev_driver_tst *)self, e_pst); - start_timer((dev_driver_tst *)self, e_pst); - return chsm_transition(self, wait_response); - - case TEST_SIG_WRITE: - chsm_exit_children(self, e_pst, ctx_pst); - send_write_request((dev_driver_tst *)self, e_pst); - start_timer((dev_driver_tst *)self, e_pst); - return chsm_transition(self, wait_response); - - } - - return chsm_handle_in_parent(self, ctx_pst, dev_driver_top, NULL, false); -} - -static chsm_result_ten wait_response(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - switch(e_pst->sig) - { - case TEST_SIG_RECEIVE: - insert_data((dev_driver_tst *)self, e_pst); - return chsm_handled(self); - - case TEST_SIG_TICK_1MS: - inc_timer((dev_driver_tst *)self, e_pst); - return chsm_handled(self); - - case TEST_SIG_CANCEL: - chsm_exit_children(self, e_pst, ctx_pst); - cancel_request((dev_driver_tst *)self, e_pst); - dev_drv_init((dev_driver_tst *)self, e_pst); - return chsm_transition(self, idle); - - } - - if(timeout((dev_driver_tst *)self, e_pst)) - { - chsm_exit_children(self, e_pst, ctx_pst); - dev_drv_init((dev_driver_tst *)self, e_pst); - return chsm_transition(self, idle); - } - - if(response_complete((dev_driver_tst *)self, e_pst)) - { - chsm_exit_children(self, e_pst, ctx_pst); - dev_drv_init((dev_driver_tst *)self, e_pst); - return chsm_transition(self, idle); - } - - return chsm_handle_in_parent(self, ctx_pst, dev_driver_top, NULL, false); -} - -chsm_result_ten dev_driver_top(chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst) -{ - switch(e_pst->sig) - { - case C_SIG_INIT: - chsm_exit_children(self, e_pst, ctx_pst); - dev_drv_init((dev_driver_tst *)self, e_pst); - return chsm_transition(self, idle); - - } - - return chsm_ignored(self); -} diff --git a/crf/test/tsrc/dev_driver_functions.c b/crf/test/tsrc/dev_driver_functions.c deleted file mode 100644 index 7d7dc9c5..00000000 --- a/crf/test/tsrc/dev_driver_functions.c +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include -#include -#include -#include "dev_driver.h" -#include "dev_driver_functions.h" -#include "crf.h" -#include - -static void load(dev_driver_tst *self, const char *str) -{ - while (*str) - { - *self->log = *str; - self->log++; - str++; - } -} - -void dev_driver_clear_log(dev_driver_tst *self) -{ - memset(&self->log_buff, 0, sizeof(self->log_buff)); - self->log = self->log_buff; -} - -void dev_drv_init(dev_driver_tst *self, const cevent_tst *e_pst) -{ - dev_driver_clear_log(self); -} - -void cancel_request(dev_driver_tst *self, const cevent_tst *e_pst) -{ - load(self, __func__); - load(self, " "); -} - -void inc_timer(dev_driver_tst *self, const cevent_tst *e_pst) -{ - load(self, __func__); - load(self, " "); -} - -void insert_data(dev_driver_tst *self, const cevent_tst *e_pst) -{ - load(self, __func__); - load(self, " "); -} - -void send_read_request(dev_driver_tst *self, const cevent_tst *e_pst) -{ - load(self, __func__); - load(self, " "); -} - -void send_write_request(dev_driver_tst *self, const cevent_tst *e_pst) -{ - load(self, __func__); - load(self, " "); -} - -void start_timer(dev_driver_tst *self, const cevent_tst *e_pst) -{ - load(self, __func__); - load(self, " "); -} - - -bool response_complete(dev_driver_tst *self, const cevent_tst *e_pst) -{ - load(self, __func__); - load(self, " "); - return self->response_complete; -} - -bool timeout(dev_driver_tst *self, const cevent_tst *e_pst) -{ - load(self, __func__); - load(self, " "); - return self->timeout; -} diff --git a/docs/doc_gen/Makefile b/docs/doc_gen/Makefile new file mode 100644 index 00000000..d0c3cbf1 --- /dev/null +++ b/docs/doc_gen/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/doc_gen/make.bat b/docs/doc_gen/make.bat new file mode 100644 index 00000000..dc1312ab --- /dev/null +++ b/docs/doc_gen/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/doc_gen/source/_static/ao-1-p09h05emwc0opbir340hby99cjq5gw6l21i1k4ypb4.png b/docs/doc_gen/source/_static/ao-1-p09h05emwc0opbir340hby99cjq5gw6l21i1k4ypb4.png new file mode 100644 index 00000000..7f01d705 Binary files /dev/null and b/docs/doc_gen/source/_static/ao-1-p09h05emwc0opbir340hby99cjq5gw6l21i1k4ypb4.png differ diff --git a/modules/canopen/doc/canopen.html b/docs/doc_gen/source/_static/canopen.html similarity index 99% rename from modules/canopen/doc/canopen.html rename to docs/doc_gen/source/_static/canopen.html index d7a1ef46..cf528506 100644 --- a/modules/canopen/doc/canopen.html +++ b/docs/doc_gen/source/_static/canopen.html @@ -171,7 +171,7 @@
- + diff --git a/docs/doc_gen/source/_static/core_crf_buildup.rnote b/docs/doc_gen/source/_static/core_crf_buildup.rnote new file mode 100644 index 00000000..aedc9e91 Binary files /dev/null and b/docs/doc_gen/source/_static/core_crf_buildup.rnote differ diff --git a/docs/doc_gen/source/_static/crf_SwAD.drawio b/docs/doc_gen/source/_static/crf_SwAD.drawio new file mode 100644 index 00000000..67b7d77c --- /dev/null +++ b/docs/doc_gen/source/_static/crf_SwAD.drawio @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/doc_gen/source/_static/decorator.css b/docs/doc_gen/source/_static/decorator.css new file mode 100644 index 00000000..b299b1a5 --- /dev/null +++ b/docs/doc_gen/source/_static/decorator.css @@ -0,0 +1,11 @@ +.wy-nav-content { + padding: 1.618em 3.236em; + height: 100%; + max-width: 1400px; + margin: auto; +} + +/* .document { + width: 80%; + margin: auto; +} */ \ No newline at end of file diff --git a/docs/doc_gen/source/_static/first_view.png b/docs/doc_gen/source/_static/first_view.png new file mode 100644 index 00000000..87f9e6cc Binary files /dev/null and b/docs/doc_gen/source/_static/first_view.png differ diff --git a/docs/doc_gen/source/_static/i2c_master.html b/docs/doc_gen/source/_static/i2c_master.html new file mode 100644 index 00000000..6568e849 --- /dev/null +++ b/docs/doc_gen/source/_static/i2c_master.html @@ -0,0 +1,1844 @@ + + + + + + +
+ + + + + + [i2c_master_fault_cnt(I2C_MASTER_FAUL_CNT)]SIG_I2C_DEFER_QUEUE_OVERFLOW/ i2c_master_clear_defer_queue()SIG_I2C_QUEUE_OVERFLOW/ i2c_master_clear_queue()[i2c_master_device_addr_max_cnt()]SIG_I2C_WRITE_SUCCESS/ i2c_master_inc_success_dev_addr()SIG_I2C_WRITE_FAIL/ i2c_master_inc_dev_addr()SIG_I2C_ADDRS_RELEASESIG_I2C_W_TRANSACTIONSIG_I2C_BUS_SCANSIG_I2C_READ_FAIL/ i2c_master_send_fail_response()SIG_I2C_WRITE_FAIL/ i2c_master_send_fail_response()SIG_I2C_READ_SUCCESS/ i2c_master_send_success_response()SIG_I2C_WRITE_SUCCESSSIG_I2C_WR_TRANSACTIONSIG_I2C_READ_SUCCESS/ i2c_master_send_success_response()SIG_I2C_R_TRANSACTIONSIG_I2C_WRITE_SUCCESS/ i2c_master_send_success_response()SIG_I2C_W_TRANSACTION + __top__s_idleinit/ clear_transaction_info()entry/ chsm_recalls_busyentry/ store_transaction_info()exit/ i2c_master_stop()SIG_I2C_W_TRANSACTION/ chsm_deferSIG_I2C_R_TRANSACTION/ chsm_deferSIG_I2C_WR_TRANSACTION/ chsm_defers_writeentry/ i2c_master_start_tx()s_readentry/ i2c_master_start_rx()s_write_reads_wr_writeentry/ i2c_master_start_tx()s_wr_readentry/ i2c_master_start_rx()s_i2c_masterinit/ i2c_master_init()SIG_SYS_TICK_1ms/ i2c_1ms_callback()s_bus_scanentry/ scan_init()s_scan_idleentry/ chsm_recalls_scan_writeentry/ i2c_scan_start_step()s_scan_busyentry/ store_transaction_info()s_i2c_bus_resetentry/ i2c_master_bus_reset() + + +
+ +
+ json +
+            {
+    "states": {
+        "__top__": {
+            "pos": [
+                -100000000,
+                -100000000
+            ],
+            "size": [
+                200000000,
+                200000000
+            ],
+            "title": "__top__",
+            "text": [],
+            "connectors": [],
+            "parent": null,
+            "children": [
+                "state_7",
+                "istate_2"
+            ],
+            "type": "top"
+        },
+        "state_0": {
+            "pos": [
+                12,
+                23
+            ],
+            "size": [
+                19,
+                59
+            ],
+            "title": "s_idle",
+            "text": [
+                "init/ clear_transaction_info()",
+                "entry/ chsm_recall"
+            ],
+            "connectors": [
+                "conn_2",
+                "conn_5",
+                "conn_6",
+                "conn_9",
+                "conn_14",
+                "conn_21",
+                "conn_11",
+                "conn_13",
+                "conn_26",
+                "conn_29",
+                "conn_39",
+                "conn_41",
+                "conn_43",
+                "conn_45"
+            ],
+            "parent": "state_7",
+            "children": [],
+            "type": "normal"
+        },
+        "state_1": {
+            "pos": [
+                91,
+                20
+            ],
+            "size": [
+                32,
+                67
+            ],
+            "title": "s_busy",
+            "text": [
+                "entry/ store_transaction_info()",
+                "exit/ i2c_master_stop()",
+                "SIG_I2C_W_TRANSACTION/ chsm_defer",
+                "SIG_I2C_R_TRANSACTION/ chsm_defer",
+                "SIG_I2C_WR_TRANSACTION/ chsm_defer"
+            ],
+            "connectors": [
+                "conn_10",
+                "conn_12",
+                "conn_38",
+                "conn_40",
+                "conn_42"
+            ],
+            "parent": "state_7",
+            "children": [
+                "state_2",
+                "state_3",
+                "state_4"
+            ],
+            "type": "normal"
+        },
+        "state_2": {
+            "pos": [
+                93,
+                39
+            ],
+            "size": [
+                23,
+                7
+            ],
+            "title": "s_write",
+            "text": [
+                "entry/ i2c_master_start_tx()"
+            ],
+            "connectors": [
+                "conn_3",
+                "conn_4"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "normal"
+        },
+        "state_3": {
+            "pos": [
+                93,
+                48
+            ],
+            "size": [
+                23,
+                7
+            ],
+            "title": "s_read",
+            "text": [
+                "entry/ i2c_master_start_rx()"
+            ],
+            "connectors": [
+                "conn_7",
+                "conn_8"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "normal"
+        },
+        "state_4": {
+            "pos": [
+                93,
+                57
+            ],
+            "size": [
+                28,
+                28
+            ],
+            "title": "s_write_read",
+            "text": [
+                ""
+            ],
+            "connectors": [
+                "conn_15"
+            ],
+            "parent": "state_1",
+            "children": [
+                "state_5",
+                "state_6",
+                "istate_1"
+            ],
+            "type": "normal"
+        },
+        "state_5": {
+            "pos": [
+                96,
+                67
+            ],
+            "size": [
+                17,
+                6
+            ],
+            "title": "s_wr_write",
+            "text": [
+                "entry/ i2c_master_start_tx()"
+            ],
+            "connectors": [
+                "conn_18",
+                "conn_17"
+            ],
+            "parent": "state_4",
+            "children": [],
+            "type": "normal"
+        },
+        "state_6": {
+            "pos": [
+                96,
+                77
+            ],
+            "size": [
+                17,
+                6
+            ],
+            "title": "s_wr_read",
+            "text": [
+                "entry/ i2c_master_start_rx()"
+            ],
+            "connectors": [
+                "conn_19",
+                "conn_20"
+            ],
+            "parent": "state_4",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_1": {
+            "pos": [
+                104,
+                64
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_1",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_16"
+            ],
+            "parent": "state_4",
+            "children": [],
+            "type": "initial"
+        },
+        "state_7": {
+            "pos": [
+                9,
+                -12
+            ],
+            "size": [
+                120,
+                132
+            ],
+            "title": "s_i2c_master",
+            "text": [
+                "init/ i2c_master_init()",
+                "SIG_SYS_TICK_1ms/ i2c_1ms_callback()"
+            ],
+            "connectors": [
+                "conn_23"
+            ],
+            "parent": "__top__",
+            "children": [
+                "state_0",
+                "state_1",
+                "state_8",
+                "istate_0",
+                "state_12"
+            ],
+            "type": "normal"
+        },
+        "istate_2": {
+            "pos": [
+                42,
+                -15
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_2",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_22"
+            ],
+            "parent": "__top__",
+            "children": [],
+            "type": "initial"
+        },
+        "state_8": {
+            "pos": [
+                15,
+                89
+            ],
+            "size": [
+                88,
+                29
+            ],
+            "title": "s_bus_scan",
+            "text": [
+                "entry/ scan_init()"
+            ],
+            "connectors": [
+                "conn_27"
+            ],
+            "parent": "state_7",
+            "children": [
+                "istate_3",
+                "state_9",
+                "state_10"
+            ],
+            "type": "normal"
+        },
+        "istate_3": {
+            "pos": [
+                23,
+                95
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_3",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_30"
+            ],
+            "parent": "state_8",
+            "children": [],
+            "type": "initial"
+        },
+        "state_9": {
+            "pos": [
+                17,
+                99
+            ],
+            "size": [
+                18,
+                15
+            ],
+            "title": "s_scan_idle",
+            "text": [
+                "entry/ chsm_recall"
+            ],
+            "connectors": [
+                "conn_31",
+                "conn_24",
+                "conn_28",
+                "conn_33",
+                "conn_35",
+                "conn_36",
+                "conn_37"
+            ],
+            "parent": "state_8",
+            "children": [],
+            "type": "normal"
+        },
+        "state_11": {
+            "pos": [
+                77,
+                102
+            ],
+            "size": [
+                18,
+                12
+            ],
+            "title": "s_scan_write",
+            "text": [
+                "entry/ i2c_scan_start_step()",
+                ""
+            ],
+            "connectors": [
+                "conn_25",
+                "conn_34"
+            ],
+            "parent": "state_10",
+            "children": [],
+            "type": "normal"
+        },
+        "state_10": {
+            "pos": [
+                73,
+                96
+            ],
+            "size": [
+                27,
+                19
+            ],
+            "title": "s_scan_busy",
+            "text": [
+                "entry/ store_transaction_info()"
+            ],
+            "connectors": [
+                "conn_32"
+            ],
+            "parent": "state_8",
+            "children": [
+                "state_11"
+            ],
+            "type": "normal"
+        },
+        "istate_0": {
+            "pos": [
+                19,
+                0
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_0",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_0"
+            ],
+            "parent": "state_7",
+            "children": [],
+            "type": "initial"
+        },
+        "state_12": {
+            "pos": [
+                12,
+                5
+            ],
+            "size": [
+                20,
+                9
+            ],
+            "title": "s_i2c_bus_reset",
+            "text": [
+                "entry/ i2c_master_bus_reset()"
+            ],
+            "connectors": [
+                "conn_1",
+                "conn_44"
+            ],
+            "parent": "state_7",
+            "children": [],
+            "type": "normal"
+        }
+    },
+    "connectors": {
+        "conn_2": {
+            "parent": "state_0",
+            "offset": 18,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_1"
+        },
+        "conn_3": {
+            "parent": "state_2",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_1"
+        },
+        "conn_4": {
+            "parent": "state_2",
+            "offset": 4,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_2"
+        },
+        "conn_5": {
+            "parent": "state_0",
+            "offset": 20,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_2"
+        },
+        "conn_6": {
+            "parent": "state_0",
+            "offset": 27,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_3"
+        },
+        "conn_7": {
+            "parent": "state_3",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_3"
+        },
+        "conn_8": {
+            "parent": "state_3",
+            "offset": 4,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_4"
+        },
+        "conn_9": {
+            "parent": "state_0",
+            "offset": 29,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_4"
+        },
+        "conn_14": {
+            "parent": "state_0",
+            "offset": 36,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_7"
+        },
+        "conn_15": {
+            "parent": "state_4",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_7"
+        },
+        "conn_18": {
+            "parent": "state_5",
+            "offset": 2,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_9"
+        },
+        "conn_19": {
+            "parent": "state_6",
+            "offset": 2,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_9"
+        },
+        "conn_20": {
+            "parent": "state_6",
+            "offset": 3,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_10"
+        },
+        "conn_21": {
+            "parent": "state_0",
+            "offset": 57,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_10"
+        },
+        "conn_10": {
+            "parent": "state_1",
+            "offset": 9,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_5"
+        },
+        "conn_11": {
+            "parent": "state_0",
+            "offset": 6,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_5"
+        },
+        "conn_12": {
+            "parent": "state_1",
+            "offset": 11,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_6"
+        },
+        "conn_13": {
+            "parent": "state_0",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_6"
+        },
+        "conn_16": {
+            "parent": "istate_1",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_8"
+        },
+        "conn_17": {
+            "parent": "state_5",
+            "offset": 8,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_8"
+        },
+        "conn_22": {
+            "parent": "istate_2",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_11"
+        },
+        "conn_23": {
+            "parent": "state_7",
+            "offset": 33,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_11"
+        },
+        "conn_26": {
+            "parent": "state_0",
+            "offset": 4,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_13"
+        },
+        "conn_27": {
+            "parent": "state_8",
+            "offset": 1,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_13"
+        },
+        "conn_30": {
+            "parent": "istate_3",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_15"
+        },
+        "conn_31": {
+            "parent": "state_9",
+            "offset": 6,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_15"
+        },
+        "conn_24": {
+            "parent": "state_9",
+            "offset": 9,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_12"
+        },
+        "conn_25": {
+            "parent": "state_11",
+            "offset": 6,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_12"
+        },
+        "conn_28": {
+            "parent": "state_9",
+            "offset": 12,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_14"
+        },
+        "conn_29": {
+            "parent": "state_0",
+            "offset": 17,
+            "side": "bottom",
+            "dir": "in",
+            "transition": "trans_14"
+        },
+        "conn_32": {
+            "parent": "state_10",
+            "offset": 9,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_16"
+        },
+        "conn_33": {
+            "parent": "state_9",
+            "offset": 6,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_16"
+        },
+        "conn_34": {
+            "parent": "state_11",
+            "offset": 9,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_17"
+        },
+        "conn_35": {
+            "parent": "state_9",
+            "offset": 12,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_17"
+        },
+        "conn_36": {
+            "parent": "state_9",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_18"
+        },
+        "conn_37": {
+            "parent": "state_9",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_18"
+        },
+        "conn_38": {
+            "parent": "state_1",
+            "offset": 6,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_19"
+        },
+        "conn_39": {
+            "parent": "state_0",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_19"
+        },
+        "conn_40": {
+            "parent": "state_1",
+            "offset": 4,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_20"
+        },
+        "conn_41": {
+            "parent": "state_0",
+            "offset": 1,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_20"
+        },
+        "conn_42": {
+            "parent": "state_1",
+            "offset": 14,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_21"
+        },
+        "conn_43": {
+            "parent": "state_0",
+            "offset": 11,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_21"
+        },
+        "conn_0": {
+            "parent": "istate_0",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_0"
+        },
+        "conn_1": {
+            "parent": "state_12",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_0"
+        },
+        "conn_44": {
+            "parent": "state_12",
+            "offset": 7,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_22"
+        },
+        "conn_45": {
+            "parent": "state_0",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_22"
+        }
+    },
+    "transitions": {
+        "trans_1": {
+            "start": "conn_2",
+            "end": "conn_3",
+            "vertices": [
+                [
+                    31,
+                    41
+                ],
+                [
+                    42,
+                    41
+                ],
+                [
+                    42,
+                    41
+                ],
+                [
+                    93,
+                    41
+                ]
+            ],
+            "label": "SIG_I2C_W_TRANSACTION",
+            "label_offset": [
+                4.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                35.5,
+                40.6
+            ]
+        },
+        "trans_2": {
+            "start": "conn_4",
+            "end": "conn_5",
+            "vertices": [
+                [
+                    93,
+                    43
+                ],
+                [
+                    42,
+                    43
+                ],
+                [
+                    42,
+                    43
+                ],
+                [
+                    31,
+                    43
+                ]
+            ],
+            "label": "SIG_I2C_WRITE_SUCCESS/ i2c_master_send_success_response()",
+            "label_offset": [
+                -1,
+                -0.3999999999999986
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                41,
+                42.6
+            ]
+        },
+        "trans_3": {
+            "start": "conn_6",
+            "end": "conn_7",
+            "vertices": [
+                [
+                    31,
+                    50
+                ],
+                [
+                    42,
+                    50
+                ],
+                [
+                    42,
+                    50
+                ],
+                [
+                    93,
+                    50
+                ]
+            ],
+            "label": "SIG_I2C_R_TRANSACTION",
+            "label_offset": [
+                4.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                35.5,
+                49.6
+            ]
+        },
+        "trans_4": {
+            "start": "conn_8",
+            "end": "conn_9",
+            "vertices": [
+                [
+                    93,
+                    52
+                ],
+                [
+                    42,
+                    52
+                ],
+                [
+                    42,
+                    52
+                ],
+                [
+                    31,
+                    52
+                ]
+            ],
+            "label": "SIG_I2C_READ_SUCCESS/ i2c_master_send_success_response()",
+            "label_offset": [
+                -1,
+                -0.3999999999999986
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                41,
+                51.6
+            ]
+        },
+        "trans_7": {
+            "start": "conn_14",
+            "end": "conn_15",
+            "vertices": [
+                [
+                    31,
+                    59
+                ],
+                [
+                    42,
+                    59
+                ],
+                [
+                    42,
+                    59
+                ],
+                [
+                    93,
+                    59
+                ]
+            ],
+            "label": "SIG_I2C_WR_TRANSACTION",
+            "label_offset": [
+                4.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                35.5,
+                58.6
+            ]
+        },
+        "trans_9": {
+            "start": "conn_18",
+            "end": "conn_19",
+            "vertices": [
+                [
+                    98,
+                    73
+                ],
+                [
+                    98,
+                    74
+                ],
+                [
+                    98,
+                    74
+                ],
+                [
+                    98,
+                    77
+                ]
+            ],
+            "label": "SIG_I2C_WRITE_SUCCESS",
+            "label_offset": [
+                0.5,
+                1.2000000000000028
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                98.5,
+                75.2
+            ]
+        },
+        "trans_10": {
+            "start": "conn_20",
+            "end": "conn_21",
+            "vertices": [
+                [
+                    96,
+                    80
+                ],
+                [
+                    41,
+                    80
+                ],
+                [
+                    41,
+                    80
+                ],
+                [
+                    31,
+                    80
+                ]
+            ],
+            "label": "SIG_I2C_READ_SUCCESS/ i2c_master_send_success_response()",
+            "label_offset": [
+                -54.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                41.5,
+                79.6
+            ]
+        },
+        "trans_5": {
+            "start": "conn_10",
+            "end": "conn_11",
+            "vertices": [
+                [
+                    91,
+                    29
+                ],
+                [
+                    37,
+                    29
+                ],
+                [
+                    37,
+                    29
+                ],
+                [
+                    31,
+                    29
+                ]
+            ],
+            "label": "SIG_I2C_WRITE_FAIL/ i2c_master_send_fail_response()",
+            "label_offset": [
+                -30,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                61,
+                28.6
+            ]
+        },
+        "trans_6": {
+            "start": "conn_12",
+            "end": "conn_13",
+            "vertices": [
+                [
+                    91,
+                    31
+                ],
+                [
+                    37,
+                    31
+                ],
+                [
+                    37,
+                    31
+                ],
+                [
+                    31,
+                    31
+                ]
+            ],
+            "label": "SIG_I2C_READ_FAIL/ i2c_master_send_fail_response()",
+            "label_offset": [
+                -29,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                62,
+                30.6
+            ]
+        },
+        "trans_8": {
+            "start": "conn_16",
+            "end": "conn_17",
+            "vertices": [
+                [
+                    104,
+                    64
+                ],
+                [
+                    104,
+                    64
+                ],
+                [
+                    104,
+                    67
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                1.1000000000000014
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                104.5,
+                65.1
+            ]
+        },
+        "trans_11": {
+            "start": "conn_22",
+            "end": "conn_23",
+            "vertices": [
+                [
+                    42,
+                    -15
+                ],
+                [
+                    42,
+                    -15
+                ],
+                [
+                    42,
+                    -12
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                0.09999999999999964
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                42.5,
+                -14.9
+            ]
+        },
+        "trans_13": {
+            "start": "conn_26",
+            "end": "conn_27",
+            "vertices": [
+                [
+                    16,
+                    82
+                ],
+                [
+                    16,
+                    86
+                ],
+                [
+                    16,
+                    86
+                ],
+                [
+                    16,
+                    89
+                ]
+            ],
+            "label": "SIG_I2C_BUS_SCAN",
+            "label_offset": [
+                0.5,
+                2.1999999999999886
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                16.5,
+                84.19999999999999
+            ]
+        },
+        "trans_15": {
+            "start": "conn_30",
+            "end": "conn_31",
+            "vertices": [
+                [
+                    23,
+                    95
+                ],
+                [
+                    23,
+                    95
+                ],
+                [
+                    23,
+                    99
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                2.0999999999999943
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                23.5,
+                97.1
+            ]
+        },
+        "trans_12": {
+            "start": "conn_24",
+            "end": "conn_25",
+            "vertices": [
+                [
+                    35,
+                    108
+                ],
+                [
+                    46,
+                    108
+                ],
+                [
+                    46,
+                    108
+                ],
+                [
+                    77,
+                    108
+                ]
+            ],
+            "label": "SIG_I2C_W_TRANSACTION",
+            "label_offset": [
+                0.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                35.5,
+                107.6
+            ]
+        },
+        "trans_14": {
+            "start": "conn_28",
+            "end": "conn_29",
+            "vertices": [
+                [
+                    29,
+                    99
+                ],
+                [
+                    29,
+                    84
+                ],
+                [
+                    29,
+                    84
+                ],
+                [
+                    29,
+                    82
+                ]
+            ],
+            "label": "SIG_I2C_ADDRS_RELEASE",
+            "label_offset": [
+                0.5,
+                -3.0000000000000284
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                29.5,
+                95.99999999999997
+            ]
+        },
+        "trans_16": {
+            "start": "conn_32",
+            "end": "conn_33",
+            "vertices": [
+                [
+                    73,
+                    105
+                ],
+                [
+                    51,
+                    105
+                ],
+                [
+                    51,
+                    105
+                ],
+                [
+                    35,
+                    105
+                ]
+            ],
+            "label": "SIG_I2C_WRITE_FAIL/ i2c_master_inc_dev_addr()",
+            "label_offset": [
+                -4.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                46.5,
+                104.6
+            ]
+        },
+        "trans_17": {
+            "start": "conn_34",
+            "end": "conn_35",
+            "vertices": [
+                [
+                    77,
+                    111
+                ],
+                [
+                    53,
+                    111
+                ],
+                [
+                    53,
+                    111
+                ],
+                [
+                    35,
+                    111
+                ]
+            ],
+            "label": "SIG_I2C_WRITE_SUCCESS/ i2c_master_inc_success_dev_addr()",
+            "label_offset": [
+                -14.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                38.5,
+                110.6
+            ]
+        },
+        "trans_18": {
+            "start": "conn_36",
+            "end": "conn_37",
+            "vertices": [
+                [
+                    35,
+                    100
+                ],
+                [
+                    41,
+                    100
+                ],
+                [
+                    41,
+                    102
+                ],
+                [
+                    35,
+                    102
+                ]
+            ],
+            "label": "[i2c_master_device_addr_max_cnt()]",
+            "label_offset": [
+                0.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                35.5,
+                99.6
+            ]
+        },
+        "trans_19": {
+            "start": "conn_38",
+            "end": "conn_39",
+            "vertices": [
+                [
+                    91,
+                    26
+                ],
+                [
+                    54,
+                    26
+                ],
+                [
+                    54,
+                    26
+                ],
+                [
+                    31,
+                    26
+                ]
+            ],
+            "label": "SIG_I2C_QUEUE_OVERFLOW/ i2c_master_clear_queue()",
+            "label_offset": [
+                -31,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                60,
+                25.6
+            ]
+        },
+        "trans_20": {
+            "start": "conn_40",
+            "end": "conn_41",
+            "vertices": [
+                [
+                    91,
+                    24
+                ],
+                [
+                    54,
+                    24
+                ],
+                [
+                    54,
+                    24
+                ],
+                [
+                    31,
+                    24
+                ]
+            ],
+            "label": "SIG_I2C_DEFER_QUEUE_OVERFLOW/ i2c_master_clear_defer_queue()",
+            "label_offset": [
+                -1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                52.5,
+                23.6
+            ]
+        },
+        "trans_21": {
+            "start": "conn_42",
+            "end": "conn_43",
+            "vertices": [
+                [
+                    91,
+                    34
+                ],
+                [
+                    54,
+                    34
+                ],
+                [
+                    54,
+                    34
+                ],
+                [
+                    31,
+                    34
+                ]
+            ],
+            "label": "[i2c_master_fault_cnt(I2C_MASTER_FAUL_CNT)]",
+            "label_offset": [
+                -26,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                65,
+                33.6
+            ]
+        },
+        "trans_0": {
+            "start": "conn_0",
+            "end": "conn_1",
+            "vertices": [
+                [
+                    19,
+                    0
+                ],
+                [
+                    19,
+                    0
+                ],
+                [
+                    19,
+                    5
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                1.6
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                19.5,
+                1.6
+            ]
+        },
+        "trans_22": {
+            "start": "conn_44",
+            "end": "conn_45",
+            "vertices": [
+                [
+                    19,
+                    14
+                ],
+                [
+                    19,
+                    19
+                ],
+                [
+                    19,
+                    19
+                ],
+                [
+                    19,
+                    23
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                4.100000000000001
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                19.5,
+                18.1
+            ]
+        }
+    },
+    "notes": {
+        "SIG_I2C_TRANSACTION": "",
+        "start_tx()": "Use the driver to start a write sequence, or post a WRITE_FINISHED signal to self, if the write count is 0.",
+        "chsm_defer()": "",
+        "SIG_I2C_W_TRANSACTION": "",
+        "trans_2": "",
+        "SIG_I2C_WRITE_SUCCESS": "",
+        "SIG_I2C_R_TRANSACTION": "",
+        "SIG_I2C_READ_SUCCESS": "",
+        "SIG_I2C_WRITE_FAIL": "",
+        "SIG_I2C_READ_FAIL": "",
+        "trans_12": "",
+        "i2c_inc_dev_id()": "",
+        "trans_17": "",
+        "SIG_I2C_ADDRS_RELEASE": "",
+        "i2c_master_send_fail_response()": "",
+        "SIG_I2C_WR_TRANSACTION": "",
+        "scan_init_()": "",
+        "i2c_master_inc_dev_addr()": "",
+        "device_addr_max_cnt()": "",
+        "i2c_master_stop()": "",
+        "i2c_master_start_tx()": "",
+        "SIG_SYS_TICK_1ms": "",
+        "SIG_I2C_QUEUE_OVERFLOW": "",
+        "SIG_I2C_DEFER_QUEUE_OVERFLOW": "",
+        "i2c_master_fault_cnt": "",
+        "i2c_master_clear_defer_queue()": "",
+        "i2c_master_clear_queue()": ""
+    },
+    "view": {
+        "translate": [
+            151.5,
+            146
+        ],
+        "scale": 8.5
+    }
+}
+        
+
+ + diff --git a/docs/doc_gen/source/_static/lm73.html b/docs/doc_gen/source/_static/lm73.html new file mode 100644 index 00000000..419271e5 --- /dev/null +++ b/docs/doc_gen/source/_static/lm73.html @@ -0,0 +1,2492 @@ + + + + + + +
+ + + + + + SIG_I2C_RESULT_SUCCESS[lm73_wait_cnt()]SIG_I2C_RESULT_SUCCESS[lm73_wait_cnt()]SIG_I2C_RESULT_SUCCESSSIG_I2C_RESULT_DATA_NACK/ lm73_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ lm73_inc_error_counter()[lm73_timeout(LM73_RETRY_TIMEOUT)]/ lm73_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ lm73_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ lm73_inc_error_counter()[lm73_timeout(LM73_RETRY_TIMEOUT)]/ lm73_inc_error_counter()[lm73_error_count(LM73_MAX_ERROR_COUNT)]SIG_I2C_RESULT_DATA_NACK/ lm73_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ lm73_inc_error_counter()[lm73_timeout(LM73_RETRY_TIMEOUT)]/ lm73_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ lm73_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ lm73_inc_error_counter()[lm73_timeout(LM73_RETRY_TIMEOUT)]/ lm73_inc_error_counter()SIG_I2C_RESULT_SUCCESS/ lm73_update_temp()[lm73_timeout(LM73_READ_PERIOD)]/ lm73_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ lm73_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ lm73_inc_error_counter()[lm73_timeout(LM73_READ_PERIOD)]/ lm73_reset_timer()SIG_LM73_READSIG_I2C_RESULT_SUCCESS[lm73_error_count(LM73_MAX_ERROR_COUNT)]SIG_I2C_RESULT_SUCCESS [lm73_id_match()][lm73_timeout(LM73_UNPLUGGED_TIMEOUT)]/ lm73_reset_timer()SIG_I2C_RESULT_DATA_NACKSIG_I2C_RESULT_ADDR_NACK[lm73_timeout(LM73_RETRY_TIMEOUT)] + __top__s_lm73entry/ lm73_init()SIG_SYS_TICK_10ms/ lm73_10ms_callback()s_initentry/ lm73_reset_error_cnt()s_configentry/ lm73_reset_timer()s_onlineentry/ send_online_event()exit/ send_offline_event()s_read_id_regentry/ lm73_read_id()s_unpluggedentry/ lm73_reset_timer()s_set_resolutionentry/ lm73_set_resolution()exit/ lm73_reset_timer()s_reset_ptr_regentry/ lm73_reset_pointer()exit/ lm73_reset_timer()s_idleinit/ lm73_reset_timer()entry/ lm73_reset_timer()s_readingentry/ lm73_start_read()exit/ lm73_reset_timer()s_power_downentry/ lm73_set_full_powerdown()exit/ lm73_reset_timer()s_power_upentry/ lm73_set_full_powerup()exit/ lm73_reset_timer()s_wait_power_downinit/ lm73_init_wait()s_wait_power_upinit/ lm73_init_wait() + + +
+ +
+ json +
+            {
+    "states": {
+        "__top__": {
+            "pos": [
+                -100000000,
+                -100000000
+            ],
+            "size": [
+                200000000,
+                200000000
+            ],
+            "title": "__top__",
+            "text": [],
+            "connectors": [],
+            "parent": null,
+            "children": [
+                "istate_0",
+                "state_0"
+            ],
+            "type": "top"
+        },
+        "istate_0": {
+            "pos": [
+                51,
+                8
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_0",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_0"
+            ],
+            "parent": "__top__",
+            "children": [],
+            "type": "initial"
+        },
+        "state_0": {
+            "pos": [
+                5,
+                14
+            ],
+            "size": [
+                111,
+                166
+            ],
+            "title": "s_lm73",
+            "text": [
+                "entry/ lm73_init()",
+                "SIG_SYS_TICK_10ms/ lm73_10ms_callback()"
+            ],
+            "connectors": [
+                "conn_1",
+                "conn_17",
+                "conn_51"
+            ],
+            "parent": "__top__",
+            "children": [
+                "state_1",
+                "state_2",
+                "state_3",
+                "istate_1"
+            ],
+            "type": "normal"
+        },
+        "state_1": {
+            "pos": [
+                10,
+                28
+            ],
+            "size": [
+                91,
+                24
+            ],
+            "title": "s_init",
+            "text": [
+                "entry/ lm73_reset_error_cnt()"
+            ],
+            "connectors": [
+                "conn_3"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_4",
+                "state_5",
+                "istate_2"
+            ],
+            "type": "normal"
+        },
+        "state_2": {
+            "pos": [
+                24,
+                56
+            ],
+            "size": [
+                89,
+                79
+            ],
+            "title": "s_config",
+            "text": [
+                "entry/ lm73_reset_timer()"
+            ],
+            "connectors": [
+                "conn_15",
+                "conn_50"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_6",
+                "state_7",
+                "istate_3",
+                "state_10",
+                "state_11",
+                "state_12",
+                "state_13"
+            ],
+            "type": "normal"
+        },
+        "state_3": {
+            "pos": [
+                11,
+                146
+            ],
+            "size": [
+                86,
+                29
+            ],
+            "title": "s_online",
+            "text": [
+                "entry/ send_online_event()",
+                "exit/ send_offline_event()"
+            ],
+            "connectors": [
+                "conn_16",
+                "conn_23"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_8",
+                "state_9",
+                "istate_4"
+            ],
+            "type": "normal"
+        },
+        "istate_1": {
+            "pos": [
+                16,
+                24
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_1",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_2"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "initial"
+        },
+        "state_4": {
+            "pos": [
+                15,
+                35
+            ],
+            "size": [
+                16,
+                13
+            ],
+            "title": "s_read_id_reg",
+            "text": [
+                "entry/ lm73_read_id()"
+            ],
+            "connectors": [
+                "conn_5",
+                "conn_6",
+                "conn_8",
+                "conn_10",
+                "conn_13",
+                "conn_14"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "normal"
+        },
+        "state_5": {
+            "pos": [
+                75,
+                35
+            ],
+            "size": [
+                17,
+                13
+            ],
+            "title": "s_unplugged",
+            "text": [
+                "entry/ lm73_reset_timer()"
+            ],
+            "connectors": [
+                "conn_7",
+                "conn_9",
+                "conn_11",
+                "conn_12"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_2": {
+            "pos": [
+                12,
+                36
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_2",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_4"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "initial"
+        },
+        "state_6": {
+            "pos": [
+                52,
+                84
+            ],
+            "size": [
+                18,
+                12
+            ],
+            "title": "s_set_resolution",
+            "text": [
+                "entry/ lm73_set_resolution()",
+                "exit/ lm73_reset_timer()"
+            ],
+            "connectors": [
+                "conn_38",
+                "conn_39",
+                "conn_40",
+                "conn_41",
+                "conn_42",
+                "conn_43",
+                "conn_71",
+                "conn_62"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_7": {
+            "pos": [
+                53,
+                118
+            ],
+            "size": [
+                17,
+                12
+            ],
+            "title": "s_reset_ptr_reg",
+            "text": [
+                "entry/ lm73_reset_pointer()",
+                "exit/ lm73_reset_timer()"
+            ],
+            "connectors": [
+                "conn_22",
+                "conn_44",
+                "conn_45",
+                "conn_46",
+                "conn_47",
+                "conn_48",
+                "conn_49",
+                "conn_65"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_3": {
+            "pos": [
+                33,
+                63
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_3",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_66"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "initial"
+        },
+        "state_8": {
+            "pos": [
+                16,
+                156
+            ],
+            "size": [
+                15,
+                18
+            ],
+            "title": "s_idle",
+            "text": [
+                "init/ lm73_reset_timer()",
+                "entry/ lm73_reset_timer()"
+            ],
+            "connectors": [
+                "conn_26",
+                "conn_28",
+                "conn_31",
+                "conn_33",
+                "conn_35",
+                "conn_37"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "normal"
+        },
+        "state_9": {
+            "pos": [
+                71,
+                156
+            ],
+            "size": [
+                15,
+                17
+            ],
+            "title": "s_reading",
+            "text": [
+                "entry/ lm73_start_read()",
+                "exit/ lm73_reset_timer()"
+            ],
+            "connectors": [
+                "conn_25",
+                "conn_27",
+                "conn_29",
+                "conn_30",
+                "conn_32",
+                "conn_34",
+                "conn_36"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_4": {
+            "pos": [
+                92,
+                155
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_4",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_24"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "initial"
+        },
+        "state_10": {
+            "pos": [
+                54,
+                66
+            ],
+            "size": [
+                20,
+                12
+            ],
+            "title": "s_power_down",
+            "text": [
+                "entry/ lm73_set_full_powerdown()",
+                "exit/ lm73_reset_timer()"
+            ],
+            "connectors": [
+                "conn_18",
+                "conn_19",
+                "conn_20",
+                "conn_21",
+                "conn_52",
+                "conn_53",
+                "conn_60",
+                "conn_67"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_11": {
+            "pos": [
+                52,
+                102
+            ],
+            "size": [
+                20,
+                9
+            ],
+            "title": "s_power_up",
+            "text": [
+                "entry/ lm73_set_full_powerup()",
+                "exit/ lm73_reset_timer()"
+            ],
+            "connectors": [
+                "conn_54",
+                "conn_55",
+                "conn_56",
+                "conn_57",
+                "conn_58",
+                "conn_59",
+                "conn_63",
+                "conn_74"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_12": {
+            "pos": [
+                33,
+                72
+            ],
+            "size": [
+                15,
+                7
+            ],
+            "title": "s_wait_power_down",
+            "text": [
+                "init/ lm73_init_wait()"
+            ],
+            "connectors": [
+                "conn_61",
+                "conn_70"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_13": {
+            "pos": [
+                33,
+                102
+            ],
+            "size": [
+                15,
+                6
+            ],
+            "title": "s_wait_power_up",
+            "text": [
+                "init/ lm73_init_wait()"
+            ],
+            "connectors": [
+                "conn_64",
+                "conn_75"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        }
+    },
+    "connectors": {
+        "conn_0": {
+            "parent": "istate_0",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_0"
+        },
+        "conn_1": {
+            "parent": "state_0",
+            "offset": 46,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_0"
+        },
+        "conn_2": {
+            "parent": "istate_1",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_1"
+        },
+        "conn_3": {
+            "parent": "state_1",
+            "offset": 2,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_1"
+        },
+        "conn_4": {
+            "parent": "istate_2",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_2"
+        },
+        "conn_5": {
+            "parent": "state_4",
+            "offset": 1,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_2"
+        },
+        "conn_6": {
+            "parent": "state_4",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_3"
+        },
+        "conn_7": {
+            "parent": "state_5",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_3"
+        },
+        "conn_8": {
+            "parent": "state_4",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_4"
+        },
+        "conn_9": {
+            "parent": "state_5",
+            "offset": 4,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_4"
+        },
+        "conn_10": {
+            "parent": "state_4",
+            "offset": 6,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_5"
+        },
+        "conn_11": {
+            "parent": "state_5",
+            "offset": 6,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_5"
+        },
+        "conn_12": {
+            "parent": "state_5",
+            "offset": 11,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_6"
+        },
+        "conn_13": {
+            "parent": "state_4",
+            "offset": 11,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_6"
+        },
+        "conn_14": {
+            "parent": "state_4",
+            "offset": 5,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_7"
+        },
+        "conn_15": {
+            "parent": "state_2",
+            "offset": 3,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_7"
+        },
+        "conn_16": {
+            "parent": "state_3",
+            "offset": 3,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_8"
+        },
+        "conn_17": {
+            "parent": "state_0",
+            "offset": 128,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_8"
+        },
+        "conn_22": {
+            "parent": "state_7",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_11"
+        },
+        "conn_23": {
+            "parent": "state_3",
+            "offset": 56,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_11"
+        },
+        "conn_24": {
+            "parent": "istate_4",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_12"
+        },
+        "conn_25": {
+            "parent": "state_9",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_12"
+        },
+        "conn_26": {
+            "parent": "state_8",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_13"
+        },
+        "conn_27": {
+            "parent": "state_9",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_13"
+        },
+        "conn_28": {
+            "parent": "state_8",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_14"
+        },
+        "conn_29": {
+            "parent": "state_9",
+            "offset": 4,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_14"
+        },
+        "conn_30": {
+            "parent": "state_9",
+            "offset": 7,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_15"
+        },
+        "conn_31": {
+            "parent": "state_8",
+            "offset": 7,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_15"
+        },
+        "conn_32": {
+            "parent": "state_9",
+            "offset": 9,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_16"
+        },
+        "conn_33": {
+            "parent": "state_8",
+            "offset": 9,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_16"
+        },
+        "conn_34": {
+            "parent": "state_9",
+            "offset": 11,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_17"
+        },
+        "conn_35": {
+            "parent": "state_8",
+            "offset": 11,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_17"
+        },
+        "conn_36": {
+            "parent": "state_9",
+            "offset": 16,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_18"
+        },
+        "conn_37": {
+            "parent": "state_8",
+            "offset": 16,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_18"
+        },
+        "conn_38": {
+            "parent": "state_6",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_19"
+        },
+        "conn_39": {
+            "parent": "state_6",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_19"
+        },
+        "conn_40": {
+            "parent": "state_6",
+            "offset": 5,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_20"
+        },
+        "conn_41": {
+            "parent": "state_6",
+            "offset": 6,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_20"
+        },
+        "conn_42": {
+            "parent": "state_6",
+            "offset": 9,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_21"
+        },
+        "conn_43": {
+            "parent": "state_6",
+            "offset": 10,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_21"
+        },
+        "conn_44": {
+            "parent": "state_7",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_22"
+        },
+        "conn_45": {
+            "parent": "state_7",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_22"
+        },
+        "conn_46": {
+            "parent": "state_7",
+            "offset": 5,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_23"
+        },
+        "conn_47": {
+            "parent": "state_7",
+            "offset": 6,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_23"
+        },
+        "conn_48": {
+            "parent": "state_7",
+            "offset": 9,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_24"
+        },
+        "conn_49": {
+            "parent": "state_7",
+            "offset": 10,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_24"
+        },
+        "conn_50": {
+            "parent": "state_2",
+            "offset": 19,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_25"
+        },
+        "conn_51": {
+            "parent": "state_0",
+            "offset": 126,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_25"
+        },
+        "conn_18": {
+            "parent": "state_10",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_9"
+        },
+        "conn_19": {
+            "parent": "state_10",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_9"
+        },
+        "conn_20": {
+            "parent": "state_10",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_10"
+        },
+        "conn_21": {
+            "parent": "state_10",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_10"
+        },
+        "conn_52": {
+            "parent": "state_10",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_26"
+        },
+        "conn_53": {
+            "parent": "state_10",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_26"
+        },
+        "conn_54": {
+            "parent": "state_11",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_27"
+        },
+        "conn_55": {
+            "parent": "state_11",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_27"
+        },
+        "conn_56": {
+            "parent": "state_11",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_28"
+        },
+        "conn_57": {
+            "parent": "state_11",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_28"
+        },
+        "conn_58": {
+            "parent": "state_11",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_29"
+        },
+        "conn_59": {
+            "parent": "state_11",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_29"
+        },
+        "conn_60": {
+            "parent": "state_10",
+            "offset": 1,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_30"
+        },
+        "conn_61": {
+            "parent": "state_12",
+            "offset": 1,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_30"
+        },
+        "conn_70": {
+            "parent": "state_12",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_35"
+        },
+        "conn_71": {
+            "parent": "state_6",
+            "offset": 8,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_35"
+        },
+        "conn_62": {
+            "parent": "state_6",
+            "offset": 9,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_31"
+        },
+        "conn_63": {
+            "parent": "state_11",
+            "offset": 9,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_31"
+        },
+        "conn_64": {
+            "parent": "state_13",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_32"
+        },
+        "conn_65": {
+            "parent": "state_7",
+            "offset": 8,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_32"
+        },
+        "conn_74": {
+            "parent": "state_11",
+            "offset": 3,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_37"
+        },
+        "conn_75": {
+            "parent": "state_13",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_37"
+        },
+        "conn_66": {
+            "parent": "istate_3",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_33"
+        },
+        "conn_67": {
+            "parent": "state_10",
+            "offset": 10,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_33"
+        }
+    },
+    "transitions": {
+        "trans_0": {
+            "start": "conn_0",
+            "end": "conn_1",
+            "vertices": [
+                [
+                    51,
+                    8
+                ],
+                [
+                    51,
+                    8
+                ],
+                [
+                    51,
+                    14
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                2.5999999999999996
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                51.5,
+                10.6
+            ]
+        },
+        "trans_1": {
+            "start": "conn_2",
+            "end": "conn_3",
+            "vertices": [
+                [
+                    16,
+                    24
+                ],
+                [
+                    12,
+                    24
+                ],
+                [
+                    12,
+                    28
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                1.6000000000000014
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                12.5,
+                25.6
+            ]
+        },
+        "trans_2": {
+            "start": "conn_4",
+            "end": "conn_5",
+            "vertices": [
+                [
+                    12,
+                    36
+                ],
+                [
+                    14,
+                    36
+                ],
+                [
+                    14,
+                    36
+                ],
+                [
+                    15,
+                    36
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                2,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                14,
+                35.6
+            ]
+        },
+        "trans_3": {
+            "start": "conn_6",
+            "end": "conn_7",
+            "vertices": [
+                [
+                    31,
+                    37
+                ],
+                [
+                    51,
+                    37
+                ],
+                [
+                    51,
+                    37
+                ],
+                [
+                    75,
+                    37
+                ]
+            ],
+            "label": "[lm73_timeout(LM73_RETRY_TIMEOUT)]",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                36.6
+            ]
+        },
+        "trans_4": {
+            "start": "conn_8",
+            "end": "conn_9",
+            "vertices": [
+                [
+                    31,
+                    39
+                ],
+                [
+                    51,
+                    39
+                ],
+                [
+                    51,
+                    39
+                ],
+                [
+                    75,
+                    39
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                38.6
+            ]
+        },
+        "trans_5": {
+            "start": "conn_10",
+            "end": "conn_11",
+            "vertices": [
+                [
+                    31,
+                    41
+                ],
+                [
+                    51,
+                    41
+                ],
+                [
+                    51,
+                    41
+                ],
+                [
+                    75,
+                    41
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                40.6
+            ]
+        },
+        "trans_6": {
+            "start": "conn_12",
+            "end": "conn_13",
+            "vertices": [
+                [
+                    75,
+                    46
+                ],
+                [
+                    51,
+                    46
+                ],
+                [
+                    51,
+                    46
+                ],
+                [
+                    31,
+                    46
+                ]
+            ],
+            "label": "[lm73_timeout(LM73_UNPLUGGED_TIMEOUT)]/ lm73_reset_timer()",
+            "label_offset": [
+                -11.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                39.5,
+                45.6
+            ]
+        },
+        "trans_7": {
+            "start": "conn_14",
+            "end": "conn_15",
+            "vertices": [
+                [
+                    20,
+                    48
+                ],
+                [
+                    20,
+                    59
+                ],
+                [
+                    24,
+                    59
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS [lm73_id_match()]",
+            "label_offset": [
+                0.5,
+                6.700000000000003
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                20.5,
+                54.7
+            ]
+        },
+        "trans_8": {
+            "start": "conn_16",
+            "end": "conn_17",
+            "vertices": [
+                [
+                    14,
+                    146
+                ],
+                [
+                    14,
+                    142
+                ],
+                [
+                    5,
+                    142
+                ]
+            ],
+            "label": "[lm73_error_count(LM73_MAX_ERROR_COUNT)]",
+            "label_offset": [
+                0.5,
+                -1.8000000000000114
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                14.5,
+                144.2
+            ]
+        },
+        "trans_11": {
+            "start": "conn_22",
+            "end": "conn_23",
+            "vertices": [
+                [
+                    67,
+                    130
+                ],
+                [
+                    67,
+                    133
+                ],
+                [
+                    67,
+                    133
+                ],
+                [
+                    67,
+                    146
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                0.5,
+                10.799999999999983
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                67.5,
+                143.79999999999998
+            ]
+        },
+        "trans_12": {
+            "start": "conn_24",
+            "end": "conn_25",
+            "vertices": [
+                [
+                    92,
+                    155
+                ],
+                [
+                    90,
+                    155
+                ],
+                [
+                    90,
+                    159
+                ],
+                [
+                    86,
+                    159
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                2.5999999999999943
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                90.5,
+                157.6
+            ]
+        },
+        "trans_13": {
+            "start": "conn_26",
+            "end": "conn_27",
+            "vertices": [
+                [
+                    31,
+                    158
+                ],
+                [
+                    53,
+                    158
+                ],
+                [
+                    53,
+                    158
+                ],
+                [
+                    71,
+                    158
+                ]
+            ],
+            "label": "SIG_LM73_READ",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                157.6
+            ]
+        },
+        "trans_14": {
+            "start": "conn_28",
+            "end": "conn_29",
+            "vertices": [
+                [
+                    31,
+                    160
+                ],
+                [
+                    53,
+                    160
+                ],
+                [
+                    53,
+                    160
+                ],
+                [
+                    71,
+                    160
+                ]
+            ],
+            "label": "[lm73_timeout(LM73_READ_PERIOD)]/ lm73_reset_timer()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                159.6
+            ]
+        },
+        "trans_15": {
+            "start": "conn_30",
+            "end": "conn_31",
+            "vertices": [
+                [
+                    71,
+                    163
+                ],
+                [
+                    53,
+                    163
+                ],
+                [
+                    53,
+                    163
+                ],
+                [
+                    31,
+                    163
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ lm73_inc_error_counter()",
+            "label_offset": [
+                -12.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                40.5,
+                162.6
+            ]
+        },
+        "trans_16": {
+            "start": "conn_32",
+            "end": "conn_33",
+            "vertices": [
+                [
+                    71,
+                    165
+                ],
+                [
+                    53,
+                    165
+                ],
+                [
+                    53,
+                    165
+                ],
+                [
+                    31,
+                    165
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ lm73_inc_error_counter()",
+            "label_offset": [
+                -12.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                40.5,
+                164.6
+            ]
+        },
+        "trans_17": {
+            "start": "conn_34",
+            "end": "conn_35",
+            "vertices": [
+                [
+                    71,
+                    167
+                ],
+                [
+                    53,
+                    167
+                ],
+                [
+                    53,
+                    167
+                ],
+                [
+                    31,
+                    167
+                ]
+            ],
+            "label": "[lm73_timeout(LM73_READ_PERIOD)]/ lm73_inc_error_counter()",
+            "label_offset": [
+                -15.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                37.5,
+                166.6
+            ]
+        },
+        "trans_18": {
+            "start": "conn_36",
+            "end": "conn_37",
+            "vertices": [
+                [
+                    71,
+                    172
+                ],
+                [
+                    53,
+                    172
+                ],
+                [
+                    53,
+                    172
+                ],
+                [
+                    31,
+                    172
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS/ lm73_update_temp()",
+            "label_offset": [
+                -9.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                43.5,
+                171.6
+            ]
+        },
+        "trans_19": {
+            "start": "conn_38",
+            "end": "conn_39",
+            "vertices": [
+                [
+                    70,
+                    86
+                ],
+                [
+                    77,
+                    86
+                ],
+                [
+                    77,
+                    87
+                ],
+                [
+                    70,
+                    87
+                ]
+            ],
+            "label": "[lm73_timeout(LM73_RETRY_TIMEOUT)]/ lm73_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71,
+                85.6
+            ]
+        },
+        "trans_20": {
+            "start": "conn_40",
+            "end": "conn_41",
+            "vertices": [
+                [
+                    70,
+                    89
+                ],
+                [
+                    77,
+                    89
+                ],
+                [
+                    77,
+                    90
+                ],
+                [
+                    70,
+                    90
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ lm73_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                88.6
+            ]
+        },
+        "trans_21": {
+            "start": "conn_42",
+            "end": "conn_43",
+            "vertices": [
+                [
+                    70,
+                    93
+                ],
+                [
+                    77,
+                    93
+                ],
+                [
+                    77,
+                    94
+                ],
+                [
+                    70,
+                    94
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ lm73_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                92.6
+            ]
+        },
+        "trans_22": {
+            "start": "conn_44",
+            "end": "conn_45",
+            "vertices": [
+                [
+                    70,
+                    119
+                ],
+                [
+                    77,
+                    119
+                ],
+                [
+                    77,
+                    120
+                ],
+                [
+                    70,
+                    120
+                ]
+            ],
+            "label": "[lm73_timeout(LM73_RETRY_TIMEOUT)]/ lm73_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                118.6
+            ]
+        },
+        "trans_23": {
+            "start": "conn_46",
+            "end": "conn_47",
+            "vertices": [
+                [
+                    70,
+                    123
+                ],
+                [
+                    77,
+                    123
+                ],
+                [
+                    77,
+                    124
+                ],
+                [
+                    70,
+                    124
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ lm73_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                122.6
+            ]
+        },
+        "trans_24": {
+            "start": "conn_48",
+            "end": "conn_49",
+            "vertices": [
+                [
+                    70,
+                    127
+                ],
+                [
+                    77,
+                    127
+                ],
+                [
+                    77,
+                    128
+                ],
+                [
+                    70,
+                    128
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ lm73_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                126.6
+            ]
+        },
+        "trans_25": {
+            "start": "conn_50",
+            "end": "conn_51",
+            "vertices": [
+                [
+                    43,
+                    135
+                ],
+                [
+                    43,
+                    140
+                ],
+                [
+                    16,
+                    140
+                ],
+                [
+                    5,
+                    140
+                ]
+            ],
+            "label": "[lm73_error_count(LM73_MAX_ERROR_COUNT)]",
+            "label_offset": [
+                -26.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                16.5,
+                139.6
+            ]
+        },
+        "trans_9": {
+            "start": "conn_18",
+            "end": "conn_19",
+            "vertices": [
+                [
+                    74,
+                    67
+                ],
+                [
+                    80,
+                    67
+                ],
+                [
+                    80,
+                    68
+                ],
+                [
+                    74,
+                    68
+                ]
+            ],
+            "label": "[lm73_timeout(LM73_RETRY_TIMEOUT)]/ lm73_inc_error_counter()",
+            "label_offset": [
+                3,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                77,
+                66.6
+            ]
+        },
+        "trans_10": {
+            "start": "conn_20",
+            "end": "conn_21",
+            "vertices": [
+                [
+                    74,
+                    70
+                ],
+                [
+                    80,
+                    70
+                ],
+                [
+                    80,
+                    71
+                ],
+                [
+                    74,
+                    71
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ lm73_inc_error_counter()",
+            "label_offset": [
+                2,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                76,
+                69.6
+            ]
+        },
+        "trans_26": {
+            "start": "conn_52",
+            "end": "conn_53",
+            "vertices": [
+                [
+                    74,
+                    73
+                ],
+                [
+                    80,
+                    73
+                ],
+                [
+                    80,
+                    74
+                ],
+                [
+                    74,
+                    74
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ lm73_inc_error_counter()",
+            "label_offset": [
+                2,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                76,
+                72.6
+            ]
+        },
+        "trans_27": {
+            "start": "conn_54",
+            "end": "conn_55",
+            "vertices": [
+                [
+                    72,
+                    103
+                ],
+                [
+                    77,
+                    103
+                ],
+                [
+                    77,
+                    104
+                ],
+                [
+                    72,
+                    104
+                ]
+            ],
+            "label": "[lm73_timeout(LM73_RETRY_TIMEOUT)]/ lm73_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                102.6
+            ]
+        },
+        "trans_28": {
+            "start": "conn_56",
+            "end": "conn_57",
+            "vertices": [
+                [
+                    72,
+                    106
+                ],
+                [
+                    77,
+                    106
+                ],
+                [
+                    77,
+                    107
+                ],
+                [
+                    72,
+                    107
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ lm73_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                105.6
+            ]
+        },
+        "trans_29": {
+            "start": "conn_58",
+            "end": "conn_59",
+            "vertices": [
+                [
+                    72,
+                    109
+                ],
+                [
+                    77,
+                    109
+                ],
+                [
+                    77,
+                    110
+                ],
+                [
+                    72,
+                    110
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ lm73_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                108.6
+            ]
+        },
+        "trans_30": {
+            "start": "conn_60",
+            "end": "conn_61",
+            "vertices": [
+                [
+                    54,
+                    67
+                ],
+                [
+                    34,
+                    67
+                ],
+                [
+                    34,
+                    72
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                -16.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                37.5,
+                66.6
+            ]
+        },
+        "trans_35": {
+            "start": "conn_70",
+            "end": "conn_71",
+            "vertices": [
+                [
+                    47,
+                    79
+                ],
+                [
+                    47,
+                    82
+                ],
+                [
+                    60,
+                    82
+                ],
+                [
+                    60,
+                    84
+                ]
+            ],
+            "label": "[lm73_wait_cnt()]",
+            "label_offset": [
+                3.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                50.5,
+                81.6
+            ]
+        },
+        "trans_31": {
+            "start": "conn_62",
+            "end": "conn_63",
+            "vertices": [
+                [
+                    61,
+                    96
+                ],
+                [
+                    61,
+                    99
+                ],
+                [
+                    61,
+                    99
+                ],
+                [
+                    61,
+                    102
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                0.5,
+                1.1999999999999886
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                61.5,
+                100.19999999999999
+            ]
+        },
+        "trans_32": {
+            "start": "conn_64",
+            "end": "conn_65",
+            "vertices": [
+                [
+                    47,
+                    108
+                ],
+                [
+                    47,
+                    115
+                ],
+                [
+                    61,
+                    115
+                ],
+                [
+                    61,
+                    118
+                ]
+            ],
+            "label": "[lm73_wait_cnt()]",
+            "label_offset": [
+                4,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                51,
+                114.6
+            ]
+        },
+        "trans_37": {
+            "start": "conn_74",
+            "end": "conn_75",
+            "vertices": [
+                [
+                    55,
+                    102
+                ],
+                [
+                    55,
+                    99
+                ],
+                [
+                    40,
+                    99
+                ],
+                [
+                    40,
+                    102
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                -14.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                40.5,
+                98.6
+            ]
+        },
+        "trans_33": {
+            "start": "conn_66",
+            "end": "conn_67",
+            "vertices": [
+                [
+                    33,
+                    63
+                ],
+                [
+                    64,
+                    63
+                ],
+                [
+                    64,
+                    66
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                14,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                47,
+                62.6
+            ]
+        }
+    },
+    "notes": {
+        "lm73_timeout": "",
+        "SIG_I2C_RESULT_ADDR_NACK": "",
+        "SIG_I2C_RESULT_DATA_NACK": "",
+        "trans_7": "",
+        "SIG_I2C_RESULT_SUCCESS": "",
+        "trans_24": "",
+        "trans_23": "",
+        "trans_22": "",
+        "trans_21": "",
+        "trans_20": "",
+        "trans_19": "",
+        "trans_25": "",
+        "SIG_LM73_READ": "",
+        "lm73_error_count": "",
+        "trans_9": "",
+        "lm73_inc_wait_cnt()": "",
+        "LM73_RETRY_TIMEOUT": "",
+        "LM73_MAX_ERROR_COUNT": ""
+    },
+    "view": {
+        "translate": [
+            55,
+            -326.5
+        ],
+        "scale": 7.5
+    }
+}
+        
+
+ + diff --git a/docs/doc_gen/source/_static/module_view.drawio b/docs/doc_gen/source/_static/module_view.drawio new file mode 100644 index 00000000..d044eda3 --- /dev/null +++ b/docs/doc_gen/source/_static/module_view.drawio @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/doc_gen/source/_static/qpn_classes.gif b/docs/doc_gen/source/_static/qpn_classes.gif new file mode 100644 index 00000000..5f6637f1 Binary files /dev/null and b/docs/doc_gen/source/_static/qpn_classes.gif differ diff --git a/modules/spi_master/doc/spi_master.html b/docs/doc_gen/source/_static/spi_master.html similarity index 99% rename from modules/spi_master/doc/spi_master.html rename to docs/doc_gen/source/_static/spi_master.html index 22f3152b..25fc1618 100644 --- a/modules/spi_master/doc/spi_master.html +++ b/docs/doc_gen/source/_static/spi_master.html @@ -171,7 +171,7 @@
- + diff --git a/docs/doc_gen/source/_static/srs-ao.png b/docs/doc_gen/source/_static/srs-ao.png new file mode 100644 index 00000000..0ef65cd3 Binary files /dev/null and b/docs/doc_gen/source/_static/srs-ao.png differ diff --git a/docs/doc_gen/source/_static/tmp468.html b/docs/doc_gen/source/_static/tmp468.html new file mode 100644 index 00000000..545ce3cb --- /dev/null +++ b/docs/doc_gen/source/_static/tmp468.html @@ -0,0 +1,2666 @@ + + + + + + +
+ + + + + + SIG_I2C_RESULT_DATA_NACKSIG_I2C_RESULT_ADDR_NACK[tmp468_timeoutEvaluates to true if the internal timer counter is greater than or equal to the parameter.(TMP468_RETRY_TIMEOUT)]SIG_I2C_RESULT_DATA_NACKSIG_I2C_RESULT_ADDR_NACK[tmp468_timeoutEvaluates to true if the internal timer counter is greater than or equal to the parameter.(TMP468_RETRY_TIMEOUT)]SIG_I2C_RESULT_DATA_NACKSIG_I2C_RESULT_ADDR_NACK[tmp468_timeoutEvaluates to true if the internal timer counter is greater than or equal to the parameter.(TMP468_RETRY_TIMEOUT)]SIG_I2C_RESULT_DATA_NACKSIG_I2C_RESULT_ADDR_NACK[tmp468_timeoutEvaluates to true if the internal timer counter is greater than or equal to the parameter.(TMP468_RETRY_TIMEOUT)][tmp468_timeoutEvaluates to true if the internal timer counter is greater than or equal to the parameter.(TMP468_READ_PERIOD)]/ tmp468_inc_error_counter()Increase the error counter.[tmp468_status_timeout(TMP468_STATUS_READ_PERIOD)]/ tmp468_inc_error_counter()Increase the error counter.SIG_I2C_RESULT_SUCCESS/ tmp468_update_status()SIG_I2C_RESULT_DATA_NACKSIG_I2C_RESULT_ADDR_NACK[tmp468_timeoutEvaluates to true if the internal timer counter is greater than or equal to the parameter.(TMP468_RETRY_TIMEOUT)][tmp468_timeoutEvaluates to true if the internal timer counter is greater than or equal to the parameter.(TMP468_READ_PERIOD)]/ tmp468_reset_timer()Reset the timer counter.SIG_I2C_RESULT_SUCCESSSIG_I2C_RESULT_SUCCESSSIG_I2C_RESULT_SUCCESS SIG_I2C_RESULT_SUCCESSSIG_I2C_RESULT_SUCCESSSIG_I2C_RESULT_DATA_NACK/ tmp468_inc_error_counter()Increase the error counter.SIG_I2C_RESULT_DATA_NACK/ tmp468_inc_error_counter()Increase the error counter.SIG_I2C_RESULT_SUCCESS/ tmp468_update_temp()- Update the temperature display +- Send an event with the new value +- Decrease the error counterSIG_I2C_RESULT_ADDR_NACK/ tmp468_inc_error_counter()Increase the error counter.[tmp468_status_timeout(TMP468_STATUS_READ_PERIOD)]/ tmp468_reset_status_timer()SIG_I2C_RESULT_DATA_NACKSIG_I2C_RESULT_ADDR_NACKSIG_I2C_RESULT_SUCCESS [tmp468_id_match()True, if the response data is equal to 0x190. See TMP468 datasheet section: 7.5.1.7 Identification Register][tmp468_error_countReturn true, if the error counter is greater or equal then the parameter.(TMP468_MAX_ERROR_COUNT)][tmp468_timeoutEvaluates to true if the internal timer counter is greater than or equal to the parameter.(TMP468_RETRY_TIMEOUT)]SIG_I2C_RESULT_ADDR_NACK/ tmp468_inc_error_counter()Increase the error counter. + __top__s_tmp468entry/ tmp468_init()SIG_SYS_TICK_10ms/ tmp468_10ms_callback()SIG_TMP468_I2C_POWER_STATE/ tmp468_i2c_power_state()s_idleentry/ tmp468_reset_timer()Reset the timer counter.s_read_tempentry/ tmp468_read_temp()s_read_id_reginit/ tmp468_read_id()Try to read the ID register from the TMP468 by sending a write-read transaction to the I2C master.entry/ tmp468_reset_timer()Reset the timer counter.s_onlineentry/ tmp468_send_online_event()exit/ tmp468_send_offline_event()s_read_sensor_statusentry/ tmp468_read_sensor_status()s_set_n_factors_set_n_factor1init/ tmp468_set_n_factor1()entry/ tmp468_reset_timer()Reset the timer counter.s_set_n_factor2init/ tmp468_set_n_factor2()entry/ tmp468_reset_timer()Reset the timer counter.s_set_n_factor3init/ tmp468_set_n_factor3()entry/ tmp468_reset_timer()Reset the timer counter.s_set_n_factor4init/ tmp468_set_n_factor4()entry/ tmp468_reset_timer()Reset the timer counter.s_unlock_regsinit/ tmp468_unlock_regs()entry/ tmp468_reset_timer()Reset the timer counter.s_init + + +
+ +
+ json +
+            {
+    "states": {
+        "__top__": {
+            "pos": [
+                -100000003,
+                -100000004
+            ],
+            "size": [
+                200000000,
+                200000000
+            ],
+            "title": "__top__",
+            "text": [],
+            "connectors": [],
+            "parent": null,
+            "children": [
+                "state_0",
+                "istate_0"
+            ],
+            "type": "top"
+        },
+        "state_0": {
+            "pos": [
+                7,
+                11
+            ],
+            "size": [
+                115,
+                156
+            ],
+            "title": "s_tmp468",
+            "text": [
+                "entry/ tmp468_init()",
+                "SIG_SYS_TICK_10ms/ tmp468_10ms_callback()",
+                "SIG_TMP468_I2C_POWER_STATE/ tmp468_i2c_power_state()"
+            ],
+            "connectors": [
+                "conn_1"
+            ],
+            "parent": "__top__",
+            "children": [
+                "state_5",
+                "state_12",
+                "istate_4"
+            ],
+            "type": "normal"
+        },
+        "istate_0": {
+            "pos": [
+                46,
+                8
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_0",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_0"
+            ],
+            "parent": "__top__",
+            "children": [],
+            "type": "initial"
+        },
+        "state_1": {
+            "pos": [
+                16,
+                116
+            ],
+            "size": [
+                18,
+                37
+            ],
+            "title": "s_idle",
+            "text": [
+                "entry/ tmp468_reset_timer()",
+                ""
+            ],
+            "connectors": [
+                "conn_7",
+                "conn_28",
+                "conn_33",
+                "conn_3",
+                "conn_23",
+                "conn_25",
+                "conn_5",
+                "conn_42",
+                "conn_35",
+                "conn_51",
+                "conn_53"
+            ],
+            "parent": "state_5",
+            "children": [],
+            "type": "normal"
+        },
+        "state_2": {
+            "pos": [
+                85,
+                137
+            ],
+            "size": [
+                23,
+                15
+            ],
+            "title": "s_read_temp",
+            "text": [
+                "entry/ tmp468_read_temp()"
+            ],
+            "connectors": [
+                "conn_6",
+                "conn_2",
+                "conn_24",
+                "conn_43",
+                "conn_52"
+            ],
+            "parent": "state_5",
+            "children": [],
+            "type": "normal"
+        },
+        "state_3": {
+            "pos": [
+                73,
+                40
+            ],
+            "size": [
+                18,
+                10
+            ],
+            "title": "s_read_id_reg",
+            "text": [
+                "init/ tmp468_read_id()",
+                "entry/ tmp468_reset_timer()"
+            ],
+            "connectors": [
+                "conn_10",
+                "conn_11",
+                "conn_12",
+                "conn_14",
+                "conn_15",
+                "conn_16",
+                "conn_17",
+                "conn_9"
+            ],
+            "parent": "state_12",
+            "children": [],
+            "type": "normal"
+        },
+        "state_5": {
+            "pos": [
+                12,
+                102
+            ],
+            "size": [
+                100,
+                59
+            ],
+            "title": "s_online",
+            "text": [
+                "entry/ tmp468_send_online_event()",
+                "exit/ tmp468_send_offline_event()"
+            ],
+            "connectors": [
+                "conn_18",
+                "conn_41"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_1",
+                "state_2",
+                "istate_2",
+                "state_4"
+            ],
+            "type": "normal"
+        },
+        "istate_2": {
+            "pos": [
+                24,
+                112
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_2",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_4"
+            ],
+            "parent": "state_5",
+            "children": [],
+            "type": "initial"
+        },
+        "state_4": {
+            "pos": [
+                85,
+                117
+            ],
+            "size": [
+                23,
+                16
+            ],
+            "title": "s_read_sensor_status",
+            "text": [
+                "entry/ tmp468_read_sensor_status()"
+            ],
+            "connectors": [
+                "conn_29",
+                "conn_32",
+                "conn_22",
+                "conn_34",
+                "conn_50"
+            ],
+            "parent": "state_5",
+            "children": [],
+            "type": "normal"
+        },
+        "state_6": {
+            "pos": [
+                16,
+                35
+            ],
+            "size": [
+                52,
+                57
+            ],
+            "title": "s_set_n_factor",
+            "text": [
+                ""
+            ],
+            "connectors": [
+                "conn_21"
+            ],
+            "parent": "state_12",
+            "children": [
+                "state_7",
+                "state_8",
+                "state_9",
+                "state_10",
+                "istate_3"
+            ],
+            "type": "normal"
+        },
+        "state_7": {
+            "pos": [
+                23,
+                42
+            ],
+            "size": [
+                19,
+                9
+            ],
+            "title": "s_set_n_factor1",
+            "text": [
+                "init/ tmp468_set_n_factor1()",
+                "entry/ tmp468_reset_timer()"
+            ],
+            "connectors": [
+                "conn_27",
+                "conn_30",
+                "conn_54",
+                "conn_55",
+                "conn_56",
+                "conn_57",
+                "conn_58",
+                "conn_59"
+            ],
+            "parent": "state_6",
+            "children": [],
+            "type": "normal"
+        },
+        "state_8": {
+            "pos": [
+                23,
+                54
+            ],
+            "size": [
+                19,
+                9
+            ],
+            "title": "s_set_n_factor2",
+            "text": [
+                "init/ tmp468_set_n_factor2()",
+                "entry/ tmp468_reset_timer()"
+            ],
+            "connectors": [
+                "conn_31",
+                "conn_36",
+                "conn_60",
+                "conn_61",
+                "conn_62",
+                "conn_63",
+                "conn_64",
+                "conn_65"
+            ],
+            "parent": "state_6",
+            "children": [],
+            "type": "normal"
+        },
+        "state_9": {
+            "pos": [
+                23,
+                66
+            ],
+            "size": [
+                19,
+                9
+            ],
+            "title": "s_set_n_factor3",
+            "text": [
+                "init/ tmp468_set_n_factor3()",
+                "entry/ tmp468_reset_timer()"
+            ],
+            "connectors": [
+                "conn_38",
+                "conn_37",
+                "conn_66",
+                "conn_67",
+                "conn_68",
+                "conn_69",
+                "conn_70",
+                "conn_71"
+            ],
+            "parent": "state_6",
+            "children": [],
+            "type": "normal"
+        },
+        "state_10": {
+            "pos": [
+                23,
+                78
+            ],
+            "size": [
+                19,
+                9
+            ],
+            "title": "s_set_n_factor4",
+            "text": [
+                "init/ tmp468_set_n_factor4()",
+                "entry/ tmp468_reset_timer()"
+            ],
+            "connectors": [
+                "conn_39",
+                "conn_40",
+                "conn_72",
+                "conn_73",
+                "conn_74",
+                "conn_75",
+                "conn_76",
+                "conn_77"
+            ],
+            "parent": "state_6",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_3": {
+            "pos": [
+                18,
+                43
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_3",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_26"
+            ],
+            "parent": "state_6",
+            "children": [],
+            "type": "initial"
+        },
+        "state_11": {
+            "pos": [
+                72,
+                60
+            ],
+            "size": [
+                20,
+                11
+            ],
+            "title": "s_unlock_regs",
+            "text": [
+                "init/ tmp468_unlock_regs()",
+                "entry/ tmp468_reset_timer()"
+            ],
+            "connectors": [
+                "conn_13",
+                "conn_20",
+                "conn_44",
+                "conn_45",
+                "conn_46",
+                "conn_47",
+                "conn_48",
+                "conn_49"
+            ],
+            "parent": "state_12",
+            "children": [],
+            "type": "normal"
+        },
+        "state_12": {
+            "pos": [
+                12,
+                26
+            ],
+            "size": [
+                105,
+                70
+            ],
+            "title": "s_init",
+            "text": [
+                ""
+            ],
+            "connectors": [
+                "conn_19",
+                "conn_79"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_3",
+                "state_6",
+                "state_11",
+                "istate_1"
+            ],
+            "type": "normal"
+        },
+        "istate_1": {
+            "pos": [
+                81,
+                36
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_1",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_8"
+            ],
+            "parent": "state_12",
+            "children": [],
+            "type": "initial"
+        },
+        "istate_4": {
+            "pos": [
+                59,
+                22
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_4",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_78"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "initial"
+        }
+    },
+    "connectors": {
+        "conn_0": {
+            "parent": "istate_0",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_0"
+        },
+        "conn_1": {
+            "parent": "state_0",
+            "offset": 39,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_0"
+        },
+        "conn_6": {
+            "parent": "state_2",
+            "offset": 6,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_3"
+        },
+        "conn_7": {
+            "parent": "state_1",
+            "offset": 27,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_3"
+        },
+        "conn_10": {
+            "parent": "state_3",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_5"
+        },
+        "conn_11": {
+            "parent": "state_3",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_5"
+        },
+        "conn_18": {
+            "parent": "state_5",
+            "offset": 56,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_9"
+        },
+        "conn_19": {
+            "parent": "state_12",
+            "offset": 50,
+            "side": "bottom",
+            "dir": "in",
+            "transition": "trans_9"
+        },
+        "conn_12": {
+            "parent": "state_3",
+            "offset": 8,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_6"
+        },
+        "conn_13": {
+            "parent": "state_11",
+            "offset": 9,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_6"
+        },
+        "conn_14": {
+            "parent": "state_3",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_7"
+        },
+        "conn_15": {
+            "parent": "state_3",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_7"
+        },
+        "conn_16": {
+            "parent": "state_3",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_8"
+        },
+        "conn_17": {
+            "parent": "state_3",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_8"
+        },
+        "conn_28": {
+            "parent": "state_1",
+            "offset": 3,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_14"
+        },
+        "conn_29": {
+            "parent": "state_4",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_14"
+        },
+        "conn_32": {
+            "parent": "state_4",
+            "offset": 6,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_16"
+        },
+        "conn_33": {
+            "parent": "state_1",
+            "offset": 7,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_16"
+        },
+        "conn_2": {
+            "parent": "state_2",
+            "offset": 14,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_1"
+        },
+        "conn_3": {
+            "parent": "state_1",
+            "offset": 35,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_1"
+        },
+        "conn_22": {
+            "parent": "state_4",
+            "offset": 8,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_11"
+        },
+        "conn_23": {
+            "parent": "state_1",
+            "offset": 9,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_11"
+        },
+        "conn_24": {
+            "parent": "state_2",
+            "offset": 8,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_12"
+        },
+        "conn_25": {
+            "parent": "state_1",
+            "offset": 29,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_12"
+        },
+        "conn_4": {
+            "parent": "istate_2",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_2"
+        },
+        "conn_5": {
+            "parent": "state_1",
+            "offset": 8,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_2"
+        },
+        "conn_26": {
+            "parent": "istate_3",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_13"
+        },
+        "conn_27": {
+            "parent": "state_7",
+            "offset": 1,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_13"
+        },
+        "conn_30": {
+            "parent": "state_7",
+            "offset": 3,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_15"
+        },
+        "conn_31": {
+            "parent": "state_8",
+            "offset": 3,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_15"
+        },
+        "conn_38": {
+            "parent": "state_9",
+            "offset": 3,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_19"
+        },
+        "conn_39": {
+            "parent": "state_10",
+            "offset": 3,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_19"
+        },
+        "conn_36": {
+            "parent": "state_8",
+            "offset": 3,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_18"
+        },
+        "conn_37": {
+            "parent": "state_9",
+            "offset": 3,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_18"
+        },
+        "conn_40": {
+            "parent": "state_10",
+            "offset": 3,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_20"
+        },
+        "conn_41": {
+            "parent": "state_5",
+            "offset": 14,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_20"
+        },
+        "conn_20": {
+            "parent": "state_11",
+            "offset": 15,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_10"
+        },
+        "conn_21": {
+            "parent": "state_6",
+            "offset": 47,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_10"
+        },
+        "conn_42": {
+            "parent": "state_1",
+            "offset": 23,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_21"
+        },
+        "conn_43": {
+            "parent": "state_2",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_21"
+        },
+        "conn_44": {
+            "parent": "state_11",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_22"
+        },
+        "conn_45": {
+            "parent": "state_11",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_22"
+        },
+        "conn_46": {
+            "parent": "state_11",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_23"
+        },
+        "conn_47": {
+            "parent": "state_11",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_23"
+        },
+        "conn_48": {
+            "parent": "state_11",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_24"
+        },
+        "conn_49": {
+            "parent": "state_11",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_24"
+        },
+        "conn_34": {
+            "parent": "state_4",
+            "offset": 14,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_17"
+        },
+        "conn_35": {
+            "parent": "state_1",
+            "offset": 15,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_17"
+        },
+        "conn_50": {
+            "parent": "state_4",
+            "offset": 10,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_25"
+        },
+        "conn_51": {
+            "parent": "state_1",
+            "offset": 11,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_25"
+        },
+        "conn_52": {
+            "parent": "state_2",
+            "offset": 10,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_26"
+        },
+        "conn_53": {
+            "parent": "state_1",
+            "offset": 31,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_26"
+        },
+        "conn_54": {
+            "parent": "state_7",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_27"
+        },
+        "conn_55": {
+            "parent": "state_7",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_27"
+        },
+        "conn_56": {
+            "parent": "state_7",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_28"
+        },
+        "conn_57": {
+            "parent": "state_7",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_28"
+        },
+        "conn_58": {
+            "parent": "state_7",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_29"
+        },
+        "conn_59": {
+            "parent": "state_7",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_29"
+        },
+        "conn_60": {
+            "parent": "state_8",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_30"
+        },
+        "conn_61": {
+            "parent": "state_8",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_30"
+        },
+        "conn_62": {
+            "parent": "state_8",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_31"
+        },
+        "conn_63": {
+            "parent": "state_8",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_31"
+        },
+        "conn_64": {
+            "parent": "state_8",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_32"
+        },
+        "conn_65": {
+            "parent": "state_8",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_32"
+        },
+        "conn_66": {
+            "parent": "state_9",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_33"
+        },
+        "conn_67": {
+            "parent": "state_9",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_33"
+        },
+        "conn_68": {
+            "parent": "state_9",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_34"
+        },
+        "conn_69": {
+            "parent": "state_9",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_34"
+        },
+        "conn_70": {
+            "parent": "state_9",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_35"
+        },
+        "conn_71": {
+            "parent": "state_9",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_35"
+        },
+        "conn_72": {
+            "parent": "state_10",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_36"
+        },
+        "conn_73": {
+            "parent": "state_10",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_36"
+        },
+        "conn_74": {
+            "parent": "state_10",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_37"
+        },
+        "conn_75": {
+            "parent": "state_10",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_37"
+        },
+        "conn_76": {
+            "parent": "state_10",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_38"
+        },
+        "conn_77": {
+            "parent": "state_10",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_38"
+        },
+        "conn_8": {
+            "parent": "istate_1",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_4"
+        },
+        "conn_9": {
+            "parent": "state_3",
+            "offset": 8,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_4"
+        },
+        "conn_78": {
+            "parent": "istate_4",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_39"
+        },
+        "conn_79": {
+            "parent": "state_12",
+            "offset": 47,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_39"
+        }
+    },
+    "transitions": {
+        "trans_0": {
+            "start": "conn_0",
+            "end": "conn_1",
+            "vertices": [
+                [
+                    46,
+                    8
+                ],
+                [
+                    46,
+                    8
+                ],
+                [
+                    46,
+                    11
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                0.5999999999999996
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                46.5,
+                8.6
+            ]
+        },
+        "trans_3": {
+            "start": "conn_6",
+            "end": "conn_7",
+            "vertices": [
+                [
+                    85,
+                    143
+                ],
+                [
+                    41,
+                    143
+                ],
+                [
+                    41,
+                    143
+                ],
+                [
+                    34,
+                    143
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ tmp468_inc_error_counter()",
+            "label_offset": [
+                -4,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                37,
+                142.6
+            ]
+        },
+        "trans_5": {
+            "start": "conn_10",
+            "end": "conn_11",
+            "vertices": [
+                [
+                    91,
+                    41
+                ],
+                [
+                    114,
+                    41
+                ],
+                [
+                    114,
+                    42
+                ],
+                [
+                    91,
+                    42
+                ]
+            ],
+            "label": "[tmp468_timeout(TMP468_RETRY_TIMEOUT)]",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                92.5,
+                40.6
+            ]
+        },
+        "trans_9": {
+            "start": "conn_18",
+            "end": "conn_19",
+            "vertices": [
+                [
+                    68,
+                    102
+                ],
+                [
+                    68,
+                    100
+                ],
+                [
+                    62,
+                    100
+                ],
+                [
+                    62,
+                    96
+                ]
+            ],
+            "label": "[tmp468_error_count(TMP468_MAX_ERROR_COUNT)]",
+            "label_offset": [
+                0.5,
+                -2.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                68.5,
+                99.6
+            ]
+        },
+        "trans_6": {
+            "start": "conn_12",
+            "end": "conn_13",
+            "vertices": [
+                [
+                    81,
+                    50
+                ],
+                [
+                    81,
+                    55
+                ],
+                [
+                    81,
+                    55
+                ],
+                [
+                    81,
+                    60
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS [tmp468_id_match()]",
+            "label_offset": [
+                0.5,
+                4.600000000000001
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                81.5,
+                54.6
+            ]
+        },
+        "trans_7": {
+            "start": "conn_14",
+            "end": "conn_15",
+            "vertices": [
+                [
+                    91,
+                    44
+                ],
+                [
+                    114,
+                    44
+                ],
+                [
+                    114,
+                    45
+                ],
+                [
+                    91,
+                    45
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK",
+            "label_offset": [
+                2,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                93,
+                43.6
+            ]
+        },
+        "trans_8": {
+            "start": "conn_16",
+            "end": "conn_17",
+            "vertices": [
+                [
+                    91,
+                    47
+                ],
+                [
+                    114,
+                    47
+                ],
+                [
+                    114,
+                    48
+                ],
+                [
+                    91,
+                    48
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK",
+            "label_offset": [
+                2,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                93,
+                46.6
+            ]
+        },
+        "trans_14": {
+            "start": "conn_28",
+            "end": "conn_29",
+            "vertices": [
+                [
+                    34,
+                    119
+                ],
+                [
+                    55,
+                    119
+                ],
+                [
+                    55,
+                    119
+                ],
+                [
+                    85,
+                    119
+                ]
+            ],
+            "label": "[tmp468_status_timeout(TMP468_STATUS_READ_PERIOD)]/ tmp468_reset_status_timer()",
+            "label_offset": [
+                2.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                36.5,
+                118.6
+            ]
+        },
+        "trans_16": {
+            "start": "conn_32",
+            "end": "conn_33",
+            "vertices": [
+                [
+                    85,
+                    123
+                ],
+                [
+                    55,
+                    123
+                ],
+                [
+                    55,
+                    123
+                ],
+                [
+                    34,
+                    123
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ tmp468_inc_error_counter()",
+            "label_offset": [
+                -18,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                37,
+                122.6
+            ]
+        },
+        "trans_1": {
+            "start": "conn_2",
+            "end": "conn_3",
+            "vertices": [
+                [
+                    85,
+                    151
+                ],
+                [
+                    53,
+                    151
+                ],
+                [
+                    53,
+                    151
+                ],
+                [
+                    34,
+                    151
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS/ tmp468_update_temp()",
+            "label_offset": [
+                -16,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                37,
+                150.6
+            ]
+        },
+        "trans_11": {
+            "start": "conn_22",
+            "end": "conn_23",
+            "vertices": [
+                [
+                    85,
+                    125
+                ],
+                [
+                    53,
+                    125
+                ],
+                [
+                    53,
+                    125
+                ],
+                [
+                    34,
+                    125
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ tmp468_inc_error_counter()",
+            "label_offset": [
+                -16,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                37,
+                124.6
+            ]
+        },
+        "trans_12": {
+            "start": "conn_24",
+            "end": "conn_25",
+            "vertices": [
+                [
+                    85,
+                    145
+                ],
+                [
+                    53,
+                    145
+                ],
+                [
+                    53,
+                    145
+                ],
+                [
+                    34,
+                    145
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ tmp468_inc_error_counter()",
+            "label_offset": [
+                -16,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                37,
+                144.6
+            ]
+        },
+        "trans_2": {
+            "start": "conn_4",
+            "end": "conn_5",
+            "vertices": [
+                [
+                    24,
+                    112
+                ],
+                [
+                    24,
+                    112
+                ],
+                [
+                    24,
+                    116
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                3.5999999999999943
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                24.5,
+                115.6
+            ]
+        },
+        "trans_13": {
+            "start": "conn_26",
+            "end": "conn_27",
+            "vertices": [
+                [
+                    18,
+                    43
+                ],
+                [
+                    20,
+                    43
+                ],
+                [
+                    20,
+                    43
+                ],
+                [
+                    23,
+                    43
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                2.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                20.5,
+                42.6
+            ]
+        },
+        "trans_15": {
+            "start": "conn_30",
+            "end": "conn_31",
+            "vertices": [
+                [
+                    26,
+                    51
+                ],
+                [
+                    26,
+                    52
+                ],
+                [
+                    26,
+                    52
+                ],
+                [
+                    26,
+                    54
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                0.5,
+                0.6000000000000085
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                26.5,
+                52.60000000000001
+            ]
+        },
+        "trans_19": {
+            "start": "conn_38",
+            "end": "conn_39",
+            "vertices": [
+                [
+                    26,
+                    75
+                ],
+                [
+                    26,
+                    77
+                ],
+                [
+                    26,
+                    77
+                ],
+                [
+                    26,
+                    78
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                0.5,
+                -0.20000000000001705
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                26.5,
+                76.79999999999998
+            ]
+        },
+        "trans_18": {
+            "start": "conn_36",
+            "end": "conn_37",
+            "vertices": [
+                [
+                    26,
+                    63
+                ],
+                [
+                    26,
+                    65
+                ],
+                [
+                    26,
+                    65
+                ],
+                [
+                    26,
+                    66
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS ",
+            "label_offset": [
+                0.5,
+                1.5999999999999943
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                26.5,
+                64.6
+            ]
+        },
+        "trans_20": {
+            "start": "conn_40",
+            "end": "conn_41",
+            "vertices": [
+                [
+                    26,
+                    87
+                ],
+                [
+                    26,
+                    96
+                ],
+                [
+                    26,
+                    96
+                ],
+                [
+                    26,
+                    102
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                0.5,
+                2.799999999999983
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                26.5,
+                89.79999999999998
+            ]
+        },
+        "trans_10": {
+            "start": "conn_20",
+            "end": "conn_21",
+            "vertices": [
+                [
+                    87,
+                    71
+                ],
+                [
+                    87,
+                    82
+                ],
+                [
+                    68,
+                    82
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                -17.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                69.5,
+                81.6
+            ]
+        },
+        "trans_21": {
+            "start": "conn_42",
+            "end": "conn_43",
+            "vertices": [
+                [
+                    34,
+                    139
+                ],
+                [
+                    53,
+                    139
+                ],
+                [
+                    53,
+                    139
+                ],
+                [
+                    85,
+                    139
+                ]
+            ],
+            "label": "[tmp468_timeout(TMP468_READ_PERIOD)]/ tmp468_reset_timer()",
+            "label_offset": [
+                2.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                36.5,
+                138.6
+            ]
+        },
+        "trans_22": {
+            "start": "conn_44",
+            "end": "conn_45",
+            "vertices": [
+                [
+                    92,
+                    61
+                ],
+                [
+                    99,
+                    61
+                ],
+                [
+                    99,
+                    62
+                ],
+                [
+                    92,
+                    62
+                ]
+            ],
+            "label": "[tmp468_timeout(TMP468_RETRY_TIMEOUT)]",
+            "label_offset": [
+                0.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                92.5,
+                60.599999999999994
+            ]
+        },
+        "trans_23": {
+            "start": "conn_46",
+            "end": "conn_47",
+            "vertices": [
+                [
+                    92,
+                    64
+                ],
+                [
+                    99,
+                    64
+                ],
+                [
+                    99,
+                    65
+                ],
+                [
+                    92,
+                    65
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK",
+            "label_offset": [
+                0.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                92.5,
+                63.599999999999994
+            ]
+        },
+        "trans_24": {
+            "start": "conn_48",
+            "end": "conn_49",
+            "vertices": [
+                [
+                    92,
+                    67
+                ],
+                [
+                    99,
+                    67
+                ],
+                [
+                    99,
+                    68
+                ],
+                [
+                    92,
+                    68
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK",
+            "label_offset": [
+                0.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                92.5,
+                66.6
+            ]
+        },
+        "trans_17": {
+            "start": "conn_34",
+            "end": "conn_35",
+            "vertices": [
+                [
+                    85,
+                    131
+                ],
+                [
+                    60,
+                    131
+                ],
+                [
+                    60,
+                    131
+                ],
+                [
+                    34,
+                    131
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS/ tmp468_update_status()",
+            "label_offset": [
+                -23.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                36.5,
+                130.6
+            ]
+        },
+        "trans_25": {
+            "start": "conn_50",
+            "end": "conn_51",
+            "vertices": [
+                [
+                    85,
+                    127
+                ],
+                [
+                    60,
+                    127
+                ],
+                [
+                    60,
+                    127
+                ],
+                [
+                    34,
+                    127
+                ]
+            ],
+            "label": "[tmp468_status_timeout(TMP468_STATUS_READ_PERIOD)]/ tmp468_inc_error_counter()",
+            "label_offset": [
+                -23.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                36.5,
+                126.6
+            ]
+        },
+        "trans_26": {
+            "start": "conn_52",
+            "end": "conn_53",
+            "vertices": [
+                [
+                    85,
+                    147
+                ],
+                [
+                    60,
+                    147
+                ],
+                [
+                    60,
+                    147
+                ],
+                [
+                    34,
+                    147
+                ]
+            ],
+            "label": "[tmp468_timeout(TMP468_READ_PERIOD)]/ tmp468_inc_error_counter()",
+            "label_offset": [
+                -23.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                36.5,
+                146.6
+            ]
+        },
+        "trans_27": {
+            "start": "conn_54",
+            "end": "conn_55",
+            "vertices": [
+                [
+                    42,
+                    43
+                ],
+                [
+                    49,
+                    43
+                ],
+                [
+                    49,
+                    44
+                ],
+                [
+                    42,
+                    44
+                ]
+            ],
+            "label": "[tmp468_timeout(TMP468_RETRY_TIMEOUT)]",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                43.5,
+                42.6
+            ]
+        },
+        "trans_28": {
+            "start": "conn_56",
+            "end": "conn_57",
+            "vertices": [
+                [
+                    42,
+                    46
+                ],
+                [
+                    49,
+                    46
+                ],
+                [
+                    49,
+                    47
+                ],
+                [
+                    42,
+                    47
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                43.5,
+                45.6
+            ]
+        },
+        "trans_29": {
+            "start": "conn_58",
+            "end": "conn_59",
+            "vertices": [
+                [
+                    42,
+                    49
+                ],
+                [
+                    49,
+                    49
+                ],
+                [
+                    49,
+                    50
+                ],
+                [
+                    42,
+                    50
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                43.5,
+                48.6
+            ]
+        },
+        "trans_30": {
+            "start": "conn_60",
+            "end": "conn_61",
+            "vertices": [
+                [
+                    42,
+                    55
+                ],
+                [
+                    49,
+                    55
+                ],
+                [
+                    49,
+                    56
+                ],
+                [
+                    42,
+                    56
+                ]
+            ],
+            "label": "[tmp468_timeout(TMP468_RETRY_TIMEOUT)]",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                43.5,
+                54.6
+            ]
+        },
+        "trans_31": {
+            "start": "conn_62",
+            "end": "conn_63",
+            "vertices": [
+                [
+                    42,
+                    58
+                ],
+                [
+                    49,
+                    58
+                ],
+                [
+                    49,
+                    59
+                ],
+                [
+                    42,
+                    59
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                43.5,
+                57.6
+            ]
+        },
+        "trans_32": {
+            "start": "conn_64",
+            "end": "conn_65",
+            "vertices": [
+                [
+                    42,
+                    61
+                ],
+                [
+                    49,
+                    61
+                ],
+                [
+                    49,
+                    62
+                ],
+                [
+                    42,
+                    62
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                43.5,
+                60.6
+            ]
+        },
+        "trans_33": {
+            "start": "conn_66",
+            "end": "conn_67",
+            "vertices": [
+                [
+                    42,
+                    67
+                ],
+                [
+                    49,
+                    67
+                ],
+                [
+                    49,
+                    68
+                ],
+                [
+                    42,
+                    68
+                ]
+            ],
+            "label": "[tmp468_timeout(TMP468_RETRY_TIMEOUT)]",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                43.5,
+                66.6
+            ]
+        },
+        "trans_34": {
+            "start": "conn_68",
+            "end": "conn_69",
+            "vertices": [
+                [
+                    42,
+                    70
+                ],
+                [
+                    49,
+                    70
+                ],
+                [
+                    49,
+                    71
+                ],
+                [
+                    42,
+                    71
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                43.5,
+                69.6
+            ]
+        },
+        "trans_35": {
+            "start": "conn_70",
+            "end": "conn_71",
+            "vertices": [
+                [
+                    42,
+                    73
+                ],
+                [
+                    49,
+                    73
+                ],
+                [
+                    49,
+                    74
+                ],
+                [
+                    42,
+                    74
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                43.5,
+                72.6
+            ]
+        },
+        "trans_36": {
+            "start": "conn_72",
+            "end": "conn_73",
+            "vertices": [
+                [
+                    42,
+                    79
+                ],
+                [
+                    49,
+                    79
+                ],
+                [
+                    49,
+                    80
+                ],
+                [
+                    42,
+                    80
+                ]
+            ],
+            "label": "[tmp468_timeout(TMP468_RETRY_TIMEOUT)]",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                43.5,
+                78.6
+            ]
+        },
+        "trans_37": {
+            "start": "conn_74",
+            "end": "conn_75",
+            "vertices": [
+                [
+                    42,
+                    82
+                ],
+                [
+                    49,
+                    82
+                ],
+                [
+                    49,
+                    83
+                ],
+                [
+                    42,
+                    83
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                43.5,
+                81.6
+            ]
+        },
+        "trans_38": {
+            "start": "conn_76",
+            "end": "conn_77",
+            "vertices": [
+                [
+                    42,
+                    85
+                ],
+                [
+                    49,
+                    85
+                ],
+                [
+                    49,
+                    86
+                ],
+                [
+                    42,
+                    86
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                43.5,
+                84.6
+            ]
+        },
+        "trans_4": {
+            "start": "conn_8",
+            "end": "conn_9",
+            "vertices": [
+                [
+                    81,
+                    36
+                ],
+                [
+                    81,
+                    36
+                ],
+                [
+                    81,
+                    40
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                81.5,
+                35.6
+            ]
+        },
+        "trans_39": {
+            "start": "conn_78",
+            "end": "conn_79",
+            "vertices": [
+                [
+                    59,
+                    22
+                ],
+                [
+                    59,
+                    22
+                ],
+                [
+                    59,
+                    26
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                0.6000000000000014
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                59.5,
+                22.6
+            ]
+        }
+    },
+    "notes": {
+        "TMP468_READ_TIMEOUT": "",
+        "SIG_I2C_RESULT_ADDR_NACK": "",
+        "trans_4": "",
+        "SIG_I2C_RESULT_DATA_NACK": "",
+        "tmp468_update_temp()": "- Update the temperature display\n- Send an event with the new value\n- Decrease the error counter",
+        "tmp468_reset_timer()": "Reset the timer counter.",
+        "tmp468_inc_error_counter()": "Increase the error counter.",
+        "tmp468_1ms_callback()": "Increase the timer counter.",
+        "tmp468_reset_temp()": "Reset the temperature to an undefined/invalid value and send an event with it.",
+        "tmp468_start_read()": "Send a read transaction to the TMP468.",
+        "tmp468_error_count": "Return true, if the error counter is greater or equal then the parameter.",
+        "tmp468_read_id()": "Try to read the ID register from the TMP468 by sending a write-read transaction to the I2C master.",
+        "entry": "",
+        "trans_7": "",
+        "SIG_I2C_RESULT_SUCCESS": "",
+        "tmp468_id_match()": "True, if the response data is equal to 0x190. See TMP468 datasheet section: 7.5.1.7 Identification Register",
+        "tmp468_timeout": "Evaluates to true if the internal timer counter is greater than or equal to the parameter.",
+        "trans_8": "",
+        "TMP468_MAX_ERROR_COUNT": "",
+        "tmp468_reset_pointer()": "Reset the pointer register in the TMP468 to 0, so all subsequent reads will access the temperature register.",
+        "send_online_event()": "Send a SIG_TMP468_ONLINE event. This can be used to detect successful initialization.",
+        "TMP468_RETRY_TIMEOUT": "",
+        "send_offline_event()": "Send a SIG_TMP468_OFFLINE event. This can be used to detect communication errors between the module and the I2C slave.",
+        "SIG_TMP468_READ": "",
+        "trans_13": "",
+        "SIG_TMP468_AVAIBLE": "",
+        "trans_6": "",
+        "SIG_TMP468_READ_SENSOR_STATUS": "",
+        "trans_14": "",
+        "TMP468_READ_PERIOD": "",
+        "trans_15": "",
+        "trans_16": "",
+        "tmp468_bus_scan()": "asdfsdf",
+        "tmp468_status_timeout": "",
+        "SIG_TMP468_READ_SUCCESS": "",
+        "TMP468_READ_REG_NUM": "",
+        "trans_11": "",
+        "trans_18": "",
+        "trans_1": "",
+        "tmp468_read_temp()": "",
+        "tmp468_increment_reg_index()": "",
+        "tmp468_read_temp2()": "",
+        "trans_20": "",
+        "tmp468_set_n_factor()": "",
+        "tmp468_temp_timeout": "",
+        "trans_27": "",
+        "trans_28": "",
+        "trans_29": "",
+        "trans_31": "",
+        "trans_30": "",
+        "trans_32": "",
+        "trans_34": "",
+        "trans_35": "",
+        "trans_37": "",
+        "trans_38": ""
+    },
+    "view": {
+        "translate": [
+            42.5,
+            -32.5
+        ],
+        "scale": 7
+    }
+}
+        
+
+ + diff --git a/docs/doc_gen/source/_templates/layout.html b/docs/doc_gen/source/_templates/layout.html new file mode 100644 index 00000000..38677065 --- /dev/null +++ b/docs/doc_gen/source/_templates/layout.html @@ -0,0 +1,5 @@ +{% extends "!layout.html" %} + +{% block extrahead %} + +{% endblock %} diff --git a/docs/doc_gen/source/conf.py b/docs/doc_gen/source/conf.py new file mode 100644 index 00000000..d1241c85 --- /dev/null +++ b/docs/doc_gen/source/conf.py @@ -0,0 +1,68 @@ +import sys +import os +import shutil +from pathlib import Path + +# Get the absolute path of the directory containing conf.py +dir_path = Path(__file__).parent.absolute() + +# Combine this with the relative path to get the absolute path to plantuml.jar +plantuml_jar_path = dir_path / 'plantuml.jar' + +plantuml = f'java -jar {plantuml_jar_path}' + + +# Protocols +sys.path.insert(0, os.path.abspath('../../../languages/c/modules/protocols/i2c_master/doc')) +shutil.copyfile("../../../languages/c/modules/protocols/i2c_master/doc/i2c_master.html", "./_static/i2c_master.html") + +sys.path.insert(0, os.path.abspath('../../../languages/c/modules/protocols/spi_master/doc')) +shutil.copyfile("../../../languages/c/modules/protocols/spi_master/doc/spi_master.html", "./_static/spi_master.html") + +sys.path.insert(0, os.path.abspath('../../../languages/c/modules/protocols/canopen/doc')) +shutil.copyfile("../../../languages/c/modules/protocols/canopen/doc/canopen.html", "./_static/canopen.html") + +# Devices +sys.path.insert(0, os.path.abspath('../../../languages/c/modules/devices/temperature/lm73/doc')) +shutil.copyfile("../../../languages/c/modules/devices/temperature/lm73/doc/lm73.html", "./_static/lm73.html") + +sys.path.insert(0, os.path.abspath('../../../languages/c/modules/devices/temperature/tmp468/doc')) +shutil.copyfile("../../../languages/c/modules/devices/temperature/tmp468/doc/tmp468.html", "./_static/tmp468.html") + + + +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'CHSM' +copyright = '2023, Janos Szeman' +author = 'Janos Szeman' +release = '1.0.0.' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = ['m2r', + 'sphinx_rtd_dark_mode', + 'sphinxcontrib.plantuml', + 'sphinxcontrib.datatemplates', + 'sphinxcontrib.drawio'] + +templates_path = ['_templates'] +exclude_patterns = [] + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'sphinx_rtd_theme' +html_static_path = ['_static'] +html_css_files = [ + 'decorator.css', +] +html_output_folder = '.' \ No newline at end of file diff --git a/docs/doc_gen/source/development/index.rst b/docs/doc_gen/source/development/index.rst new file mode 100644 index 00000000..5445f418 --- /dev/null +++ b/docs/doc_gen/source/development/index.rst @@ -0,0 +1,45 @@ +.. sectnum:: + :start: 2 + +Development ++++++++++++++ + +Overview +========= + +Hierarchical +------------- + +.. drawio-image:: ../_static/crf_SwAD.drawio + :format: svg + :page-index: 0 + +.. code-block:: text + + myproject/ + ├── conf.py + ├── plantuml.jar + ├── index.rst + ├── _build/ + ├── _static/ + ├── _templates/ + └── modules/ + ├── module1.rst + └── module2.rst + +Functional +----------- + +GUI +~~~~~ + +.. uml:: + + Alice -> Bob: Hi! + Alice <- Bob: How are you? + +.. include:: ./theming.rst + +Statemachine +~~~~~~~~~~~~~ + diff --git a/docs/doc_gen/source/development/theming.rst b/docs/doc_gen/source/development/theming.rst new file mode 100644 index 00000000..9077db7f --- /dev/null +++ b/docs/doc_gen/source/development/theming.rst @@ -0,0 +1,3 @@ + +Theming +----------------- diff --git a/docs/doc_gen/source/examples/index.rst b/docs/doc_gen/source/examples/index.rst new file mode 100644 index 00000000..d9d6dc01 --- /dev/null +++ b/docs/doc_gen/source/examples/index.rst @@ -0,0 +1,6 @@ +.. sectnum:: + :start: 4 + +Examples ++++++++++ + diff --git a/docs/doc_gen/source/index.rst b/docs/doc_gen/source/index.rst new file mode 100644 index 00000000..3af9b987 --- /dev/null +++ b/docs/doc_gen/source/index.rst @@ -0,0 +1,35 @@ + +CHSM +++++++ + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Introduction + + usage/index.rst + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Development + + development/index + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Modules + + modules/index + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Exaples + + examples/index + +.. image:: ./_static/first_view.png + +.. mdinclude:: ../../../README.md \ No newline at end of file diff --git a/docs/doc_gen/source/modules/index.rst b/docs/doc_gen/source/modules/index.rst new file mode 100644 index 00000000..a83e2250 --- /dev/null +++ b/docs/doc_gen/source/modules/index.rst @@ -0,0 +1,45 @@ +.. sectnum:: + :start: 3 + +Modules ++++++++++ + +i2c_master +=========== + +.. raw:: html + + + +tests +------ + +spi_master +=========== + +.. raw:: html + + + +tests +------ + +canopen +========= + +.. raw:: html + + + +tests +------ + +lm73 +======= + +.. raw:: html + + + +tests +------ diff --git a/docs/doc_gen/source/plantuml.jar b/docs/doc_gen/source/plantuml.jar new file mode 100644 index 00000000..429bd322 Binary files /dev/null and b/docs/doc_gen/source/plantuml.jar differ diff --git a/docs/doc_gen/source/usage/configuration.rst b/docs/doc_gen/source/usage/configuration.rst new file mode 100644 index 00000000..eab7719e --- /dev/null +++ b/docs/doc_gen/source/usage/configuration.rst @@ -0,0 +1,4 @@ + + +Configuration +============== \ No newline at end of file diff --git a/docs/doc_gen/source/usage/index.rst b/docs/doc_gen/source/usage/index.rst new file mode 100644 index 00000000..1e5c9211 --- /dev/null +++ b/docs/doc_gen/source/usage/index.rst @@ -0,0 +1,36 @@ +.. sectnum:: + :start: 1 + +Usage ++++++++ + +Introductions +=============== + + - The project consists of two main parts: an editor (CHSM) to draw state machines and a C library (CRF) that is able to drive the C code generated by the editor. + + - CHSM (editor) features: + - Written in Python and Vanilla Javascript. (Tested with Python 3.7+ and Chromium on RPi4 and with Chrome and Firefox on Win10.) + - The editor can generate C code from the drawings. + - Application file format is Html. Can be opened without the editor in view-only mode with any browser. + - Comments can be added to any string. + - Comments are displayed as tooltips on mouse hover and added as actual C comments to the generated code. + - Mostly follows the UML statecharts specification (event deferral is an exception). + + - The CRF (C Reactive Framework) design was heavily influenced by Miro Samek's excellent book: [Practical UML Statecharts in C/C++](http://www.state-machine.com/psicc2/). If you are not familiar with UML statechars then I recommend reading it. All the important concepts are explained very clearly in a first few chapters with easy to understand examples. + + - CRF features: + - Run-to-completion (RTC) execution model + - Written in C99. (Uses C11 atomics when available, if not, than the application must define two simple atomic functions.) + - State transitions are precalculated at code generation to avoid the runtime cost of hierarchy discovery. + - All states are represented by functions that process events with a switch statement. + - Optional event pools that provide simple O(1) dynamic memory handling to releive modules from buffering. + - Wait-free multi-producer single-consumer event queues for each state machines. + - Events can be deferred and recalled. + - Events can be safely generated and distributed by interrupts. + - Optional event generators for "analog" int32 values and uint8_t bitfields. + - Unit tests (using the Unity framework). + +.. include:: ./installation.rst +.. include:: ./configuration.rst +.. include:: ./quickstart.rst diff --git a/docs/doc_gen/source/usage/installation.rst b/docs/doc_gen/source/usage/installation.rst new file mode 100644 index 00000000..3f475659 --- /dev/null +++ b/docs/doc_gen/source/usage/installation.rst @@ -0,0 +1,26 @@ + +Installing for CHSM +==================== + +Of the GUI and code generation +------------------------------- + +#. Chrome. Theoretically other browsers can be used, but only Chrome was tested. +#. Python 3.7+ +#. You can install the packages like this: + +.. code-block:: bash + + pip3 install eel docopt + +Of the C unit tests +-------------------- +The C code uses the Unity unit testing framework for running the tests. The +CMake script that builds the tests assumes that the Unity and the CHSM repos +are in the same directory. + +Cloning: + +.. code-block:: bash + + git clone https://github.com/ThrowTheSwitch/Unity.git diff --git a/docs/doc_gen/source/usage/quickstart.rst b/docs/doc_gen/source/usage/quickstart.rst new file mode 100644 index 00000000..69b4adca --- /dev/null +++ b/docs/doc_gen/source/usage/quickstart.rst @@ -0,0 +1,3 @@ + +Quick Start +============ diff --git a/docs/modules b/docs/modules new file mode 160000 index 00000000..fb9c38b2 --- /dev/null +++ b/docs/modules @@ -0,0 +1 @@ +Subproject commit fb9c38b2d3128c580d0c2f9af0ae3870a83b4e4a diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..9a3d719f --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,6 @@ +sphinx>=7.0 +sphinx-rtd-theme>=2.0 +myst-parser>=2.0 +sphinx-copybutton +sphinx-design +sphinxcontrib-mermaid diff --git a/docs/sphinx/Makefile b/docs/sphinx/Makefile new file mode 100644 index 00000000..1ece1c30 --- /dev/null +++ b/docs/sphinx/Makefile @@ -0,0 +1,28 @@ +# Makefile for CHSM Sphinx documentation + +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +.PHONY: help clean html pdf linkcheck + +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +clean: + rm -rf $(BUILDDIR) + +html: + @$(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + @echo "Build finished. HTML pages are in $(BUILDDIR)/html." + +pdf: + @$(SPHINXBUILD) -M latexpdf "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + @echo "Build finished. PDF is in $(BUILDDIR)/latex." + +linkcheck: + @$(SPHINXBUILD) -M linkcheck "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/sphinx/_static/custom.css b/docs/sphinx/_static/custom.css new file mode 100644 index 00000000..3142ffec --- /dev/null +++ b/docs/sphinx/_static/custom.css @@ -0,0 +1,28 @@ +/* CHSM Documentation — Custom Styles */ + +:root { + --chsm-accent: #0077b6; + --chsm-dark: #1e1e1e; +} + +/* Signature table styling */ +table.field-list td { + padding: 4px 8px; +} + +/* Improved code block contrast */ +div.highlight pre { + font-size: 0.88em; + line-height: 1.5; +} + +/* API reference parameter tables */ +.rst-content table.docutils td, +.rst-content table.docutils th { + padding: 6px 12px; +} + +/* Sidebar logo area */ +.wy-side-nav-search { + background-color: var(--chsm-dark) !important; +} diff --git a/docs/sphinx/appendices/changelog.rst b/docs/sphinx/appendices/changelog.rst new file mode 100644 index 00000000..200bcd6f --- /dev/null +++ b/docs/sphinx/appendices/changelog.rst @@ -0,0 +1,32 @@ +.. _appendix_changelog: + +========================== +Changelog +========================== + +v1.0.0 +======= + +*Current release.* + +Features +--------- + +* **Visual State Editor** — Browser-based hierarchical state machine + designer with drag-and-drop states and transitions. +* **Multi-language code generation** — C, Python, JavaScript, Java, + VHDL output from a single model. +* **CRF Runtime Library** — Zero-malloc, ISR-safe active-object + framework for embedded C targets. +* **New Module Wizard** — Cookiecutter-based project scaffolding with + I2C/SPI peripheral templates. +* **Debug Channel** — Real-time TCP debug server for monitoring state + changes from the GUI. +* **Configurable footprint** — ``CHSM_CFG_LITE``, ``CHSM_CFG_NO_FAULT_CNT``, + ``CHSM_CFG_NO_DEBUG`` flags for RAM/flash optimisation. +* **Theming** — Default, Solarized Light, and Solarized Dark editor + themes. +* **CMake integration** — ``add_module_lib`` / ``add_module_test`` + helper macros with Unity test framework support. +* **Sphinx + Typst documentation** — Enterprise-grade docs with HTML, + PDF (LaTeX), and Typst output. diff --git a/docs/sphinx/appendices/faq.rst b/docs/sphinx/appendices/faq.rst new file mode 100644 index 00000000..78e93cb1 --- /dev/null +++ b/docs/sphinx/appendices/faq.rst @@ -0,0 +1,72 @@ +.. _appendix_faq: + +========================== +FAQ +========================== + +General +======== + +**What is CHSM?** + CHSM (C Hierarchical State Machine) is a visual editor and code + generation framework for designing UML-style hierarchical state + machines and generating runtime code for embedded systems. + +**Which languages are supported?** + C, Python, JavaScript, Java, and VHDL. + +**Is the generated C code suitable for safety-critical systems?** + The runtime uses no dynamic memory, no recursion beyond bounded + nesting, and deterministic execution. It can serve as a foundation + for safety-relevant code, but formal qualification (e.g. DO-178C, + IEC 61508) requires additional verification steps. + +Runtime +======== + +**How deep can states be nested?** + Up to ``CHSM_MAX_NESTING_LEVEL`` (default 8). Increase the constant + in ``chsm.h`` if deeper hierarchies are required. + +**What happens when a queue overflows?** + ``cqueue_put`` returns ``-1`` and increments ``fault_cnt`` (unless + disabled). The event is **not** silently dropped. + +**Can I use CHSM with an RTOS?** + Yes. Call ``crf_step()`` from a dedicated task. Queue put + operations are ISR-safe. Protect ``crf_step`` with a mutex if + multiple tasks consume events. + +**How do I reduce RAM usage?** + Enable ``CHSM_CFG_LITE``, ``CHSM_CFG_NO_FAULT_CNT``, and + ``CHSM_CFG_NO_DEBUG``. See :ref:`config_runtime_tuning`. + +Code Generation +================ + +**Can I regenerate code without losing my function implementations?** + Yes. The generator outputs the state-machine skeleton + (``.c/.h``) and a separate functions file + (``_functions.c/.h``). Only the skeleton is overwritten; + your function bodies are preserved. + +**How do I add a new target language?** + 1. Create a ``gui/_gen/`` directory. + 2. Write a ``render.py`` with a ``render(ast)`` function. + 3. Add a Jinja2 ``.j2`` template. + 4. Register the language in the editor's Generate menu. + +GUI +==== + +**The editor window doesn't open.** + Ensure Chromium or Chrome is installed. Eel requires a Chromium-based + browser. Alternatively, set ``eel.start(..., mode='default')`` to + use the system default browser. + +**Can I run the editor headless for CI?** + Use the code-generation modules directly from Python without the GUI: + + .. code-block:: bash + + python -m gui.c_gen.hsm.sm model.json --output build/gen/ diff --git a/docs/sphinx/appendices/license.rst b/docs/sphinx/appendices/license.rst new file mode 100644 index 00000000..1ae3e047 --- /dev/null +++ b/docs/sphinx/appendices/license.rst @@ -0,0 +1,32 @@ +.. _appendix_license: + +========================== +Licence +========================== + +CHSM is distributed under the MIT Licence. + +.. code-block:: text + + MIT License + + Copyright (c) Janos Szeman + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/docs/sphinx/architecture/crf_runtime.rst b/docs/sphinx/architecture/crf_runtime.rst new file mode 100644 index 00000000..fa316417 --- /dev/null +++ b/docs/sphinx/architecture/crf_runtime.rst @@ -0,0 +1,113 @@ +.. _crf_runtime: + +=========================== +CRF Runtime Library +=========================== + +The C Reactive Framework (CRF) provides a deterministic active-object +runtime for embedded targets. + +Design Principles +================== + +* **Run-to-completion (RTC):** Each event is fully processed before the + next one is dequeued. No preemption within a state machine step. +* **Static memory only:** All queues and pools are pre-allocated. + No ``malloc`` at runtime. +* **ISR-safe event posting:** ``cqueue_put`` is wait-free (atomic + compare-and-swap) so interrupts can inject events safely. +* **Pre-calculated transitions:** The code generator computes exit/entry + paths at generation time; the runtime does not walk the hierarchy. + +Execution Model +================ + +.. mermaid:: + + sequenceDiagram + participant ISR as Interrupt / Thread + participant Q as Event Queue + participant CRF as crf_step() + participant HSM as State Handler + + ISR->>Q: cqueue_put(event) + loop Main loop + CRF->>Q: cqueue_get() + Q-->>CRF: event pointer + CRF->>HSM: state_handler(self, event) + HSM-->>CRF: HANDLED / TRANSITION / IGNORED + CRF->>CRF: crf_gc(event) + end + +The ``crf_step()`` function iterates over all registered HSMs, dequeues one +event per HSM and dispatches it to the current state handler. After +dispatch, events with a reference count of zero are returned to their pool. + +Struct Relationships +===================== + +.. mermaid:: + + classDiagram + class crf_tst { + +chsm_tst **chsm_ap + +cpool_tst *pool_ast + +uint16_t pool_cnt_u16 + +crf_step() bool + +crf_new_event() void* + +crf_gc() void + } + class chsm_tst { + +cqueue_tst event_q_st + +cqueue_tst defer_q_st + +state_handler_pft + +send() + +next : chsm_tst* + } + class cqueue_tst { + +cevent_tst **events + +uint16_t max + +atomic head, tail + +put() / get() + } + class cpool_tst { + +uint8_t *pool + +uint16_t esize, ecnt + +atomic head + +new() / gc() + } + class cevent_tst { + +signal_t sig + +gc_info_tst gc_info + } + crf_tst --> chsm_tst : manages + crf_tst --> cpool_tst : owns + chsm_tst --> cqueue_tst : embeds 2× + cpool_tst --> cevent_tst : allocates + cqueue_tst --> cevent_tst : stores pointers + +Thread Safety +============== + +.. list-table:: + :widths: 30 20 50 + :header-rows: 1 + + * - Function + - Safety + - Notes + * - ``cqueue_put`` + - ISR-safe + - Atomic CAS on head; multiple producers allowed. + * - ``cqueue_get`` + - Main-thread only + - Single consumer assumed. + * - ``cpool_new`` + - ISR-safe + - CAS-based free-list pop. + * - ``cpool_gc`` + - ISR-safe + - CAS-based free-list push. + * - ``crf_step`` + - Main-thread only + - Iterates HSMs sequentially. diff --git a/docs/sphinx/architecture/event_model.rst b/docs/sphinx/architecture/event_model.rst new file mode 100644 index 00000000..b0a85f1a --- /dev/null +++ b/docs/sphinx/architecture/event_model.rst @@ -0,0 +1,145 @@ +.. _event_model: + +======================== +Event Model +======================== + +Events are the sole communication mechanism between state machines and +the outside world. Every event carries a signal identifier and +garbage-collection metadata. + +Base Event Structure +===================== + +.. code-block:: c + + typedef struct cevent_tst { + signal_t sig; /* event type identifier */ + gc_info_tst gc_info; /* pool id + reference count */ + } cevent_tst; + +``signal_t`` defaults to ``uint16_t`` and can be redefined via the +``SIGNAL_T`` preprocessor macro before including ``cevent.h``. + +Signal Classes +=============== + +Signals are grouped into *classes* of ``CRF_SIGNAL_CLASS_SIZE`` (100) +each. Two classes are reserved: + +.. list-table:: + :widths: 35 15 50 + :header-rows: 1 + + * - Constant + - Value + - Purpose + * - ``C_SIG_NONE`` + - 0 + - Null signal — no event. + * - ``C_SIG_INIT`` + - 1 + - Internal initialisation signal. + * - ``CRF_SIGNAL_CLASS_MOD_INTERNAL`` + - 1 + - Module-internal signal class. + * - ``CRF_SIGNAL_CLASS_START`` + - 2 + - First application-defined class. + +Use the ``SIGNAL_FROM_CLASS`` macro to compute the base signal number +for a given class: + +.. code-block:: c + + #define MY_CLASS 3 + enum my_signals { + SIG_BUTTON_PRESS = SIGNAL_FROM_CLASS(MY_CLASS), /* 300 */ + SIG_BUTTON_RELEASE, /* 301 */ + }; + +Derived Events +=============== + +Application events extend ``cevent_tst`` by placing it as the first +member: + +.. code-block:: c + + typedef struct { + cevent_tst super; + uint8_t button_id; + uint32_t timestamp; + } button_event_tst; + +The framework allocates and casts through the ``CRF_NEW`` and +``CRF_SIG_VAR`` macros: + +.. code-block:: c + + /* Allocate */ + #define SIG_BUTTON_PRESS_TYPE button_event_tst + button_event_tst *e = CRF_NEW(SIG_BUTTON_PRESS); + e->button_id = 3; + e->timestamp = HAL_GetTick(); + CRF_EMIT(e); + + /* Receive */ + CRF_SIG_VAR(SIG_BUTTON_PRESS, btn, e_pst); + process(btn->button_id); + +Garbage Collection Metadata +============================ + +.. code-block:: c + + typedef struct { + uint16_t ref_cnt : 12; /* max 4095 references */ + uint16_t pool_id : 4; /* pool 0 = static event */ + } gc_info_tst; + +* **ref_cnt** — Incremented by ``cevent_ref_cnt_inc`` when an event is + posted to a queue, decremented by ``cevent_ref_cnt_dec`` after + dispatch. When it reaches zero the framework returns the event to + its pool. +* **pool_id** — Identifies the ``cpool_tst`` from which the event was + allocated. A ``pool_id`` of ``CEVENT_INVALID_POOL`` (0) indicates + a static / const event that must never be freed. + +Reference Counting Flow +======================== + +.. mermaid:: + + sequenceDiagram + participant App as Application + participant CRF as crf + participant Pool as cpool + + App->>CRF: CRF_NEW(SIG_X) → ref_cnt=0 + CRF->>Pool: cpool_new() + Pool-->>CRF: event* + CRF-->>App: event* + App->>CRF: CRF_POST(event, &q) → ref_cnt++ + Note over CRF: dispatch to handler + CRF->>CRF: crf_gc(event) → ref_cnt-- + alt ref_cnt == 0 + CRF->>Pool: cpool_gc(event) → return to free list + end + +Static Events +============== + +Events that live for the entire program lifetime (e.g. timer ticks or +constant commands) can be declared as ``const`` globals with +``pool_id = 0``: + +.. code-block:: c + + static const cevent_tst tick_event = { + .sig = SIG_TICK, + .gc_info = {.ref_cnt = 0, .pool_id = CEVENT_INVALID_POOL} + }; + +Static events are never garbage-collected regardless of their reference +count. diff --git a/docs/sphinx/architecture/memory_management.rst b/docs/sphinx/architecture/memory_management.rst new file mode 100644 index 00000000..dd391206 --- /dev/null +++ b/docs/sphinx/architecture/memory_management.rst @@ -0,0 +1,164 @@ +.. _memory_management: + +============================ +Memory Management +============================ + +CHSM targets bare-metal and RTOS environments where dynamic allocation +is forbidden. All memory is statically pre-allocated; the runtime never +calls ``malloc``. + +Pool Allocator — ``cpool`` +=========================== + +Each ``cpool_tst`` manages a contiguous buffer partitioned into +equal-sized blocks. Allocation and deallocation are lock-free (CAS +based). + +Initialisation +-------------- + +.. code-block:: c + + #define EVT_SIZE sizeof(button_event_tst) + #define EVT_COUNT 8 + + static uint8_t pool_buf[EVT_SIZE * EVT_COUNT]; + static cpool_tst pool; + + cpool_init(&pool, pool_buf, EVT_SIZE, EVT_COUNT); + +``cpool_init`` threads a free-list through the buffer: each block stores +the byte offset to the next free block. The terminator value is +``0xFFFF``. + +Allocation — CAS Pop +--------------------- + +.. code-block:: text + + head ──► [block 0] ──► [block 1] ──► ... ──► 0xFFFF + + 1. Read head (atomically). + 2. Compute next = *(uint16_t *)block[head]. + 3. CAS(head, head, next). + • Success: return block pointer. + • Failure: retry from step 1. + +Because the CAS loop is bounded to the pool size, ``cpool_new`` is +wait-free in practice. + +Deallocation — CAS Push +------------------------- + +.. code-block:: text + + 1. Read head (atomically). + 2. Store head offset inside the freed block. + 3. CAS(head, old_head, freed_block_offset). + • Success: done. + • Failure: retry from step 1. + +``cpool_gc`` additionally validates the pool by checking the event's +``pool_id`` against the pool array index. + +Queue — ``cqueue`` +==================== + +``cqueue_tst`` is a circular FIFO of ``cevent_tst`` pointers. The +capacity **must** be a power of two for efficient masking. + +Operations +----------- + +.. list-table:: + :widths: 25 15 60 + :header-rows: 1 + + * - Function + - Producer + - Behaviour + * - ``cqueue_put`` + - ISR / Thread + - Append to right (tail). Atomic increment of ``head``. + * - ``cqueue_put_left`` + - ISR / Thread + - Prepend to left — used for priority / recalled events. + * - ``cqueue_get`` + - Main only + - Pop from left (tail side). Single-consumer. + * - ``cqueue_get_right`` + - Main only + - Pop from right — used by ``chsm_recall``. + +Overflow Handling +------------------ + +When the queue is full, ``cqueue_put`` returns ``-1`` and increments +``fault_cnt`` (unless disabled by ``CHSM_CFG_NO_FAULT_CNT``). +The event is **not** silently dropped — the caller can inspect the +return value and take corrective action. + +Zero-Malloc Integration +========================= + +A typical system declares all pools and queues statically: + +.. code-block:: c + + /* Event buffers */ + static const cevent_tst *q_buf[16]; + static const cevent_tst *d_buf[4]; + + /* Pool buffer */ + static uint8_t pool_buf[sizeof(my_event_tst) * 8]; + + /* Instances */ + static cpool_tst pools[1]; + static chsm_tst *machines[] = {(chsm_tst *)&my_hsm, NULL}; + static crf_tst crf; + + void init(void) { + cpool_init(&pools[0], pool_buf, + sizeof(my_event_tst), 8); + chsm_ctor((chsm_tst *)&my_hsm, + my_init_state, q_buf, 16, 4); + crf_init(&crf, machines, pools, 1); + chsm_init((chsm_tst *)&my_hsm); + } + + void main_loop(void) { + while (1) { + crf_step(&crf); + __WFI(); /* sleep until next interrupt */ + } + } + +RAM Budget +=========== + +.. list-table:: + :widths: 35 25 40 + :header-rows: 1 + + * - Component + - Size (bytes) + - Notes + * - ``cevent_tst`` + - 4 + - 2 (signal) + 2 (gc_info) + * - ``cqueue_tst`` + - 28 / 16 + - 28 normal, 16 with ``CHSM_CFG_LITE`` + * - ``cpool_tst`` + - 20 / 10 + - 20 normal, 10 with ``CHSM_CFG_LITE`` + * - ``crf_tst`` + - 48 / 12 + - 48 normal, 12 with ``CHSM_CFG_LITE`` + * - Queue buffer + - ``N × sizeof(void*)`` + - Pointer array — 4 B each on Cortex-M + * - Pool buffer + - ``N × event_size`` + - Aligned to event struct size diff --git a/docs/sphinx/architecture/overview.rst b/docs/sphinx/architecture/overview.rst new file mode 100644 index 00000000..43bd52e9 --- /dev/null +++ b/docs/sphinx/architecture/overview.rst @@ -0,0 +1,108 @@ +.. _architecture_overview: + +====================== +Architecture Overview +====================== + +CHSM is organised into three layers that can be used independently. + +.. mermaid:: + + graph TD + A[GUI Editor
Python + JS] --> B[Code Generator
AST → C / Py / JS / Java / VHDL] + B --> C[CRF Runtime
C11 library] + C --> D[Target Hardware
ARM Cortex-M / POSIX] + +Layers +====== + +GUI Editor +---------- + +A browser-based drawing tool served by a Python Eel backend. +State machines are stored as JSON embedded in self-contained HTML files, +making them viewable in any browser without the editor. + +* **Frontend:** Vanilla JavaScript (no framework), SVG canvas. +* **Backend:** ``chsm_backend.py`` — Eel web-socket bridge, file I/O, + code generation trigger, debug server. +* **Themes:** Solarized Light, Solarized Dark, Default. + +Code Generator +-------------- + +Transforms the model JSON into compilable source code. + +.. list-table:: + :widths: 15 20 65 + :header-rows: 1 + + * - Language + - Module + - Output + * - C + - ``gui/c_gen/hsm/sm.py`` + - AST-based ``.c`` + ``_functions.h`` via ``ast.py`` + * - Python + - ``gui/py_gen/render.py`` + - Jinja2 template → ``.py`` + * - JavaScript + - ``gui/js_gen/render.py`` + - Jinja2 template → ``.js`` + * - Java + - ``gui/java_gen/render.py`` + - Jinja2 template → ``.java`` + * - VHDL + - ``gui/vhdl_gen/render.py`` + - Jinja2 template → ``.vhd`` + +The C generator (``sm.py``) constructs a full abstract syntax tree and emits +C source through ``__str__`` methods on the AST nodes. All other generators +use the shared Jinja state machine class (``sm_jinja.py``) with +language-specific templates. + +CRF Runtime Library +------------------- + +A self-contained C11 library at ``languages/c/c_rf/``. + +.. list-table:: + :widths: 20 80 + :header-rows: 1 + + * - File + - Purpose + * - ``chsm.c / .h`` + - Hierarchical state machine core (ctor, init, dispatch, defer, recall) + * - ``cevent.h`` + - 4-byte base event (signal + GC bit-field) + * - ``cqueue.c / .h`` + - Wait-free MPSC event queue (atomic head/tail) + * - ``cpool.c / .h`` + - Lock-free O(1) memory pool (CAS-based allocation) + * - ``crf.c / .h`` + - Active object framework (new, post, step, gc) + * - ``chsm_cfg.h`` + - Compile-time footprint configuration + +Directory Layout +================= + +:: + + chsm/ + ├── gui/ Editor + code generators + │ ├── chsm_backend.py Eel backend + │ ├── c_gen/ C code generator (AST-based) + │ ├── py_gen/ Python generator (Jinja2) + │ ├── js_gen/ JavaScript generator (Jinja2) + │ ├── java_gen/ Java generator (Jinja2) + │ ├── vhdl_gen/ VHDL generator (Jinja2) + │ ├── module_generator/ New-module wizard (cookiecutter) + │ └── web/ HTML/CSS/JS frontend + ├── languages/ + │ └── c/ + │ ├── c_rf/ CRF runtime library + │ ├── modules/ Protocol & device driver modules + │ └── unity/ Unity test framework (submodule) + └── docs/ This documentation diff --git a/docs/sphinx/c_api/cevent.rst b/docs/sphinx/c_api/cevent.rst new file mode 100644 index 00000000..86857506 --- /dev/null +++ b/docs/sphinx/c_api/cevent.rst @@ -0,0 +1,142 @@ +.. _api_cevent: + +========================= +``cevent`` — Event Base +========================= + +.. contents:: On this page + :local: + :depth: 2 + +Header +====== + +.. code-block:: c + + #include + +Types +===== + +``signal_t`` +------------- + +Event signal identifier. Defaults to ``uint16_t``. + +To override, define ``SIGNAL_T`` before including ``cevent.h``: + +.. code-block:: c + + #define SIGNAL_T uint8_t /* save 1 byte per event */ + #include + +``gc_info_tst`` +---------------- + +Garbage-collection metadata packed into 16 bits: + +.. code-block:: c + + typedef struct { + uint16_t ref_cnt : 12; /* 0 – 4095 */ + uint16_t pool_id : 4; /* 0 – 15 */ + } gc_info_tst; + +``cevent_tst`` +--------------- + +Base event structure — **all** events must start with this layout: + +.. code-block:: c + + typedef struct cevent_tst { + signal_t sig; + gc_info_tst gc_info; + } cevent_tst; + +Total size: 4 bytes (with default ``signal_t``). + +Constants +========= + +.. list-table:: + :widths: 40 15 45 + :header-rows: 1 + + * - Name + - Value + - Description + * - ``CEVENT_INVALID_POOL`` + - 0 + - Pool ID for static events (never freed). + * - ``CRF_SIGNAL_CLASS_MOD_INTERNAL`` + - 1 + - Module-internal signal class. + * - ``CRF_SIGNAL_CLASS_START`` + - 2 + - First application-defined signal class. + * - ``CRF_SIGNAL_CLASS_SIZE`` + - 100 + - Signals per class. + +Macros +====== + +``SIGNAL_FROM_CLASS`` +---------------------- + +.. code-block:: c + + #define SIGNAL_FROM_CLASS(CLASS) ((CLASS) * CRF_SIGNAL_CLASS_SIZE) + +Compute the base signal value for a given class ID. + +Functions +========= + +``cevent_ref_cnt_inc`` +----------------------- + +.. code-block:: c + + static inline void + cevent_ref_cnt_inc(const cevent_tst *e_pst); + +Increment the event's reference count. No-op if ``pool_id`` is +``CEVENT_INVALID_POOL``. + +``cevent_ref_cnt_dec`` +----------------------- + +.. code-block:: c + + static inline void + cevent_ref_cnt_dec(const cevent_tst *e_pst); + +Decrement the event's reference count. No-op if ``pool_id`` is +``CEVENT_INVALID_POOL``. + +Deriving Custom Events +======================= + +.. code-block:: c + + /* 1. Define the struct */ + typedef struct { + cevent_tst super; /* MUST be first member */ + int16_t value; + uint8_t channel; + } adc_event_tst; + + /* 2. Bind signal → type */ + #define SIG_ADC_READY_TYPE adc_event_tst + + /* 3. Allocate */ + adc_event_tst *e = CRF_NEW(SIG_ADC_READY); + e->value = adc_read(); + e->channel = 4; + CRF_EMIT(e); + + /* 4. Receive */ + CRF_SIG_VAR(SIG_ADC_READY, adc, e_pst); + handle(adc->value, adc->channel); diff --git a/docs/sphinx/c_api/chsm.rst b/docs/sphinx/c_api/chsm.rst new file mode 100644 index 00000000..c55e8c17 --- /dev/null +++ b/docs/sphinx/c_api/chsm.rst @@ -0,0 +1,207 @@ +.. _api_chsm: + +=========================== +``chsm`` — State Machine +=========================== + +.. contents:: On this page + :local: + :depth: 2 + +Header +====== + +.. code-block:: c + + #include + +Types +===== + +``chsm_tst`` +------------- + +Opaque state-machine instance. Application state machines embed this +struct as their first member: + +.. code-block:: c + + typedef struct my_hsm_tst { + chsm_tst base; /* must be first */ + uint32_t counter; /* application data */ + } my_hsm_tst; + +``chsm_state_tpft`` +--------------------- + +State handler function pointer: + +.. code-block:: c + + typedef chsm_result_ten (*chsm_state_tpft)( + chsm_tst *self, + const cevent_tst *e_pst); + +``chsm_user_func_tpft`` +------------------------- + +User action (entry / exit) function pointer: + +.. code-block:: c + + typedef void (*chsm_user_func_tpft)( + chsm_tst *self, + const cevent_tst *e_pst); + +``chsm_result_ten`` +-------------------- + +Return value from state handlers: + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Value + - Meaning + * - ``C_RES_HANDLED`` + - Event processed by this state. + * - ``C_RES_TRANS`` + - Event triggers a state transition. + * - ``C_RES_PARENT`` + - Delegate to parent state handler. + * - ``C_RES_IGNORED`` + - Event intentionally ignored. + * - ``C_RES_GUARDS`` + - Guard condition(s) evaluated — none true. + +``chsm_call_ctx_st`` +--------------------- + +Internal call context used during event dispatch. Not normally accessed +by application code. + +.. code-block:: c + + typedef struct { + chsm_user_func_tpft exit_stack_apft[CHSM_MAX_NESTING_LEVEL]; + chsm_user_func_tpft *exit_ppft; + chsm_state_tpft start_pft; + } chsm_call_ctx_st; + +Constants +========= + +.. list-table:: + :widths: 40 60 + :header-rows: 1 + + * - Name + - Description + * - ``CHSM_MAX_NESTING_LEVEL`` + - Maximum hierarchy depth (default 8). + * - ``C_SIG_NONE`` + - Null signal (0). + * - ``C_SIG_INIT`` + - Initialisation signal (1). + +Functions +========= + +``chsm_ctor`` +-------------- + +.. code-block:: c + + void chsm_ctor(chsm_tst *self, + chsm_state_tpft init_state_pft, + const cevent_tst **events, + uint16_t event_q_len, + uint16_t defer_q_len); + +Construct a state machine. + +:param self: Pointer to the state-machine instance. +:param init_state_pft: Initial (top-level) state handler. +:param events: Pre-allocated pointer array shared by event & defer queues. +:param event_q_len: Size of the event queue (power of 2). +:param defer_q_len: Size of the defer queue (power of 2). + +``chsm_init`` +-------------- + +.. code-block:: c + + void chsm_init(chsm_tst *self); + +Send the ``C_SIG_INIT`` event and execute the initial transition chain. +Call once after ``chsm_ctor`` and ``crf_init``. + +``chsm_dispatch`` +------------------ + +.. code-block:: c + + void chsm_dispatch(chsm_tst *self, + const cevent_tst *e_pst); + +Dispatch an event to the current state handler. If the handler returns +``C_RES_PARENT``, the event is propagated up the hierarchy. + +``chsm_defer`` +--------------- + +.. code-block:: c + + void chsm_defer(chsm_tst *self, + const cevent_tst *e_pst); + +Move the current event to the defer queue. The event's reference count +is incremented. + +``chsm_recall`` +---------------- + +.. code-block:: c + + void chsm_recall(chsm_tst *self, + const cevent_tst *e_pst); + +Move all events from the defer queue to the front of the main event +queue. + +Inline Helpers +=============== + +``chsm_transition`` +-------------------- + +.. code-block:: c + + static inline chsm_result_ten + chsm_transition(chsm_tst *self, chsm_state_tpft target); + +Record a transition target and return ``C_RES_TRANS``. Used inside +state handlers: + +.. code-block:: c + + return chsm_transition(self, my_target_state); + +``chsm_handled`` +----------------- + +.. code-block:: c + + static inline chsm_result_ten chsm_handled(chsm_tst *self); + +Return ``C_RES_HANDLED``. + +``chsm_ignored`` +----------------- + +.. code-block:: c + + static inline chsm_result_ten chsm_ignored(chsm_tst *self); + +Return ``C_RES_IGNORED``. diff --git a/docs/sphinx/c_api/chsm_cfg.rst b/docs/sphinx/c_api/chsm_cfg.rst new file mode 100644 index 00000000..d4d05aab --- /dev/null +++ b/docs/sphinx/c_api/chsm_cfg.rst @@ -0,0 +1,125 @@ +.. _api_chsm_cfg: + +======================================= +``chsm_cfg`` — Build Configuration +======================================= + +.. contents:: On this page + :local: + :depth: 2 + +Header +====== + +.. code-block:: c + + #include + +Include this header **before** any other CRF header, or pass the macros +as compiler flags (``-DCHSM_CFG_LITE``). + +Configuration Macros +===================== + +``CHSM_CFG_LITE`` +------------------- + +Strip virtual-dispatch function pointers from ``cqueue_tst``, +``cpool_tst``, and ``crf_tst``. All calls become direct function +invocations, enabling the compiler to inline them. + +**Impact:** + +* Removes 4 function pointers from ``cqueue_tst`` (−16 B per queue on 32-bit). +* Removes 2 function pointers from ``cpool_tst`` (−8 B per pool). +* Removes 5 function pointers from ``crf_tst`` (−20 B per framework). +* Enables inlining of hot-path queue and pool operations. + +``CHSM_CFG_NO_FAULT_CNT`` +--------------------------- + +Remove the ``fault_cnt`` field from ``cqueue_tst``. + +**Impact:** + +* Saves 4 bytes per queue instance (2 queues per HSM → −8 B / HSM). +* Queue overflow is still reported via the ``-1`` return code; the + counter is simply unavailable for diagnostics. + +``CHSM_CFG_NO_DEBUG`` +----------------------- + +Omit debug-log function pointer and the state-name buffer from +generated code. + +**Impact:** + +* Approximately −20 bytes per module (varies with generated code). +* The TCP debug channel in the GUI will not receive state-change + notifications from modules compiled without debug. + +RAM Savings Summary +==================== + +The following table shows approximate RAM savings on a 32-bit +Cortex-M target with one HSM, one pool, and one framework instance. + +.. list-table:: + :widths: 35 20 20 25 + :header-rows: 1 + + * - Configuration + - Queue (×2) + - Pool + - Framework + * - Default (all features) + - 56 B + - 20 B + - 48 B + * - ``CHSM_CFG_LITE`` + - 24 B + - 10 B + - 12 B + * - ``+ NO_FAULT_CNT`` + - 16 B + - 10 B + - 12 B + * - ``+ NO_DEBUG`` + - 16 B + - 10 B + - 12 B + +**Total savings** (all three flags): **~86 bytes** per HSM system. + +Recommended Profiles +===================== + +.. list-table:: + :widths: 20 40 40 + :header-rows: 1 + + * - Profile + - Flags + - Use Case + * - Development + - *(none)* + - Full diagnostics, debug logging, fault counters. + * - Release + - ``CHSM_CFG_LITE`` + - Reduced RAM, keep overflow diagnostics. + * - Minimal + - ``LITE + NO_FAULT_CNT + NO_DEBUG`` + - Smallest footprint for constrained MCUs (e.g. Cortex-M0 with ≤8 KB RAM). + +CMake Integration +================== + +.. code-block:: cmake + + target_compile_definitions(my_target PRIVATE + CHSM_CFG_LITE + CHSM_CFG_NO_FAULT_CNT + CHSM_CFG_NO_DEBUG + ) + +Or define them in a shared ``chsm_cfg.h`` included by all modules. diff --git a/docs/sphinx/c_api/cpool.rst b/docs/sphinx/c_api/cpool.rst new file mode 100644 index 00000000..594268e2 --- /dev/null +++ b/docs/sphinx/c_api/cpool.rst @@ -0,0 +1,164 @@ +.. _api_cpool: + +============================== +``cpool`` — Memory Pool +============================== + +.. contents:: On this page + :local: + :depth: 2 + +Header +====== + +.. code-block:: c + + #include + +Overview +======== + +``cpool_tst`` is a lock-free, fixed-size block allocator. It manages a +contiguous byte buffer partitioned into equal-sized slots. Free slots +are chained via an intrusive singly-linked list; allocation and +deallocation use atomic compare-and-swap. + +Types +===== + +``cpool_tst`` +-------------- + +.. code-block:: c + + typedef struct cpool_tst { + #ifndef CHSM_CFG_LITE + void* (*new)(struct cpool_tst *); + bool (*gc)(struct cpool_tst *, const cevent_tst *); + #endif + uint8_t *pool; + uint16_t esize; /* bytes per block */ + uint16_t ecnt; /* total block count */ + atomic_uint16_t head; /* offset to first free block */ + } cpool_tst; + +Constants +========= + +.. list-table:: + :widths: 40 60 + :header-rows: 1 + + * - Name + - Description + * - ``CPOOL_TERMINATOR`` (0xFFFF) + - End-of-chain marker in the free list. + +Functions +========= + +``cpool_init`` +--------------- + +.. code-block:: c + + void cpool_init(cpool_tst *self, + uint8_t *buff, + uint16_t event_size, + uint16_t event_count); + +Initialise the pool and thread the free list through ``buff``. + +:param self: Pool instance. +:param buff: Pre-allocated buffer (``event_size × event_count`` bytes). +:param event_size: Size of each event block. +:param event_count: Number of blocks. + +After initialisation the free list is: + +.. code-block:: text + + head → [block 0] → [block 1] → … → [block N-1] → 0xFFFF + +``cpool_new`` +-------------- + +.. code-block:: c + + void* cpool_new(cpool_tst *self); + +Allocate one block from the pool. + +:returns: Pointer to the allocated block, or ``NULL`` if the pool is + exhausted. + +**Algorithm (CAS pop):** + +1. ``old_head = atomic_load(self->head)`` +2. If ``old_head == CPOOL_TERMINATOR`` → return ``NULL`` +3. ``next = *(uint16_t *)(pool + old_head)`` +4. ``CAS(&self->head, old_head, next)`` + — on failure, retry from step 1. + +**Thread safety:** ISR-safe. + +``cpool_gc`` +------------- + +.. code-block:: c + + bool cpool_gc(cpool_tst *self, + const cevent_tst *e_pst); + +Return an event block to the pool. + +:param self: Pool instance. +:param e_pst: Event to free. +:returns: ``true`` if the event belonged to this pool and was freed, + ``false`` otherwise. + +**Algorithm (CAS push):** + +1. Compute block offset from ``e_pst``. +2. ``old_head = atomic_load(self->head)`` +3. Store ``old_head`` inside the freed block (next pointer). +4. ``CAS(&self->head, old_head, block_offset)`` + — on failure, retry from step 2. + +**Thread safety:** ISR-safe. + +Dispatch Macros +================ + +.. list-table:: + :widths: 30 35 35 + :header-rows: 1 + + * - Macro + - Normal mode + - ``CHSM_CFG_LITE`` + * - ``CPOOL_NEW(p)`` + - ``(p)->new((p))`` + - ``cpool_new((p))`` + * - ``CPOOL_GC(p, e)`` + - ``(p)->gc((p), (e))`` + - ``cpool_gc((p), (e))`` + +Sizing Guidelines +================== + +1. Count the peak number of events that can be in-flight simultaneously + (queued + deferred + being dispatched). +2. Add a margin of 2–4 events for ISR bursts. +3. Choose ``event_size`` as the **largest** derived event struct that + will be allocated from the pool. + +.. code-block:: c + + /* Example: up to 12 simultaneous ADC events */ + #define ADC_POOL_SIZE 12 + static uint8_t adc_pool_buf[sizeof(adc_event_tst) * ADC_POOL_SIZE]; + static cpool_tst adc_pool; + + cpool_init(&adc_pool, adc_pool_buf, + sizeof(adc_event_tst), ADC_POOL_SIZE); diff --git a/docs/sphinx/c_api/cqueue.rst b/docs/sphinx/c_api/cqueue.rst new file mode 100644 index 00000000..1b5898fb --- /dev/null +++ b/docs/sphinx/c_api/cqueue.rst @@ -0,0 +1,169 @@ +.. _api_cqueue: + +============================== +``cqueue`` — Event Queue +============================== + +.. contents:: On this page + :local: + :depth: 2 + +Header +====== + +.. code-block:: c + + #include + +Overview +======== + +``cqueue_tst`` is a circular FIFO of ``cevent_tst`` pointers. It supports +multiple **interrupt-safe** producers (``put``, ``put_left``) and a +single main-thread consumer (``get``, ``get_right``). + +The capacity **must** be a power of two; the implementation uses bitmask +wrapping instead of modulo. + +Types +===== + +``cqueue_tst`` +--------------- + +.. code-block:: c + + typedef struct cqueue_tst { + #ifndef CHSM_CFG_LITE + int32_t (*put)(struct cqueue_tst *, const cevent_tst *); + int32_t (*put_left)(struct cqueue_tst *, const cevent_tst *); + const cevent_tst* (*get)(struct cqueue_tst *); + const cevent_tst* (*get_right)(struct cqueue_tst *); + #endif + const cevent_tst **events; + uint16_t max; + atomic_uint16_t head; + atomic_uint16_t tail; + uint16_t mask; + #ifndef CHSM_CFG_NO_FAULT_CNT + uint32_t fault_cnt; + #endif + } cqueue_tst; + +Functions +========= + +``cqueue_init`` +---------------- + +.. code-block:: c + + int32_t cqueue_init(cqueue_tst *self, + const cevent_tst **events, + uint16_t max_event_count); + +Initialise a queue. + +:param self: Queue instance. +:param events: Pre-allocated pointer array of size ``max_event_count``. +:param max_event_count: Capacity (must be power of 2). +:returns: ``0`` on success. + +``cqueue_put`` +--------------- + +.. code-block:: c + + int32_t cqueue_put(cqueue_tst *self, + const cevent_tst *e); + +Enqueue an event at the **right** (tail) end. + +:returns: ``0`` on success, ``-1`` if the queue is full. + +**Thread safety:** ISR-safe (atomic increment of ``head``). + +``cqueue_put_left`` +-------------------- + +.. code-block:: c + + int32_t cqueue_put_left(cqueue_tst *self, + const cevent_tst *e_pst); + +Insert an event at the **left** (head) end — used for high-priority or +recalled events. + +:returns: ``0`` on success, ``-1`` if the queue is full. + +**Thread safety:** ISR-safe. + +``cqueue_get`` +--------------- + +.. code-block:: c + + const cevent_tst* cqueue_get(cqueue_tst *self); + +Dequeue an event from the **left** (tail) end. + +:returns: Event pointer, or ``NULL`` if empty. + +**Thread safety:** Main-thread only (single consumer). + +``cqueue_get_right`` +--------------------- + +.. code-block:: c + + const cevent_tst* cqueue_get_right(cqueue_tst *self); + +Dequeue an event from the **right** (head) end — used by +``chsm_recall`` to drain the defer queue. + +:returns: Event pointer, or ``NULL`` if empty. + +**Thread safety:** Main-thread only. + +Dispatch Macros +================ + +When ``CHSM_CFG_LITE`` is defined, function-pointer dispatch is replaced +by direct calls: + +.. list-table:: + :widths: 35 30 35 + :header-rows: 1 + + * - Macro + - Normal mode + - ``CHSM_CFG_LITE`` + * - ``CQUEUE_PUT(q, e)`` + - ``(q)->put((q), (e))`` + - ``cqueue_put((q), (e))`` + * - ``CQUEUE_PUT_LEFT(q, e)`` + - ``(q)->put_left((q), (e))`` + - ``cqueue_put_left((q), (e))`` + * - ``CQUEUE_GET(q)`` + - ``(q)->get((q))`` + - ``cqueue_get((q))`` + * - ``CQUEUE_GET_RIGHT(q)`` + - ``(q)->get_right((q))`` + - ``cqueue_get_right((q))`` + +Always use the macros in application code to remain compatible with +both build modes. + +Overflow Diagnostics +===================== + +Unless ``CHSM_CFG_NO_FAULT_CNT`` is defined, every failed ``put`` / +``put_left`` increments ``fault_cnt``. Monitor this counter during +development to size queues correctly: + +.. code-block:: c + + if (my_hsm.base.event_q_st.fault_cnt > 0) { + log_error("Queue overflow detected: %lu", + my_hsm.base.event_q_st.fault_cnt); + } diff --git a/docs/sphinx/c_api/crf.rst b/docs/sphinx/c_api/crf.rst new file mode 100644 index 00000000..08bdbbb0 --- /dev/null +++ b/docs/sphinx/c_api/crf.rst @@ -0,0 +1,209 @@ +.. _api_crf: + +================================= +``crf`` — Reactive Framework +================================= + +.. contents:: On this page + :local: + :depth: 2 + +Header +====== + +.. code-block:: c + + #include + +Overview +======== + +``crf_tst`` is the top-level framework object. It owns the array of +state machines and memory pools, drives the event loop, and provides +the event allocation / garbage-collection API. + +A single global instance ``crf`` is declared in ``crf.c``. + +Types +===== + +``crf_tst`` +------------ + +.. code-block:: c + + typedef struct crf_tst { + #ifndef CHSM_CFG_LITE + void* (*new_event)(struct crf_tst *, uint32_t, signal_t); + void (*publish)(struct crf_tst *, const cevent_tst *); + void (*post)(struct crf_tst *, cevent_tst *, cqueue_tst *); + bool (*step)(struct crf_tst *); + void (*gc)(struct crf_tst *, const cevent_tst *); + #endif + chsm_tst **chsm_ap; /* NULL-terminated HSM array */ + cpool_tst *pool_ast; /* pool array */ + uint16_t pool_cnt_u16; /* number of pools */ + } crf_tst; + +Constants +========= + +.. list-table:: + :widths: 40 60 + :header-rows: 1 + + * - Name + - Description + * - ``CRF_MAX_POOL_COUNT`` + - Maximum pools per instance (default 4). + +Functions +========= + +``crf_init`` +------------- + +.. code-block:: c + + bool crf_init(crf_tst *self, + chsm_tst **chsm_ap, + cpool_tst *pool_ast, + uint16_t pool_cnt); + +Initialise the framework. + +:param self: Framework instance. +:param chsm_ap: NULL-terminated array of state machine pointers. +:param pool_ast: Array of memory pools. +:param pool_cnt: Number of pools (≤ ``CRF_MAX_POOL_COUNT``). +:returns: ``false`` on parameter error. + +``crf_new_event`` +------------------ + +.. code-block:: c + + void* crf_new_event(crf_tst *self, + uint32_t size, + signal_t sig); + +Allocate an event from the first pool whose block size ≥ ``size``. + +:param size: Required event size in bytes. +:param sig: Signal to write into ``cevent_tst.sig``. +:returns: Pointer to the new event, or ``NULL`` if no pool can serve + the request. + +The ``gc_info`` is initialised: ``ref_cnt = 0``, ``pool_id`` set to the +matching pool index + 1. + +``crf_publish`` +---------------- + +.. code-block:: c + + void crf_publish(crf_tst *self, + const cevent_tst *e); + +Placeholder for publish/subscribe. Posts the event to **every** +registered state machine's event queue while incrementing ``ref_cnt`` +accordingly. + +``crf_post`` +------------- + +.. code-block:: c + + void crf_post(crf_tst *self, + cevent_tst *e, + cqueue_tst *q); + +Post an event to a specific queue (increments ``ref_cnt``). + +``crf_step`` +------------- + +.. code-block:: c + + bool crf_step(crf_tst *self); + +Run one processing cycle: + +1. Iterate over all state machines in ``chsm_ap``. +2. For each HSM, dequeue one event. +3. Dispatch the event (``chsm_dispatch``). +4. Garbage-collect the event (``crf_gc``). + +:returns: ``true`` if at least one event was processed. + +``crf_gc`` +----------- + +.. code-block:: c + + void crf_gc(crf_tst *self, + const cevent_tst *e); + +Decrement the event's ``ref_cnt``. If it reaches zero, return the +event to its pool via ``cpool_gc``. Static events (``pool_id == 0``) +are never freed. + +Convenience Macros +=================== + +These macros operate on the global ``crf`` instance. + +.. list-table:: + :widths: 40 60 + :header-rows: 1 + + * - Macro + - Expansion + * - ``CRF_NEW_EVENT(type, sig)`` + - ``crf_new_event(&crf, sizeof(type), sig)`` + * - ``CRF_NEW(SIGNAL)`` + - ``CRF_NEW_EVENT(TYPEOF(SIGNAL), SIGNAL)`` + * - ``CRF_POST(e, q)`` + - ``crf_post(&crf, e, q)`` + * - ``CRF_STEP()`` + - ``crf_step(&crf)`` + * - ``CRF_GC(e)`` + - ``crf_gc(&crf, e)`` + * - ``CRF_POST_TO_SELF(e)`` + - Post to own queue with priority (``put_left``). + * - ``CRF_EMIT(e)`` + - Call the active HSM's ``send`` callback. + * - ``CRF_SIG_VAR(SIG, var, e)`` + - Declare and cast: ``TYPEOF(SIG) *var = (TYPEOF(SIG) *)e`` + * - ``TYPEOF(SIGNAL)`` + - Expands to ``SIGNAL##_TYPE``. + +``CRF_SEND_FUNC`` / ``CRF_SET_SEND_FUNC`` +------------------------------------------- + +.. code-block:: c + + #define CRF_SEND_FUNC(hsm) ((hsm)->send) + #define CRF_SET_SEND_FUNC(hsm, fn) ((hsm)->send = (fn)) + +Access or assign the ``send`` callback of a state machine. The +``send`` function is called by ``CRF_EMIT`` and is typically wired +to a communication peripheral driver. + +Usage Pattern +============== + +.. code-block:: c + + /* Allocate event */ + my_event_tst *e = CRF_NEW(SIG_MY_EVENT); + e->payload = 42; + + /* Route A — post to a specific queue */ + CRF_POST(e, &target_hsm.base.event_q_st); + + /* Route B — emit via send callback */ + CRF_EMIT(e); + + /* Route C — publish to all HSMs */ + crf.publish(&crf, (const cevent_tst *)e); diff --git a/docs/sphinx/conf.py b/docs/sphinx/conf.py new file mode 100644 index 00000000..50f0ae81 --- /dev/null +++ b/docs/sphinx/conf.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +# CHSM Documentation — Sphinx Configuration +# =========================================== + +import os +import sys +from datetime import datetime + +# -- Path setup --------------------------------------------------------------- +sys.path.insert(0, os.path.abspath("../../gui")) + +# -- Project information ------------------------------------------------------ +project = "CHSM" +author = "Janos Szeman" +copyright = f"2019–{datetime.now().year}, {author}" +release = "1.0.0" +version = "1.0" + +# -- General configuration ---------------------------------------------------- +extensions = [ + "myst_parser", # Markdown support (replaces m2r) + "sphinx.ext.autodoc", # Python API docs + "sphinx.ext.viewcode", # [source] links + "sphinx.ext.intersphinx", # Cross-project references + "sphinx_copybutton", # Copy button on code blocks + "sphinx_design", # Cards, tabs, grids + "sphinxcontrib.mermaid", # Mermaid diagrams +] + +templates_path = ["_templates"] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] +source_suffix = {".rst": "restructuredtext", ".md": "markdown"} +master_doc = "index" + +# -- MyST configuration ------------------------------------------------------- +myst_enable_extensions = [ + "colon_fence", + "deflist", + "fieldlist", + "tasklist", +] +myst_heading_anchors = 3 + +# -- Options for HTML output --------------------------------------------------- +html_theme = "sphinx_rtd_theme" +html_theme_options = { + "logo_only": False, + "navigation_depth": 4, + "collapse_navigation": False, + "sticky_navigation": True, + "style_nav_header_background": "#2b2b2b", +} +html_static_path = ["_static"] +html_css_files = ["custom.css"] +html_title = "CHSM Documentation" +html_short_title = "CHSM" + +# -- Options for LaTeX output -------------------------------------------------- +latex_engine = "xelatex" +latex_documents = [ + (master_doc, "chsm.tex", "CHSM — Hierarchical State Machine Framework", + author, "manual"), +] +latex_elements = { + "papersize": "a4paper", + "pointsize": "11pt", + "preamble": r""" +\usepackage{enumitem} +\setlistdepth{9} +""", +} + +# -- Intersphinx --------------------------------------------------------------- +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), +} + +# -- Mermaid -------------------------------------------------------------------- +mermaid_output_format = "raw" diff --git a/docs/sphinx/configuration/build_system.rst b/docs/sphinx/configuration/build_system.rst new file mode 100644 index 00000000..b484bea2 --- /dev/null +++ b/docs/sphinx/configuration/build_system.rst @@ -0,0 +1,94 @@ +.. _config_build_system: + +============================== +CMake Build System +============================== + +The C language port uses CMake with a set of helper macros defined in +``languages/c/cmake_utils/cmake_utils.cmake``. + +Project Layout +=============== + +.. code-block:: text + + languages/c/ + ├── CMakeLists.txt ↠top-level project + ├── cmake_utils/ + │ └── cmake_utils.cmake ↠helper macros + ├── c_rf/ ↠CRF runtime library + ├── unity/ ↠Unity test framework + ├── modules/ + │ ├── chsm/ ↠HSM core module + │ ├── lm73/ ↠example: temperature sensor + │ ├── spi_master/ ↠example: SPI bus master + │ └── ... + └── scripts/ + +Key CMake Macros +================= + +``add_module_lib`` +------------------- + +.. code-block:: cmake + + add_module_lib( + NAME lm73 + SOURCES src/lm73.c src/lm73_functions.c + INCLUDES inc + DEPENDS chsm c_rf + ) + +Creates a static library target with correct include paths and +link dependencies. + +``add_module_test`` +-------------------- + +.. code-block:: cmake + + add_module_test( + NAME test_lm73 + SOURCES test/test_lm73.c + DEPENDS lm73 unity + ) + +Creates a test executable linked to Unity and the module under test. + +Build Commands +=============== + +.. code-block:: bash + + cd languages/c + cmake -B build -S . -DCMAKE_BUILD_TYPE=Release + cmake --build build + ctest --test-dir build --output-on-failure + +Cross-Compilation +================== + +Pass a toolchain file for embedded targets: + +.. code-block:: bash + + cmake -B build -S . \ + -DCMAKE_TOOLCHAIN_FILE=cmake_utils/compilers/arm-none-eabi.cmake \ + -DCMAKE_BUILD_TYPE=MinSizeRel + +The ``compilers/`` directory contains pre-made toolchain files for +common embedded compilers (ARM GCC, IAR, MSVC for simulation). + +Adding a New Module +==================== + +1. Use the New Module Wizard (see :ref:`gui_new_module_wizard`), or + manually create the directory under ``languages/c/modules/``. +2. Add the module to the top-level ``CMakeLists.txt``: + + .. code-block:: cmake + + add_subdirectory(modules/my_module) + +3. Build and test. diff --git a/docs/sphinx/configuration/project_settings.rst b/docs/sphinx/configuration/project_settings.rst new file mode 100644 index 00000000..93fb2ce1 --- /dev/null +++ b/docs/sphinx/configuration/project_settings.rst @@ -0,0 +1,91 @@ +.. _config_project_settings: + +============================== +Project Settings +============================== + +The CHSM editor stores per-project configuration in JSON files alongside +the state-machine model. + +``settings.json`` +================== + +Located at ``gui/c_gen/templates/settings.json``, this file provides +defaults for code generation: + +.. code-block:: json + + { + "output_dir": "build/gen", + "language": "c", + "indent": 4, + "line_ending": "lf", + "header_guard_style": "pragma_once" + } + +.. list-table:: + :widths: 25 15 60 + :header-rows: 1 + + * - Key + - Type + - Description + * - ``output_dir`` + - string + - Relative path for generated files. + * - ``language`` + - string + - Default target language (``c``, ``python``, ``js``, ``java``, ``vhdl``). + * - ``indent`` + - int + - Indentation width in spaces. + * - ``line_ending`` + - string + - ``lf`` or ``crlf``. + * - ``header_guard_style`` + - string + - ``pragma_once`` or ``ifndef``. + +``model.json`` +=============== + +The template model file (``gui/c_gen/templates/model.json``) defines +the default structure for new state-machine projects: + +.. code-block:: json + + { + "name": "", + "states": [], + "transitions": [], + "settings": {} + } + +Per-Module Overrides +===================== + +Each module directory may contain its own ``settings.json`` that +overrides the global defaults. The code generator merges settings +with module-level values taking precedence. + +Theme Configuration +==================== + +Visual themes are CSS files under ``gui/web/themes/``. To create a +custom theme: + +1. Copy ``default.css`` to ``my_theme.css`` in the same directory. +2. Edit CSS custom properties: + + .. code-block:: css + + :root { + --bg-primary: #1a1a2e; + --text-primary: #e0e0e0; + --accent: #0f3460; + --state-fill: #16213e; + --state-stroke: #0f3460; + --transition-color: #e94560; + } + +3. The theme appears automatically in the sidebar theme selector. diff --git a/docs/sphinx/configuration/runtime_tuning.rst b/docs/sphinx/configuration/runtime_tuning.rst new file mode 100644 index 00000000..0ed3938f --- /dev/null +++ b/docs/sphinx/configuration/runtime_tuning.rst @@ -0,0 +1,107 @@ +.. _config_runtime_tuning: + +============================== +Runtime Tuning +============================== + +CHSM provides three compile-time flags that trade features for smaller +RAM and flash footprint. See :ref:`api_chsm_cfg` for the full API +reference. + +Quick Reference +================ + +.. list-table:: + :widths: 30 15 55 + :header-rows: 1 + + * - Flag + - Default + - Effect + * - ``CHSM_CFG_LITE`` + - OFF + - Replace function-pointer dispatch with direct calls. + * - ``CHSM_CFG_NO_FAULT_CNT`` + - OFF + - Remove queue overflow counter. + * - ``CHSM_CFG_NO_DEBUG`` + - OFF + - Strip debug instrumentation from generated code. + +Choosing a Profile +=================== + +Development +----------- + +Leave all flags **undefined**. Full diagnostics are available: + +* ``fault_cnt`` tracks queue overflows. +* Debug channel reports every state change. +* Function pointers allow mock injection in unit tests. + +Release +-------- + +Define ``CHSM_CFG_LITE`` only: + +.. code-block:: cmake + + target_compile_definitions(my_target PRIVATE CHSM_CFG_LITE) + +* Queue / pool calls are inlined by the compiler. +* Fault counter remains for field diagnostics. +* Debug channel still operational. + +Minimal (≤ 8 KB RAM MCUs) +--------------------------- + +Define all three flags: + +.. code-block:: cmake + + target_compile_definitions(my_target PRIVATE + CHSM_CFG_LITE + CHSM_CFG_NO_FAULT_CNT + CHSM_CFG_NO_DEBUG + ) + +Approximate savings on Cortex-M0: + +* **−32 B** per queue (×2 per HSM = −64 B). +* **−10 B** per pool. +* **−36 B** per framework instance. +* **−20 B** per module (debug buffers). + +Queue Sizing +============= + +Each HSM has two queues: **event** and **defer**. Choose sizes as the +smallest power of 2 that satisfies the worst-case burst: + +.. list-table:: + :widths: 30 20 50 + :header-rows: 1 + + * - Queue + - Typical size + - Rationale + * - Event queue + - 8–16 + - Covers ISR burst between two ``crf_step`` calls. + * - Defer queue + - 4 + - Rarely more than 2–3 events deferred simultaneously. + +Pool Sizing +============ + +1. Identify the largest derived event type. +2. Count peak in-flight events (queued + deferred + dispatching). +3. Add 2–4 blocks margin. + +.. code-block:: c + + /* Worst case: 2 HSMs × 8 queue depth + 4 defer = 20 events */ + #define POOL_COUNT 24 + static uint8_t buf[sizeof(biggest_event_tst) * POOL_COUNT]; diff --git a/docs/sphinx/getting_started/first_module.rst b/docs/sphinx/getting_started/first_module.rst new file mode 100644 index 00000000..115043c6 --- /dev/null +++ b/docs/sphinx/getting_started/first_module.rst @@ -0,0 +1,83 @@ +.. _first_module: + +================================= +Creating Your First Module +================================= + +The **New Module Wizard** scaffolds a complete CHSM module with state machine +code, CMake build file, headers, documentation stub and unit tests. + +Launch the Wizard +================== + +1. In the editor sidebar click **New Module**. +2. A new browser tab opens with the module creation form. + +Fill in the Form +================= + +.. list-table:: + :widths: 25 75 + :header-rows: 1 + + * - Field + - Description + * - **Module name** + - Identifier used for file names and C symbols (e.g. ``lm73``). + * - **Module version** + - Semantic version string (e.g. ``0.1.0``). + * - **Author Nick / Full Name** + - Attribution for file headers. + * - **Description** + - Brief text inserted into generated file comments. + * - **Device Address** + - I²C/SPI slave address (hex string, e.g. ``0x48``). + * - **Communication peripheral** + - ``I2C``, ``SPI``, ``CAN`` or ``None``. Controls which protocol + library is linked and included. + * - **Licence** + - ``MIT``, ``BSD-3``, ``GPL-3.0``, ``Apache-2.0`` or ``MPL-2.0``. + * - **Module location** + - Output directory. Use **Browse** to pick a folder. + * - **Package Name** + - CMake package namespace (default ``chsm``). + * - **Linked Libs** + - Additional CMake link targets (space-separated). + +Click **Generate**. On success the button turns green and the following +tree is created: + +:: + + / + ├── CMakeLists.txt + ├── doc/ + │ └── .html + ├── inc/ + │ ├── .h + │ ├── _functions.h + │ └── _regs.h + ├── src/ + │ ├── .c + │ └── _functions.c + └── test/ + ├── CMakeLists.txt + ├── tinc/ + └── tsrc/ + ├── main.c + └── ut__test.c + +Next Steps +=========== + +* Open ``inc/.h`` in the CHSM editor to start drawing the + state machine. +* Implement action functions in ``src/_functions.c``. +* Add the module to your top-level ``CMakeLists.txt`` with + ``add_subdirectory()``. +* Build and run unit tests: + + .. code-block:: bash + + cmake --build . -t _test + ctest -VV -R _test diff --git a/docs/sphinx/getting_started/installation.rst b/docs/sphinx/getting_started/installation.rst new file mode 100644 index 00000000..7b56303f --- /dev/null +++ b/docs/sphinx/getting_started/installation.rst @@ -0,0 +1,86 @@ +.. _installation: + +============ +Installation +============ + +Prerequisites +============= + +.. list-table:: + :widths: 30 70 + :header-rows: 1 + + * - Component + - Requirement + * - Python + - 3.7 or later + * - Browser + - Chromium-based (Chrome, Edge) recommended; Firefox supported + * - C Compiler + - Any C11-compliant compiler (GCC, Clang, ARMCC, IAR) + * - CMake + - 3.19 or later (for building modules and tests) + +Install the GUI and Code Generator +=================================== + +1. Clone the repository: + + .. code-block:: bash + + git clone https://github.com/xsession/chsm.git + cd chsm + +2. Install Python dependencies: + + .. code-block:: bash + + pip install eel docopt cookiecutter + +3. Launch the editor: + + .. code-block:: bash + + python gui/chsm_backend.py + + The editor opens in your default browser at ``http://127.0.0.1:/main.html``. + +Install the C Unit Test Framework +================================== + +The C tests use the `Unity `_ test +framework. Clone it beside the ``chsm`` directory: + +.. code-block:: bash + + git clone https://github.com/ThrowTheSwitch/Unity.git + +Build and run all tests: + +.. code-block:: bash + + cd chsm/languages/c + mkdir build && cd build + cmake .. + cmake --build . + ctest -VV + +Optional: Documentation Dependencies +====================================== + +To build this documentation locally: + +.. code-block:: bash + + pip install -r docs/requirements.txt + cd docs/sphinx + make html # HTML output in _build/html/ + +For PDF output via Typst: + +.. code-block:: bash + + # Install Typst: https://github.com/typst/typst/releases + cd docs/typst + typst compile main.typ chsm_reference.pdf diff --git a/docs/sphinx/getting_started/quickstart.rst b/docs/sphinx/getting_started/quickstart.rst new file mode 100644 index 00000000..7cdfa6fa --- /dev/null +++ b/docs/sphinx/getting_started/quickstart.rst @@ -0,0 +1,100 @@ +.. _quickstart: + +=========== +Quick Start +=========== + +This guide walks through creating a simple two-state machine and generating +C code from it. + +Step 1 — Launch the Editor +=========================== + +.. code-block:: bash + + python gui/chsm_backend.py + +A browser window opens with an empty canvas. + +Step 2 — Open a Header File +============================= + +Click **Open** in the sidebar and select an existing ``.h`` file that declares +your state machine's top-level handler, for example: + +.. code-block:: c + + /* my_module.h */ + #ifndef MY_MODULE_H + #define MY_MODULE_H + + #include "crf.h" + + typedef struct my_module_tst { + chsm_tst super; + /* module-specific fields */ + } my_module_tst; + + chsm_result_ten my_module_top(chsm_tst *self, const cevent_tst *e_pst); + + #endif + +The editor parses the header and creates a canvas with the ``__top__`` state. + +Step 3 — Draw States +===================== + +* **Add a state:** Double-click on the canvas inside the ``__top__`` boundary. +* **Rename a state:** Select the state, type the new name in the *Label* + field, click *Apply*. +* **Add an initial transition:** Double-click to create an *initial node*, + then drag from it to the entry state. + +Step 4 — Add Transitions +========================== + +1. Hover the source state until a connector appears. +2. Drag from the connector to the target state. +3. Select the transition and set its label using the pattern: + + :: + + signal [guard()] / action() + + Examples: ``SIG_TICK / increment()``, ``SIG_DONE [is_ready()]``. + +Step 5 — Generate Code +======================== + +Click **Code gen** in the sidebar. Two files are produced: + +* ``src/.c`` — State handler functions with switch-case dispatch. +* ``inc/_functions.h`` — Prototypes for user action / guard functions. + +Step 6 — Integrate with CRF +============================= + +.. code-block:: c + + #include "crf.h" + #include "my_module.h" + + /* Event queue storage */ + static const cevent_tst *my_module_events[8]; + + /* Instantiate the state machine */ + my_module_tst my_module_st; + + /* All HSMs in the application */ + chsm_tst *hsm_list[] = {(chsm_tst *)&my_module_st, NULL}; + + /* Construct and initialise */ + chsm_ctor((chsm_tst *)&my_module_st, my_module_top, + my_module_events, 8, 0); + crf_init(&crf, hsm_list, NULL, 0); + chsm_init((chsm_tst *)&my_module_st); + + /* Main loop */ + while (1) { + crf_step(&crf); + } diff --git a/docs/sphinx/gui/code_generation.rst b/docs/sphinx/gui/code_generation.rst new file mode 100644 index 00000000..a6c4e225 --- /dev/null +++ b/docs/sphinx/gui/code_generation.rst @@ -0,0 +1,116 @@ +.. _gui_code_generation: + +========================== +Code Generation Pipeline +========================== + +The code generator transforms the visual model into compileable source +files for five target languages. + +Pipeline Overview +================== + +.. mermaid:: + + flowchart LR + JSON["Model JSON"] --> Parser["parser.py"] + Parser --> AST["Internal AST"] + AST --> Jinja["Jinja2 Templates"] + Jinja --> C["C output"] + Jinja --> Py["Python output"] + Jinja --> JS["JavaScript output"] + Jinja --> Java["Java output"] + Jinja --> VHDL["VHDL output"] + +1. **Model JSON** — The ``.chsm`` file saved by the editor. +2. **parser.py** — Walks the JSON, resolves parent chains, computes + exit/entry paths, and builds a flat AST dictionary. +3. **Jinja2 Templates** — Language-specific ``.j2`` templates render + the AST into source code. + +Supported Languages +==================== + +.. list-table:: + :widths: 15 30 30 25 + :header-rows: 1 + + * - Language + - Generator module + - Template + - Output + * - C + - ``gui/c_gen/hsm/sm.py`` + - ``sm_temp.c.j2``, ``sm_temp.h.j2`` + - ``.c``, ``.h`` + * - Python + - ``gui/py_gen/render.py`` + - ``state_machine_template.py.j2`` + - ``.py`` + * - JavaScript + - ``gui/js_gen/render.py`` + - ``state_machine_template.js.j2`` + - ``.js`` + * - Java + - ``gui/java_gen/render.py`` + - ``state_machine_template.java.j2`` + - ``.java`` + * - VHDL + - ``gui/vhdl_gen/render.py`` + - ``state_machine_template.vhdl.j2`` + - ``.vhdl`` + +AST Structure +============== + +The parser produces a dictionary consumed by every template: + +.. code-block:: python + + { + "name": "my_hsm", + "states": [ + {"name": "idle", "id": 0, "parent": None, + "entry": "idle_entry", "exit": "idle_exit", + "children": [1, 2]}, + ... + ], + "transitions": [ + {"source": 0, "target": 1, + "signal": "SIG_START", "guard": None, + "actions": ["start_motor"], + "exit_path": ["idle_exit"], + "entry_path": ["running_entry"]}, + ... + ], + "signals": ["SIG_START", "SIG_STOP", ...], + } + +Key computed fields: + +* **exit_path** / **entry_path** — Pre-calculated lists of user + functions to call during a transition (exits bottom-up, entries + top-down). + +C Code Generator Details +========================== + +The C generator (``gui/c_gen/hsm/sm.py``) produces two additional +artefacts per module on top of the Jinja render: + +* **Function stubs** — ``sm_functions_temp.c.j2`` / ``.h.j2`` generate + skeleton entry/exit/guard functions that the developer fills in. +* **Unit test scaffold** — ``unittest_temp.c.j2`` generates a Unity + test file with one test case per transition. + +Invoking from CLI +================== + +.. code-block:: bash + + python -m gui.c_gen.hsm.sm path/to/model.json --output build/ + + python -m gui.py_gen.render path/to/model.json + python -m gui.js_gen.render path/to/model.json + python -m gui.java_gen.render path/to/model.json + python -m gui.vhdl_gen.render path/to/model.json diff --git a/docs/sphinx/gui/debug_channel.rst b/docs/sphinx/gui/debug_channel.rst new file mode 100644 index 00000000..5138f3a1 --- /dev/null +++ b/docs/sphinx/gui/debug_channel.rst @@ -0,0 +1,114 @@ +.. _debug_channel: + +============================== +Debug Channel +============================== + +The debug channel provides real-time visibility into state-machine +execution via a TCP connection between the running firmware (simulated +or real) and the GUI editor. + +Architecture +============= + +.. mermaid:: + + sequenceDiagram + participant FW as Firmware / Sim + participant TCP as TCP Socket + participant BE as chsm_backend.py + participant FE as Browser Debug Panel + + FW->>TCP: JSON message + TCP->>BE: DebugServer receives + BE->>FE: eel.debug_message(data) + FE->>FE: Update panel + +The ``DebugServer`` class in ``chsm_backend.py`` listens on a +configurable TCP port (default **9999**). Each line received is a +JSON-encoded debug message. + +Message Protocol +================= + +All messages are single-line JSON objects terminated by ``\n``. + +State Change +------------- + +.. code-block:: json + + { + "type": "state_change", + "module": "lm73", + "from": "idle", + "to": "reading", + "signal": "SIG_START_READ" + } + +Event Dispatch +--------------- + +.. code-block:: json + + { + "type": "event", + "module": "lm73", + "signal": "SIG_RX_DONE", + "pool_id": 1, + "ref_cnt": 0 + } + +Log +---- + +.. code-block:: json + + { + "type": "log", + "level": "info", + "message": "Pool 1: 3/8 blocks used" + } + +GUI Debug Panel +================ + +The debug panel appears in the editor sidebar under the **Debug** tab. + +Features: + +* **Live state indicator** — Highlights the current state on the canvas. +* **Event log** — Scrollable list of dispatched events with timestamps. +* **Filter** — Filter by module name or signal. +* **Clear** — Reset the log. + +Connecting a Target +==================== + +Embedded firmware sends debug messages over UART → TCP bridge (e.g. via +a host-side serial-to-socket script): + +.. code-block:: bash + + # Example: pipe /dev/ttyUSB0 to TCP 9999 + socat TCP-LISTEN:9999,reuseaddr FILE:/dev/ttyUSB0,b115200 + +For desktop simulation, connect directly to ``localhost:9999``: + +.. code-block:: python + + import socket, json + + sock = socket.socket() + sock.connect(("localhost", 9999)) + msg = {"type": "state_change", "module": "lm73", + "from": "idle", "to": "reading", + "signal": "SIG_START_READ"} + sock.sendall((json.dumps(msg) + "\n").encode()) + sock.close() + +Disabling Debug in Firmware +============================= + +Compile with ``CHSM_CFG_NO_DEBUG`` to strip all debug instrumentation +from the generated C code. See :ref:`api_chsm_cfg`. diff --git a/docs/sphinx/gui/editor.rst b/docs/sphinx/gui/editor.rst new file mode 100644 index 00000000..2857db4f --- /dev/null +++ b/docs/sphinx/gui/editor.rst @@ -0,0 +1,105 @@ +.. _gui_editor: + +========================= +Visual State Editor +========================= + +The CHSM GUI is a browser-based visual editor for hierarchical state +machines. It runs locally via `Eel `_ +(Python ↔ Chromium bridge). + +Launching +========= + +.. code-block:: bash + + cd gui + python chsm_backend.py + +The editor opens in a Chromium window at ``http://localhost:8080``. + +Canvas +====== + +The central drawing area renders states as rounded rectangles and +transitions as directional arrows. Operations: + +.. list-table:: + :widths: 25 75 + :header-rows: 1 + + * - Action + - Description + * - Click + Drag + - Move a state. + * - Double-click state + - Edit state name and entry/exit actions. + * - Right-click state + - Context menu — add child state, delete. + * - Click + Drag between states + - Create a transition arrow. + * - Double-click transition + - Edit label (``signal [guard] / action``). + +Transition Labels +================== + +Labels follow UML syntax: + +.. code-block:: text + + signal [guard] / action + +* **signal** — Event name (e.g. ``SIG_BUTTON``). +* **guard** — Optional boolean expression in brackets. +* **action** — Optional semicolon-separated list of actions. + +Examples:: + + SIG_TIMEOUT / led_off(); + SIG_DATA [len > 0] / process(); ack(); + +Sidebar +======== + +* **File** — Open / Save ``.chsm`` JSON model files. +* **Generate** — Trigger code generation for selected languages. +* **Settings** — Theme selection, grid toggle, snap-to-grid. +* **Debug** — Connect to the TCP debug channel (see :ref:`debug_channel`). + +Themes +====== + +Three built-in themes are available under ``web/themes/``: + +* ``default.css`` — Light theme. +* ``solarized_light.css`` — Solarized Light. +* ``solarized_dark.css`` — Solarized Dark. + +Select a theme from the sidebar **Settings** panel. + +Model Format +============ + +The editor serialises state machines as JSON. The top-level structure: + +.. code-block:: text + + { + "name": "my_hsm", + "states": [ ... ], + "transitions": [ ... ], + "settings": { ... } + } + +Each **state** contains: + +* ``name``, ``id``, ``parent_id`` +* ``entry``, ``exit`` — Action function names. +* ``x``, ``y``, ``w``, ``h`` — Canvas geometry. + +Each **transition** contains: + +* ``source_id``, ``target_id`` +* ``signal``, ``guard``, ``actions`` +* Waypoint coordinates for routing. diff --git a/docs/sphinx/gui/new_module_wizard.rst b/docs/sphinx/gui/new_module_wizard.rst new file mode 100644 index 00000000..29ce4441 --- /dev/null +++ b/docs/sphinx/gui/new_module_wizard.rst @@ -0,0 +1,101 @@ +.. _gui_new_module_wizard: + +=========================== +New Module Wizard +=========================== + +The **New Module** wizard generates a complete, build-ready module +directory from a Cookiecutter template. + +Opening the Wizard +=================== + +1. In the editor, click **File → New Module** (or press :kbd:`Ctrl+N`). +2. A dedicated browser page opens with the module creation form. + +Form Fields +============ + +.. list-table:: + :widths: 25 15 60 + :header-rows: 1 + + * - Field + - Required + - Description + * - Module Name + - Yes + - Snake-case identifier (e.g. ``lm73``). + * - Description + - No + - One-line summary. + * - Author + - No + - Author name for file headers. + * - Company + - No + - Company name for copyright headers. + * - Licence + - No + - Licence identifier: ``MIT``, ``BSD``, ``Apache``, ``Proprietary``. + * - Output Directory + - Yes + - Root path where the module folder is created. + * - Comm Peripheral + - Yes + - ``i2c``, ``spi``, or ``none``. + * - Unit Test + - No + - Generate Unity test scaffold (checkbox). + * - Signal Class + - No + - Integer signal class ID for the module. + * - Queue Size + - No + - Event queue depth (power of 2). + * - Defer Queue Size + - No + - Defer queue depth (power of 2). + +Communication Peripheral +========================= + +When ``Comm Peripheral`` is set to ``i2c`` or ``spi``, the template +includes: + +* A peripheral driver header include. +* Pre-defined I/O events (``SIG_TX_DONE``, ``SIG_RX_DONE``). +* A ``send`` callback stub wired to the peripheral HAL. + +When set to ``none``, peripheral-specific code is omitted entirely. + +Generated Directory Structure +============================== + +.. code-block:: text + + / + ├── CMakeLists.txt + ├── inc/ + │ └── .h + ├── src/ + │ └── .c + └── test/ + └── test_.c ↠only if Unit Test checked + +The generated ``CMakeLists.txt`` integrates with the project's +``add_module_lib`` / ``add_module_test`` CMake macros. + +After Generation +================= + +1. Copy or move the directory into ``languages/c/modules/``. +2. Open the ``.chsm`` model in the editor and draw states. +3. Generate code to populate the state-machine logic. +4. Build: + + .. code-block:: bash + + cd languages/c + cmake -B build -S . + cmake --build build diff --git a/docs/sphinx/index.rst b/docs/sphinx/index.rst new file mode 100644 index 00000000..a831d8a6 --- /dev/null +++ b/docs/sphinx/index.rst @@ -0,0 +1,102 @@ +.. _index: + +============================================== +CHSM — Hierarchical State Machine Framework +============================================== + +.. image:: https://github.com/xsession/chsm/workflows/chsm_crf_ci/badge.svg + :target: https://github.com/xsession/chsm/actions + :alt: CI Status + +.. image:: https://github.com/xsession/chsm/workflows/chsm_modules_ci/badge.svg + :target: https://github.com/xsession/chsm/actions + :alt: Modules CI Status + +**CHSM** is a complete toolkit for designing, editing and executing +UML-compliant hierarchical state machines targeting embedded C systems. +It consists of a graphical editor, a multi-language code generator and +the **CRF** (C Reactive Framework) runtime library. + +Key Features +============ + +.. grid:: 2 + :gutter: 3 + + .. grid-item-card:: Visual State Machine Editor + :margin: 0 + + Draw, annotate and simulate state machines in a browser-based GUI. + Export as self-contained HTML or generate production code. + + .. grid-item-card:: Multi-Language Code Generation + :margin: 0 + + Generate C, Python, JavaScript, Java and VHDL state machine + implementations from a single model. + + .. grid-item-card:: CRF Runtime Library + :margin: 0 + + Deterministic, real-time C framework with lock-free queues, + O(1) memory pools and run-to-completion semantics. + + .. grid-item-card:: Configurable Footprint + :margin: 0 + + Compile-time switches strip function pointers, debug + infrastructure and counters for sub-1 KB RAM targets. + + +.. toctree:: + :maxdepth: 2 + :caption: Getting Started + + getting_started/installation + getting_started/quickstart + getting_started/first_module + +.. toctree:: + :maxdepth: 2 + :caption: Architecture + + architecture/overview + architecture/crf_runtime + architecture/event_model + architecture/memory_management + +.. toctree:: + :maxdepth: 2 + :caption: C API Reference + + c_api/chsm + c_api/cevent + c_api/cqueue + c_api/cpool + c_api/crf + c_api/chsm_cfg + +.. toctree:: + :maxdepth: 2 + :caption: GUI & Code Generation + + gui/editor + gui/code_generation + gui/new_module_wizard + gui/debug_channel + +.. toctree:: + :maxdepth: 2 + :caption: Configuration + + configuration/build_system + configuration/runtime_tuning + configuration/project_settings + +.. toctree:: + :maxdepth: 1 + :caption: Appendices + + appendices/faq + appendices/changelog + appendices/license diff --git a/docs/sphinx/make.bat b/docs/sphinx/make.bat new file mode 100644 index 00000000..acbab2e8 --- /dev/null +++ b/docs/sphinx/make.bat @@ -0,0 +1,32 @@ +@ECHO OFF +pushd %~dp0 + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Install with: + echo. pip install -r ../requirements.txt + exit /b 1 +) + +if "%1" == "" goto help +if "%1" == "clean" ( + rmdir /s /q %BUILDDIR% 2>NUL + echo Cleaned. + goto end +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/typst/chapters/architecture.typ b/docs/typst/chapters/architecture.typ new file mode 100644 index 00000000..37fe256e --- /dev/null +++ b/docs/typst/chapters/architecture.typ @@ -0,0 +1,71 @@ += Architecture + +== Layer Model + +The CHSM system is organised into three layers. Each layer communicates strictly downward — the runtime has no dependency on the GUI. + +#table( + columns: (1fr, 3fr), + table.header([*Layer*], [*Responsibility*]), + [GUI Editor], [Visual state/transition editing, JSON model persistence, theme management, debug panel.], + [Code Generator], [Parse JSON model → build AST → render Jinja2 templates → output source files.], + [CRF Runtime], [Run-to-completion event loop, static memory pools, atomic queues, garbage collection.], +) + +== Execution Model + +The CRF runtime uses a *run-to-completion* (RTC) execution model: + ++ `crf_step()` iterates over all registered state machines. ++ For each HSM, it dequeues one event from the event queue. ++ The event is dispatched to the current state handler. ++ If the handler returns `C_RES_PARENT`, the event propagates up the hierarchy. ++ If the handler returns `C_RES_TRANS`, exit and entry functions are called in order. ++ After dispatch, `crf_gc()` decrements the reference count and frees the event if it reaches zero. + +No preemption occurs within a single dispatch cycle. This guarantees that state handlers execute atomically with respect to other events. + +== Struct Relationships + +The core data structures form a clear ownership hierarchy: + +- *`crf_tst`* owns the array of state machines and memory pools. +- *`chsm_tst`* embeds two `cqueue_tst` instances (event queue and defer queue). +- *`cpool_tst`* manages a contiguous buffer of fixed-size event blocks. +- *`cevent_tst`* is the base event type with signal and GC metadata. +- All derived events embed `cevent_tst` as their first member. + +== Thread Safety Model + +#table( + columns: (1fr, 1fr, 2fr), + table.header([*Operation*], [*Safety*], [*Notes*]), + [`cqueue_put`], [ISR-safe], [Atomic CAS on head; multiple producers allowed.], + [`cqueue_get`], [Main only], [Single consumer assumed.], + [`cpool_new`], [ISR-safe], [CAS-based free-list pop.], + [`cpool_gc`], [ISR-safe], [CAS-based free-list push.], + [`crf_step`], [Main only], [Iterates HSMs sequentially in a single thread.], +) + +== Directory Layout + +``` +chsm/ +├── gui/ # Visual editor + code generators +│ ├── chsm_backend.py # Eel backend + debug server +│ ├── c_gen/ # C code generator +│ ├── py_gen/ # Python code generator +│ ├── js_gen/ # JavaScript code generator +│ ├── java_gen/ # Java code generator +│ ├── vhdl_gen/ # VHDL code generator +│ └── web/ # Frontend HTML/CSS/JS +├── languages/ +│ └── c/ # C runtime + modules +│ ├── c_rf/ # CRF library (cevent, cqueue, cpool, crf) +│ ├── modules/ # HSM modules (chsm core + applications) +│ ├── cmake_utils/ # CMake helper macros +│ └── unity/ # Unity test framework +└── docs/ + ├── sphinx/ # Sphinx documentation (HTML/PDF) + └── typst/ # Typst documentation (PDF) +``` diff --git a/docs/typst/chapters/c_api.typ b/docs/typst/chapters/c_api.typ new file mode 100644 index 00000000..a79f937c --- /dev/null +++ b/docs/typst/chapters/c_api.typ @@ -0,0 +1,184 @@ += C API Reference + +This chapter documents every public struct, function, and macro in the CRF runtime library. + +== `cevent` — Event Base + +=== `cevent_tst` + +Base event structure. All derived events must embed this as their first member. + +```c +typedef struct cevent_tst { + signal_t sig; // event type identifier + gc_info_tst gc_info; // pool id + reference count +} cevent_tst; +``` + +Size: 4 bytes (with default `signal_t = uint16_t`). + +=== `gc_info_tst` + +```c +typedef struct { + uint16_t ref_cnt : 12; // 0 – 4095 + uint16_t pool_id : 4; // 0 – 15 +} gc_info_tst; +``` + +- *ref_cnt* — Incremented on queue insertion, decremented after dispatch. Zero triggers deallocation. +- *pool_id* — Identifies the source pool. Pool 0 (`CEVENT_INVALID_POOL`) marks static events. + +=== Signal Classes + +#table( + columns: (2fr, 1fr, 2fr), + table.header([*Constant*], [*Value*], [*Purpose*]), + [`CEVENT_INVALID_POOL`], [0], [Static event marker.], + [`CRF_SIGNAL_CLASS_MOD_INTERNAL`], [1], [Module-internal signals.], + [`CRF_SIGNAL_CLASS_START`], [2], [First application class.], + [`CRF_SIGNAL_CLASS_SIZE`], [100], [Signals per class.], +) + +Macro: `SIGNAL_FROM_CLASS(CLASS)` → `CLASS × 100`. + +=== Functions + +- `cevent_ref_cnt_inc(e)` — Increment reference count (no-op for static events). +- `cevent_ref_cnt_dec(e)` — Decrement reference count (no-op for static events). + +== `cqueue` — Event Queue + +=== `cqueue_tst` + +Circular FIFO of event pointers. Capacity must be a power of two. + +Key fields: +- `events` — Pre-allocated pointer array. +- `max` — Capacity. +- `head`, `tail` — Atomic read/write indices. +- `mask` — `max - 1` for efficient wrapping. +- `fault_cnt` — Overflow counter (omitted with `CHSM_CFG_NO_FAULT_CNT`). + +=== Functions + +#table( + columns: (2fr, 1fr, 3fr), + table.header([*Function*], [*Returns*], [*Description*]), + [`cqueue_init(q, events, max)`], [`int32_t`], [Initialise queue. Returns 0.], + [`cqueue_put(q, e)`], [`int32_t`], [Enqueue right. ISR-safe. Returns −1 on overflow.], + [`cqueue_put_left(q, e)`], [`int32_t`], [Enqueue left (priority). ISR-safe.], + [`cqueue_get(q)`], [`cevent*`], [Dequeue left. Main-thread only. NULL if empty.], + [`cqueue_get_right(q)`], [`cevent*`], [Dequeue right. Used by `chsm_recall`.], +) + +=== Dispatch Macros + +`CQUEUE_PUT`, `CQUEUE_PUT_LEFT`, `CQUEUE_GET`, `CQUEUE_GET_RIGHT` — resolve to function-pointer calls normally, or direct calls with `CHSM_CFG_LITE`. + +== `cpool` — Memory Pool + +=== `cpool_tst` + +Lock-free fixed-size block allocator using atomic CAS. + +Key fields: +- `pool` — Byte buffer. +- `esize` — Bytes per block. +- `ecnt` — Total blocks. +- `head` — Atomic offset to first free block. + +=== Functions + +#table( + columns: (2fr, 1fr, 3fr), + table.header([*Function*], [*Returns*], [*Description*]), + [`cpool_init(p, buf, size, cnt)`], [void], [Thread free-list through buffer.], + [`cpool_new(p)`], [`void*`], [CAS pop. ISR-safe. NULL if exhausted.], + [`cpool_gc(p, e)`], [`bool`], [CAS push. ISR-safe. False if wrong pool.], +) + +Dispatch macros: `CPOOL_NEW(p)`, `CPOOL_GC(p, e)`. + +== `chsm` — State Machine + +=== `chsm_tst` + +State machine instance. Embeds two queues (event + defer), a state handler pointer, a send callback, and a linked-list next pointer. + +=== Result Enum + +#table( + columns: (1fr, 2fr), + table.header([*Value*], [*Meaning*]), + [`C_RES_HANDLED`], [Event processed.], + [`C_RES_TRANS`], [State transition triggered.], + [`C_RES_PARENT`], [Delegate to parent state.], + [`C_RES_IGNORED`], [Event intentionally skipped.], + [`C_RES_GUARDS`], [Guard conditions — none true.], +) + +=== Functions + +#table( + columns: (2fr, 3fr), + table.header([*Function*], [*Description*]), + [`chsm_ctor(self, init, events, qlen, dlen)`], [Construct HSM with initial state and queue buffers.], + [`chsm_init(self)`], [Send `C_SIG_INIT` and execute initial transition.], + [`chsm_dispatch(self, e)`], [Dispatch event to current state; propagate on `C_RES_PARENT`.], + [`chsm_defer(self, e)`], [Move event to defer queue.], + [`chsm_recall(self, e)`], [Move all deferred events to front of event queue.], +) + +=== Inline Helpers + +- `chsm_transition(self, target)` — Record transition, return `C_RES_TRANS`. +- `chsm_handled(self)` — Return `C_RES_HANDLED`. +- `chsm_ignored(self)` — Return `C_RES_IGNORED`. + +== `crf` — Reactive Framework + +=== `crf_tst` + +Top-level framework. Owns the HSM array and pool array. Provides the event loop. + +=== Functions + +#table( + columns: (2fr, 3fr), + table.header([*Function*], [*Description*]), + [`crf_init(self, hsms, pools, cnt)`], [Initialise framework with HSM and pool arrays.], + [`crf_new_event(self, size, sig)`], [Allocate event from matching pool. NULL on failure.], + [`crf_publish(self, e)`], [Post event to all registered HSMs.], + [`crf_post(self, e, q)`], [Post event to specific queue.], + [`crf_step(self)`], [Process one event per HSM. Returns true if work done.], + [`crf_gc(self, e)`], [Decrement ref_cnt; free to pool if zero.], +) + +=== Convenience Macros + +#table( + columns: (1fr, 2fr), + table.header([*Macro*], [*Purpose*]), + [`CRF_NEW(SIGNAL)`], [Allocate event by signal name.], + [`CRF_POST(e, q)`], [Post event to queue.], + [`CRF_EMIT(e)`], [Send via active HSM's callback.], + [`CRF_STEP()`], [Run one event cycle.], + [`CRF_GC(e)`], [Garbage-collect event.], + [`CRF_SIG_VAR(SIG, var, e)`], [Declare and cast event pointer.], + [`CRF_POST_TO_SELF(e)`], [Post to own queue with priority.], +) + +== `chsm_cfg` — Build Configuration + +Three compile-time flags control the runtime footprint: + +#table( + columns: (2fr, 3fr), + table.header([*Flag*], [*Effect*]), + [`CHSM_CFG_LITE`], [Replace function-pointer dispatch with direct calls. Enables inlining.], + [`CHSM_CFG_NO_FAULT_CNT`], [Remove `fault_cnt` from queues (−4 B each).], + [`CHSM_CFG_NO_DEBUG`], [Strip debug instrumentation (−20 B per module).], +) + +Define in `chsm_cfg.h` (included before all CRF headers) or pass as compiler flags. diff --git a/docs/typst/chapters/code_generation.typ b/docs/typst/chapters/code_generation.typ new file mode 100644 index 00000000..0061cdb5 --- /dev/null +++ b/docs/typst/chapters/code_generation.typ @@ -0,0 +1,60 @@ += Code Generation + +== Pipeline + +The code generator transforms a visual model into compileable source files through three stages: + ++ *JSON Model* — The `.chsm` file saved by the visual editor. ++ *Parser / AST* — `parser.py` walks the JSON, resolves parent chains, computes exit/entry paths, and builds a flat AST dictionary. ++ *Jinja2 Rendering* — Language-specific `.j2` templates consume the AST and produce output files. + +== Supported Languages + +#table( + columns: (1fr, 2fr, 2fr), + table.header([*Language*], [*Generator*], [*Template*]), + [C], [`gui/c_gen/hsm/sm.py`], [`sm_temp.c.j2`, `sm_temp.h.j2`], + [Python], [`gui/py_gen/render.py`], [`state_machine_template.py.j2`], + [JavaScript], [`gui/js_gen/render.py`], [`state_machine_template.js.j2`], + [Java], [`gui/java_gen/render.py`], [`state_machine_template.java.j2`], + [VHDL], [`gui/vhdl_gen/render.py`], [`state_machine_template.vhdl.j2`], +) + +== AST Structure + +The parser produces a dictionary with the following top-level keys: + +- *name* — Module name (string). +- *states* — List of state objects with `name`, `id`, `parent`, `entry`, `exit`, `children`. +- *transitions* — List with `source`, `target`, `signal`, `guard`, `actions`, plus pre-computed `exit_path` and `entry_path`. +- *signals* — Deduplicated list of signal names. + +The `exit_path` and `entry_path` fields are the critical output of the parser: they contain the ordered list of user functions (exit bottom-up, entry top-down) that must execute during a transition. The runtime does not compute these at run time. + +== C Generator Extras + +The C generator produces additional files beyond the state machine skeleton: + +- *Function stubs* (`sm_functions_temp.c.j2` / `.h.j2`) — Skeleton implementations of entry, exit, guard, and action functions. These are generated once and preserved across regeneration. +- *Unit test scaffold* (`unittest_temp.c.j2`) — A Unity test file with one test case per transition. + +== Adding a Language + +To add a new target language: + ++ Create `gui/_gen/` directory. ++ Implement `render.py` with a `render(ast, output_path)` function. ++ Create a Jinja2 `.j2` template. ++ Register the language in the editor's Generate menu. + +== CLI Usage + +All generators can be invoked from the command line without the GUI: + +```bash +python -m gui.c_gen.hsm.sm model.json --output build/ +python -m gui.py_gen.render model.json +python -m gui.js_gen.render model.json +python -m gui.java_gen.render model.json +python -m gui.vhdl_gen.render model.json +``` diff --git a/docs/typst/chapters/configuration.typ b/docs/typst/chapters/configuration.typ new file mode 100644 index 00000000..745cb111 --- /dev/null +++ b/docs/typst/chapters/configuration.typ @@ -0,0 +1,83 @@ += Configuration + +== CMake Build System + +The C runtime uses CMake with helper macros from `cmake_utils/cmake_utils.cmake`. + +=== Key Macros + +- *`add_module_lib`* — Create a static library from module sources with correct includes and link deps. +- *`add_module_test`* — Create a Unity test executable linked to the module under test. + +=== Build Commands + +```bash +cd languages/c +cmake -B build -S . -DCMAKE_BUILD_TYPE=Release +cmake --build build +ctest --test-dir build --output-on-failure +``` + +=== Cross-Compilation + +```bash +cmake -B build -S . \ + -DCMAKE_TOOLCHAIN_FILE=cmake_utils/compilers/arm-none-eabi.cmake \ + -DCMAKE_BUILD_TYPE=MinSizeRel +``` + +== Runtime Tuning + +=== Profiles + +#table( + columns: (1fr, 2fr, 2fr), + table.header([*Profile*], [*Flags*], [*Use Case*]), + [Development], [_(none)_], [Full diagnostics, debug logging, fault counters.], + [Release], [`CHSM_CFG_LITE`], [Reduced RAM; overflow diagnostics retained.], + [Minimal], [`LITE + NO_FAULT_CNT + NO_DEBUG`], [Smallest footprint (≤ 8 KB RAM MCUs).], +) + +=== RAM Savings (Cortex-M, 32-bit) + +#table( + columns: (2fr, 1fr, 1fr, 1fr), + table.header([*Config*], [*Queue ×2*], [*Pool*], [*Framework*]), + [Default], [56 B], [20 B], [48 B], + [`CHSM_CFG_LITE`], [24 B], [10 B], [12 B], + [`+ NO_FAULT_CNT`], [16 B], [10 B], [12 B], + [`+ NO_DEBUG`], [16 B], [10 B], [12 B], +) + +Total savings with all three flags: ~86 bytes per HSM system. + +=== Queue Sizing + +- *Event queue*: 8–16 entries (power of 2). Covers ISR burst between `crf_step` calls. +- *Defer queue*: 4 entries. Rarely more than 2–3 deferred simultaneously. + +=== Pool Sizing + ++ Identify the largest derived event type. ++ Count peak in-flight events (queued + deferred + dispatching). ++ Add 2–4 blocks margin. + +== Project Settings + +=== `settings.json` + +Code generation defaults stored at `gui/c_gen/templates/settings.json`: + +#table( + columns: (1fr, 1fr, 2fr), + table.header([*Key*], [*Type*], [*Description*]), + [`output_dir`], [string], [Relative path for generated files.], + [`language`], [string], [Default target: `c`, `python`, `js`, `java`, `vhdl`.], + [`indent`], [int], [Indentation width (spaces).], + [`line_ending`], [string], [`lf` or `crlf`.], + [`header_guard_style`], [string], [`pragma_once` or `ifndef`.], +) + +=== Themes + +CSS files in `gui/web/themes/`. Create a custom theme by copying `default.css` and editing CSS custom properties (`--bg-primary`, `--accent`, `--state-fill`, etc.). diff --git a/docs/typst/chapters/introduction.typ b/docs/typst/chapters/introduction.typ new file mode 100644 index 00000000..977f9ef9 --- /dev/null +++ b/docs/typst/chapters/introduction.typ @@ -0,0 +1,36 @@ += Introduction + +== What is CHSM? + +CHSM (C Hierarchical State Machine) is an integrated toolchain for designing, generating, and executing UML-style hierarchical state machines on embedded targets. + +The project consists of three layers: + ++ *Visual Editor* — A browser-based GUI for drawing states and transitions. ++ *Code Generator* — Jinja2-based templates that produce compileable code for C, Python, JavaScript, Java, and VHDL. ++ *CRF Runtime Library* — A zero-malloc, ISR-safe active-object framework written in C for bare-metal and RTOS targets. + +== Key Features + +#table( + columns: (1fr, 2fr), + table.header([*Feature*], [*Description*]), + [Visual Editor], [Browser-based drag-and-drop state machine designer with theme support.], + [Multi-Language], [Generate C, Python, JavaScript, Java, and VHDL from a single model.], + [Zero Malloc], [All queues and pools are statically pre-allocated — no `malloc` at runtime.], + [ISR-Safe], [Event posting uses atomic compare-and-swap; safe to call from interrupts.], + [Configurable], [Three flags (`CHSM_CFG_LITE`, `NO_FAULT_CNT`, `NO_DEBUG`) trade features for smaller footprint.], + [Debug Channel], [TCP-based real-time state monitoring from the GUI editor.], + [Module Wizard], [Cookiecutter scaffolding generates build-ready module directories.], +) + +== Document Scope + +This reference manual covers: + +- System architecture and design principles. +- Complete C API reference for all runtime structs, functions, and macros. +- Code generation pipeline and template customisation. +- Build system and runtime configuration options. + +For quick-start tutorials, see the HTML documentation built with Sphinx. diff --git a/docs/typst/main.pdf b/docs/typst/main.pdf new file mode 100644 index 00000000..64d33ac9 Binary files /dev/null and b/docs/typst/main.pdf differ diff --git a/docs/typst/main.typ b/docs/typst/main.typ new file mode 100644 index 00000000..d1358d56 --- /dev/null +++ b/docs/typst/main.typ @@ -0,0 +1,17 @@ +// CHSM Reference Manual — Main Document +// Compile: typst compile main.typ + +#import "template.typ": project + +#show: project.with( + title: "CHSM Reference Manual", + subtitle: "C Hierarchical State Machine\nEditor & Runtime Framework", + version: "1.0.0", + author: "Janos Szeman", +) + +#include "chapters/introduction.typ" +#include "chapters/architecture.typ" +#include "chapters/c_api.typ" +#include "chapters/code_generation.typ" +#include "chapters/configuration.typ" diff --git a/docs/typst/template.typ b/docs/typst/template.typ new file mode 100644 index 00000000..d1c3ecc0 --- /dev/null +++ b/docs/typst/template.typ @@ -0,0 +1,133 @@ +// CHSM — Typst Document Template +// Professional enterprise-grade PDF output + +#let project( + title: "", + subtitle: "", + version: "", + author: "", + date: datetime.today().display(), + logo: none, + body, +) = { + // ── Page setup ────────────────────────────────────────────── + set page( + paper: "a4", + margin: (top: 3cm, bottom: 2.5cm, left: 2.5cm, right: 2.5cm), + header: context { + if counter(page).get().first() > 1 { + set text(8pt, fill: luma(120)) + grid( + columns: (1fr, 1fr), + align(left, title), + align(right, [v#version]), + ) + line(length: 100%, stroke: 0.4pt + luma(200)) + } + }, + footer: context { + set text(8pt, fill: luma(120)) + line(length: 100%, stroke: 0.4pt + luma(200)) + v(4pt) + grid( + columns: (1fr, 1fr), + align(left, [#author]), + align(right, counter(page).display("1 / 1", both: true)), + ) + }, + ) + + // ── Typography ────────────────────────────────────────────── + set text(font: "Libertinus Serif", size: 10.5pt, lang: "en") + set par(justify: true, leading: 0.65em) + set heading(numbering: "1.1.1") + + show heading.where(level: 1): it => { + pagebreak(weak: true) + v(1cm) + set text(18pt, weight: "bold", fill: rgb("#1a3c5e")) + block(it) + v(0.5cm) + } + + show heading.where(level: 2): it => { + v(0.6cm) + set text(14pt, weight: "bold", fill: rgb("#2a5f8f")) + block(it) + v(0.3cm) + } + + show heading.where(level: 3): it => { + v(0.4cm) + set text(12pt, weight: "bold") + block(it) + v(0.2cm) + } + + // ── Code blocks ───────────────────────────────────────────── + show raw.where(block: true): it => { + set text(9pt) + block( + fill: luma(245), + inset: 10pt, + radius: 3pt, + width: 100%, + stroke: 0.5pt + luma(220), + it, + ) + } + + show raw.where(block: false): it => { + box( + fill: luma(240), + inset: (x: 3pt, y: 0pt), + outset: (y: 3pt), + radius: 2pt, + it, + ) + } + + // ── Tables ────────────────────────────────────────────────── + set table( + stroke: 0.5pt + luma(200), + inset: 6pt, + ) + + // ── Cover page ────────────────────────────────────────────── + page( + margin: (top: 0cm, bottom: 0cm, left: 0cm, right: 0cm), + header: none, + footer: none, + )[ + #box( + width: 100%, + height: 100%, + fill: rgb("#1a3c5e"), + )[ + #align(center + horizon)[ + #block(inset: 2cm)[ + #text(36pt, weight: "bold", fill: white, title) + #v(0.5cm) + #text(18pt, fill: rgb("#8ab4d6"), subtitle) + #v(1.5cm) + #line(length: 40%, stroke: 1pt + rgb("#8ab4d6")) + #v(1cm) + #text(14pt, fill: rgb("#c0d8ec"), [Version #version]) + #v(0.5cm) + #text(12pt, fill: rgb("#c0d8ec"), date) + #v(0.5cm) + #text(12pt, fill: rgb("#c0d8ec"), author) + ] + ] + ] + ] + + // ── Table of contents ─────────────────────────────────────── + page(header: none)[ + #heading(outlined: false, numbering: none, [Table of Contents]) + #outline(indent: 1.5em, depth: 3) + ] + + // ── Body ──────────────────────────────────────────────────── + body +} diff --git a/gui/c_gen/__init__.py b/gui/c_gen/__init__.py new file mode 100644 index 00000000..53c8066c --- /dev/null +++ b/gui/c_gen/__init__.py @@ -0,0 +1 @@ +from .hsm import StateMachine \ No newline at end of file diff --git a/gui/c_gen/hsm/__init__.py b/gui/c_gen/hsm/__init__.py new file mode 100644 index 00000000..68a23cde --- /dev/null +++ b/gui/c_gen/hsm/__init__.py @@ -0,0 +1,3 @@ +from .sm import StateMachine +from .sm_jinja import JinjaStateMachine +from .parser import Parser, ParserException \ No newline at end of file diff --git a/cgen/hsm/ast.py b/gui/c_gen/hsm/ast.py similarity index 96% rename from cgen/hsm/ast.py rename to gui/c_gen/hsm/ast.py index 036ac55b..756f8839 100644 --- a/cgen/hsm/ast.py +++ b/gui/c_gen/hsm/ast.py @@ -123,7 +123,7 @@ def __str__(self): default_str = '' indent = ' ' * self.indent - return f'{indent}switch({self.variable})\n{indent}{{\n{cases_str}\n{default_str}{indent}}}\n' + return f'{indent}switch({self.variable})\n{indent}{{\n{cases_str}{default_str}{indent}}}\n' def add_case(self, case): self.cases.append(case) @@ -185,9 +185,10 @@ def __str__(self): return f'\n' class Case(Node): - def __init__(self, label, **kwargs): + def __init__(self, label, debug, **kwargs): super().__init__('case', **kwargs) self.label = label + self.debug = debug self.nodes = [] def __str__(self): @@ -200,7 +201,9 @@ def __str__(self): nodes_str += f'{" " * (self.indent + 4)}break;\n' indent = ' ' * self.indent - return f'{indent}case {self.label}:\n{nodes_str}' + case = f'{indent}case {self.label}:\n' + debug_content = f'{" " * (self.indent + 4)}{self.debug}\n' + return f'{case}{debug_content}{nodes_str}' def add(self, node): self.nodes.append(node) diff --git a/gui/c_gen/hsm/parser.py b/gui/c_gen/hsm/parser.py new file mode 100644 index 00000000..ccbb9270 --- /dev/null +++ b/gui/c_gen/hsm/parser.py @@ -0,0 +1,213 @@ +import re + +class ParserException(Exception): + pass + +# Sentinel constants +NOSIG = None # No signal (signalless guard/transition) +NOFUNC = (None, None) # No function call +NOPARAM = None # No parameter +NOGUARD = '' # Empty string key for unguarded entries +NULLFUNC = (None, None) # Null function tuple (filtered out in path_to_funcs) + +class Parser: + def __init__(self): + self.funcs_w_args = set() + self.funcs_wo_args = set() + self.guards_wo_args = set() + self.guards_w_args = set() + self.user_signals = set() + + def get_func(self, data): + data = data.lstrip() + + + m = re.match('[a-zA-z_]+\w*', data) + if m: + fname = m[0] + rem = data[m.span()[1]:] + else: + raise ParserException(f'Expected function identifier in "{data}"') + + rem = rem.lstrip() + + if len(rem) == 0 or rem[0] != '(': + return fname, None, rem + + rem = rem[1:] + + params, c_brace, rem = rem.partition(')') + + params = params.strip() + if params == '': + params = None + else: + for p in params.split(','): + ps = p.strip() + if not ps.isidentifier() and not ps.isalnum(): + raise ParserException(f'Expected identifier as function param but found: "{p}"') + + if c_brace == '': + raise ParserException(f'Expected ")" in "{data}"') + + return fname, params, rem + + def get_signal(self, data): + signal = None + rem = data + + m = re.match('[a-zA-z_]+\w*', data) + if m: + signal = m[0] + rem = data[m.span()[1]:] + + self.user_signals.add(signal) + + return signal, rem + + def get_funcs(self, data): + funcs = [] + + data = data.lstrip() + while data[0] != '}': + func, func_param, data = self.get_func(data) + funcs.append((func, func_param)) + + if func_param: + self.funcs_w_args.add(func) + else: + self.funcs_wo_args.add(func) + + data = data.lstrip() + if not len(data): + raise ParserException('Unexpected end of input') + + if data[0] == ';': + data = data[1:] + + data = data.lstrip() + + return funcs, data[1:] + + def parse_one(self, data, target=None, target_title=None, initial=False, lca=None): + signal = None + guard_func = '' + guard_param = '' + guard_key = '' + funcs = [] + + + # Try to read the sginal + data = data.lstrip() + if data[0].isidentifier(): + signal, data = self.get_signal(data) + + # If there is a guard, read it + data = data.lstrip() + if len(data) and data[0] == '[': + gf, gp, data = self.get_func(data[1:]) + guard_func = gf + guard_param = gp if gp else '' + if gp: + guard_key = f'{gf}({gp})' + self.guards_w_args.add(f'{gf}({gp})') + else: + guard_key = f'{gf}()' + self.guards_wo_args.add(gf) + data = data.lstrip() + if not len(data) or data[0] != ']': + p = gp if gp else '' + raise ParserException(f'Expected "]" after "{gf}({p})..."') + data = data[1:] + + # Find the slash character + data = data.lstrip() + if len(data) and data[0] != '/': + raise ParserException(f'Expected "/" in "{data}..."') + + if len(data): + data = data[1:] + data = data.lstrip() + + if len(data): + if data[0] == '{': + funcs, data = self.get_funcs(data[1:]) + else: + func, func_param, data = self.get_func(data) + funcs.append((func, func_param)) + if func_param: + self.funcs_w_args.add(func) + else: + self.funcs_wo_args.add(func) + + if initial: + signal = 'init' + guard_func = '' + guard_param = '' + guard_key = '' + + g = { + 'guard_func': guard_func, + 'guard_param': guard_param, + 'funcs': funcs, + 'target': target, + 'target_title': target_title, + 'lca': lca + } + + s = { + 'name': signal, + 'guards': { + guard_key: g + } + } + + return s, data + + def empty_signal(self, target=None, target_title=None, initial=False, lca=None): + signal = None + + if initial: + signal = 'init' + + g = { + 'guard_func': '', + 'guard_param': '', + 'funcs': [(None, None)], + 'target': target, + 'target_title': target_title, + 'lca': lca + } + + s = { + 'name': signal, + 'guards': { + '': g + } + } + + return [s] + + def parse(self, data, target=None, target_title=None, initial=False, lca=None): + self.signals = [] + while len(data): + s, data = self.parse_one(data, target, target_title, initial, lca) + self.signals.append(s) + data = data.strip() + + if not self.signals: + self.signals = self.empty_signal(target, target_title, initial, lca) + + return self.signals + +if __name__ == '__main__': + s = ''' +entry/ +exit/ + ''' + from pprint import pprint + p = Parser() + r = p.parse(s) + pprint(r) + pprint(p.funcs_w_args) + pprint(p.funcs_wo_args) \ No newline at end of file diff --git a/cgen/hsm/sm.py b/gui/c_gen/hsm/sm.py similarity index 80% rename from cgen/hsm/sm.py rename to gui/c_gen/hsm/sm.py index bb4dfa6b..9dce0340 100644 --- a/cgen/hsm/sm.py +++ b/gui/c_gen/hsm/sm.py @@ -3,7 +3,10 @@ import logging from datetime import datetime from .ast import Func, If, Switch, Case, Call, Break, Return, Blank, Expr, Ast, FuncDeclaration, Include, Ifndef, Define, Endif, Comment, Decl, Assignment, Enum -from typing import List, Dict +import pprint +from copy import deepcopy +from .parser import Parser, ParserException +from cookiecutter.main import cookiecutter # TODO: make sure, that there is only one exit function and it has no parameters @@ -16,8 +19,10 @@ # [guard()] EVENT_PATTERN = r'^(\s*(?P\w+)\s*)*(\[(?P\w+)\((?P[\w,\s]*)\)\])*(\s*/\s*(?P\w+)(?P\((?P[\w,\s]*)\))*\s*)*' +VERSION_STRING = 'Generated with CHSM v0.0.2' + class StateMachine: - def __init__(self, data, h_file, funcs_h_file, templates, file_config,): + def __init__(self, data, h_file, funcs_h_file, templates, file_config): self.templates = templates self.file_config = file_config self.machine_h = h_file.name @@ -31,7 +36,14 @@ def __init__(self, data, h_file, funcs_h_file, templates, file_config,): self.states = self.get_states(data) # Extract states from the data self.add_transitions_to_states(self.states, data) # Extract transition info from the data and add it to the states + self.add_parent_signals(self.states) self.process_transitions(self.states) # Calculate transition exit and entry paths and the exact end state + + with open("states.txt", 'w') as f: + pprint.pprint(self.states, f, indent=4) + + self.delete_non_leaf_states(self.states) + self.notes = data['notes'] top_func = self._get_user_symbols(h_file) @@ -58,6 +70,7 @@ def _get_user_symbols(self, hpath): with open(hpath, 'r') as h_file: h_data = h_file.read() + logging.info(f'Top func template: {self.templates["top_state_name"]}') m = re.search(self.templates['top_state_name'], h_data) if m: top_func = m.group('top_func') @@ -75,11 +88,12 @@ def build_user_declarations(self, funcs, guards, states): ast.nodes.append(Define(symbol)) ast.nodes.append(Blank()) - ast.nodes.append(Comment(f'Generated with CHSM v0.0.0 at {datetime.strftime(datetime.now(), "%Y.%m.%d %H.%M.%S")}')) + ast.nodes.append(Comment(VERSION_STRING)) ast.nodes.append(Blank()) ast.nodes.append(Blank()) ast.nodes.append(Include(self.machine_h)) + ast.nodes.append(f'#include "chsm_cfg.h"') for i in self.templates['h_include_list']: ast.nodes.append(Include(i)) @@ -93,6 +107,13 @@ def build_user_declarations(self, funcs, guards, states): ast.nodes.append(FuncDeclaration(f, 'void', self.templates['user_func_params'])) ast.nodes.append(Blank()) + ast.nodes.append(Blank()) + ast.nodes.append(f'#ifndef CHSM_CFG_NO_DEBUG') + ast.nodes.append(f'void {self.prefix}_debug_log_func(uint8_t *trans_name, const char *state_func);') + ast.nodes.append(Blank()) + + ast.nodes.append(f'extern char {self.prefix}_debug_state_ac[20];') + ast.nodes.append(f'#endif /* CHSM_CFG_NO_DEBUG */') for g in sorted(guards): ast.nodes.append(Blank()) @@ -140,30 +161,77 @@ def build_user_declarations(self, funcs, guards, states): return ast - def get_transition_funcs(self, start, end): - path = self.get_transition_path(start, end) + def get_transition_funcs(self, start, end, lca): + path = self.get_transition_path(start, end, lca) return self.path_to_funcs(path), path[-1][0] def process_transitions(self, states): for s_id, s in states.items(): + if s['children']: + continue for sig_id, sig in s['signals'].items(): if sig_id == 'init': continue for g in sig['guards'].values(): if g['target']: - tfuncs, target = self.get_transition_funcs(s_id, g['target']) + tfuncs, target = self.get_transition_funcs(s_id, g['target'], g['lca']) #g['transition_funcs'] = tfuncs g['funcs'].extend(tfuncs) g['target_title'] = states[target]['title'] #The only place where transition functions are needed for an init signal is the __top__ g = states['__top__']['signals']['init']['guards'][(None, None)] - tfuncs, target = self.get_transition_funcs('__top__', g['target']) + tfuncs, target = self.get_transition_funcs('__top__', g['target'], g['lca']) g['funcs'].extend(tfuncs) g['target_title'] = states[target]['title'] + def delete_non_leaf_states(self, states): + for s_id in [*states.keys()]: + s = states[s_id] + if s['children'] and s['parent']: + print(s['title']) + del states[s_id] + elif s['parent']: + s['parent'] = '__top__' + + def add_parent_signals(self, states): + for s_id, s in states.items(): + if not s['children'] and s['type'] == 'normal': + self.add_parent_signals_to_state(s_id, states) + + def add_parent_signals_to_state(self, state_id, states): + """ + Take a state, go through its parent states and add signal handlers + that are not already in the original state. + If the signal already has some handlers in the original state, then + go through the guards one by one and copy those that are not in the + original state. + """ + signals = states[state_id]['signals'] + + parent_id = states[state_id]['parent'] + while parent_id: + p_signals = states[parent_id]['signals'] + for sig_id, sig in p_signals.items(): + if sig_id in ('entry', 'exit', 'init'): + continue + + if not sig_id in signals: + signals[sig_id] = deepcopy(sig) + + else: + guards = signals[sig_id]['guards'] + for guard_id, p_guard in sig['guards'].items(): + if not guard_id in guards: + guards[guard_id] = deepcopy(p_guard) + + parent_id = states[parent_id]['parent'] + + - def str_to_signal(self, line, target=None, target_title=None, initial=False): + + + def str_to_signal(self, line, target=None, target_title=None, initial=False, lca=None): signal = None guard = None func = None @@ -204,7 +272,8 @@ def str_to_signal(self, line, target=None, target_title=None, initial=False): 'guard': (guard, gparams), 'funcs': [(func, fparams)], 'target': target, - 'target_title': target_title + 'target_title': target_title, + 'lca': lca } s = { @@ -263,9 +332,20 @@ def get_states(self, data): if s_id.startswith('state_'): state['num'] = int(re.findall(r'\d+', s_id)[0]) - for line in s['text']: - s = self.str_to_signal(line) - self.add_signal_to_state(state, s) + txt = '\n'.join(s['text']) + p = Parser() + try: + sigs = p.parse(txt) + except ParserException as e: + logging.info(f'Exception {str(e)} in state "{s["title"]}". Text:\n{txt}') + + for sig in sigs: + self.add_signal_to_state(state, sig) + + self.user_inc_funcs.update(p.funcs_w_args) + self.user_funcs.update(p.funcs_wo_args) + self.user_signals.update(p.user_signals) + self.user_guards.update(p.guards_wo_args) states[s_id] = state @@ -294,15 +374,34 @@ def add_transitions_to_states(self, states, data): for tr in data['transitions'].values(): start, target, label = self.resolve_transition(tr, data) + if target: + if self.is_in(start, target): + lca = target + else: + lca = self.get_LCA(start, target) + else: + lca = None + + p = Parser() + if states[start]['type'] == 'initial': start = states[start]['parent'] states[start]['initial'] = target - signal = self.str_to_signal(label, target=target, target_title=states[target]['title'], initial=True) + signals = p.parse(label, target=target, target_title=states[target]['title'], initial=True) else: - signal = self.str_to_signal(label, target, target_title=states[target]['title'], initial=False) + signals = p.parse(label, target, target_title=states[target]['title'], initial=False, lca=lca) + + try: + self.add_signal_to_state(states[start], signals[0]) + except: + print(signals) + raise - self.add_signal_to_state(states[start], signal) + self.user_inc_funcs.update(p.funcs_w_args) + self.user_funcs.update(p.funcs_wo_args) + self.user_signals.update(p.user_signals) + self.user_guards.update(p.guards_wo_args) def make_call(self, func, params, standalone=False): fparams = f', {params}' if params else '' @@ -318,9 +417,6 @@ def guard_to_ast(self, guard): i = If(self.make_call(func, param)) add(i) add = i.add_true - - if guard['target']: - add(Call(self.templates['exit_children'], self.templates['func_args'])) for func, param in guard['funcs']: if func: @@ -333,6 +429,23 @@ def guard_to_ast(self, guard): return nodes + def build_debug_func(self, landing_state = None): + printf_str = f'printf("{self.prefix}_%s --%s-->\\n", state_func, trans_name);' + return f''' +#ifndef CHSM_CFG_NO_DEBUG +char {self.prefix}_debug_state_ac[20]; + +void {self.prefix}_debug_log_func(uint8_t *trans_name, const char *state_func) +{{ +\t#ifdef CHSM_BUILD_TESTS +\t\t{printf_str} +\t#else +\t\tmemset({self.prefix}_debug_state_ac, 0, 20); +\t\tstrncpy({self.prefix}_debug_state_ac, state_func, 19); +\t\t{self.prefix}_debug_state_ac[19] = '\\0'; +\t#endif +}} +#endif /* CHSM_CFG_NO_DEBUG */''' def build_case_from_signal(self, signal): name = signal['name'] @@ -342,7 +455,7 @@ def build_case_from_signal(self, signal): else: name = f'{self.templates["signal_prefix"]}{name}' - c = Case(name) + c = Case(name,debug=f'#ifndef CHSM_CFG_NO_DEBUG\n {self.prefix}_debug_log_func("{name}", __FUNCTION__);\n #endif') for guard in signal['guards'].values(): nodes = self.guard_to_ast(guard) @@ -356,7 +469,6 @@ def build_case_from_signal(self, signal): def build_func_from_state(self, state_id, state, insert_init=False, spec=''): f = Func(name=state['title'], ftype=self.templates['func_return_type'], params=self.templates['func_params'], spec=spec) - f.add(Decl('bool', self.templates['guards_only_variable'], 'true')) s = Switch(self.templates['switch_variable']) f.add(s) @@ -370,70 +482,51 @@ def build_func_from_state(self, state_id, state, insert_init=False, spec=''): if c: s.add_case(c) - s.add_default(Assignment(self.templates['guards_only_variable'], 'false')) - for guard in state['signals'][None]['guards'].values(): - f.add(Blank()) nodes = self.guard_to_ast(guard) + if nodes: + f.add(Blank()) for n in nodes: f.add(n) + + result = self.templates['ignored_result'] f.add(Blank()) - - exit_func = 'NULL' - efw = None - try: - exit_func, exit_param = state['signals']['exit']['guards'][(None, None)]['funcs'][0] - print(f"{state['title']} exit: {exit_func}({exit_param})") - - if exit_param: - exit_func_wrapper = f"{state['title']}_exit_func_wrapper" - efw = Func(name=exit_func_wrapper, ftype='void', params=self.templates['user_func_params_t'], spec='static') - efw.add(self.make_call(exit_func, exit_param, True)) - exit_func = exit_func_wrapper - - except KeyError: - pass - - if exit_func == None: - exit_func = 'NULL' - - if state['parent']: - result = self.templates['parent_result'].format(parent=state['parent_title'], exit_func=exit_func) - else: - result = self.templates['ignored_result'] - f.add(Return(result)) - return f, efw + return f def build_ast(self, states): ast = Ast() ast.nodes.append(Blank()) + for s_id, s in states.items(): if s['type'] != 'normal': continue - state_func, exit_func_wrapper = self.build_func_from_state(s_id, s, spec='static') - - if exit_func_wrapper: - ast.nodes.append(exit_func_wrapper) + state_func = self.build_func_from_state(s_id, s, spec='static') ast.nodes.append(state_func) ast.nodes.insert(0, state_func.declaration()) - top_func, _ = self.build_func_from_state(self.top_func, states['__top__'], True) + top_func = self.build_func_from_state(self.top_func, states['__top__'], True) + debug_func = self.build_debug_func() ast.nodes.append(top_func) + ast.nodes.append(debug_func) + + ast.nodes.append(Blank()) ast.nodes.insert(0, Blank()) ast.nodes.insert(0, Include(self.funcs_h)) ast.nodes.insert(0, Include(self.machine_h)) + ast.nodes.insert(0, f'#ifndef CHSM_CFG_NO_DEBUG\n#include \n#endif') + ast.nodes.insert(0, f'#include "chsm_cfg.h"') for i in self.templates['c_include_list']: ast.nodes.insert(0, Include(i)) ast.nodes.insert(0, Blank()) - ast.nodes.insert(0, Comment(f'Generated with CHSM v0.0.0 at {datetime.strftime(datetime.now(), "%Y.%m.%d %H.%M.%S")}')) + ast.nodes.insert(0, Comment(VERSION_STRING)) return ast @@ -475,8 +568,8 @@ def is_in(self, state_id, composit_state_id): def get_LCA(self, start_state_id, target_state_id): """Find Lowest Common Ancestor""" - if self.is_in(start_state_id, target_state_id): - return target_state_id + #if self.is_in(start_state_id, target_state_id): + # return target_state_id super_id = start_state_id while True: @@ -495,11 +588,10 @@ def get_exit_path(self, start_state_id, target_state_id): return path - def get_transition_path(self, start_state_id, target_state_id): + def get_transition_path(self, start_state_id, target_state_id, lca): if target_state_id == '__top__': return self.get_exit_path(start_state_id, '__top__') else: - lca = self.get_LCA(start_state_id, target_state_id) exit_path = self.get_exit_path(start_state_id, lca) init_path = self.get_init_path(lca, target_state_id) return exit_path + init_path diff --git a/gui/c_gen/hsm/sm_jinja.py b/gui/c_gen/hsm/sm_jinja.py new file mode 100644 index 00000000..165a8aa6 --- /dev/null +++ b/gui/c_gen/hsm/sm_jinja.py @@ -0,0 +1,460 @@ +""" +Jinja-compatible StateMachine class. +Produces a data dict suitable for Jinja template rendering. +Used by the job-based code generation system alongside the existing AST-based SM. +""" +import json +import re +import logging +from copy import deepcopy +from .parser import Parser, ParserException, NOSIG, NOFUNC, NOPARAM, NOGUARD, NULLFUNC + +VERSION_STRING = 'Generated with CHSM v0.0.2' + +SYS_SIGNALS = ('entry', 'exit', 'init') + + +class JinjaStateMachine: + def __init__(self, data): + + self.user_funcs = set() + self.user_guards = set() + self.user_signals = set() + self.user_inc_funcs = set() + self.user_inc_guards = set() + + data['states']['__top__']['parent'] = "" + self.states = self.get_states(data) # Extract states from the data + self.add_transitions_to_states(self.states, data) # Extract transition info from the data and add it to the states + self.add_parent_signals(self.states) + self.process_transitions(self.states) # Calculate transition exit and entry paths and the exact end state + + self.delete_non_leaf_states(self.states) + + self.notes = data['notes'] + + self.resolve_parent_titles(self.states) + + self.remove_unnecessary_transitions(self.states) + + self.remove_initial_states(self.states) + + self.clean_up_signals() + + self.clean_up_notes() + + self.data = { + 'states': self.states, + 'user_funcs': self.user_funcs, + 'user_guards': self.user_guards, + 'user_signals': self.user_signals, + 'user_inc_funcs': self.user_inc_funcs, + 'user_inc_guards': self.user_inc_guards, + 'notes': self.notes, + } + + def clean_up_notes(self): + notes = {} + for k, v in self.notes.items(): + if v: + if k.endswith('()'): + notes[k[:-2]] = v + else: + notes[k] = v.strip() + self.notes = notes + + def clean_up_signals(self): + self.user_signals = {i for i in self.user_signals if i not in ('entry', 'exit', 'init')} + + def get_transition_funcs(self, start, end, lca): + path = self.get_transition_path(start, end, lca) + return self.path_to_funcs(path), path[-1][0] + + def process_guard_transition(self, s_id, g, states): + if g['target']: + lca = g.get('lca', '') + if not lca: + logging.warning(f'process_guard_transition: guard in state {s_id} has no lca, target={g["target"]}') + return + tfuncs, target = self.get_transition_funcs(s_id, g['target'], lca) + g['funcs'].extend(tfuncs) + g['target_title'] = states[target]['title'] + g['target_type'] = states[target]['type'] + if 'params' in states[target]: + g['target_params'] = states[target]['params'] + + def process_transitions(self, states): + for s_id, s in states.items(): + if s['children']: + continue + for sig_id, sig in s['signals'].items(): + for g in sig['guards'].values(): + self.process_guard_transition(s_id, g, states) + + for g in s['guards'].values(): + self.process_guard_transition(s_id, g, states) + + # The only place where transition functions are needed for an init signal is the __top__ + g = states['__top__']['sys_signals']['init'] + lca = g.get('lca', '__top__') or '__top__' + tfuncs, target = self.get_transition_funcs('__top__', g['target'], lca) + g['funcs'].extend(tfuncs) + g['target_title'] = states[target]['title'] + + def delete_non_leaf_states(self, states): + for s_id in [*states.keys()]: + s = states[s_id] + if s['children'] and s['parent']: + del states[s_id] + elif s['parent']: + s['parent'] = '__top__' + + def add_parent_signals(self, states): + for s_id, s in states.items(): + if not s['children'] and s['type'] == 'normal': + self.add_parent_signals_to_state(s_id, states) + + def add_parent_signals_to_state(self, state_id, states): + """ + Take a state, go through its parent states and add signal handlers + that are not already in the original state. + If the signal already has some handlers in the original state, then + go through the guards one by one and copy those that are not in the + original state. + """ + state = states[state_id] + signals = state['signals'] + + parent_id = state['parent'] + while parent_id: + parent = states[parent_id] + p_signals = parent['signals'] + for sig_id, sig in p_signals.items(): + + if not sig_id in signals: + signals[sig_id] = deepcopy(sig) + + else: + guards = signals[sig_id]['guards'] + for guard_id, p_guard in sig['guards'].items(): + if not guard_id in guards: + guards[guard_id] = deepcopy(p_guard) + + # Go through the parent state guards and copy those as well + guards = state['guards'] + for guard_id, p_guard in parent['guards'].items(): + if not guard_id in guards: + guards[guard_id] = deepcopy(p_guard) + + parent_id = states[parent_id]['parent'] + + def add_signal_to_state(self, state, signal): + signal_name = signal['name'] + + if signal_name == '': + for g_fn, g in signal['guards'].items(): + if g_fn in state['guards']: + orig_guard = state['guards'][g_fn] + + # Add functions to the original guard + orig_guard['funcs'].extend(g['funcs']) + + # Set the target + if g['target']: + if orig_guard['target'] and orig_guard['target'] != g['target']: + logging.error(f"Guard target mismatch for {g_fn} in {state['title']}: {orig_guard['target']} != {g['target']}") + else: + orig_guard['target'] = g['target'] + else: + state['guards'][g_fn] = g + + elif signal_name in SYS_SIGNALS: + if not state['sys_signals'][signal_name]: + state['sys_signals'][signal_name]['funcs'] = signal['guards']['']['funcs'] + else: + state['sys_signals'][signal_name]['funcs'].extend(signal['guards']['']['funcs']) + state['sys_signals'][signal_name]['target'] = signal['guards']['']['target'] + state['sys_signals'][signal_name]['target_title'] = signal['guards']['']['target_title'] + state['sys_signals'][signal_name]['lca'] = signal['guards']['']['lca'] + elif signal_name not in state['signals']: + state['signals'][signal_name] = signal + else: + orig_signal = state['signals'][signal_name] + + for g_fn, g in signal['guards'].items(): + if g_fn in orig_signal['guards']: + orig_guard = orig_signal['guards'][g_fn] + + # Add functions to the original guard + orig_guard['funcs'].extend(g['funcs']) + + # Set the target + if g['target']: + if orig_guard['target'] and orig_guard['target'] != g['target']: + logging.error(f"Guard target mismatch for {g_fn} in {state['title']}: {orig_guard['target']} != {g['target']}") + else: + orig_guard['target'] = g['target'] + + else: + orig_signal['guards'][g_fn] = g + + def process_state_title(self, title): + """Parse the title string. A state title can be a function identifier + or a function call. + Return: (function_name, params, is_call), where: + function: name of the function or id + params: parameter string, + is_call: True, if the title is actually a function call.""" + title = title.lstrip() + + m = re.match(r'[a-zA-z_]+\w*', title) + if m: + fname = m[0] + rem = title[m.span()[1]:] + else: + raise ParserException(f'Expected function identifier in "{title}"') + + rem = rem.lstrip() + + if len(rem) == 0 or rem[0] != '(': + return fname, "", False + + rem = rem[1:] + + params, c_brace, rem = rem.partition(')') + + params = params.strip() + if params == '': + params = "" + else: + for p in params.split(','): + ps = p.strip() + if not ps.isidentifier() and not ps.isalnum(): + raise ParserException(f'Expected identifier as function param but found: "{p}"') + + if c_brace == '': + raise ParserException(f'Expected ")" in "{title}"') + + return fname, params, True + + def get_states(self, data): + """Extract state info from drawing data into a dict""" + states = {} + + for s_id, s in data['states'].items(): + if s['type'] == 'initial': + title = s_id + params = '' + is_call = False + else: + title, params, is_call = self.process_state_title(s['title']) + + state = { + 'signals': {}, + 'sys_signals': { + 'entry': {}, + 'exit': {}, + 'init': {} + }, + 'guards': {}, + 'parent': s['parent'], + 'children': s['children'], + 'title': title, + 'type': s['type'], + } + + if is_call: + state['type'] = 'call' + state['params'] = params + else: + if s_id.startswith('state_'): + state['num'] = int(re.findall(r'\d+', s_id)[0]) + + p = Parser() + for text_entry in s['text']: + text_entry = text_entry.strip() + if not text_entry: + continue + try: + sigs = p.parse(text_entry) + except ParserException as e: + logging.info(f'Exception {str(e)} in state "{s["title"]}". Text:\n{text_entry}') + sigs = [] + + for sig in sigs: + self.add_signal_to_state(state, sig) + + self.user_inc_funcs.update(p.funcs_w_args) + self.user_inc_guards.update(p.guards_w_args) + self.user_funcs.update(p.funcs_wo_args) + self.user_signals.update(p.user_signals) + self.user_guards.update(p.guards_wo_args) + + states[s_id] = state + + return states + + def resolve_parent_titles(self, states): + for s in states.values(): + if s['parent']: + s['parent_title'] = states[s['parent']]['title'] + + def remove_initial_states(self, states): + keys = tuple(states.keys()) + for k in keys: + if states[k]['type'] == 'initial': + del states[k] + + def remove_unnecessary_transitions(self, states): + """Remove transition targets pointing to the current state.""" + for state in states.values(): + for signal in state['signals'].values(): + for guard in signal['guards'].values(): + if guard.get("target_title", "") == state['title']: + guard['target'] = "" + guard["target_title"] = "" + + def resolve_transition(self, tr, data): + """Return the label, the start and the end states of a transition""" + start_conn = data['connectors'][tr['start']] + end_conn = data['connectors'][tr['end']] + + start_state = start_conn['parent'] + end_state = end_conn['parent'] + event = tr['label'] + + return start_state, end_state, event + + def add_transitions_to_states(self, states, data): + """Go through the transitions in the state machine, and add them + to the start states""" + + for tr in data['transitions'].values(): + start, target, label = self.resolve_transition(tr, data) + + if target: + if self.is_in(start, target): + lca = target + else: + lca = self.get_LCA(start, target) + else: + lca = "" + + p = Parser() + + if states[start]['type'] == 'initial': + start = states[start]['parent'] + states[start]['initial'] = target + + signals = p.parse(label, target=target, target_title=states[target]['title'], initial=True) + else: + signals = p.parse(label, target, target_title=states[target]['title'], initial=False, lca=lca) + + try: + if signals: + self.add_signal_to_state(states[start], signals[0]) + except: + print(signals) + raise + + self.user_inc_funcs.update(p.funcs_w_args) + self.user_inc_guards.update(p.guards_w_args) + self.user_funcs.update(p.funcs_wo_args) + self.user_signals.update(p.user_signals) + self.user_guards.update(p.guards_wo_args) + + def get_entry_path(self, start_state_id, target_state_id): + + if start_state_id == target_state_id: + return tuple() + + state_id = target_state_id + path = [] + while True: + path.append((state_id, 'entry')) + + if state_id not in self.states: + return path + + super_id = self.states[state_id]['parent'] + + if super_id == start_state_id: + return reversed(path) + else: + state_id = super_id + + def is_in(self, state_id, composit_state_id): + if composit_state_id == '__top__': + return True + elif state_id == '__top__': + return False + + while True: + super_id = self.states[state_id]['parent'] + + if super_id == '__top__': + return False + elif super_id == composit_state_id: + return True + else: + state_id = super_id + + def get_LCA(self, start_state_id, target_state_id): + """Find Lowest Common Ancestor""" + + super_id = start_state_id + while True: + if self.is_in(target_state_id, super_id): + return super_id + else: + super_id = self.states[super_id]['parent'] + + def get_exit_path(self, start_state_id, target_state_id): + path = [] + s = start_state_id + + if s == "__top__": + return path + + while s != target_state_id: + path.append((s, 'exit')) + s = self.states[s]['parent'] + + return path + + def get_transition_path(self, start_state_id, target_state_id, lca): + if target_state_id == '__top__': + return self.get_exit_path(start_state_id, '__top__') + else: + exit_path = self.get_exit_path(start_state_id, lca) + init_path = self.get_init_path(lca, target_state_id) + return exit_path + init_path + + def get_init_path(self, start_state_id, target_state_id): + '''This func enters the target state and then enter the init state of the + target, if defined''' + path = [] + while True: + entry_path = self.get_entry_path(start_state_id, target_state_id) + path.extend(entry_path) + + path.append((target_state_id, 'init')) + init_state_id = self.states[target_state_id].get('initial', "") + if init_state_id == "": + return path + else: + start_state_id = target_state_id + target_state_id = init_state_id + + def path_to_funcs(self, path): + funcs = [] + for step in path: + state_id, event_id = step + try: + funcs.extend(self.states[state_id]['sys_signals'][event_id]['funcs']) + except KeyError: + pass + + funcs = [f for f in funcs if f != NULLFUNC] + + return tuple(funcs) diff --git a/gui/c_gen/module_template/_template/cookiecutter.json b/gui/c_gen/module_template/_template/cookiecutter.json new file mode 100644 index 00000000..5bd70405 --- /dev/null +++ b/gui/c_gen/module_template/_template/cookiecutter.json @@ -0,0 +1,8 @@ +{ + "module_name": "template", + "comm_periph": "i2c", + "address":"0x00", + "author":"xsession", + "full_name":"Laszlo Ivanyi", + "licence":"MIT" +} \ No newline at end of file diff --git a/gui/c_gen/module_template/_template/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h b/gui/c_gen/module_template/_template/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h new file mode 100644 index 00000000..313b22ee --- /dev/null +++ b/gui/c_gen/module_template/_template/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h @@ -0,0 +1,42 @@ +#ifndef {{cookiecutter.module_name|upper}}_FUNCTIONS_H +#define {{cookiecutter.module_name|upper}}_FUNCTIONS_H + +#include "chsm.h" +#include "cevent.h" +#include +{% for include in cookiecutter.includes %} +#include "{{include}}.h" +{% endfor %} + +{% for function in cookiecutter.functions %} +void {{cookiecutter.module_name}}_{{function}}(chsm_tst *self, const cevent_tst *e_pst); +{% endfor %} + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func); +extern char {{cookiecutter.module_name}}_debug_state_ac[20]; + +typedef enum {{cookiecutter.module_name}}_state_id_ten +{ +{% for enum in cokkiecutter.state_enums %} +{{ enum }} +{% endfor %} +} {{cookiecutter.module_name}}_state_id_ten; + +/* +Signals: +{% for %} + SIG_I2C_RESULT_ADDR_NACK + SIG_I2C_RESULT_DATA_NACK + SIG_I2C_RESULT_SUCCESS + SIG_{{cookiecutter.module_name|upper}}_READ + SIG_SYS_TICK_10ms +*/ + +/* +Other function notes: + +{{cookiecutter.module_name}}_error_count: + +{{cookiecutter.module_name}}_timeout: +*/ +#endif diff --git a/gui/c_gen/module_template/_template/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c b/gui/c_gen/module_template/_template/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c new file mode 100644 index 00000000..fe87e9b7 --- /dev/null +++ b/gui/c_gen/module_template/_template/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c @@ -0,0 +1,449 @@ +/*Generated with CHSM v0.0.0 at 2023.07.31 10.25.58*/ +#include "cevent.h" +#include "chsm.h" +#include +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_functions.h" + + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst); +char {{cookiecutter.module_name}}_debug_state_ac[20]; + +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + if({{cookiecutter.module_name}}_id_match(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + break; + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_online_event(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_{{cookiecutter.module_name|upper}}_READ: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_{{cookiecutter.module_name|upper}}_READ", __FUNCTION__); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_update_temp(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_down); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +chsm_result_ten {{cookiecutter.module_name}}_top(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case C_SIG_INIT: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "C_SIG_INIT", __FUNCTION__); + {{cookiecutter.module_name}}_init(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func) +{ + #ifdef CHSM_BUILD_TESTS + printf("{{cookiecutter.module_name}}_%s --%s-->\n", state_func, trans_name); + #else + CRF_UNUSED(self); + CRF_UNUSED(est); + CRF_UNUSED(trans_name); + CRF_UNUSED(state_func); + memset({{cookiecutter.module_name}}_debug_state_ac, 0, 20); + strncpy({{cookiecutter.module_name}}_debug_state_ac, state_func, 19); + {{cookiecutter.module_name}}_debug_state_ac[19] = '\0'; + #endif +} diff --git a/gui/c_gen/module_template/_template_new/cookiecutter.json b/gui/c_gen/module_template/_template_new/cookiecutter.json new file mode 100644 index 00000000..ca97641d --- /dev/null +++ b/gui/c_gen/module_template/_template_new/cookiecutter.json @@ -0,0 +1,15 @@ +{ + "module_name": "name", + "version": "", + "description": "", + "module_location": "", + "module_linked_libs": "", + "module_package_name": "", + "module_functions": "", + "module_includes": "", + "comm_periph": "i2c", + "address":"0x00", + "author":"author", + "full_name":"name_full", + "licence":"MIT" +} \ No newline at end of file diff --git a/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/CMakeLists.txt b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/CMakeLists.txt new file mode 100644 index 00000000..fb4fc886 --- /dev/null +++ b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/CMakeLists.txt @@ -0,0 +1,26 @@ + +add_module_lib( + NAME + {{cookiecutter.module_name}} + PACKAGE + chsm + SOURCE + src/{{cookiecutter.module_name}}.c + src/{{cookiecutter.module_name}}_functions.c + INCLUDE + inc + LINK + {% if cookiecutter.comm_periph == "i2c" %} + chsm::i2c_master + {% elif cookiecutter.comm_periph == "spi" %} + chsm::spi_master + {% elif cookiecutter.comm_periph == "can" %} + chsm::canopen + {% else %} + {% endif %} + signal_classes_modules + DEFINES + NDEBUG + STANDARD + 11 +) \ No newline at end of file diff --git a/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/doc/{{cookiecutter.module_name}}.html b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/doc/{{cookiecutter.module_name}}.html new file mode 100644 index 00000000..84fd9830 --- /dev/null +++ b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/doc/{{cookiecutter.module_name}}.html @@ -0,0 +1,2493 @@ + + + + + + +
+ + + + + + SIG_I2C_RESULT_SUCCESS[{{cookiecutter.module_name}}_wait_cnt()]SIG_I2C_RESULT_SUCCESS[{{cookiecutter.module_name}}_wait_cnt()]SIG_I2C_RESULT_SUCCESSSIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_SUCCESS/ {{cookiecutter.module_name}}_update_temp()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_reset_timer()SIG_{{cookiecutter.module_name|upper}}_READSIG_I2C_RESULT_SUCCESS[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]SIG_I2C_RESULT_SUCCESS [{{cookiecutter.module_name}}_id_match()][{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)]/ {{cookiecutter.module_name}}_reset_timer()SIG_I2C_RESULT_DATA_NACKSIG_I2C_RESULT_ADDR_NACK[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)] + __top__s_{{cookiecutter.module_name}}entry/ {{cookiecutter.module_name}}_init()SIG_SYS_TICK_10ms/ {{cookiecutter.module_name}}_10ms_callback()s_initentry/ {{cookiecutter.module_name}}_reset_error_cnt()s_configentry/ {{cookiecutter.module_name}}_reset_timer()s_onlineentry/ send_online_event()exit/ send_offline_event()s_read_id_regentry/ {{cookiecutter.module_name}}_read_id()exit/ {{cookiecutter.module_name}}_reset_timer()s_unpluggedentry/ {{cookiecutter.module_name}}_unplugged()s_set_resolutionentry/ {{cookiecutter.module_name}}_set_resolution()exit/ {{cookiecutter.module_name}}_reset_timer()s_reset_ptr_regentry/ {{cookiecutter.module_name}}_reset_pointer()exit/ {{cookiecutter.module_name}}_reset_timer()s_idleinit/ {{cookiecutter.module_name}}_reset_timer()entry/ {{cookiecutter.module_name}}_reset_timer()s_readingentry/ {{cookiecutter.module_name}}_start_read()exit/ {{cookiecutter.module_name}}_reset_timer()s_power_downentry/ {{cookiecutter.module_name}}_set_full_powerdown()exit/ {{cookiecutter.module_name}}_reset_timer()s_power_upentry/ {{cookiecutter.module_name}}_set_full_powerup()exit/ {{cookiecutter.module_name}}_reset_timer()s_wait_power_downinit/ {{cookiecutter.module_name}}_init_wait()s_wait_power_upinit/ {{cookiecutter.module_name}}_init_wait() + + +
+ +
+ json +
+            {
+    "states": {
+        "__top__": {
+            "pos": [
+                -100000000,
+                -100000000
+            ],
+            "size": [
+                200000000,
+                200000000
+            ],
+            "title": "__top__",
+            "text": [],
+            "connectors": [],
+            "parent": null,
+            "children": [
+                "istate_0",
+                "state_0"
+            ],
+            "type": "top"
+        },
+        "istate_0": {
+            "pos": [
+                51,
+                9
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_0",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_0"
+            ],
+            "parent": "__top__",
+            "children": [],
+            "type": "initial"
+        },
+        "state_0": {
+            "pos": [
+                5,
+                14
+            ],
+            "size": [
+                111,
+                166
+            ],
+            "title": "s_{{cookiecutter.module_name}}",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_init()",
+                "SIG_SYS_TICK_10ms/ {{cookiecutter.module_name}}_10ms_callback()"
+            ],
+            "connectors": [
+                "conn_1",
+                "conn_17",
+                "conn_51"
+            ],
+            "parent": "__top__",
+            "children": [
+                "state_1",
+                "state_2",
+                "state_3",
+                "istate_1"
+            ],
+            "type": "normal"
+        },
+        "state_1": {
+            "pos": [
+                10,
+                28
+            ],
+            "size": [
+                91,
+                24
+            ],
+            "title": "s_init",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_reset_error_cnt()"
+            ],
+            "connectors": [
+                "conn_3"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_4",
+                "state_5",
+                "istate_2"
+            ],
+            "type": "normal"
+        },
+        "state_2": {
+            "pos": [
+                24,
+                56
+            ],
+            "size": [
+                89,
+                79
+            ],
+            "title": "s_config",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_15",
+                "conn_50"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_6",
+                "state_7",
+                "istate_3",
+                "state_10",
+                "state_11",
+                "state_12",
+                "state_13"
+            ],
+            "type": "normal"
+        },
+        "state_3": {
+            "pos": [
+                11,
+                146
+            ],
+            "size": [
+                86,
+                29
+            ],
+            "title": "s_online",
+            "text": [
+                "entry/ send_online_event()",
+                "exit/ send_offline_event()"
+            ],
+            "connectors": [
+                "conn_16",
+                "conn_23"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_8",
+                "state_9",
+                "istate_4"
+            ],
+            "type": "normal"
+        },
+        "istate_1": {
+            "pos": [
+                12,
+                24
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_1",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_2"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "initial"
+        },
+        "state_4": {
+            "pos": [
+                15,
+                35
+            ],
+            "size": [
+                16,
+                15
+            ],
+            "title": "s_read_id_reg",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_read_id()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_5",
+                "conn_6",
+                "conn_8",
+                "conn_10",
+                "conn_13",
+                "conn_14"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "normal"
+        },
+        "state_5": {
+            "pos": [
+                75,
+                35
+            ],
+            "size": [
+                17,
+                13
+            ],
+            "title": "s_unplugged",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_unplugged()"
+            ],
+            "connectors": [
+                "conn_7",
+                "conn_9",
+                "conn_11",
+                "conn_12"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_2": {
+            "pos": [
+                12,
+                36
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_2",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_4"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "initial"
+        },
+        "state_6": {
+            "pos": [
+                52,
+                84
+            ],
+            "size": [
+                18,
+                12
+            ],
+            "title": "s_set_resolution",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_set_resolution()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_38",
+                "conn_39",
+                "conn_40",
+                "conn_41",
+                "conn_42",
+                "conn_43",
+                "conn_71",
+                "conn_62"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_7": {
+            "pos": [
+                53,
+                118
+            ],
+            "size": [
+                17,
+                12
+            ],
+            "title": "s_reset_ptr_reg",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_reset_pointer()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_22",
+                "conn_44",
+                "conn_45",
+                "conn_46",
+                "conn_47",
+                "conn_48",
+                "conn_49",
+                "conn_65"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_3": {
+            "pos": [
+                33,
+                63
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_3",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_66"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "initial"
+        },
+        "state_8": {
+            "pos": [
+                16,
+                156
+            ],
+            "size": [
+                15,
+                18
+            ],
+            "title": "s_idle",
+            "text": [
+                "init/ {{cookiecutter.module_name}}_reset_timer()",
+                "entry/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_26",
+                "conn_28",
+                "conn_31",
+                "conn_33",
+                "conn_35",
+                "conn_37"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "normal"
+        },
+        "state_9": {
+            "pos": [
+                71,
+                156
+            ],
+            "size": [
+                15,
+                17
+            ],
+            "title": "s_reading",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_start_read()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_25",
+                "conn_27",
+                "conn_29",
+                "conn_30",
+                "conn_32",
+                "conn_34",
+                "conn_36"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_4": {
+            "pos": [
+                92,
+                155
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_4",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_24"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "initial"
+        },
+        "state_10": {
+            "pos": [
+                54,
+                66
+            ],
+            "size": [
+                20,
+                12
+            ],
+            "title": "s_power_down",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_set_full_powerdown()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_18",
+                "conn_19",
+                "conn_20",
+                "conn_21",
+                "conn_52",
+                "conn_53",
+                "conn_60",
+                "conn_67"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_11": {
+            "pos": [
+                52,
+                102
+            ],
+            "size": [
+                20,
+                9
+            ],
+            "title": "s_power_up",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_set_full_powerup()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_54",
+                "conn_55",
+                "conn_56",
+                "conn_57",
+                "conn_58",
+                "conn_59",
+                "conn_63",
+                "conn_74"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_12": {
+            "pos": [
+                33,
+                72
+            ],
+            "size": [
+                15,
+                7
+            ],
+            "title": "s_wait_power_down",
+            "text": [
+                "init/ {{cookiecutter.module_name}}_init_wait()"
+            ],
+            "connectors": [
+                "conn_61",
+                "conn_70"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_13": {
+            "pos": [
+                33,
+                102
+            ],
+            "size": [
+                15,
+                6
+            ],
+            "title": "s_wait_power_up",
+            "text": [
+                "init/ {{cookiecutter.module_name}}_init_wait()"
+            ],
+            "connectors": [
+                "conn_64",
+                "conn_75"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        }
+    },
+    "connectors": {
+        "conn_0": {
+            "parent": "istate_0",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_0"
+        },
+        "conn_1": {
+            "parent": "state_0",
+            "offset": 46,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_0"
+        },
+        "conn_2": {
+            "parent": "istate_1",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_1"
+        },
+        "conn_3": {
+            "parent": "state_1",
+            "offset": 2,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_1"
+        },
+        "conn_4": {
+            "parent": "istate_2",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_2"
+        },
+        "conn_5": {
+            "parent": "state_4",
+            "offset": 1,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_2"
+        },
+        "conn_6": {
+            "parent": "state_4",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_3"
+        },
+        "conn_7": {
+            "parent": "state_5",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_3"
+        },
+        "conn_8": {
+            "parent": "state_4",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_4"
+        },
+        "conn_9": {
+            "parent": "state_5",
+            "offset": 4,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_4"
+        },
+        "conn_10": {
+            "parent": "state_4",
+            "offset": 6,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_5"
+        },
+        "conn_11": {
+            "parent": "state_5",
+            "offset": 6,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_5"
+        },
+        "conn_12": {
+            "parent": "state_5",
+            "offset": 11,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_6"
+        },
+        "conn_13": {
+            "parent": "state_4",
+            "offset": 11,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_6"
+        },
+        "conn_14": {
+            "parent": "state_4",
+            "offset": 5,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_7"
+        },
+        "conn_15": {
+            "parent": "state_2",
+            "offset": 3,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_7"
+        },
+        "conn_16": {
+            "parent": "state_3",
+            "offset": 3,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_8"
+        },
+        "conn_17": {
+            "parent": "state_0",
+            "offset": 128,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_8"
+        },
+        "conn_22": {
+            "parent": "state_7",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_11"
+        },
+        "conn_23": {
+            "parent": "state_3",
+            "offset": 56,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_11"
+        },
+        "conn_24": {
+            "parent": "istate_4",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_12"
+        },
+        "conn_25": {
+            "parent": "state_9",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_12"
+        },
+        "conn_26": {
+            "parent": "state_8",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_13"
+        },
+        "conn_27": {
+            "parent": "state_9",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_13"
+        },
+        "conn_28": {
+            "parent": "state_8",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_14"
+        },
+        "conn_29": {
+            "parent": "state_9",
+            "offset": 4,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_14"
+        },
+        "conn_30": {
+            "parent": "state_9",
+            "offset": 7,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_15"
+        },
+        "conn_31": {
+            "parent": "state_8",
+            "offset": 7,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_15"
+        },
+        "conn_32": {
+            "parent": "state_9",
+            "offset": 9,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_16"
+        },
+        "conn_33": {
+            "parent": "state_8",
+            "offset": 9,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_16"
+        },
+        "conn_34": {
+            "parent": "state_9",
+            "offset": 11,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_17"
+        },
+        "conn_35": {
+            "parent": "state_8",
+            "offset": 11,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_17"
+        },
+        "conn_36": {
+            "parent": "state_9",
+            "offset": 16,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_18"
+        },
+        "conn_37": {
+            "parent": "state_8",
+            "offset": 16,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_18"
+        },
+        "conn_38": {
+            "parent": "state_6",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_19"
+        },
+        "conn_39": {
+            "parent": "state_6",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_19"
+        },
+        "conn_40": {
+            "parent": "state_6",
+            "offset": 5,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_20"
+        },
+        "conn_41": {
+            "parent": "state_6",
+            "offset": 6,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_20"
+        },
+        "conn_42": {
+            "parent": "state_6",
+            "offset": 9,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_21"
+        },
+        "conn_43": {
+            "parent": "state_6",
+            "offset": 10,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_21"
+        },
+        "conn_44": {
+            "parent": "state_7",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_22"
+        },
+        "conn_45": {
+            "parent": "state_7",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_22"
+        },
+        "conn_46": {
+            "parent": "state_7",
+            "offset": 5,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_23"
+        },
+        "conn_47": {
+            "parent": "state_7",
+            "offset": 6,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_23"
+        },
+        "conn_48": {
+            "parent": "state_7",
+            "offset": 9,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_24"
+        },
+        "conn_49": {
+            "parent": "state_7",
+            "offset": 10,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_24"
+        },
+        "conn_50": {
+            "parent": "state_2",
+            "offset": 19,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_25"
+        },
+        "conn_51": {
+            "parent": "state_0",
+            "offset": 126,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_25"
+        },
+        "conn_18": {
+            "parent": "state_10",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_9"
+        },
+        "conn_19": {
+            "parent": "state_10",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_9"
+        },
+        "conn_20": {
+            "parent": "state_10",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_10"
+        },
+        "conn_21": {
+            "parent": "state_10",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_10"
+        },
+        "conn_52": {
+            "parent": "state_10",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_26"
+        },
+        "conn_53": {
+            "parent": "state_10",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_26"
+        },
+        "conn_54": {
+            "parent": "state_11",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_27"
+        },
+        "conn_55": {
+            "parent": "state_11",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_27"
+        },
+        "conn_56": {
+            "parent": "state_11",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_28"
+        },
+        "conn_57": {
+            "parent": "state_11",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_28"
+        },
+        "conn_58": {
+            "parent": "state_11",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_29"
+        },
+        "conn_59": {
+            "parent": "state_11",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_29"
+        },
+        "conn_60": {
+            "parent": "state_10",
+            "offset": 1,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_30"
+        },
+        "conn_61": {
+            "parent": "state_12",
+            "offset": 1,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_30"
+        },
+        "conn_70": {
+            "parent": "state_12",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_35"
+        },
+        "conn_71": {
+            "parent": "state_6",
+            "offset": 8,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_35"
+        },
+        "conn_62": {
+            "parent": "state_6",
+            "offset": 9,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_31"
+        },
+        "conn_63": {
+            "parent": "state_11",
+            "offset": 9,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_31"
+        },
+        "conn_64": {
+            "parent": "state_13",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_32"
+        },
+        "conn_65": {
+            "parent": "state_7",
+            "offset": 8,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_32"
+        },
+        "conn_74": {
+            "parent": "state_11",
+            "offset": 3,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_37"
+        },
+        "conn_75": {
+            "parent": "state_13",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_37"
+        },
+        "conn_66": {
+            "parent": "istate_3",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_33"
+        },
+        "conn_67": {
+            "parent": "state_10",
+            "offset": 10,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_33"
+        }
+    },
+    "transitions": {
+        "trans_0": {
+            "start": "conn_0",
+            "end": "conn_1",
+            "vertices": [
+                [
+                    51,
+                    9
+                ],
+                [
+                    51,
+                    9
+                ],
+                [
+                    51,
+                    14
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                1.5999999999999996
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                51.5,
+                10.6
+            ]
+        },
+        "trans_1": {
+            "start": "conn_2",
+            "end": "conn_3",
+            "vertices": [
+                [
+                    12,
+                    24
+                ],
+                [
+                    12,
+                    24
+                ],
+                [
+                    12,
+                    28
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                1.6000000000000014
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                12.5,
+                25.6
+            ]
+        },
+        "trans_2": {
+            "start": "conn_4",
+            "end": "conn_5",
+            "vertices": [
+                [
+                    12,
+                    36
+                ],
+                [
+                    14,
+                    36
+                ],
+                [
+                    14,
+                    36
+                ],
+                [
+                    15,
+                    36
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                2,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                14,
+                35.6
+            ]
+        },
+        "trans_3": {
+            "start": "conn_6",
+            "end": "conn_7",
+            "vertices": [
+                [
+                    31,
+                    37
+                ],
+                [
+                    51,
+                    37
+                ],
+                [
+                    51,
+                    37
+                ],
+                [
+                    75,
+                    37
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                36.6
+            ]
+        },
+        "trans_4": {
+            "start": "conn_8",
+            "end": "conn_9",
+            "vertices": [
+                [
+                    31,
+                    39
+                ],
+                [
+                    51,
+                    39
+                ],
+                [
+                    51,
+                    39
+                ],
+                [
+                    75,
+                    39
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                38.6
+            ]
+        },
+        "trans_5": {
+            "start": "conn_10",
+            "end": "conn_11",
+            "vertices": [
+                [
+                    31,
+                    41
+                ],
+                [
+                    51,
+                    41
+                ],
+                [
+                    51,
+                    41
+                ],
+                [
+                    75,
+                    41
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                40.6
+            ]
+        },
+        "trans_6": {
+            "start": "conn_12",
+            "end": "conn_13",
+            "vertices": [
+                [
+                    75,
+                    46
+                ],
+                [
+                    51,
+                    46
+                ],
+                [
+                    51,
+                    46
+                ],
+                [
+                    31,
+                    46
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)]/ {{cookiecutter.module_name}}_reset_timer()",
+            "label_offset": [
+                -11.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                39.5,
+                45.6
+            ]
+        },
+        "trans_7": {
+            "start": "conn_14",
+            "end": "conn_15",
+            "vertices": [
+                [
+                    20,
+                    50
+                ],
+                [
+                    20,
+                    59
+                ],
+                [
+                    24,
+                    59
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS [{{cookiecutter.module_name}}_id_match()]",
+            "label_offset": [
+                0.5,
+                4.700000000000003
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                20.5,
+                54.7
+            ]
+        },
+        "trans_8": {
+            "start": "conn_16",
+            "end": "conn_17",
+            "vertices": [
+                [
+                    14,
+                    146
+                ],
+                [
+                    14,
+                    142
+                ],
+                [
+                    5,
+                    142
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]",
+            "label_offset": [
+                0.5,
+                -1.8000000000000114
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                14.5,
+                144.2
+            ]
+        },
+        "trans_11": {
+            "start": "conn_22",
+            "end": "conn_23",
+            "vertices": [
+                [
+                    67,
+                    130
+                ],
+                [
+                    67,
+                    133
+                ],
+                [
+                    67,
+                    133
+                ],
+                [
+                    67,
+                    146
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                0.5,
+                10.799999999999983
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                67.5,
+                143.79999999999998
+            ]
+        },
+        "trans_12": {
+            "start": "conn_24",
+            "end": "conn_25",
+            "vertices": [
+                [
+                    92,
+                    155
+                ],
+                [
+                    90,
+                    155
+                ],
+                [
+                    90,
+                    159
+                ],
+                [
+                    86,
+                    159
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                2.5999999999999943
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                90.5,
+                157.6
+            ]
+        },
+        "trans_13": {
+            "start": "conn_26",
+            "end": "conn_27",
+            "vertices": [
+                [
+                    31,
+                    158
+                ],
+                [
+                    53,
+                    158
+                ],
+                [
+                    53,
+                    158
+                ],
+                [
+                    71,
+                    158
+                ]
+            ],
+            "label": "SIG_{{cookiecutter.module_name|upper}}_READ",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                157.6
+            ]
+        },
+        "trans_14": {
+            "start": "conn_28",
+            "end": "conn_29",
+            "vertices": [
+                [
+                    31,
+                    160
+                ],
+                [
+                    53,
+                    160
+                ],
+                [
+                    53,
+                    160
+                ],
+                [
+                    71,
+                    160
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_reset_timer()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                159.6
+            ]
+        },
+        "trans_15": {
+            "start": "conn_30",
+            "end": "conn_31",
+            "vertices": [
+                [
+                    71,
+                    163
+                ],
+                [
+                    53,
+                    163
+                ],
+                [
+                    53,
+                    163
+                ],
+                [
+                    31,
+                    163
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                -12.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                40.5,
+                162.6
+            ]
+        },
+        "trans_16": {
+            "start": "conn_32",
+            "end": "conn_33",
+            "vertices": [
+                [
+                    71,
+                    165
+                ],
+                [
+                    53,
+                    165
+                ],
+                [
+                    53,
+                    165
+                ],
+                [
+                    31,
+                    165
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                -12.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                40.5,
+                164.6
+            ]
+        },
+        "trans_17": {
+            "start": "conn_34",
+            "end": "conn_35",
+            "vertices": [
+                [
+                    71,
+                    167
+                ],
+                [
+                    53,
+                    167
+                ],
+                [
+                    53,
+                    167
+                ],
+                [
+                    31,
+                    167
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                -15.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                37.5,
+                166.6
+            ]
+        },
+        "trans_18": {
+            "start": "conn_36",
+            "end": "conn_37",
+            "vertices": [
+                [
+                    71,
+                    172
+                ],
+                [
+                    53,
+                    172
+                ],
+                [
+                    53,
+                    172
+                ],
+                [
+                    31,
+                    172
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS/ {{cookiecutter.module_name}}_update_temp()",
+            "label_offset": [
+                -9.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                43.5,
+                171.6
+            ]
+        },
+        "trans_19": {
+            "start": "conn_38",
+            "end": "conn_39",
+            "vertices": [
+                [
+                    70,
+                    86
+                ],
+                [
+                    77,
+                    86
+                ],
+                [
+                    77,
+                    87
+                ],
+                [
+                    70,
+                    87
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71,
+                85.6
+            ]
+        },
+        "trans_20": {
+            "start": "conn_40",
+            "end": "conn_41",
+            "vertices": [
+                [
+                    70,
+                    89
+                ],
+                [
+                    77,
+                    89
+                ],
+                [
+                    77,
+                    90
+                ],
+                [
+                    70,
+                    90
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                88.6
+            ]
+        },
+        "trans_21": {
+            "start": "conn_42",
+            "end": "conn_43",
+            "vertices": [
+                [
+                    70,
+                    93
+                ],
+                [
+                    77,
+                    93
+                ],
+                [
+                    77,
+                    94
+                ],
+                [
+                    70,
+                    94
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                92.6
+            ]
+        },
+        "trans_22": {
+            "start": "conn_44",
+            "end": "conn_45",
+            "vertices": [
+                [
+                    70,
+                    119
+                ],
+                [
+                    77,
+                    119
+                ],
+                [
+                    77,
+                    120
+                ],
+                [
+                    70,
+                    120
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                118.6
+            ]
+        },
+        "trans_23": {
+            "start": "conn_46",
+            "end": "conn_47",
+            "vertices": [
+                [
+                    70,
+                    123
+                ],
+                [
+                    77,
+                    123
+                ],
+                [
+                    77,
+                    124
+                ],
+                [
+                    70,
+                    124
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                122.6
+            ]
+        },
+        "trans_24": {
+            "start": "conn_48",
+            "end": "conn_49",
+            "vertices": [
+                [
+                    70,
+                    127
+                ],
+                [
+                    77,
+                    127
+                ],
+                [
+                    77,
+                    128
+                ],
+                [
+                    70,
+                    128
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                126.6
+            ]
+        },
+        "trans_25": {
+            "start": "conn_50",
+            "end": "conn_51",
+            "vertices": [
+                [
+                    43,
+                    135
+                ],
+                [
+                    43,
+                    140
+                ],
+                [
+                    16,
+                    140
+                ],
+                [
+                    5,
+                    140
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]",
+            "label_offset": [
+                -26.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                16.5,
+                139.6
+            ]
+        },
+        "trans_9": {
+            "start": "conn_18",
+            "end": "conn_19",
+            "vertices": [
+                [
+                    74,
+                    67
+                ],
+                [
+                    80,
+                    67
+                ],
+                [
+                    80,
+                    68
+                ],
+                [
+                    74,
+                    68
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                3,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                77,
+                66.6
+            ]
+        },
+        "trans_10": {
+            "start": "conn_20",
+            "end": "conn_21",
+            "vertices": [
+                [
+                    74,
+                    70
+                ],
+                [
+                    80,
+                    70
+                ],
+                [
+                    80,
+                    71
+                ],
+                [
+                    74,
+                    71
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                2,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                76,
+                69.6
+            ]
+        },
+        "trans_26": {
+            "start": "conn_52",
+            "end": "conn_53",
+            "vertices": [
+                [
+                    74,
+                    73
+                ],
+                [
+                    80,
+                    73
+                ],
+                [
+                    80,
+                    74
+                ],
+                [
+                    74,
+                    74
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                2,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                76,
+                72.6
+            ]
+        },
+        "trans_27": {
+            "start": "conn_54",
+            "end": "conn_55",
+            "vertices": [
+                [
+                    72,
+                    103
+                ],
+                [
+                    77,
+                    103
+                ],
+                [
+                    77,
+                    104
+                ],
+                [
+                    72,
+                    104
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                102.6
+            ]
+        },
+        "trans_28": {
+            "start": "conn_56",
+            "end": "conn_57",
+            "vertices": [
+                [
+                    72,
+                    106
+                ],
+                [
+                    77,
+                    106
+                ],
+                [
+                    77,
+                    107
+                ],
+                [
+                    72,
+                    107
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                105.6
+            ]
+        },
+        "trans_29": {
+            "start": "conn_58",
+            "end": "conn_59",
+            "vertices": [
+                [
+                    72,
+                    109
+                ],
+                [
+                    77,
+                    109
+                ],
+                [
+                    77,
+                    110
+                ],
+                [
+                    72,
+                    110
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                108.6
+            ]
+        },
+        "trans_30": {
+            "start": "conn_60",
+            "end": "conn_61",
+            "vertices": [
+                [
+                    54,
+                    67
+                ],
+                [
+                    34,
+                    67
+                ],
+                [
+                    34,
+                    72
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                -16.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                37.5,
+                66.6
+            ]
+        },
+        "trans_35": {
+            "start": "conn_70",
+            "end": "conn_71",
+            "vertices": [
+                [
+                    47,
+                    79
+                ],
+                [
+                    47,
+                    82
+                ],
+                [
+                    60,
+                    82
+                ],
+                [
+                    60,
+                    84
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_wait_cnt()]",
+            "label_offset": [
+                3.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                50.5,
+                81.6
+            ]
+        },
+        "trans_31": {
+            "start": "conn_62",
+            "end": "conn_63",
+            "vertices": [
+                [
+                    61,
+                    96
+                ],
+                [
+                    61,
+                    99
+                ],
+                [
+                    61,
+                    99
+                ],
+                [
+                    61,
+                    102
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                0.5,
+                1.1999999999999886
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                61.5,
+                100.19999999999999
+            ]
+        },
+        "trans_32": {
+            "start": "conn_64",
+            "end": "conn_65",
+            "vertices": [
+                [
+                    47,
+                    108
+                ],
+                [
+                    47,
+                    115
+                ],
+                [
+                    61,
+                    115
+                ],
+                [
+                    61,
+                    118
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_wait_cnt()]",
+            "label_offset": [
+                4,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                51,
+                114.6
+            ]
+        },
+        "trans_37": {
+            "start": "conn_74",
+            "end": "conn_75",
+            "vertices": [
+                [
+                    55,
+                    102
+                ],
+                [
+                    55,
+                    99
+                ],
+                [
+                    40,
+                    99
+                ],
+                [
+                    40,
+                    102
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                -14.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                40.5,
+                98.6
+            ]
+        },
+        "trans_33": {
+            "start": "conn_66",
+            "end": "conn_67",
+            "vertices": [
+                [
+                    33,
+                    63
+                ],
+                [
+                    64,
+                    63
+                ],
+                [
+                    64,
+                    66
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                14,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                47,
+                62.6
+            ]
+        }
+    },
+    "notes": {
+        "{{cookiecutter.module_name}}_timeout": "",
+        "SIG_I2C_RESULT_ADDR_NACK": "",
+        "SIG_I2C_RESULT_DATA_NACK": "",
+        "trans_7": "",
+        "SIG_I2C_RESULT_SUCCESS": "",
+        "trans_24": "",
+        "trans_23": "",
+        "trans_22": "",
+        "trans_21": "",
+        "trans_20": "",
+        "trans_19": "",
+        "trans_25": "",
+        "SIG_{{cookiecutter.module_name|upper}}_READ": "",
+        "{{cookiecutter.module_name}}_error_count": "",
+        "trans_9": "",
+        "{{cookiecutter.module_name}}_inc_wait_cnt()": "",
+        "{{cookiecutter.module_name|upper}}_RETRY_TIMEOUT": "",
+        "{{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT": ""
+    },
+    "view": {
+        "translate": [
+            132,
+            -144.5
+        ],
+        "scale": 9
+    }
+}
+        
+
+ + diff --git a/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}.h b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}.h new file mode 100644 index 00000000..d7aac86e --- /dev/null +++ b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}.h @@ -0,0 +1,117 @@ +#ifndef {{cookiecutter.module_name|upper}}_H +#define {{cookiecutter.module_name|upper}}_H + +#include "crf.h" +#include "sys_if.h" +{% if cookiecutter.comm_periph == "i2c" %} +#include "i2c_driver_if.h" +#include "i2c_master.h" +{% elif cookiecutter.comm_periph == "spi" %} +#include "spi_master.h" +{% elif cookiecutter.comm_periph == "can" %} +#include "canopen.h" +{% endif %} +#include "signal_classes_modules.h" + +/* +{{cookiecutter.module_name|upper}} driver +========== + +This module implements a high level driver for the {{cookiecutter.module_name|upper}} temperature sensor. + +Requirements for the {{cookiecutter.module_name|upper}} module: + * Read out the ID register to test the communication + * Retry the ID register reading after a timeout if the previous read failed + * Send an online event, when the link is established + * Send an offline event if the temperature read operation fails for a number of times + * Send periodic temperature events + * Allow triggered temperature reads + * Add a user defined ID into the events (so the application can differentiate between + the different {{cookiecutter.module_name|upper}} events) +*/ + +/* + * {{cookiecutter.module_name|upper}} SIGNALS + */ + +typedef enum {{cookiecutter.module_name}}_signals_ten +{ + SIG_{{cookiecutter.module_name|upper}}_TEMP = SIGNAL_FROM_CLASS(SIG_CLASS_{{cookiecutter.module_name|upper}}), + SIG_{{cookiecutter.module_name|upper}}_ONLINE, + SIG_{{cookiecutter.module_name|upper}}_OFFLINE, + SIG_{{cookiecutter.module_name|upper}}_READ +} {{cookiecutter.module_name}}_signals_ten; + +#define SIG_{{cookiecutter.module_name|upper}}_TEMP_TYPE {{cookiecutter.module_name}}_temp_tst +#define SIG_{{cookiecutter.module_name|upper}}_ONLINE_TYPE {{cookiecutter.module_name}}_status_tst +#define SIG_{{cookiecutter.module_name|upper}}_OFFLINE_TYPE {{cookiecutter.module_name}}_status_tst +#define SIG_{{cookiecutter.module_name|upper}}_READ_TYPE cevent_tst + + +/* + * EVENT DEFINITIONS + */ + +typedef struct {{cookiecutter.module_name}}_temp_tst +{ + cevent_tst super; // Signal and GC stuff + int32_t temp_C_i32; // Temperature + uint16_t id_u16; // Sensor ID +} {{cookiecutter.module_name}}_temp_tst; + +typedef struct {{cookiecutter.module_name}}_status_tst +{ + cevent_tst super; // Signal and GC stuff + uint16_t id_u16; // Sensor ID +} {{cookiecutter.module_name}}_status_tst; + +/* + * ACTIVE OBJECT + */ + +typedef struct {{cookiecutter.module_name}}_cfg_tst +{ + uint16_t id_u16; // This ID will be inserted into temperature events + uint16_t period_ms_u16; // Temperature read period in ms + uint16_t max_error_cnt_u16; // Number of times the module is allowed to fail a read operation before going offline + uint8_t address_u8; // I2C slave address of the sensor +} {{cookiecutter.module_name}}_cfg_tst; + +typedef struct {{cookiecutter.module_name}}_tst {{cookiecutter.module_name}}_tst; + +struct {{cookiecutter.module_name}}_tst +{ + /* PUBLIC */ + chsm_tst super; + {{cookiecutter.module_name}}_cfg_tst config_st; + int16_t temp_C_i32; + bool valid_b; + uint16_t resolution_u16; + + /* PRIVATE */ + uint32_t counter_u32; + uint16_t error_counter_u32; + uint16_t wait_cnt_u16; + + i2c_transaction_tst t_st; + uint8_t tx_buff_au8[4]; + uint8_t rx_buff_au8[4]; +}; + +chsm_result_ten {{cookiecutter.module_name}}_top(chsm_tst *self, const cevent_tst *e_pst); + +bool {{cookiecutter.module_name}}_timeout(chsm_tst *self, const cevent_tst *e_pst, uint32_t timeout_u32); +bool {{cookiecutter.module_name}}_error_count(chsm_tst *self, const cevent_tst *e_pst, uint16_t error_cnt_threshold_u16); + + +#define {{cookiecutter.module_name|upper}}_READ_PERIOD_VALUE (100UL) +#define {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT_VALUE (20UL) +#define {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT (500UL) +#define {{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT (2000UL) +#define {{cookiecutter.module_name|upper}}_ID_REG_VALUE (0x190) +#define {{cookiecutter.module_name|upper}}_WAIT_CNT (12UL) + +#define {{cookiecutter.module_name|upper}}_READ_PERIOD ((({{cookiecutter.module_name}}_tst *)self)->config_st.period_ms_u16) +#define {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT ((({{cookiecutter.module_name}}_tst *)self)->config_st.max_error_cnt_u16) + +#endif diff --git a/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h new file mode 100644 index 00000000..2d469139 --- /dev/null +++ b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h @@ -0,0 +1,79 @@ +#ifndef {{cookiecutter.module_name|upper}}_FUNCTIONS_H +#define {{cookiecutter.module_name|upper}}_FUNCTIONS_H + +#include "{{cookiecutter.module_name}}.h" +#include "chsm.h" +#include "cevent.h" +#include + +void {{cookiecutter.module_name}}_10ms_callback(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_inc_error_counter(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_init(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_init_wait(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_read_id(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_error_cnt(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_pointer(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_timer(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_full_powerdown(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_full_powerup(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_resolution(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_start_read(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_unplugged(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_update_temp(chsm_tst *self, const cevent_tst *e_pst); + +void send_offline_event(chsm_tst *self, const cevent_tst *e_pst); + +void send_online_event(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func); +extern char {{cookiecutter.module_name}}_debug_state_ac[20]; + +bool {{cookiecutter.module_name}}_id_match(chsm_tst *self, const cevent_tst *e_pst); + +bool {{cookiecutter.module_name}}_wait_cnt(chsm_tst *self, const cevent_tst *e_pst); + +typedef enum {{cookiecutter.module_name}}_state_id_ten +{ + S_READ_ID_REG = 4, + S_UNPLUGGED = 5, + S_SET_RESOLUTION = 6, + S_RESET_PTR_REG = 7, + S_IDLE = 8, + S_READING = 9, + S_POWER_DOWN = 10, + S_POWER_UP = 11, + S_WAIT_POWER_DOWN = 12, + S_WAIT_POWER_UP = 13, +} {{cookiecutter.module_name}}_state_id_ten; + + +/* +Signals: + SIG_I2C_RESULT_ADDR_NACK + SIG_I2C_RESULT_DATA_NACK + SIG_I2C_RESULT_SUCCESS + SIG_{{cookiecutter.module_name|upper}}_READ + SIG_SYS_TICK_10ms +*/ + +/* +Other function notes: + +{{cookiecutter.module_name}}_error_count: + +{{cookiecutter.module_name}}_timeout: +*/ +#endif diff --git a/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_regs.h b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_regs.h new file mode 100644 index 00000000..9f7c864b --- /dev/null +++ b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_regs.h @@ -0,0 +1,13 @@ + +#ifndef {{cookiecutter.module_name|upper}}_REGS_H_ +#define {{cookiecutter.module_name|upper}}_REGS_H_ + +// Config reg bits + +// Control/status reg bits + +// Registers + +// Device addresses + +#endif /* {{cookiecutter.module_name|upper}}_REGS_H_ */ diff --git a/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c new file mode 100644 index 00000000..fe87e9b7 --- /dev/null +++ b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c @@ -0,0 +1,449 @@ +/*Generated with CHSM v0.0.0 at 2023.07.31 10.25.58*/ +#include "cevent.h" +#include "chsm.h" +#include +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_functions.h" + + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst); +char {{cookiecutter.module_name}}_debug_state_ac[20]; + +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + if({{cookiecutter.module_name}}_id_match(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + break; + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_online_event(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_{{cookiecutter.module_name|upper}}_READ: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_{{cookiecutter.module_name|upper}}_READ", __FUNCTION__); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_update_temp(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_down); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +chsm_result_ten {{cookiecutter.module_name}}_top(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case C_SIG_INIT: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "C_SIG_INIT", __FUNCTION__); + {{cookiecutter.module_name}}_init(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func) +{ + #ifdef CHSM_BUILD_TESTS + printf("{{cookiecutter.module_name}}_%s --%s-->\n", state_func, trans_name); + #else + CRF_UNUSED(self); + CRF_UNUSED(est); + CRF_UNUSED(trans_name); + CRF_UNUSED(state_func); + memset({{cookiecutter.module_name}}_debug_state_ac, 0, 20); + strncpy({{cookiecutter.module_name}}_debug_state_ac, state_func, 19); + {{cookiecutter.module_name}}_debug_state_ac[19] = '\0'; + #endif +} diff --git a/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}_functions.c b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}_functions.c new file mode 100644 index 00000000..01fe3c47 --- /dev/null +++ b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}_functions.c @@ -0,0 +1,317 @@ +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_regs.h" +#include "{{cookiecutter.module_name}}_functions.h" +#include "crf.h" +#include "cevent.h" +#include + +static const cevent_tst sig_reset_slave_comm_st = {.sig = SIG_I2C_RESET_SLAVE_COMM}; +static const cevent_tst sig_reset_periph_st = {.sig = SIG_I2C_RESET_SLAVE_COMM}; + +void {{cookiecutter.module_name}}_init(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->counter_u32 = 0; + self->error_counter_u32 = 0; + + self->t_st.super.sig = SIG_I2C_WR_TRANSACTION; + self->t_st.slave_addr_u16 = self->config_st.address_u8; + self->t_st.target_q_pst = (cqueue_tst *)self; + self->t_st.read_data_pu8 = self->rx_buff_au8; + self->t_st.write_data_pu8 = self->tx_buff_au8; +} + +/*Increase the timer counter.*/ +void {{cookiecutter.module_name}}_10ms_callback(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->counter_u32 += 10; +} + +/*Increase the error counter.*/ +void {{cookiecutter.module_name}}_inc_error_counter(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->error_counter_u32++; +} + +void {{cookiecutter.module_name}}_reset_error_cnt(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->error_counter_u32 = 0; +} + +/*Try to read the ID register from the {{cookiecutter.module_name|upper}} by sending a write-read transaction to the I2C master.*/ +void {{cookiecutter.module_name}}_read_id(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_WR_TRANSACTION; + self->t_st.write_cnt_u16 = 1; + self->t_st.read_cnt_u16 = 2; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_ID; + self->rx_buff_au8[0] = 0; + self->rx_buff_au8[1] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +void {{cookiecutter.module_name}}_reset_pointer(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 1; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +/*Send a SIG_{{cookiecutter.module_name|upper}}_OFFLINE event. This can be used to detect communication errors between the module and the I2C slave.*/ +void send_offline_event(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->valid_b = false; + + TYPEOF(SIG_{{cookiecutter.module_name|upper}}_OFFLINE)* offline_pst = CRF_NEW(SIG_{{cookiecutter.module_name|upper}}_OFFLINE); + + offline_pst->id_u16 = self->config_st.id_u16; + + CRF_EMIT(offline_pst); +} + +/*Send a SIG_{{cookiecutter.module_name|upper}}_ONLINE event. This can be used to detect successful initialization.*/ +void send_online_event(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->valid_b = true; + TYPEOF(SIG_{{cookiecutter.module_name|upper}}_ONLINE)* online_pst = CRF_NEW(SIG_{{cookiecutter.module_name|upper}}_ONLINE); + + online_pst->id_u16 = self->config_st.id_u16; + + CRF_EMIT(online_pst); +} + +/*Reset the timer counter.*/ +void {{cookiecutter.module_name}}_reset_timer(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->counter_u32 = 0; +} + +/*Send a read transaction to the {{cookiecutter.module_name|upper}}.*/ +void {{cookiecutter.module_name}}_start_read(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_R_TRANSACTION; + self->t_st.write_cnt_u16 = 0; + self->t_st.read_cnt_u16 = 2; + self->rx_buff_au8[0] = 0; + self->rx_buff_au8[1] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +void {{cookiecutter.module_name}}_set_full_powerdown(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 2; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CONFIG; + self->tx_buff_au8[1] = {{cookiecutter.module_name|upper}}_POWER_OFF; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} +void {{cookiecutter.module_name}}_set_full_powerup(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 2; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CONFIG; + self->tx_buff_au8[1] = {{cookiecutter.module_name|upper}}_POWER_ON; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +bool {{cookiecutter.module_name}}_wait_cnt(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + if(self->wait_cnt_u16++ >= {{cookiecutter.module_name|upper}}_WAIT_CNT) + { + self->wait_cnt_u16 = 0; + return true; + } + else + { + return false; + } +} + +bool {{cookiecutter.module_name}}_inc_wait_cnt(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + self->wait_cnt_u16++; + return false; +} + +void {{cookiecutter.module_name}}_init_wait(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; +// self->wait_cnt_u16 = 0; +} + +void {{cookiecutter.module_name}}_get_resolution(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_WR_TRANSACTION; + self->t_st.write_cnt_u16 = 1; + self->t_st.read_cnt_u16 = 1; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CTRLSTATUS; + self->rx_buff_au8[1] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +void {{cookiecutter.module_name}}_update_resolution(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + uint16_t reg_u16 = self->rx_buff_au8[0]; + {{cookiecutter.module_name}}_resolution_t resolution = {{cookiecutter.module_name|upper}}_RESOLUTION_14BIT; + + self->resolution_u16 = (reg_u16 & {{cookiecutter.module_name|upper}}_MASK_RESOLUTION) | resolution; +} + +void {{cookiecutter.module_name}}_set_resolution(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 2; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CTRLSTATUS; + self->tx_buff_au8[1] = {{cookiecutter.module_name|upper}}_RESOLUTION_14BIT; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +/*Update the temperature display and send an event with the new value.*/ +void {{cookiecutter.module_name}}_update_temp(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + {{cookiecutter.module_name}}_temp_tst* temp_pst = CRF_NEW(SIG_{{cookiecutter.module_name|upper}}_TEMP); //{{cookiecutter.module_name}}_temp_tst + + if (NULL == temp_pst) return; + + // Compile the value of the Temperature Data Register into a variable + double tdr_reg_u32 = ((((self->rx_buff_au8[0] << 8) | self->rx_buff_au8[1]) >> 2) * 0.03125); + int32_t temp_c_i32 = tdr_reg_u32*1000; + + temp_pst->super.sig = SIG_{{cookiecutter.module_name|upper}}_TEMP; + temp_pst->temp_C_i32 = temp_c_i32; + temp_pst->id_u16 = self->config_st.id_u16; + + self->temp_C_i32 = temp_c_i32; + self->valid_b = true; + + self->super.send(_self, (const cevent_tst *)temp_pst); + + if (self->error_counter_u32) + { + self->error_counter_u32--; + } +} + +/*True, if the response data is equal to 0x190. See {{cookiecutter.module_name|upper}} datasheet section: 7.5.1.7 Identification Register*/ +bool {{cookiecutter.module_name}}_id_match(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + // Compile the value of the Identification Register into a variable + uint16_t idr_reg_u16 = self->rx_buff_au8[0]; + idr_reg_u16 <<= 8; + idr_reg_u16 |= self->rx_buff_au8[1]; + + return {{cookiecutter.module_name|upper}}_ID_REG_VALUE == idr_reg_u16; +} + +/*Return true, if the error counter is greater or equal then the parameter.*/ +bool {{cookiecutter.module_name}}_error_count(chsm_tst *_self, const cevent_tst *e_pst, uint16_t error_cnt_threshold_u16) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + return self->error_counter_u32 >= error_cnt_threshold_u16; +} + +bool {{cookiecutter.module_name}}_timeout(chsm_tst *_self, const cevent_tst *e_pst, uint32_t timeout_u32) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + return self->counter_u32 >= timeout_u32; +} + +void {{cookiecutter.module_name}}_unplugged(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + CRF_EMIT(&sig_reset_slave_comm_st); +} + diff --git a/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/CMakeLists.txt b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/CMakeLists.txt new file mode 100644 index 00000000..869689d4 --- /dev/null +++ b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/CMakeLists.txt @@ -0,0 +1,24 @@ + +add_module_test( + NAME + {{cookiecutter.module_name}}_test + SOURCE + tsrc/main.c + tsrc/ut_{{cookiecutter.module_name}}_test.c + INCLUDE + tinc + LINK + unity + {% if cookiecutter.comm_periph == "i2c" %} + i2c_drv_mock + {% endif %} + {{cookiecutter.module_name}} + DEFINES + NDEBUG + CHSM_BUILD_TESTS + STANDARD + 11 +) + +set_property(TARGET {{cookiecutter.module_name}}_test PROPERTY ECLIPSE_GENERATE_SOURCE_PROJECT ON) +set_property(TARGET {{cookiecutter.module_name}}_test PROPERTY ECLIPSE_GENERATE_LINKED_RESOURCES ON) \ No newline at end of file diff --git a/cgen/templates/__init__.py b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tinc/.gitkeep similarity index 100% rename from cgen/templates/__init__.py rename to gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tinc/.gitkeep diff --git a/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/main.c b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/main.c new file mode 100644 index 00000000..9164d34f --- /dev/null +++ b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/main.c @@ -0,0 +1,24 @@ +#include +#include "unity_fixture.h" +#include "unity.h" + + +void disableInterrupts(void) +{ + +} + +void enableInterrupts(void) +{ + +} + +void run_{{cookiecutter.module_name}}_tests(void) +{ + RUN_TEST_GROUP({{cookiecutter.module_name}}); +} + +int main(int argc, const char * argv[]) +{ + return UnityMain(argc, argv, run_{{cookiecutter.module_name}}_tests); +} \ No newline at end of file diff --git a/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/ut_{{cookiecutter.module_name}}_test.c b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/ut_{{cookiecutter.module_name}}_test.c new file mode 100644 index 00000000..e98a475c --- /dev/null +++ b/gui/c_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/ut_{{cookiecutter.module_name}}_test.c @@ -0,0 +1,417 @@ +/* + * ut_{{cookiecutter.module_name}}_test.c + * + * Created on: 2020. dec. 30. + * Author: jszeman + */ + +#include +#include +#include +#include +#include +#include "unity_fixture.h" +#include "crf.h" +#include "cbits.h" +#include "ut_i2c_driver_mock.h" +#include "i2c_master.h" +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_regs.h" +#include "cevent.h" +#include "sys_if.h" + +TEST_GROUP({{cookiecutter.module_name}}); + +ut_i2c_driver_mock_tst drv_mock_st; +i2c_driver_if_tst* drv_pst = (i2c_driver_if_tst *)&drv_mock_st; + +const cevent_tst* i2c_master_events_apst[8]; +i2c_master_tst i2c_master_st; +uint8_t i2c_master_scanned_ids[127]; + +const cevent_tst* {{cookiecutter.module_name}}_events_apst[8]; +{{cookiecutter.module_name}}_tst {{cookiecutter.module_name}}_st; + + +{{cookiecutter.module_name}}_tst *self = &{{cookiecutter.module_name}}_st; // This is necessary for macros like {{cookiecutter.module_name|upper}}_READ_PERIOD to work here + +chsm_tst* hsm_apst[] = { + (chsm_tst*)(&i2c_master_st), + (chsm_tst*)(&{{cookiecutter.module_name}}_st), + NULL}; + +uint8_t pool_buff_au8[1024]; +cpool_tst pool_ast[1]; + +crf_tst crf; + +const cevent_tst* events_apst[4]; +cqueue_tst q_st; + +const cevent_tst tick_10ms_st = {.sig = SIG_SYS_TICK_10ms}; + +static void tick_ms(uint32_t tick_cnt_u32) +{ + while(tick_cnt_u32--) + { + drv_mock_st.tick(&drv_mock_st); + + CRF_POST(&tick_10ms_st, &{{cookiecutter.module_name}}_st); + + while(CRF_STEP()) + { + printf("| "); + } + } +} + +void {{cookiecutter.module_name}}_send(chsm_tst *self, const cevent_tst *e_pst) +{ + //printf("\n%s\n", __FUNCTION__); + switch(e_pst->sig) + { + case SIG_{{cookiecutter.module_name|upper}}_TEMP: + case SIG_{{cookiecutter.module_name|upper}}_ONLINE: + case SIG_{{cookiecutter.module_name|upper}}_OFFLINE: + CRF_POST(e_pst, &q_st); + break; + + default: + CRF_POST(e_pst, &i2c_master_st); + } +} + + +TEST_SETUP({{cookiecutter.module_name}}) +{ + memset(events_apst, 0, sizeof(events_apst)); + memset(&q_st, 0, sizeof(q_st)); + memset(&drv_mock_st, 0, sizeof(drv_mock_st)); + memset(&i2c_master_st, 0, sizeof(i2c_master_st)); + memset(&crf, 0, sizeof(crf)); + memset(&i2c_master_events_apst, 0, sizeof(i2c_master_events_apst)); + memset(&pool_buff_au8, 0, sizeof(pool_buff_au8)); + memset(&pool_ast, 0, sizeof(pool_ast)); + memset(&{{cookiecutter.module_name}}_st, 0, sizeof({{cookiecutter.module_name}}_st)); + + cpool_init(pool_ast+0, pool_buff_au8, 24, 16); + + cqueue_init(&q_st, events_apst, 4); + + ut_i2c_driver_mock_init(&drv_mock_st); + + i2c_master_st.config_st.driver_pst = drv_pst; + // i2c_master_st.config_st.scan_result_au8[0] = &i2c_master_scanned_ids; + chsm_ctor(&i2c_master_st.super, i2c_master_top, i2c_master_events_apst, 4, 4); + chsm_ctor(&{{cookiecutter.module_name}}_st.super, {{cookiecutter.module_name}}_top, {{cookiecutter.module_name}}_events_apst, 8, 0); + + {{cookiecutter.module_name}}_st.config_st = ({{cookiecutter.module_name}}_cfg_tst){ + .address_u8 = {{cookiecutter.module_name|upper}}_0_I2C_FLOAT, + .id_u16 = 0xabcd, + .period_ms_u16 = {{cookiecutter.module_name|upper}}_READ_PERIOD_VALUE, + .max_error_cnt_u16 = {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT_VALUE + }; + + CRF_SEND_FUNC(&{{cookiecutter.module_name}}_st) = {{cookiecutter.module_name}}_send; + + crf_init(&crf, hsm_apst, pool_ast, 1); + chsm_init((chsm_tst *)&i2c_master_st); + chsm_init((chsm_tst *)&{{cookiecutter.module_name}}_st); +} + +TEST_TEAR_DOWN({{cookiecutter.module_name}}) +{ +} + +/* + * Just call setup + */ +TEST({{cookiecutter.module_name}}, init) +{ + printf("\n%s\n", __FUNCTION__); +} + +TEST({{cookiecutter.module_name}}, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = {{cookiecutter.module_name|upper}}_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, // sensor id + 0xf3, 0x80, // -25° measured value + 0x0c, 0x80 // +25° measured value + } + }; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + +} + +/* read_temp_twice: + * Setup the mock device to send the id bytes and two temperature reading (-25 and 25) to the master. + * Check, that two temperature events were sent + */ +TEST({{cookiecutter.module_name}}, read_temp_twice) +{ + printf("\n%s\n", __FUNCTION__); + i2c_mock_slave_device_tst dev_st = { + .address_u8 = 0x12, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + + const {{cookiecutter.module_name}}_temp_tst* e_pst; + const {{cookiecutter.module_name}}_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + TEST_ASSERT(s_pst); + TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + + e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + + tick_ms(({{cookiecutter.module_name|upper}}_READ_PERIOD/10)+1); + + uint8_t expected_au8[4] = {7, 0, 0, 0}; + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); + TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); + TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + + e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +} + +/* read_id_retry: + * Check that a failed ID read will be repeated after the configured time. + */ +TEST({{cookiecutter.module_name}}, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = {{cookiecutter.module_name|upper}}_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + const {{cookiecutter.module_name}}_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + TEST_ASSERT_NULL(s_pst); + + // dev_st.address_u8 = 0x12; + + // tick_ms({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT-10); + + // s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NULL(s_pst); + + // tick_ms(10); + + // s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NOT_NULL(s_pst); + // TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); +} + +// /* read_id_retry_bad_id: +// * Check that a failed ID read will be repeated after the configured time if the data sent back +// * by the slave is not 0x190 for the first try. +// */ +// TEST({{cookiecutter.module_name}}, read_id_retry_bad_id) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x91, 0x01, 0x90, 0x0c, 0x80} +// }; + +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms(({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT-10)/10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NOT_NULL(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); +// } + +// /* go_online: +// * Check that after reading temperature data fails for more than {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST({{cookiecutter.module_name}}, go_online) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const {{cookiecutter.module_name}}_temp_tst* e_pst; +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(({{cookiecutter.module_name|upper}}_READ_PERIOD_VALUE / 10) + 1); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE({{cookiecutter.module_name}}_st.valid_b); +// } + +// /* go_offline: +// * Check that after reading temperature data fails for more than {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST({{cookiecutter.module_name}}, go_offline) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const {{cookiecutter.module_name}}_temp_tst* e_pst; +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(({{cookiecutter.module_name|upper}}_READ_PERIOD/10) + 1); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE({{cookiecutter.module_name}}_st.valid_b); + +// dev_st.address_u8 = 0x13; + +// tick_ms((({{cookiecutter.module_name|upper}}_READ_PERIOD/10) + 1) * {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT + 1); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_OFFLINE, s_pst->super.sig); + +// TEST_ASSERT_FALSE({{cookiecutter.module_name}}_st.valid_b); +// } + +// /* triggered_read: +// * Check that it is possible to trigger a read before the read period timeout elapses. +// */ +// TEST({{cookiecutter.module_name}}, triggered_read) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const cevent_tst read_event = {.sig = SIG_{{cookiecutter.module_name|upper}}_READ}; + + +// const {{cookiecutter.module_name}}_temp_tst* e_pst; +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(1); + +// CRF_POST(&read_event, &{{cookiecutter.module_name}}_st); + +// tick_ms(10); + +// uint8_t expected_au8[4] = {7, 0, 0, 0}; +// TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); +// TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); +// TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +// } + +TEST_GROUP_RUNNER({{cookiecutter.module_name}}) +{ + RUN_TEST_CASE({{cookiecutter.module_name}}, init); + RUN_TEST_CASE({{cookiecutter.module_name}}, read_id); + // RUN_TEST_CASE({{cookiecutter.module_name}}, read_temp_twice); + // RUN_TEST_CASE({{cookiecutter.module_name}}, read_id_retry); + // RUN_TEST_CASE({{cookiecutter.module_name}}, read_id_retry_bad_id); + // RUN_TEST_CASE({{cookiecutter.module_name}}, go_offline); + // RUN_TEST_CASE({{cookiecutter.module_name}}, go_online); + // RUN_TEST_CASE({{cookiecutter.module_name}}, triggered_read); +} diff --git a/gui/c_gen/module_template/_template_without_crf/cookiecutter.json b/gui/c_gen/module_template/_template_without_crf/cookiecutter.json new file mode 100644 index 00000000..635ada19 --- /dev/null +++ b/gui/c_gen/module_template/_template_without_crf/cookiecutter.json @@ -0,0 +1,3 @@ +{ + "module_name": "template" +} \ No newline at end of file diff --git a/gui/c_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h b/gui/c_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h new file mode 100644 index 00000000..93ef40a8 --- /dev/null +++ b/gui/c_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h @@ -0,0 +1,48 @@ +#ifndef PCA9554_FUNCTIONS_H +#define PCA9554_FUNCTIONS_H + +/*Generated with CHSM v0.0.0 at 2023.07.27 14.07.05*/ + +#include "pca9554.h" +#include + + +void pca9554_process_input(pca9554_tst *self); + +void pca9554_read_input(pca9554_tst *self); + +void pca9554_reset_timer(pca9554_tst *self); + +/*Start a I2C transaction to write the DIRECTION register in the slave device.*/ +void pca9554_set_direction(pca9554_tst *self); + +void pca9554_set_output(pca9554_tst *self); + +void pca9554_set_polarity(pca9554_tst *self); + + +typedef enum pca9554_state_id_ten +{ + S_PCA9554_WAIT_DIR = 1, + S_PCA9554_WAIT_POL = 2, + S_PCA9554_WAIT_OUTPUT = 3, + S_PCA9554_WAIT_READ = 4, + S_PCA9554_BACK_OFF = 5, +} pca9554_state_id_ten; + + +/* +Signals: + I2C_FAIL + I2C_SUCCESS + START_READ +*/ + +/* +Other function notes: + +pca9554_set_status: + +pca9554_timeout: +*/ +#endif diff --git a/gui/c_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c b/gui/c_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c new file mode 100644 index 00000000..28a6511c --- /dev/null +++ b/gui/c_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c @@ -0,0 +1,115 @@ +/*Generated with CHSM v0.0.1*/ +#include "pca9554.h" +#include "pca9554_functions.h" + + +static void s_pca9554_back_off(pca9554_tst *self); +static void s_pca9554_wait_read(pca9554_tst *self); +static void s_pca9554_wait_output(pca9554_tst *self); +static void s_pca9554_wait_pol(pca9554_tst *self); +static void s_pca9554_wait_dir(pca9554_tst *self); + +static void s_pca9554_wait_dir(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_polarity(self); + return pca9554_set_state(self, s_pca9554_wait_pol); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_pol(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_output(self); + return pca9554_set_state(self, s_pca9554_wait_output); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_output(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_read(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_status(self, PCA9554_READY); + pca9554_process_input(self); + break; + + case PCA9554_SIG_START_READ: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_back_off(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + if(pca9554_timeout(self, 1000)) + { + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} + +void pca9554_top(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_INIT: + pca9554_set_status(self, PCA9554_STARTING); + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} diff --git a/gui/c_gen/module_template/_template_without_crf_new/cookiecutter.json b/gui/c_gen/module_template/_template_without_crf_new/cookiecutter.json new file mode 100644 index 00000000..635ada19 --- /dev/null +++ b/gui/c_gen/module_template/_template_without_crf_new/cookiecutter.json @@ -0,0 +1,3 @@ +{ + "module_name": "template" +} \ No newline at end of file diff --git a/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/.chsm/pca9554.json b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/.chsm/pca9554.json new file mode 100644 index 00000000..35f0d37a --- /dev/null +++ b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/.chsm/pca9554.json @@ -0,0 +1,26 @@ +{ + "src_dir": "../src", + "doc_dir": "../doc", + + "templates": { + "init_signal": "PCA9554_SIG_INIT", + "signal_prefix": "PCA9554_SIG_", + "func_args": "self", + "func_params": "pca9554_tst *self", + "user_func_args_t": "self", + "user_func_params_t": "pca9554_tst *self", + "func_return_type": "void", + "guard_return_type": "uint16_t", + "switch_variable": "self->signal_en", + "trans_result": "pca9554_set_state(self, {target})", + "ignored_result": "", + "c_include_list": [], + "h_include_list": [""], + "top_state_name": "void\\s+(?P\\w+)\\(void\\s+\\*self,\\s+uint32_t\\s+e_u32\\)\\s*;", + "set_state_id": "" + }, + + "pca9554.h": { + "top_func": "pca9554_top" + } +} \ No newline at end of file diff --git a/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/CMakeLists.txt b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/CMakeLists.txt new file mode 100644 index 00000000..46fba169 --- /dev/null +++ b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/CMakeLists.txt @@ -0,0 +1,19 @@ + +add_module_lib( + NAME + lm73 + PACKAGE + chsm + SOURCE + src/lm73.c + src/lm73_functions.c + INCLUDE + inc + LINK + chsm::i2c_master + signal_classes_modules + DEFINES + NDEBUG + STANDARD + 11 +) \ No newline at end of file diff --git a/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/doc/pca9554.html b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/doc/pca9554.html new file mode 100644 index 00000000..6162916b --- /dev/null +++ b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/doc/pca9554.html @@ -0,0 +1,865 @@ + + + + + + +
+ + + + + + START_READ[pca9554_timeout(1000)]I2C_FAILI2C_SUCCESSI2C_SUCCESSI2C_SUCCESS + __top__s_pca9554init/ pca9554_set_status(PCA9554_STARTING)s_pca9554_wait_dirinit/ pca9554_set_direction()Start a I2C transaction to write the DIRECTION register in the slave device.s_pca9554_wait_polinit/ pca9554_set_polarity()s_pca9554_wait_outputinit/ pca9554_set_output()s_pca9554_wait_readinit/ pca9554_read_input()I2C_SUCCESS/ { pca9554_set_status(PCA9554_READY) pca9554_process_input()}s_pca9554_back_offinit/ pca9554_reset_timer()entry/ pca9554_set_status(PCA9554_NOT_FOUND) + + +
+ +
+ json +
+            {
+    "states": {
+        "__top__": {
+            "pos": [
+                -100000000,
+                -100000000
+            ],
+            "size": [
+                200000000,
+                200000000
+            ],
+            "title": "__top__",
+            "text": [],
+            "connectors": [],
+            "parent": null,
+            "children": [
+                "state_0",
+                "istate_0"
+            ],
+            "type": "top"
+        },
+        "state_0": {
+            "pos": [
+                42,
+                17
+            ],
+            "size": [
+                82,
+                73
+            ],
+            "title": "s_pca9554",
+            "text": [
+                "init/ pca9554_set_status(PCA9554_STARTING)"
+            ],
+            "connectors": [
+                "conn_1",
+                "conn_10"
+            ],
+            "parent": "__top__",
+            "children": [
+                "state_1",
+                "istate_1",
+                "state_2",
+                "state_3",
+                "state_4",
+                "state_5"
+            ],
+            "type": "normal"
+        },
+        "istate_0": {
+            "pos": [
+                55,
+                9
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_0",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_0"
+            ],
+            "parent": "__top__",
+            "children": [],
+            "type": "initial"
+        },
+        "state_1": {
+            "pos": [
+                48,
+                32
+            ],
+            "size": [
+                20,
+                6
+            ],
+            "title": "s_pca9554_wait_dir",
+            "text": [
+                "init/ pca9554_set_direction()"
+            ],
+            "connectors": [
+                "conn_3",
+                "conn_4",
+                "conn_13"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_1": {
+            "pos": [
+                55,
+                26
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_1",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_2"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "initial"
+        },
+        "state_2": {
+            "pos": [
+                48,
+                44
+            ],
+            "size": [
+                20,
+                6
+            ],
+            "title": "s_pca9554_wait_pol",
+            "text": [
+                "init/ pca9554_set_polarity()"
+            ],
+            "connectors": [
+                "conn_5",
+                "conn_6"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "state_3": {
+            "pos": [
+                48,
+                56
+            ],
+            "size": [
+                20,
+                6
+            ],
+            "title": "s_pca9554_wait_output",
+            "text": [
+                "init/ pca9554_set_output()"
+            ],
+            "connectors": [
+                "conn_7",
+                "conn_8"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "state_4": {
+            "pos": [
+                49,
+                70
+            ],
+            "size": [
+                31,
+                16
+            ],
+            "title": "s_pca9554_wait_read",
+            "text": [
+                "init/ pca9554_read_input()",
+                "I2C_SUCCESS/ {",
+                "   pca9554_set_status(PCA9554_READY)",
+                "   pca9554_process_input()",
+                "}"
+            ],
+            "connectors": [
+                "conn_9",
+                "conn_14",
+                "conn_15"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "state_5": {
+            "pos": [
+                88,
+                43
+            ],
+            "size": [
+                32,
+                8
+            ],
+            "title": "s_pca9554_back_off",
+            "text": [
+                "init/ pca9554_reset_timer()",
+                "entry/ pca9554_set_status(PCA9554_NOT_FOUND)"
+            ],
+            "connectors": [
+                "conn_11",
+                "conn_12"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        }
+    },
+    "connectors": {
+        "conn_0": {
+            "parent": "istate_0",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_0"
+        },
+        "conn_1": {
+            "parent": "state_0",
+            "offset": 13,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_0"
+        },
+        "conn_2": {
+            "parent": "istate_1",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_1"
+        },
+        "conn_3": {
+            "parent": "state_1",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_1"
+        },
+        "conn_4": {
+            "parent": "state_1",
+            "offset": 7,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_2"
+        },
+        "conn_5": {
+            "parent": "state_2",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_2"
+        },
+        "conn_6": {
+            "parent": "state_2",
+            "offset": 7,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_3"
+        },
+        "conn_7": {
+            "parent": "state_3",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_3"
+        },
+        "conn_8": {
+            "parent": "state_3",
+            "offset": 7,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_4"
+        },
+        "conn_9": {
+            "parent": "state_4",
+            "offset": 6,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_4"
+        },
+        "conn_10": {
+            "parent": "state_0",
+            "offset": 18,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_5"
+        },
+        "conn_11": {
+            "parent": "state_5",
+            "offset": 15,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_5"
+        },
+        "conn_12": {
+            "parent": "state_5",
+            "offset": 12,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_6"
+        },
+        "conn_13": {
+            "parent": "state_1",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_6"
+        },
+        "conn_14": {
+            "parent": "state_4",
+            "offset": 11,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_7"
+        },
+        "conn_15": {
+            "parent": "state_4",
+            "offset": 7,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_7"
+        }
+    },
+    "transitions": {
+        "trans_0": {
+            "start": "conn_0",
+            "end": "conn_1",
+            "vertices": [
+                [
+                    55,
+                    9
+                ],
+                [
+                    55,
+                    9
+                ],
+                [
+                    55,
+                    17
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                4.1
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                55.5,
+                13.1
+            ]
+        },
+        "trans_1": {
+            "start": "conn_2",
+            "end": "conn_3",
+            "vertices": [
+                [
+                    55,
+                    26
+                ],
+                [
+                    55,
+                    26
+                ],
+                [
+                    55,
+                    32
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                2.6000000000000014
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                55.5,
+                28.6
+            ]
+        },
+        "trans_2": {
+            "start": "conn_4",
+            "end": "conn_5",
+            "vertices": [
+                [
+                    55,
+                    38
+                ],
+                [
+                    55,
+                    43
+                ],
+                [
+                    55,
+                    43
+                ],
+                [
+                    55,
+                    44
+                ]
+            ],
+            "label": "I2C_SUCCESS",
+            "label_offset": [
+                0.5,
+                2.700000000000003
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                55.5,
+                40.7
+            ]
+        },
+        "trans_3": {
+            "start": "conn_6",
+            "end": "conn_7",
+            "vertices": [
+                [
+                    55,
+                    50
+                ],
+                [
+                    55,
+                    54
+                ],
+                [
+                    55,
+                    54
+                ],
+                [
+                    55,
+                    56
+                ]
+            ],
+            "label": "I2C_SUCCESS",
+            "label_offset": [
+                0.5,
+                2.8000000000000043
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                55.5,
+                52.800000000000004
+            ]
+        },
+        "trans_4": {
+            "start": "conn_8",
+            "end": "conn_9",
+            "vertices": [
+                [
+                    55,
+                    62
+                ],
+                [
+                    55,
+                    66
+                ],
+                [
+                    55,
+                    66
+                ],
+                [
+                    55,
+                    70
+                ]
+            ],
+            "label": "I2C_SUCCESS",
+            "label_offset": [
+                0.5,
+                3.5999999999999943
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                55.5,
+                65.6
+            ]
+        },
+        "trans_5": {
+            "start": "conn_10",
+            "end": "conn_11",
+            "vertices": [
+                [
+                    124,
+                    35
+                ],
+                [
+                    103,
+                    35
+                ],
+                [
+                    103,
+                    43
+                ]
+            ],
+            "label": "I2C_FAIL",
+            "label_offset": [
+                -19.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                104.5,
+                34.6
+            ]
+        },
+        "trans_6": {
+            "start": "conn_12",
+            "end": "conn_13",
+            "vertices": [
+                [
+                    100,
+                    43
+                ],
+                [
+                    100,
+                    35
+                ],
+                [
+                    68,
+                    35
+                ]
+            ],
+            "label": "[pca9554_timeout(1000)]",
+            "label_offset": [
+                -23.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                76.5,
+                34.6
+            ]
+        },
+        "trans_7": {
+            "start": "conn_14",
+            "end": "conn_15",
+            "vertices": [
+                [
+                    80,
+                    81
+                ],
+                [
+                    93,
+                    81
+                ],
+                [
+                    93,
+                    77
+                ],
+                [
+                    80,
+                    77
+                ]
+            ],
+            "label": "START_READ",
+            "label_offset": [
+                -10,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                83,
+                76.6
+            ]
+        }
+    },
+    "notes": {
+        "pca9554_i2c_success()": "",
+        "I2C_SUCCESS": "",
+        "pca9554_set_direction()": "Start a I2C transaction to write the DIRECTION register in the slave device.",
+        "PCA9554_SIG_I2C_FAIL": "",
+        "START_READ": ""
+    },
+    "view": {
+        "translate": [
+            -13.5,
+            -34
+        ],
+        "scale": 8.5
+    }
+}
+        
+
+ + diff --git a/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554.h b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554.h new file mode 100644 index 00000000..dc3dbf66 --- /dev/null +++ b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554.h @@ -0,0 +1,98 @@ +/* + * lm73.h + * + * Created on: 2015 máj. 20 + * Author: jszeman + */ + +#ifndef INC_PCA9554_H_ +#define INC_PCA9554_H_ + +#include +#include "i2cMaster.h" + +#define PCA_A0_HIGH (1<<0) +#define PCA_A0_LOW (0) + +#define PCA_A1_HIGH (1<<1) +#define PCA_A1_LOW (0) + +#define PCA_A2_HIGH (1<<2) +#define PCA_A2_LOW (0) + +enum PCA9554_STATUS { + PCA9554_READY, /**< The driver is ready for operation */ + PCA9554_BUSY, /**< The driver is in the process of reading or writing data. The in field is not valid. */ + PCA9554_NOT_FOUND, /**< The configured device did not acknowledged its address */ + PCA9554_STARTING /**< The driver is in the process of initializing the device */ +}; + +enum PCA9554_PART { + PCA9554 = 0x20, + PCA9554A = 0x38 +}; + +typedef enum pca9554_sig_ten { + PCA9554_SIG_NONE, + PCA9554_SIG_I2C_SUCCESS, + PCA9554_SIG_I2C_FAIL, + PCA9554_SIG_INIT, + PCA9554_SIG_START_READ +} pca9554_sig_ten; + +struct pca9554_config +{ + i2cMaster_h i2cH; /**< Pointer to a previously configured I2C master driver */ + enum PCA9554_PART type; /**< Exact device type. Necessary for address calculation */ + uint16_t a; /** Address pin (A0, A1, A2) configuration */ + uint16_t out; /** Initial output value */ + uint16_t polarity; /** Input pin polarity */ + uint16_t direction; /** Pin direction */ +}; + +typedef struct pca9554_t *pca9554_h; +typedef struct pca9554_t pca9554_tst; + +struct pca9554_t +{ + /* PUBLIC */ + struct pca9554_config config; + enum PCA9554_STATUS status; + + uint16_t in; + uint16_t inputChanged; + + void (*setOutput)(pca9554_h self, uint16_t o); + void (*setDirection)(pca9554_h self, uint16_t d); + void (*setPolarity)(pca9554_h self, uint16_t p); + void (*readInput)(pca9554_h self); + void (*callback_1ms)(pca9554_h self); + + /* PRIVATE */ + struct i2cTransaction_t transaction; + uint8_t wbuff[4]; + uint8_t rbuff[2]; + + pca9554_sig_ten signal_en; + pca9554_sig_ten op_en; + + uint32_t timer_u32; + uint32_t fault_cnt_u32; + + void (*sm_callback)(pca9554_tst *self); +}; + + + +void pca9554_init(pca9554_h self); +void pca9554_top(pca9554_tst *self); + +void pca9554_set_status(pca9554_tst *self, enum PCA9554_STATUS status_en); +uint16_t pca9554_timeout(pca9554_tst *self, uint32_t timeout_u32); + +static inline void pca9554_set_state(pca9554_tst *self, void (*state_pft)(pca9554_tst *self)) +{ + self->sm_callback = state_pft; +} + +#endif /* INC_PCA9554_H_ */ diff --git a/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554_functions.h b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554_functions.h new file mode 100644 index 00000000..93ef40a8 --- /dev/null +++ b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554_functions.h @@ -0,0 +1,48 @@ +#ifndef PCA9554_FUNCTIONS_H +#define PCA9554_FUNCTIONS_H + +/*Generated with CHSM v0.0.0 at 2023.07.27 14.07.05*/ + +#include "pca9554.h" +#include + + +void pca9554_process_input(pca9554_tst *self); + +void pca9554_read_input(pca9554_tst *self); + +void pca9554_reset_timer(pca9554_tst *self); + +/*Start a I2C transaction to write the DIRECTION register in the slave device.*/ +void pca9554_set_direction(pca9554_tst *self); + +void pca9554_set_output(pca9554_tst *self); + +void pca9554_set_polarity(pca9554_tst *self); + + +typedef enum pca9554_state_id_ten +{ + S_PCA9554_WAIT_DIR = 1, + S_PCA9554_WAIT_POL = 2, + S_PCA9554_WAIT_OUTPUT = 3, + S_PCA9554_WAIT_READ = 4, + S_PCA9554_BACK_OFF = 5, +} pca9554_state_id_ten; + + +/* +Signals: + I2C_FAIL + I2C_SUCCESS + START_READ +*/ + +/* +Other function notes: + +pca9554_set_status: + +pca9554_timeout: +*/ +#endif diff --git a/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554.c b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554.c new file mode 100644 index 00000000..28a6511c --- /dev/null +++ b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554.c @@ -0,0 +1,115 @@ +/*Generated with CHSM v0.0.1*/ +#include "pca9554.h" +#include "pca9554_functions.h" + + +static void s_pca9554_back_off(pca9554_tst *self); +static void s_pca9554_wait_read(pca9554_tst *self); +static void s_pca9554_wait_output(pca9554_tst *self); +static void s_pca9554_wait_pol(pca9554_tst *self); +static void s_pca9554_wait_dir(pca9554_tst *self); + +static void s_pca9554_wait_dir(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_polarity(self); + return pca9554_set_state(self, s_pca9554_wait_pol); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_pol(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_output(self); + return pca9554_set_state(self, s_pca9554_wait_output); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_output(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_read(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_status(self, PCA9554_READY); + pca9554_process_input(self); + break; + + case PCA9554_SIG_START_READ: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_back_off(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + if(pca9554_timeout(self, 1000)) + { + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} + +void pca9554_top(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_INIT: + pca9554_set_status(self, PCA9554_STARTING); + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} diff --git a/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554_functions.c b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554_functions.c new file mode 100644 index 00000000..65c4e42e --- /dev/null +++ b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554_functions.c @@ -0,0 +1,153 @@ +/* + * lm73.c + * + * Created on: 2015 máj. 20 + * Author: jszeman + */ + +#include +#include "i2cMaster.h" +#include "math.h" +#include "pca9554.h" + +#define PCA_REG_INPUT 0 +#define PCA_REG_OUTPUT 1 +#define PCA_REG_POLARITY 2 +#define PCA_REG_DIRECTION 3 + +static void startRegWrite(pca9554_h self) +{ + self->transaction.writeLength = 2; // write pointer byte + self->transaction.readLength = 0; + self->config.i2cH->start(self->config.i2cH, &self->transaction); + + //self->status = PCA9554_BUSY; +} + +static void setOutput(pca9554_h self, uint16_t o) +{ + self->wbuff[0] = PCA_REG_OUTPUT; + self->wbuff[1] = o; + + startRegWrite(self); +} + +static void setDirection(pca9554_h self, uint16_t d) +{ + self->wbuff[0] = PCA_REG_DIRECTION; + self->wbuff[1] = d; + + startRegWrite(self); +} + +static void setPolarity(pca9554_h self, uint16_t p) +{ + self->wbuff[0] = PCA_REG_POLARITY; + self->wbuff[1] = p; + + startRegWrite(self); +} + +static void readInput(pca9554_h self) +{ + self->wbuff[0] = PCA_REG_INPUT; + self->transaction.writeLength = 1; // write pointer byte + self->transaction.readLength = 1; + self->config.i2cH->start(self->config.i2cH, &self->transaction); + + self->status = PCA9554_BUSY; +} + +static void start_read(pca9554_h self) +{ + self->op_en = PCA9554_SIG_START_READ; +} + +static void callback(pca9554_h self) +{ + self->signal_en = PCA9554_SIG_NONE; + + switch (self->transaction.result) + { + case I2C_SUCCESS: + self->signal_en = PCA9554_SIG_I2C_SUCCESS; + self->transaction.result = I2C_NONE; + break; + + case I2C_ADDRESS_NACK: + case I2C_DATA_NACK: + self->signal_en = PCA9554_SIG_I2C_FAIL; + self->transaction.result = I2C_NONE; + self->fault_cnt_u32++; + break; + + default: + self->signal_en = self->op_en; + self->op_en = PCA9554_SIG_NONE; + } + + self->sm_callback(self); + + self->timer_u32++; +} + +void pca9554_set_status(pca9554_tst *self, enum PCA9554_STATUS status_en) +{ + self->status = status_en; +} + +void pca9554_process_input(pca9554_tst *self) +{ + self->in = self->rbuff[0]; + self->inputChanged = 1; +} + +void pca9554_read_input(pca9554_tst *self) +{ + readInput(self); +} + +void pca9554_set_direction(pca9554_tst *self) +{ + setDirection(self, self->config.direction); +} + +void pca9554_set_output(pca9554_tst *self) +{ + setOutput(self, self->config.out); +} + +void pca9554_set_polarity(pca9554_tst *self) +{ + setPolarity(self, self->config.polarity); +} + +void pca9554_reset_timer(pca9554_tst *self) +{ + self->timer_u32 = 0; +} + +uint16_t pca9554_timeout(pca9554_tst *self, uint32_t timeout_u32) +{ + return self->timer_u32 >= timeout_u32; +} + +void pca9554_init(pca9554_h self) +{ + self->setOutput = setOutput; + self->setDirection = setDirection; + self->setPolarity = setPolarity; + self->readInput = start_read; + self->callback_1ms = callback; + + self->transaction.address = self->config.type | (self->config.a & 0x07); + self->transaction.result = I2C_NONE; + self->transaction.readData = self->rbuff; + self->transaction.writeData = self->wbuff; + self->inputChanged = 0; + self->fault_cnt_u32 = 0; + + self->sm_callback = pca9554_top; + self->op_en = PCA9554_SIG_INIT; + +} diff --git a/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/CMakeLists.txt b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/CMakeLists.txt new file mode 100644 index 00000000..4b648cb6 --- /dev/null +++ b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/CMakeLists.txt @@ -0,0 +1,22 @@ + +add_module_test( + NAME + lm73_test + SOURCE + tsrc/main.c + tsrc/ut_lm73_test.c + INCLUDE + tinc + LINK + unity + i2c_drv_mock + lm73 + DEFINES + NDEBUG + CHSM_BUILD_TESTS + STANDARD + 11 +) + +set_property(TARGET lm73_test PROPERTY ECLIPSE_GENERATE_SOURCE_PROJECT ON) +set_property(TARGET lm73_test PROPERTY ECLIPSE_GENERATE_LINKED_RESOURCES ON) \ No newline at end of file diff --git a/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/doc/signal_classes_distribution.puml b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/doc/signal_classes_distribution.puml new file mode 100644 index 00000000..bc36d642 --- /dev/null +++ b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/doc/signal_classes_distribution.puml @@ -0,0 +1,32 @@ +@startuml signal_classes_distribution +scale 800 width +skinparam backgroundColor #FFEBDC +scale 1 + +skinparam cloud { + backgroundColor Olive + borderColor orange +} + +title Architecture Diagram of the CHSM package + +left to right direction + +package chsm { + package interfaces{ + rectangle signal_classes_if{ + typedef enum sig_class_ten { + SIG_CLASS_SYS = CRF_SIGNAL_CLASS_START, + SIG_CLASS_I2C_DRIVER, + SIG_CLASS_SPI_DRIVER, + SIG_CLASS_MEM, + SIG_CLASS_CAN, + SIG_APP_NAMESPACE_START, +} sig_class_ten; + } + + } +} + + +@enduml \ No newline at end of file diff --git a/modules/lm73/test/src/main.c b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/main.c similarity index 99% rename from modules/lm73/test/src/main.c rename to gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/main.c index d71a386b..d8154db0 100644 --- a/modules/lm73/test/src/main.c +++ b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/main.c @@ -2,6 +2,7 @@ #include "unity_fixture.h" #include "unity.h" + void disableInterrupts(void) { diff --git a/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/ut_lm73_test.c b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/ut_lm73_test.c new file mode 100644 index 00000000..431baa94 --- /dev/null +++ b/gui/c_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/ut_lm73_test.c @@ -0,0 +1,417 @@ +/* + * ut_lm73_test.c + * + * Created on: 2020. dec. 30. + * Author: jszeman + */ + +#include +#include +#include +#include +#include +#include "unity_fixture.h" +#include "crf.h" +#include "cbits.h" +#include "ut_i2c_driver_mock.h" +#include "i2c_master.h" +#include "lm73.h" +#include "lm73_regs.h" +#include "cevent.h" +#include "sys_if.h" + +TEST_GROUP(lm73); + +ut_i2c_driver_mock_tst drv_mock_st; +i2c_driver_if_tst* drv_pst = (i2c_driver_if_tst *)&drv_mock_st; + +const cevent_tst* i2c_master_events_apst[8]; +i2c_master_tst i2c_master_st; +uint8_t i2c_master_scanned_ids[127]; + +const cevent_tst* lm73_events_apst[8]; +lm73_tst lm73_st; + + +lm73_tst *self = &lm73_st; // This is necessary for macros like LM73_READ_PERIOD to work here + +chsm_tst* hsm_apst[] = { + (chsm_tst*)(&i2c_master_st), + (chsm_tst*)(&lm73_st), + NULL}; + +uint8_t pool_buff_au8[1024]; +cpool_tst pool_ast[1]; + +crf_tst crf; + +const cevent_tst* events_apst[4]; +cqueue_tst q_st; + +const cevent_tst tick_10ms_st = {.sig = SIG_SYS_TICK_10ms}; + +static void tick_ms(uint32_t tick_cnt_u32) +{ + while(tick_cnt_u32--) + { + drv_mock_st.tick(&drv_mock_st); + + CRF_POST(&tick_10ms_st, &lm73_st); + + while(CRF_STEP()) + { + printf("| "); + } + } +} + +void lm73_send(chsm_tst *self, const cevent_tst *e_pst) +{ + //printf("\n%s\n", __FUNCTION__); + switch(e_pst->sig) + { + case SIG_LM73_TEMP: + case SIG_LM73_ONLINE: + case SIG_LM73_OFFLINE: + CRF_POST(e_pst, &q_st); + break; + + default: + CRF_POST(e_pst, &i2c_master_st); + } +} + + +TEST_SETUP(lm73) +{ + memset(events_apst, 0, sizeof(events_apst)); + memset(&q_st, 0, sizeof(q_st)); + memset(&drv_mock_st, 0, sizeof(drv_mock_st)); + memset(&i2c_master_st, 0, sizeof(i2c_master_st)); + memset(&crf, 0, sizeof(crf)); + memset(&i2c_master_events_apst, 0, sizeof(i2c_master_events_apst)); + memset(&pool_buff_au8, 0, sizeof(pool_buff_au8)); + memset(&pool_ast, 0, sizeof(pool_ast)); + memset(&lm73_st, 0, sizeof(lm73_st)); + + cpool_init(pool_ast+0, pool_buff_au8, 24, 16); + + cqueue_init(&q_st, events_apst, 4); + + ut_i2c_driver_mock_init(&drv_mock_st); + + i2c_master_st.config_st.driver_pst = drv_pst; + // i2c_master_st.config_st.scan_result_au8[0] = &i2c_master_scanned_ids; + chsm_ctor(&i2c_master_st.super, i2c_master_top, i2c_master_events_apst, 4, 4); + chsm_ctor(&lm73_st.super, lm73_top, lm73_events_apst, 8, 0); + + lm73_st.config_st = (lm73_cfg_tst){ + .address_u8 = LM73_0_I2C_FLOAT, + .id_u16 = 0xabcd, + .period_ms_u16 = LM73_READ_PERIOD_VALUE, + .max_error_cnt_u16 = LM73_MAX_ERROR_COUNT_VALUE + }; + + CRF_SEND_FUNC(&lm73_st) = lm73_send; + + crf_init(&crf, hsm_apst, pool_ast, 1); + chsm_init((chsm_tst *)&i2c_master_st); + chsm_init((chsm_tst *)&lm73_st); +} + +TEST_TEAR_DOWN(lm73) +{ +} + +/* + * Just call setup + */ +TEST(lm73, init) +{ + printf("\n%s\n", __FUNCTION__); +} + +TEST(lm73, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = LM73_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, // sensor id + 0xf3, 0x80, // -25° measured value + 0x0c, 0x80 // +25° measured value + } + }; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + +} + +/* read_temp_twice: + * Setup the mock device to send the id bytes and two temperature reading (-25 and 25) to the master. + * Check, that two temperature events were sent + */ +TEST(lm73, read_temp_twice) +{ + printf("\n%s\n", __FUNCTION__); + i2c_mock_slave_device_tst dev_st = { + .address_u8 = 0x12, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + + const lm73_temp_tst* e_pst; + const lm73_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = (lm73_status_tst*)q_st.get(&q_st); + TEST_ASSERT(s_pst); + TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + + e_pst = (lm73_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + + tick_ms((LM73_READ_PERIOD/10)+1); + + uint8_t expected_au8[4] = {7, 0, 0, 0}; + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); + TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); + TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + + e_pst = (lm73_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +} + +/* read_id_retry: + * Check that a failed ID read will be repeated after the configured time. + */ +TEST(lm73, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = LM73_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + const lm73_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = (lm73_status_tst*)q_st.get(&q_st); + TEST_ASSERT_NULL(s_pst); + + // dev_st.address_u8 = 0x12; + + // tick_ms(LM73_RETRY_TIMEOUT-10); + + // s_pst = (lm73_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NULL(s_pst); + + // tick_ms(10); + + // s_pst = (lm73_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NOT_NULL(s_pst); + // TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); +} + +// /* read_id_retry_bad_id: +// * Check that a failed ID read will be repeated after the configured time if the data sent back +// * by the slave is not 0x190 for the first try. +// */ +// TEST(lm73, read_id_retry_bad_id) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x91, 0x01, 0x90, 0x0c, 0x80} +// }; + +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms((LM73_RETRY_TIMEOUT-10)/10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NOT_NULL(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); +// } + +// /* go_online: +// * Check that after reading temperature data fails for more than LM73_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST(lm73, go_online) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const lm73_temp_tst* e_pst; +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms((LM73_READ_PERIOD_VALUE / 10) + 1); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE(lm73_st.valid_b); +// } + +// /* go_offline: +// * Check that after reading temperature data fails for more than LM73_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST(lm73, go_offline) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const lm73_temp_tst* e_pst; +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms((LM73_READ_PERIOD/10) + 1); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE(lm73_st.valid_b); + +// dev_st.address_u8 = 0x13; + +// tick_ms(((LM73_READ_PERIOD/10) + 1) * LM73_MAX_ERROR_COUNT + 1); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_OFFLINE, s_pst->super.sig); + +// TEST_ASSERT_FALSE(lm73_st.valid_b); +// } + +// /* triggered_read: +// * Check that it is possible to trigger a read before the read period timeout elapses. +// */ +// TEST(lm73, triggered_read) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const cevent_tst read_event = {.sig = SIG_LM73_READ}; + + +// const lm73_temp_tst* e_pst; +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(1); + +// CRF_POST(&read_event, &lm73_st); + +// tick_ms(10); + +// uint8_t expected_au8[4] = {7, 0, 0, 0}; +// TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); +// TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); +// TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +// } + +TEST_GROUP_RUNNER(lm73) +{ + RUN_TEST_CASE(lm73, init); + RUN_TEST_CASE(lm73, read_id); + // RUN_TEST_CASE(lm73, read_temp_twice); + // RUN_TEST_CASE(lm73, read_id_retry); + // RUN_TEST_CASE(lm73, read_id_retry_bad_id); + // RUN_TEST_CASE(lm73, go_offline); + // RUN_TEST_CASE(lm73, go_online); + // RUN_TEST_CASE(lm73, triggered_read); +} diff --git a/crf/build/.keep b/gui/c_gen/templates/__init__.py similarity index 100% rename from crf/build/.keep rename to gui/c_gen/templates/__init__.py diff --git a/gui/c_gen/templates/chsm_java_template.jinja b/gui/c_gen/templates/chsm_java_template.jinja new file mode 100644 index 00000000..64c877e5 --- /dev/null +++ b/gui/c_gen/templates/chsm_java_template.jinja @@ -0,0 +1,120 @@ +// Generated by CHSM - Hierarchical State Machine Framework +{% set class_name = data.template_params.get('class_name', 'StateMachine') if data.template_params else 'StateMachine' %} +{% set package_name = data.template_params.get('package_name', '') if data.template_params else '' %} +{% if package_name %} +package {{ package_name }}; +{% endif %} + +public class {{ class_name }} { + + // State constants + public enum State { +{% for state_id, state in data.states.items() | sort(attribute='1.title') if state.type == 'normal' and state_id != '__top__' %} + {{ state.title.upper() }}({{ state.num }}){{ "," if not loop.last else ";" }} +{% endfor %} + + private final int value; + State(int value) { this.value = value; } + public int getValue() { return value; } + } + + private State state; + + public {{ class_name }}() { + init(); + } + + public State getState() { + return state; + } + + private void init() { +{% for func, param in data.states.__top__.sys_signals.init.funcs %} +{% if func %} + {{ func }}({{ param if param else '' }}); +{% endif %} +{% endfor %} + state = State.{{ data.states.__top__.sys_signals.init.target_title.upper() }}; + } + + /** + * Dispatch a signal to the current state handler. + * @param signal the signal name + */ + public void dispatch(String signal) { + switch (state) { +{% for state_id, state in data.states.items() | sort(attribute='1.title') if state.type == 'normal' and state_id != '__top__' %} + case {{ state.title.upper() }}: + handle_{{ state.title }}(signal); + break; +{% endfor %} + } + } + +{% for state_id, state in data.states.items() | sort(attribute='1.title') if state.type == 'normal' and state_id != '__top__' %} + private void handle_{{ state.title }}(String signal) { + switch (signal) { +{% for signal_id in state.signals.keys() | sort %} +{% set sig = state.signals[signal_id] %} + case "{{ signal_id }}": +{% for guard_id, guard in sig.guards.items() %} +{% if not guard_id %} +{% for func, param in guard.funcs %} +{% if func %} + {{ func }}({{ param if param else '' }}); +{% endif %} +{% endfor %} +{% if guard.target %} + state = State.{{ guard.target_title.upper() }}; +{% endif %} +{% else %} + if ({{ guard.guard_func }}({{ guard.guard_param if guard.guard_param else '' }})) { +{% for func, param in guard.funcs %} +{% if func %} + {{ func }}({{ param if param else '' }}); +{% endif %} +{% endfor %} +{% if guard.target %} + state = State.{{ guard.target_title.upper() }}; +{% endif %} + } +{% endif %} +{% endfor %} + break; +{% endfor %} + } +{% for guard_id, guard in state.guards.items() %} +{% if guard.guard_func %} + if ({{ guard.guard_func }}({{ guard.guard_param if guard.guard_param else '' }})) { +{% for func, param in guard.funcs %} +{% if func %} + {{ func }}({{ param if param else '' }}); +{% endif %} +{% endfor %} +{% if guard.target %} + state = State.{{ guard.target_title.upper() }}; +{% endif %} + } +{% endif %} +{% endfor %} + } + +{% endfor %} + // --- User action functions (override in subclass) --- +{% for func in data.user_funcs | sort %} + protected void {{ func }}() { } +{% endfor %} +{% for func_sig in data.user_inc_funcs | sort %} + /** {{ func_sig }} */ + protected void {{ func_sig.split('(')[0] }}(Object... args) { } +{% endfor %} + + // --- Guard functions (override in subclass) --- +{% for func in data.user_guards | sort %} + protected boolean {{ func }}() { return false; } +{% endfor %} +{% for func_sig in data.user_inc_guards | sort %} + /** {{ func_sig }} */ + protected boolean {{ func_sig.split('(')[0] }}(Object... args) { return false; } +{% endfor %} +} diff --git a/gui/c_gen/templates/chsm_js_template.jinja b/gui/c_gen/templates/chsm_js_template.jinja new file mode 100644 index 00000000..705c3021 --- /dev/null +++ b/gui/c_gen/templates/chsm_js_template.jinja @@ -0,0 +1,109 @@ +// Generated by CHSM - Hierarchical State Machine Framework +{% set class_name = data.template_params.get('class_name', 'StateMachine') if data.template_params else 'StateMachine' %} +{% set use_export = data.template_params.get('export', true) if data.template_params else true %} + +class {{ class_name }} { + // State constants +{% for state_id, state in data.states.items() | sort(attribute='1.title') if state.type == 'normal' and state_id != '__top__' %} + static {{ state.title.upper() }} = {{ state.num }}; +{% endfor %} + + constructor() { + this.state = null; + this._init(); + } + + _init() { +{% for func, param in data.states.__top__.sys_signals.init.funcs %} +{% if func %} + this.{{ func }}({{ param if param else '' }}); +{% endif %} +{% endfor %} + this.state = {{ class_name }}.{{ data.states.__top__.sys_signals.init.target_title.upper() }}; + } + + /** + * Dispatch a signal to the current state handler. + * @param {string} signal + */ + dispatch(signal) { + switch (this.state) { +{% for state_id, state in data.states.items() | sort(attribute='1.title') if state.type == 'normal' and state_id != '__top__' %} + case {{ class_name }}.{{ state.title.upper() }}: + this._handle_{{ state.title }}(signal); + break; +{% endfor %} + } + } + +{% for state_id, state in data.states.items() | sort(attribute='1.title') if state.type == 'normal' and state_id != '__top__' %} + _handle_{{ state.title }}(signal) { + switch (signal) { +{% for signal_id in state.signals.keys() | sort %} +{% set sig = state.signals[signal_id] %} + case "{{ signal_id }}": +{% for guard_id, guard in sig.guards.items() %} +{% if not guard_id %} +{% for func, param in guard.funcs %} +{% if func %} + this.{{ func }}({{ param if param else '' }}); +{% endif %} +{% endfor %} +{% if guard.target %} + this.state = {{ class_name }}.{{ guard.target_title.upper() }}; +{% endif %} +{% else %} + if (this.{{ guard.guard_func }}({{ guard.guard_param if guard.guard_param else '' }})) { +{% for func, param in guard.funcs %} +{% if func %} + this.{{ func }}({{ param if param else '' }}); +{% endif %} +{% endfor %} +{% if guard.target %} + this.state = {{ class_name }}.{{ guard.target_title.upper() }}; +{% endif %} + } +{% endif %} +{% endfor %} + break; +{% endfor %} + } +{% for guard_id, guard in state.guards.items() %} +{% if guard.guard_func %} + if (this.{{ guard.guard_func }}({{ guard.guard_param if guard.guard_param else '' }})) { +{% for func, param in guard.funcs %} +{% if func %} + this.{{ func }}({{ param if param else '' }}); +{% endif %} +{% endfor %} +{% if guard.target %} + this.state = {{ class_name }}.{{ guard.target_title.upper() }}; +{% endif %} + } +{% endif %} +{% endfor %} + } + +{% endfor %} + // --- User action functions (override in subclass) --- +{% for func in data.user_funcs | sort %} + {{ func }}() { } +{% endfor %} +{% for func_sig in data.user_inc_funcs | sort %} + /** {{ func_sig }} */ + {{ func_sig.split('(')[0] }}(...args) { } +{% endfor %} + + // --- Guard functions (override in subclass) --- +{% for func in data.user_guards | sort %} + {{ func }}() { return false; } +{% endfor %} +{% for func_sig in data.user_inc_guards | sort %} + /** {{ func_sig }} */ + {{ func_sig.split('(')[0] }}(...args) { return false; } +{% endfor %} +} + +{% if use_export %} +export default {{ class_name }}; +{% endif %} diff --git a/gui/c_gen/templates/chsm_py_template.jinja b/gui/c_gen/templates/chsm_py_template.jinja new file mode 100644 index 00000000..f27c6d20 --- /dev/null +++ b/gui/c_gen/templates/chsm_py_template.jinja @@ -0,0 +1,115 @@ +"""Generated by CHSM - Hierarchical State Machine Framework""" +{% set class_name = data.template_params.get('class_name', 'StateMachine') if data.template_params else 'StateMachine' %} + + +class {{ class_name }}: + """Hierarchical State Machine. + + Signals: +{% for sig in data.user_signals | sort %} + {{ sig }} +{% endfor %} + """ + + # State constants +{% for state_id, state in data.states.items() | sort(attribute='1.title') if state.type == 'normal' and state_id != '__top__' %} + {{ state.title.upper() }} = {{ state.num }} +{% endfor %} + + def __init__(self): + self.state = None + self._init() + + def _init(self): + """Initialize to the starting state.""" +{% for func, param in data.states.__top__.sys_signals.init.funcs %} +{% if func %} + self.{{ func }}({{ param if param else '' }}) +{% endif %} +{% endfor %} + self.state = self.{{ data.states.__top__.sys_signals.init.target_title.upper() }} + + def dispatch(self, signal): + """Dispatch a signal to the current state handler.""" +{% for state_id, state in data.states.items() | sort(attribute='1.title') if state.type == 'normal' and state_id != '__top__' %} +{% if loop.first %} + if self.state == self.{{ state.title.upper() }}: +{% else %} + elif self.state == self.{{ state.title.upper() }}: +{% endif %} + self._handle_{{ state.title }}(signal) +{% endfor %} + +{% for state_id, state in data.states.items() | sort(attribute='1.title') if state.type == 'normal' and state_id != '__top__' %} + def _handle_{{ state.title }}(self, signal): + """Handler for state {{ state.title }}.""" +{% for signal_id in state.signals.keys() | sort %} +{% set sig = state.signals[signal_id] %} +{% if loop.first %} + if signal == "{{ signal_id }}": +{% else %} + elif signal == "{{ signal_id }}": +{% endif %} +{% for guard_id, guard in sig.guards.items() %} +{% if not guard_id %} +{% for func, param in guard.funcs %} +{% if func %} + self.{{ func }}({{ param if param else '' }}) +{% endif %} +{% endfor %} +{% if guard.target %} + self.state = self.{{ guard.target_title.upper() }} +{% endif %} +{% else %} + if self.{{ guard.guard_func }}({{ guard.guard_param if guard.guard_param else '' }}): +{% for func, param in guard.funcs %} +{% if func %} + self.{{ func }}({{ param if param else '' }}) +{% endif %} +{% endfor %} +{% if guard.target %} + self.state = self.{{ guard.target_title.upper() }} +{% endif %} +{% endif %} +{% endfor %} +{% endfor %} +{% for guard_id, guard in state.guards.items() %} +{% if guard.guard_func %} + if self.{{ guard.guard_func }}({{ guard.guard_param if guard.guard_param else '' }}): +{% for func, param in guard.funcs %} +{% if func %} + self.{{ func }}({{ param if param else '' }}) +{% endif %} +{% endfor %} +{% if guard.target %} + self.state = self.{{ guard.target_title.upper() }} +{% endif %} +{% endif %} +{% endfor %} + +{% endfor %} + # --- User action functions (implement in subclass or override) --- +{% for func in data.user_funcs | sort %} + + def {{ func }}(self): + pass +{% endfor %} +{% for func_sig in data.user_inc_funcs | sort %} + + def {{ func_sig.split('(')[0] }}(self, *args): + """{{ func_sig }}""" + pass +{% endfor %} + + # --- Guard functions (implement in subclass or override) --- +{% for func in data.user_guards | sort %} + + def {{ func }}(self): + return False +{% endfor %} +{% for func_sig in data.user_inc_guards | sort %} + + def {{ func_sig.split('(')[0] }}(self, *args): + """{{ func_sig }}""" + return False +{% endfor %} diff --git a/gui/c_gen/templates/chsm_vhdl_template.jinja b/gui/c_gen/templates/chsm_vhdl_template.jinja new file mode 100644 index 00000000..7cfdf3d8 --- /dev/null +++ b/gui/c_gen/templates/chsm_vhdl_template.jinja @@ -0,0 +1,121 @@ +-- Generated by CHSM - Hierarchical State Machine Framework +{% set entity_name = data.template_params.get('entity_name', 'state_machine') if data.template_params else 'state_machine' %} +{% set clock_name = data.template_params.get('clock_name', 'clk') if data.template_params else 'clk' %} +{% set reset_name = data.template_params.get('reset_name', 'rst') if data.template_params else 'rst' %} +{% set event_width = data.template_params.get('event_width', 8) if data.template_params else 8 %} + +library ieee; +use ieee.std_logic_1164.all; + +entity {{ entity_name }} is + port ( + {{ clock_name }} : in std_logic; + {{ reset_name }} : in std_logic; + event_i : in std_logic_vector({{ event_width - 1 }} downto 0); + event_en : in std_logic; + state_o : out std_logic_vector(7 downto 0) + ); +end entity {{ entity_name }}; + +architecture rtl of {{ entity_name }} is + + -- State type enumeration + type state_type is ( +{% for state_id, state in data.states.items() | sort(attribute='1.title') if state.type == 'normal' and state_id != '__top__' %} + ST_{{ state.title.upper() }}{{ "," if not loop.last }} +{% endfor %} + ); + + -- Event constants +{% for sig in data.user_signals | sort %} + constant EVT_{{ sig.upper() }} : std_logic_vector({{ event_width - 1 }} downto 0) := x"{{ '%02X' % loop.index0 }}"; +{% endfor %} + + signal current_state : state_type; + signal next_state : state_type; + +begin + + -- State register process + p_state_reg : process({{ clock_name }}, {{ reset_name }}) + begin + if {{ reset_name }} = '1' then + current_state <= ST_{{ data.states.__top__.sys_signals.init.target_title.upper() }}; + elsif rising_edge({{ clock_name }}) then + current_state <= next_state; + end if; + end process p_state_reg; + + -- Next state and output logic + p_next_state : process(current_state, event_i, event_en) + begin + next_state <= current_state; -- default: hold state + + if event_en = '1' then + case current_state is +{% for state_id, state in data.states.items() | sort(attribute='1.title') if state.type == 'normal' and state_id != '__top__' %} + when ST_{{ state.title.upper() }} => +{% for signal_id in state.signals.keys() | sort %} +{% set sig = state.signals[signal_id] %} + if event_i = EVT_{{ signal_id.upper() }} then +{% for guard_id, guard in sig.guards.items() %} +{% if not guard_id %} +{% if guard.target %} + next_state <= ST_{{ guard.target_title.upper() }}; +{% endif %} + -- Actions: {% for func, param in guard.funcs %}{% if func %}{{ func }}({{ param if param else '' }}){{ ", " if not loop.last }}{% endif %}{% endfor %} + +{% else %} + -- Guard: {{ guard.guard_func }}({{ guard.guard_param if guard.guard_param else '' }}) +{% if guard.target %} + -- next_state <= ST_{{ guard.target_title.upper() }}; -- guarded transition +{% endif %} +{% endif %} +{% endfor %} +{% if not loop.last %} + els{% endif %}{% endfor %} + end if; +{% if state.guards | length > 0 %} +{% for guard_id, guard in state.guards.items() %} +{% if guard.guard_func %} + -- Signalless guard: {{ guard.guard_func }}({{ guard.guard_param if guard.guard_param else '' }}) +{% if guard.target %} + -- next_state <= ST_{{ guard.target_title.upper() }}; +{% endif %} +{% endif %} +{% endfor %} +{% endif %} + +{% endfor %} + when others => + next_state <= ST_{{ data.states.__top__.sys_signals.init.target_title.upper() }}; + end case; + end if; + end process p_next_state; + + -- State output encoding + with current_state select state_o <= +{% for state_id, state in data.states.items() | sort(attribute='1.title') if state.type == 'normal' and state_id != '__top__' %} + x"{{ '%02X' % state.num }}" when ST_{{ state.title.upper() }}{{ "," if not loop.last else ";" }} +{% endfor %} + + -- + -- User action procedures (implement in a wrapper architecture or package) + -- +{% for func in data.user_funcs | sort %} + -- procedure {{ func }}; +{% endfor %} +{% for func_sig in data.user_inc_funcs | sort %} + -- procedure {{ func_sig }}; +{% endfor %} + -- + -- Guard functions (implement as signals or conditions) + -- +{% for func in data.user_guards | sort %} + -- signal {{ func }}_s : boolean; +{% endfor %} +{% for func_sig in data.user_inc_guards | sort %} + -- signal {{ func_sig.split('(')[0] }}_s : boolean; +{% endfor %} + +end architecture rtl; diff --git a/cgen/templates/model.json b/gui/c_gen/templates/model.json similarity index 100% rename from cgen/templates/model.json rename to gui/c_gen/templates/model.json diff --git a/cgen/templates/settings.json b/gui/c_gen/templates/settings.json similarity index 90% rename from cgen/templates/settings.json rename to gui/c_gen/templates/settings.json index 212041fe..3b3b702d 100644 --- a/cgen/templates/settings.json +++ b/gui/c_gen/templates/settings.json @@ -6,7 +6,7 @@ "init_signal": "C_SIG_INIT", "signal_prefix": "", "func_args": "self, e_pst, ctx_pst", - "func_params": "chsm_tst *self, const cevent_tst *e_pst, chsm_call_ctx_tst *ctx_pst", + "func_params": "chsm_tst *self, const cevent_tst *e_pst", "user_func_args_t": "self, e_pst", "user_func_params_t": "chsm_tst *self, const cevent_tst *e_pst", "func_return_type": "chsm_result_ten", @@ -20,7 +20,7 @@ "exit_children": "chsm_exit_children", "c_include_list": ["chsm.h", "cevent.h"], "h_include_list": ["chsm.h", "cevent.h", ""], - "top_state_name": "chsm_result_ten\\s+(?P\\w+)\\(chsm_tst\\s+\\*self,\\s+const\\s+cevent_tst\\s+\\*e_pst,\\s+chsm_call_ctx_tst\\s+\\*ctx_pst\\)\\s*;", + "top_state_name": "chsm_result_ten\\s+(?P\\w+)\\(chsm_tst\\s+\\*self,\\s+const\\s+cevent_tst\\s+\\*e_pst\\)\\s*;", "set_state_id": "" }, diff --git a/cgen/templates/template.html b/gui/c_gen/templates/template.html similarity index 96% rename from cgen/templates/template.html rename to gui/c_gen/templates/template.html index e1aa03aa..3f6b43f2 100644 --- a/cgen/templates/template.html +++ b/gui/c_gen/templates/template.html @@ -18,6 +18,7 @@ height: 100%; }} + {theme_style} {style} diff --git a/cgen/templates/wheel.js b/gui/c_gen/templates/wheel.js similarity index 100% rename from cgen/templates/wheel.js rename to gui/c_gen/templates/wheel.js diff --git a/cgen/chsm_backend.py b/gui/chsm_backend.py similarity index 53% rename from cgen/chsm_backend.py rename to gui/chsm_backend.py index 92886d5a..7aa66a9b 100644 --- a/cgen/chsm_backend.py +++ b/gui/chsm_backend.py @@ -7,36 +7,57 @@ Options: -s, --server-only Do not open the application with Chrome app mode just wait for clients at http://127.0.0.1:8000/main.html -c, --code-gen Generate code and quit. Don't start the GUI. + -o, --output-lang Set witch language will you generate the output. (c, python, javascript, java) """ import re +from time import time import eel +import os +import sys import json from pathlib import Path from docopt import docopt import logging from pprint import pprint import collections - +import subprocess import tkinter as tk from tkinter.filedialog import askopenfilename, asksaveasfilename - -from hsm import StateMachine +from c_gen import StateMachine +import module_generator +import random +import threading +import socket +import select +import gevent + +def resource_path(relative_path): + """ Get absolute path to resource, works for dev and for PyInstaller """ + try: + # PyInstaller creates a temp folder and stores path in _MEIPASS + base_path = sys._MEIPASS + except Exception: + base_path = os.path.abspath(".") + + return os.path.join(base_path, relative_path) class HtmlException(Exception): pass -TOP_STATE_NAME = r'chsm_result_ten\s+(?P\w+)\(chsm_tst\s+\*self,\s+const\s+cevent_tst\s+\*e_pst,\s+chsm_call_ctx_tst\s+\*ctx_pst\)\s*;' - +TOP_STATE_NAME = r'chsm_result_ten\s+(?P\w+)\(chsm_tst\s+\*self,\s+const\s+cevent_tst\s+\*e_pst)\s*;' +random_port = random.randint(1,65535) class ChsmException(Exception): pass def save_html(html_fname: Path, drawing: str, json_data: str): backend_path = (Path(__file__).parent).absolute().resolve() - template_dir = (backend_path / 'templates').absolute().resolve() + template_dir = (backend_path / 'c_gen' / 'templates').absolute().resolve() template_html = template_dir / 'template.html' drawing_js = template_dir / 'wheel.js' - web_dir = (backend_path / '../web').absolute().resolve() + web_dir = (backend_path / 'web').absolute().resolve() drawing_css = web_dir / 'drawing.css' + theme_css = web_dir / 'themes' / 'default.css' + if not template_html.exists(): logging.error(f'File not found: {template_html}') @@ -64,15 +85,26 @@ def save_html(html_fname: Path, drawing: str, json_data: str): 'message': f'File not found: {drawing_css}', }) return + + if not theme_css.exists(): + logging.error(f'File not found: {theme_css}') + eel.send_event('SAVE_RESULT', { + 'result': False, + 'file': f'{theme_css}', + 'message': f'File not found: {theme_css}', + }) + return with open(template_html, 'r') as tmp_html, \ - open(drawing_css, 'r') as drw_css, \ - open(drawing_js, 'r') as drw_js, \ - open(html_fname, 'w') as html: + open(drawing_css, 'r') as drw_css, \ + open(theme_css, 'r') as theme_css_, \ + open(drawing_js, 'r') as drw_js, \ + open(html_fname, 'w') as html: template = tmp_html.read() css = drw_css.read() js = drw_js.read() - output = template.format(style=css, drawing=drawing, json_data=json_data, script=js) + theme_style = theme_css_.read() + output = template.format(style=css, theme_style=theme_style ,drawing=drawing, json_data=json_data, script=js) html.write(output) logging.info(f'Saved drawing in {html_fname}') eel.send_event('SAVE_RESULT', { @@ -98,7 +130,7 @@ def open_html(html_path): class Project: def __init__(self, h_file_path=None): self.backend_path = (Path(__file__).parent).absolute().resolve() - self.template_dir = (self.backend_path / 'templates').absolute().resolve() + self.template_dir = (self.backend_path / 'c_gen' / 'templates').absolute().resolve() self.h_file_path = Path(h_file_path) if h_file_path else self._open_header_dialog() @@ -208,7 +240,6 @@ def _find_user_config_file(self, h_dir, h_name): return self._find_file(h_dir, 'settings.json') - def _load_user_config(self, hpath): user_cfg_path = self._find_user_config_file(hpath.parent, hpath.stem) @@ -233,15 +264,175 @@ def generate_code(self): sm = StateMachine(self.model, self.h_file_path, self.func_h_path.name, self.c_templates, self.file_config) with open(self.c_file_path, 'w') as cfile: - logging.info(f'Generating code int file: {self.c_file_path}') + logging.info(f'Generating code into file: {self.c_file_path}') cfile.write(str(sm.ast)) with open(self.func_h_path, 'w') as hfile: - logging.info(f'Generating code int file: {self.func_h_path}') + logging.info(f'Generating code into file: {self.func_h_path}') hfile.write(str(sm.h_ast)) + def print_repository_info(self, repo): + print('Repository description: {}'.format(repo.description)) + print('Repository active branch is {}'.format(repo.active_branch)) + + for remote in repo.remotes: + print('Remote named "{}" with URL "{}"'.format(remote, remote.url)) + + print('Last commit for repository is {}.'.format(str(repo.head.commit.hexsha))) + print('pickpack version name : {}'.format(repo.active_branch).format(str(repo.head.commit.hexsha))) project = None +# --------------------------------------------------------------------------- +# Debug channel – TCP server that accepts JSON-line messages from a running +# state machine and forwards them to the GUI via Eel. +# +# Protocol (one JSON object per line, terminated with \n): +# {"type": "state", "active": ["state_title_1", "state_title_2"]} +# {"type": "variables", "vars": {"counter": 5, "flag": true}} +# {"type": "event", "name": "EVT_START", "data": "optional payload"} +# {"type": "reset"} +# --------------------------------------------------------------------------- + +class DebugServer: + def __init__(self): + self._server_socket = None + self._client = None + self._thread = None + self._running = False + self.port = 0 + self.log = [] # last N events for the event-log panel + self.MAX_LOG = 200 + + @property + def connected(self): + return self._client is not None + + def start(self, port): + if self._running: + self.stop() + + self.port = port + self._running = True + self._thread = threading.Thread(target=self._serve, daemon=True) + self._thread.start() + logging.info(f'Debug server started on port {self.port}') + + def stop(self): + self._running = False + if self._client: + try: + self._client.close() + except Exception: + pass + self._client = None + if self._server_socket: + try: + self._server_socket.close() + except Exception: + pass + self._server_socket = None + logging.info('Debug server stopped') + + def _serve(self): + try: + self._server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self._server_socket.bind(('127.0.0.1', self.port)) + self._server_socket.listen(1) + self._server_socket.settimeout(1.0) + except OSError as e: + logging.error(f'Debug server bind failed: {e}') + eel.send_event('DEBUG_STATUS', {'connected': False, 'error': str(e)}) + self._running = False + return + + eel.send_event('DEBUG_STATUS', {'connected': False, 'listening': True, 'port': self.port}) + + while self._running: + # Accept loop + try: + ready, _, _ = select.select([self._server_socket], [], [], 1.0) + if not ready: + continue + client, addr = self._server_socket.accept() + except (OSError, socket.timeout): + continue + + self._client = client + self._client.settimeout(1.0) + logging.info(f'Debug client connected from {addr}') + eel.send_event('DEBUG_STATUS', {'connected': True, 'port': self.port}) + + buf = '' + while self._running and self._client: + try: + data = self._client.recv(4096) + if not data: + break + buf += data.decode('utf-8', errors='replace') + while '\n' in buf: + line, buf = buf.split('\n', 1) + line = line.strip() + if not line: + continue + try: + msg = json.loads(line) + self._handle_message(msg) + except json.JSONDecodeError as e: + logging.warning(f'Debug bad JSON: {e}') + except socket.timeout: + continue + except (ConnectionResetError, OSError): + break + + self._client = None + logging.info('Debug client disconnected') + eel.send_event('DEBUG_STATUS', {'connected': False, 'listening': True, 'port': self.port}) + eel.send_event('DEBUG_UPDATE', {'type': 'reset'}) + + def _handle_message(self, msg): + msg_type = msg.get('type', '') + + if msg_type == 'event': + if len(self.log) >= self.MAX_LOG: + self.log.pop(0) + self.log.append(msg) + + eel.send_event('DEBUG_UPDATE', msg) + + def send_to_target(self, msg): + if self._client: + try: + self._client.sendall((json.dumps(msg) + '\n').encode('utf-8')) + except (OSError, BrokenPipeError) as e: + logging.warning(f'Debug send failed: {e}') + + +debug_server = DebugServer() + + +@eel.expose +def debug_start(port): + """Start the debug TCP server on the given port.""" + try: + port = int(port) + except (ValueError, TypeError): + port = 9999 + debug_server.start(port) + + +@eel.expose +def debug_stop(): + """Stop the debug TCP server.""" + debug_server.stop() + eel.send_event('DEBUG_STATUS', {'connected': False, 'listening': False}) + + +@eel.expose +def debug_send(msg): + """Send a JSON command to the connected target (e.g. step, continue).""" + debug_server.send_to_target(msg) + @eel.expose def save_state_machine(drawing: str, json_data: str, filepath: str): if project: @@ -256,6 +447,12 @@ def save_state_machine(drawing: str, json_data: str, filepath: str): logging.info(f'User selected path: {filepath}') save_html(Path(filepath), drawing, json_data) +@eel.expose +def open_window(): + python_path = os.environ['PYTHON_PATH'] + print("Python environment variable:") + print(python_path) + subprocess.Popen([ python_path + "/python.exe","./gui/chsm_backend.py"], shell=True) @eel.expose def open_file(): @@ -283,18 +480,37 @@ def open_file(): def genereate_code(): project.generate_code() +@eel.expose +def exit_program(): + quit() + @eel.expose def startup(): if project: eel.load_json(json.dumps(project.model), Path(args['FILE']).name, args['FILE']) + +def exit_program_(page, sockets): + print('exit_program') + eel.start('main.html', port=random_port, mode='None', block=False, close_callback=exit_program_) + +def monitor_power_events_windows(port_number): + import win32api + import win32con + + def on_power_broadcast(hwnd, msg, wparam, lparam): + if wparam == win32con.PBT_APMRESUMEAUTOMATIC: # System wakes up from sleep + eel.start('main.html', port=random_port, mode='None', block=False, close_callback=exit_program_) + win32api.SetConsoleCtrlHandler(on_power_broadcast, 1) + + if __name__ == '__main__': logging.basicConfig(level=logging.INFO, format='%(asctime)s %(filename)-20s:%(lineno)-4s %(message)s') args = docopt(__doc__) print(args) - #project = Project('/home/pi/projects/chsm/crf/test/tinc/chsm_test_machine.h') - #project.generate_code() + if args['--output-lang']: + pass if args['FILE']: p = Path(args['FILE']) @@ -304,10 +520,19 @@ def startup(): project.generate_code() quit() - eel.init((Path(__file__).parent / '../web').absolute().resolve()) - + eel.init((Path(__file__).parent / 'web').absolute().resolve()) + if args['--server-only']: - eel.start('main.html', mode=None, port=0) + eel.start('main.html', mode=None, port=random_port) else: - eel.start('main.html', port=0) + eel.start('main.html', port=random_port, mode='None') + # eel.start('main.html', port=random_port, mode='None', block=False, close_callback=exit_program_) + # gevent.get_hub().join() + # try: + # while True: + # print("Waiting for power event") + # monitor_power_events_windows(random_port) + # eel.start('main.html', port=random_port, mode='None', block=False, close_callback=exit_program_) + # except KeyboardInterrupt: + # print('KeyboardInterrupt') diff --git a/modules/canopen/test/build/.keep b/gui/gui.dockerfile similarity index 100% rename from modules/canopen/test/build/.keep rename to gui/gui.dockerfile diff --git a/modules/fram/test/build/.keep b/gui/java_gen/.gitkeep similarity index 100% rename from modules/fram/test/build/.keep rename to gui/java_gen/.gitkeep diff --git a/gui/java_gen/module_template/_template/cookiecutter.json b/gui/java_gen/module_template/_template/cookiecutter.json new file mode 100644 index 00000000..5bd70405 --- /dev/null +++ b/gui/java_gen/module_template/_template/cookiecutter.json @@ -0,0 +1,8 @@ +{ + "module_name": "template", + "comm_periph": "i2c", + "address":"0x00", + "author":"xsession", + "full_name":"Laszlo Ivanyi", + "licence":"MIT" +} \ No newline at end of file diff --git a/gui/java_gen/module_template/_template/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h b/gui/java_gen/module_template/_template/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h new file mode 100644 index 00000000..2d469139 --- /dev/null +++ b/gui/java_gen/module_template/_template/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h @@ -0,0 +1,79 @@ +#ifndef {{cookiecutter.module_name|upper}}_FUNCTIONS_H +#define {{cookiecutter.module_name|upper}}_FUNCTIONS_H + +#include "{{cookiecutter.module_name}}.h" +#include "chsm.h" +#include "cevent.h" +#include + +void {{cookiecutter.module_name}}_10ms_callback(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_inc_error_counter(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_init(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_init_wait(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_read_id(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_error_cnt(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_pointer(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_timer(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_full_powerdown(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_full_powerup(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_resolution(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_start_read(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_unplugged(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_update_temp(chsm_tst *self, const cevent_tst *e_pst); + +void send_offline_event(chsm_tst *self, const cevent_tst *e_pst); + +void send_online_event(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func); +extern char {{cookiecutter.module_name}}_debug_state_ac[20]; + +bool {{cookiecutter.module_name}}_id_match(chsm_tst *self, const cevent_tst *e_pst); + +bool {{cookiecutter.module_name}}_wait_cnt(chsm_tst *self, const cevent_tst *e_pst); + +typedef enum {{cookiecutter.module_name}}_state_id_ten +{ + S_READ_ID_REG = 4, + S_UNPLUGGED = 5, + S_SET_RESOLUTION = 6, + S_RESET_PTR_REG = 7, + S_IDLE = 8, + S_READING = 9, + S_POWER_DOWN = 10, + S_POWER_UP = 11, + S_WAIT_POWER_DOWN = 12, + S_WAIT_POWER_UP = 13, +} {{cookiecutter.module_name}}_state_id_ten; + + +/* +Signals: + SIG_I2C_RESULT_ADDR_NACK + SIG_I2C_RESULT_DATA_NACK + SIG_I2C_RESULT_SUCCESS + SIG_{{cookiecutter.module_name|upper}}_READ + SIG_SYS_TICK_10ms +*/ + +/* +Other function notes: + +{{cookiecutter.module_name}}_error_count: + +{{cookiecutter.module_name}}_timeout: +*/ +#endif diff --git a/gui/java_gen/module_template/_template/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c b/gui/java_gen/module_template/_template/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c new file mode 100644 index 00000000..fe87e9b7 --- /dev/null +++ b/gui/java_gen/module_template/_template/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c @@ -0,0 +1,449 @@ +/*Generated with CHSM v0.0.0 at 2023.07.31 10.25.58*/ +#include "cevent.h" +#include "chsm.h" +#include +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_functions.h" + + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst); +char {{cookiecutter.module_name}}_debug_state_ac[20]; + +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + if({{cookiecutter.module_name}}_id_match(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + break; + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_online_event(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_{{cookiecutter.module_name|upper}}_READ: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_{{cookiecutter.module_name|upper}}_READ", __FUNCTION__); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_update_temp(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_down); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +chsm_result_ten {{cookiecutter.module_name}}_top(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case C_SIG_INIT: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "C_SIG_INIT", __FUNCTION__); + {{cookiecutter.module_name}}_init(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func) +{ + #ifdef CHSM_BUILD_TESTS + printf("{{cookiecutter.module_name}}_%s --%s-->\n", state_func, trans_name); + #else + CRF_UNUSED(self); + CRF_UNUSED(est); + CRF_UNUSED(trans_name); + CRF_UNUSED(state_func); + memset({{cookiecutter.module_name}}_debug_state_ac, 0, 20); + strncpy({{cookiecutter.module_name}}_debug_state_ac, state_func, 19); + {{cookiecutter.module_name}}_debug_state_ac[19] = '\0'; + #endif +} diff --git a/gui/java_gen/module_template/_template_new/cookiecutter.json b/gui/java_gen/module_template/_template_new/cookiecutter.json new file mode 100644 index 00000000..ca97641d --- /dev/null +++ b/gui/java_gen/module_template/_template_new/cookiecutter.json @@ -0,0 +1,15 @@ +{ + "module_name": "name", + "version": "", + "description": "", + "module_location": "", + "module_linked_libs": "", + "module_package_name": "", + "module_functions": "", + "module_includes": "", + "comm_periph": "i2c", + "address":"0x00", + "author":"author", + "full_name":"name_full", + "licence":"MIT" +} \ No newline at end of file diff --git a/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/CMakeLists.txt b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/CMakeLists.txt new file mode 100644 index 00000000..fb4fc886 --- /dev/null +++ b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/CMakeLists.txt @@ -0,0 +1,26 @@ + +add_module_lib( + NAME + {{cookiecutter.module_name}} + PACKAGE + chsm + SOURCE + src/{{cookiecutter.module_name}}.c + src/{{cookiecutter.module_name}}_functions.c + INCLUDE + inc + LINK + {% if cookiecutter.comm_periph == "i2c" %} + chsm::i2c_master + {% elif cookiecutter.comm_periph == "spi" %} + chsm::spi_master + {% elif cookiecutter.comm_periph == "can" %} + chsm::canopen + {% else %} + {% endif %} + signal_classes_modules + DEFINES + NDEBUG + STANDARD + 11 +) \ No newline at end of file diff --git a/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/doc/{{cookiecutter.module_name}}.html b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/doc/{{cookiecutter.module_name}}.html new file mode 100644 index 00000000..84fd9830 --- /dev/null +++ b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/doc/{{cookiecutter.module_name}}.html @@ -0,0 +1,2493 @@ + + + + + + +
+ + + + + + SIG_I2C_RESULT_SUCCESS[{{cookiecutter.module_name}}_wait_cnt()]SIG_I2C_RESULT_SUCCESS[{{cookiecutter.module_name}}_wait_cnt()]SIG_I2C_RESULT_SUCCESSSIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_SUCCESS/ {{cookiecutter.module_name}}_update_temp()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_reset_timer()SIG_{{cookiecutter.module_name|upper}}_READSIG_I2C_RESULT_SUCCESS[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]SIG_I2C_RESULT_SUCCESS [{{cookiecutter.module_name}}_id_match()][{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)]/ {{cookiecutter.module_name}}_reset_timer()SIG_I2C_RESULT_DATA_NACKSIG_I2C_RESULT_ADDR_NACK[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)] + __top__s_{{cookiecutter.module_name}}entry/ {{cookiecutter.module_name}}_init()SIG_SYS_TICK_10ms/ {{cookiecutter.module_name}}_10ms_callback()s_initentry/ {{cookiecutter.module_name}}_reset_error_cnt()s_configentry/ {{cookiecutter.module_name}}_reset_timer()s_onlineentry/ send_online_event()exit/ send_offline_event()s_read_id_regentry/ {{cookiecutter.module_name}}_read_id()exit/ {{cookiecutter.module_name}}_reset_timer()s_unpluggedentry/ {{cookiecutter.module_name}}_unplugged()s_set_resolutionentry/ {{cookiecutter.module_name}}_set_resolution()exit/ {{cookiecutter.module_name}}_reset_timer()s_reset_ptr_regentry/ {{cookiecutter.module_name}}_reset_pointer()exit/ {{cookiecutter.module_name}}_reset_timer()s_idleinit/ {{cookiecutter.module_name}}_reset_timer()entry/ {{cookiecutter.module_name}}_reset_timer()s_readingentry/ {{cookiecutter.module_name}}_start_read()exit/ {{cookiecutter.module_name}}_reset_timer()s_power_downentry/ {{cookiecutter.module_name}}_set_full_powerdown()exit/ {{cookiecutter.module_name}}_reset_timer()s_power_upentry/ {{cookiecutter.module_name}}_set_full_powerup()exit/ {{cookiecutter.module_name}}_reset_timer()s_wait_power_downinit/ {{cookiecutter.module_name}}_init_wait()s_wait_power_upinit/ {{cookiecutter.module_name}}_init_wait() + + +
+ +
+ json +
+            {
+    "states": {
+        "__top__": {
+            "pos": [
+                -100000000,
+                -100000000
+            ],
+            "size": [
+                200000000,
+                200000000
+            ],
+            "title": "__top__",
+            "text": [],
+            "connectors": [],
+            "parent": null,
+            "children": [
+                "istate_0",
+                "state_0"
+            ],
+            "type": "top"
+        },
+        "istate_0": {
+            "pos": [
+                51,
+                9
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_0",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_0"
+            ],
+            "parent": "__top__",
+            "children": [],
+            "type": "initial"
+        },
+        "state_0": {
+            "pos": [
+                5,
+                14
+            ],
+            "size": [
+                111,
+                166
+            ],
+            "title": "s_{{cookiecutter.module_name}}",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_init()",
+                "SIG_SYS_TICK_10ms/ {{cookiecutter.module_name}}_10ms_callback()"
+            ],
+            "connectors": [
+                "conn_1",
+                "conn_17",
+                "conn_51"
+            ],
+            "parent": "__top__",
+            "children": [
+                "state_1",
+                "state_2",
+                "state_3",
+                "istate_1"
+            ],
+            "type": "normal"
+        },
+        "state_1": {
+            "pos": [
+                10,
+                28
+            ],
+            "size": [
+                91,
+                24
+            ],
+            "title": "s_init",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_reset_error_cnt()"
+            ],
+            "connectors": [
+                "conn_3"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_4",
+                "state_5",
+                "istate_2"
+            ],
+            "type": "normal"
+        },
+        "state_2": {
+            "pos": [
+                24,
+                56
+            ],
+            "size": [
+                89,
+                79
+            ],
+            "title": "s_config",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_15",
+                "conn_50"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_6",
+                "state_7",
+                "istate_3",
+                "state_10",
+                "state_11",
+                "state_12",
+                "state_13"
+            ],
+            "type": "normal"
+        },
+        "state_3": {
+            "pos": [
+                11,
+                146
+            ],
+            "size": [
+                86,
+                29
+            ],
+            "title": "s_online",
+            "text": [
+                "entry/ send_online_event()",
+                "exit/ send_offline_event()"
+            ],
+            "connectors": [
+                "conn_16",
+                "conn_23"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_8",
+                "state_9",
+                "istate_4"
+            ],
+            "type": "normal"
+        },
+        "istate_1": {
+            "pos": [
+                12,
+                24
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_1",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_2"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "initial"
+        },
+        "state_4": {
+            "pos": [
+                15,
+                35
+            ],
+            "size": [
+                16,
+                15
+            ],
+            "title": "s_read_id_reg",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_read_id()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_5",
+                "conn_6",
+                "conn_8",
+                "conn_10",
+                "conn_13",
+                "conn_14"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "normal"
+        },
+        "state_5": {
+            "pos": [
+                75,
+                35
+            ],
+            "size": [
+                17,
+                13
+            ],
+            "title": "s_unplugged",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_unplugged()"
+            ],
+            "connectors": [
+                "conn_7",
+                "conn_9",
+                "conn_11",
+                "conn_12"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_2": {
+            "pos": [
+                12,
+                36
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_2",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_4"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "initial"
+        },
+        "state_6": {
+            "pos": [
+                52,
+                84
+            ],
+            "size": [
+                18,
+                12
+            ],
+            "title": "s_set_resolution",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_set_resolution()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_38",
+                "conn_39",
+                "conn_40",
+                "conn_41",
+                "conn_42",
+                "conn_43",
+                "conn_71",
+                "conn_62"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_7": {
+            "pos": [
+                53,
+                118
+            ],
+            "size": [
+                17,
+                12
+            ],
+            "title": "s_reset_ptr_reg",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_reset_pointer()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_22",
+                "conn_44",
+                "conn_45",
+                "conn_46",
+                "conn_47",
+                "conn_48",
+                "conn_49",
+                "conn_65"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_3": {
+            "pos": [
+                33,
+                63
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_3",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_66"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "initial"
+        },
+        "state_8": {
+            "pos": [
+                16,
+                156
+            ],
+            "size": [
+                15,
+                18
+            ],
+            "title": "s_idle",
+            "text": [
+                "init/ {{cookiecutter.module_name}}_reset_timer()",
+                "entry/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_26",
+                "conn_28",
+                "conn_31",
+                "conn_33",
+                "conn_35",
+                "conn_37"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "normal"
+        },
+        "state_9": {
+            "pos": [
+                71,
+                156
+            ],
+            "size": [
+                15,
+                17
+            ],
+            "title": "s_reading",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_start_read()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_25",
+                "conn_27",
+                "conn_29",
+                "conn_30",
+                "conn_32",
+                "conn_34",
+                "conn_36"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_4": {
+            "pos": [
+                92,
+                155
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_4",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_24"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "initial"
+        },
+        "state_10": {
+            "pos": [
+                54,
+                66
+            ],
+            "size": [
+                20,
+                12
+            ],
+            "title": "s_power_down",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_set_full_powerdown()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_18",
+                "conn_19",
+                "conn_20",
+                "conn_21",
+                "conn_52",
+                "conn_53",
+                "conn_60",
+                "conn_67"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_11": {
+            "pos": [
+                52,
+                102
+            ],
+            "size": [
+                20,
+                9
+            ],
+            "title": "s_power_up",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_set_full_powerup()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_54",
+                "conn_55",
+                "conn_56",
+                "conn_57",
+                "conn_58",
+                "conn_59",
+                "conn_63",
+                "conn_74"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_12": {
+            "pos": [
+                33,
+                72
+            ],
+            "size": [
+                15,
+                7
+            ],
+            "title": "s_wait_power_down",
+            "text": [
+                "init/ {{cookiecutter.module_name}}_init_wait()"
+            ],
+            "connectors": [
+                "conn_61",
+                "conn_70"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_13": {
+            "pos": [
+                33,
+                102
+            ],
+            "size": [
+                15,
+                6
+            ],
+            "title": "s_wait_power_up",
+            "text": [
+                "init/ {{cookiecutter.module_name}}_init_wait()"
+            ],
+            "connectors": [
+                "conn_64",
+                "conn_75"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        }
+    },
+    "connectors": {
+        "conn_0": {
+            "parent": "istate_0",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_0"
+        },
+        "conn_1": {
+            "parent": "state_0",
+            "offset": 46,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_0"
+        },
+        "conn_2": {
+            "parent": "istate_1",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_1"
+        },
+        "conn_3": {
+            "parent": "state_1",
+            "offset": 2,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_1"
+        },
+        "conn_4": {
+            "parent": "istate_2",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_2"
+        },
+        "conn_5": {
+            "parent": "state_4",
+            "offset": 1,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_2"
+        },
+        "conn_6": {
+            "parent": "state_4",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_3"
+        },
+        "conn_7": {
+            "parent": "state_5",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_3"
+        },
+        "conn_8": {
+            "parent": "state_4",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_4"
+        },
+        "conn_9": {
+            "parent": "state_5",
+            "offset": 4,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_4"
+        },
+        "conn_10": {
+            "parent": "state_4",
+            "offset": 6,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_5"
+        },
+        "conn_11": {
+            "parent": "state_5",
+            "offset": 6,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_5"
+        },
+        "conn_12": {
+            "parent": "state_5",
+            "offset": 11,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_6"
+        },
+        "conn_13": {
+            "parent": "state_4",
+            "offset": 11,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_6"
+        },
+        "conn_14": {
+            "parent": "state_4",
+            "offset": 5,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_7"
+        },
+        "conn_15": {
+            "parent": "state_2",
+            "offset": 3,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_7"
+        },
+        "conn_16": {
+            "parent": "state_3",
+            "offset": 3,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_8"
+        },
+        "conn_17": {
+            "parent": "state_0",
+            "offset": 128,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_8"
+        },
+        "conn_22": {
+            "parent": "state_7",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_11"
+        },
+        "conn_23": {
+            "parent": "state_3",
+            "offset": 56,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_11"
+        },
+        "conn_24": {
+            "parent": "istate_4",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_12"
+        },
+        "conn_25": {
+            "parent": "state_9",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_12"
+        },
+        "conn_26": {
+            "parent": "state_8",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_13"
+        },
+        "conn_27": {
+            "parent": "state_9",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_13"
+        },
+        "conn_28": {
+            "parent": "state_8",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_14"
+        },
+        "conn_29": {
+            "parent": "state_9",
+            "offset": 4,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_14"
+        },
+        "conn_30": {
+            "parent": "state_9",
+            "offset": 7,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_15"
+        },
+        "conn_31": {
+            "parent": "state_8",
+            "offset": 7,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_15"
+        },
+        "conn_32": {
+            "parent": "state_9",
+            "offset": 9,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_16"
+        },
+        "conn_33": {
+            "parent": "state_8",
+            "offset": 9,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_16"
+        },
+        "conn_34": {
+            "parent": "state_9",
+            "offset": 11,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_17"
+        },
+        "conn_35": {
+            "parent": "state_8",
+            "offset": 11,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_17"
+        },
+        "conn_36": {
+            "parent": "state_9",
+            "offset": 16,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_18"
+        },
+        "conn_37": {
+            "parent": "state_8",
+            "offset": 16,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_18"
+        },
+        "conn_38": {
+            "parent": "state_6",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_19"
+        },
+        "conn_39": {
+            "parent": "state_6",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_19"
+        },
+        "conn_40": {
+            "parent": "state_6",
+            "offset": 5,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_20"
+        },
+        "conn_41": {
+            "parent": "state_6",
+            "offset": 6,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_20"
+        },
+        "conn_42": {
+            "parent": "state_6",
+            "offset": 9,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_21"
+        },
+        "conn_43": {
+            "parent": "state_6",
+            "offset": 10,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_21"
+        },
+        "conn_44": {
+            "parent": "state_7",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_22"
+        },
+        "conn_45": {
+            "parent": "state_7",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_22"
+        },
+        "conn_46": {
+            "parent": "state_7",
+            "offset": 5,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_23"
+        },
+        "conn_47": {
+            "parent": "state_7",
+            "offset": 6,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_23"
+        },
+        "conn_48": {
+            "parent": "state_7",
+            "offset": 9,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_24"
+        },
+        "conn_49": {
+            "parent": "state_7",
+            "offset": 10,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_24"
+        },
+        "conn_50": {
+            "parent": "state_2",
+            "offset": 19,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_25"
+        },
+        "conn_51": {
+            "parent": "state_0",
+            "offset": 126,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_25"
+        },
+        "conn_18": {
+            "parent": "state_10",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_9"
+        },
+        "conn_19": {
+            "parent": "state_10",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_9"
+        },
+        "conn_20": {
+            "parent": "state_10",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_10"
+        },
+        "conn_21": {
+            "parent": "state_10",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_10"
+        },
+        "conn_52": {
+            "parent": "state_10",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_26"
+        },
+        "conn_53": {
+            "parent": "state_10",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_26"
+        },
+        "conn_54": {
+            "parent": "state_11",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_27"
+        },
+        "conn_55": {
+            "parent": "state_11",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_27"
+        },
+        "conn_56": {
+            "parent": "state_11",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_28"
+        },
+        "conn_57": {
+            "parent": "state_11",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_28"
+        },
+        "conn_58": {
+            "parent": "state_11",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_29"
+        },
+        "conn_59": {
+            "parent": "state_11",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_29"
+        },
+        "conn_60": {
+            "parent": "state_10",
+            "offset": 1,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_30"
+        },
+        "conn_61": {
+            "parent": "state_12",
+            "offset": 1,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_30"
+        },
+        "conn_70": {
+            "parent": "state_12",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_35"
+        },
+        "conn_71": {
+            "parent": "state_6",
+            "offset": 8,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_35"
+        },
+        "conn_62": {
+            "parent": "state_6",
+            "offset": 9,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_31"
+        },
+        "conn_63": {
+            "parent": "state_11",
+            "offset": 9,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_31"
+        },
+        "conn_64": {
+            "parent": "state_13",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_32"
+        },
+        "conn_65": {
+            "parent": "state_7",
+            "offset": 8,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_32"
+        },
+        "conn_74": {
+            "parent": "state_11",
+            "offset": 3,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_37"
+        },
+        "conn_75": {
+            "parent": "state_13",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_37"
+        },
+        "conn_66": {
+            "parent": "istate_3",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_33"
+        },
+        "conn_67": {
+            "parent": "state_10",
+            "offset": 10,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_33"
+        }
+    },
+    "transitions": {
+        "trans_0": {
+            "start": "conn_0",
+            "end": "conn_1",
+            "vertices": [
+                [
+                    51,
+                    9
+                ],
+                [
+                    51,
+                    9
+                ],
+                [
+                    51,
+                    14
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                1.5999999999999996
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                51.5,
+                10.6
+            ]
+        },
+        "trans_1": {
+            "start": "conn_2",
+            "end": "conn_3",
+            "vertices": [
+                [
+                    12,
+                    24
+                ],
+                [
+                    12,
+                    24
+                ],
+                [
+                    12,
+                    28
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                1.6000000000000014
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                12.5,
+                25.6
+            ]
+        },
+        "trans_2": {
+            "start": "conn_4",
+            "end": "conn_5",
+            "vertices": [
+                [
+                    12,
+                    36
+                ],
+                [
+                    14,
+                    36
+                ],
+                [
+                    14,
+                    36
+                ],
+                [
+                    15,
+                    36
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                2,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                14,
+                35.6
+            ]
+        },
+        "trans_3": {
+            "start": "conn_6",
+            "end": "conn_7",
+            "vertices": [
+                [
+                    31,
+                    37
+                ],
+                [
+                    51,
+                    37
+                ],
+                [
+                    51,
+                    37
+                ],
+                [
+                    75,
+                    37
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                36.6
+            ]
+        },
+        "trans_4": {
+            "start": "conn_8",
+            "end": "conn_9",
+            "vertices": [
+                [
+                    31,
+                    39
+                ],
+                [
+                    51,
+                    39
+                ],
+                [
+                    51,
+                    39
+                ],
+                [
+                    75,
+                    39
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                38.6
+            ]
+        },
+        "trans_5": {
+            "start": "conn_10",
+            "end": "conn_11",
+            "vertices": [
+                [
+                    31,
+                    41
+                ],
+                [
+                    51,
+                    41
+                ],
+                [
+                    51,
+                    41
+                ],
+                [
+                    75,
+                    41
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                40.6
+            ]
+        },
+        "trans_6": {
+            "start": "conn_12",
+            "end": "conn_13",
+            "vertices": [
+                [
+                    75,
+                    46
+                ],
+                [
+                    51,
+                    46
+                ],
+                [
+                    51,
+                    46
+                ],
+                [
+                    31,
+                    46
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)]/ {{cookiecutter.module_name}}_reset_timer()",
+            "label_offset": [
+                -11.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                39.5,
+                45.6
+            ]
+        },
+        "trans_7": {
+            "start": "conn_14",
+            "end": "conn_15",
+            "vertices": [
+                [
+                    20,
+                    50
+                ],
+                [
+                    20,
+                    59
+                ],
+                [
+                    24,
+                    59
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS [{{cookiecutter.module_name}}_id_match()]",
+            "label_offset": [
+                0.5,
+                4.700000000000003
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                20.5,
+                54.7
+            ]
+        },
+        "trans_8": {
+            "start": "conn_16",
+            "end": "conn_17",
+            "vertices": [
+                [
+                    14,
+                    146
+                ],
+                [
+                    14,
+                    142
+                ],
+                [
+                    5,
+                    142
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]",
+            "label_offset": [
+                0.5,
+                -1.8000000000000114
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                14.5,
+                144.2
+            ]
+        },
+        "trans_11": {
+            "start": "conn_22",
+            "end": "conn_23",
+            "vertices": [
+                [
+                    67,
+                    130
+                ],
+                [
+                    67,
+                    133
+                ],
+                [
+                    67,
+                    133
+                ],
+                [
+                    67,
+                    146
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                0.5,
+                10.799999999999983
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                67.5,
+                143.79999999999998
+            ]
+        },
+        "trans_12": {
+            "start": "conn_24",
+            "end": "conn_25",
+            "vertices": [
+                [
+                    92,
+                    155
+                ],
+                [
+                    90,
+                    155
+                ],
+                [
+                    90,
+                    159
+                ],
+                [
+                    86,
+                    159
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                2.5999999999999943
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                90.5,
+                157.6
+            ]
+        },
+        "trans_13": {
+            "start": "conn_26",
+            "end": "conn_27",
+            "vertices": [
+                [
+                    31,
+                    158
+                ],
+                [
+                    53,
+                    158
+                ],
+                [
+                    53,
+                    158
+                ],
+                [
+                    71,
+                    158
+                ]
+            ],
+            "label": "SIG_{{cookiecutter.module_name|upper}}_READ",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                157.6
+            ]
+        },
+        "trans_14": {
+            "start": "conn_28",
+            "end": "conn_29",
+            "vertices": [
+                [
+                    31,
+                    160
+                ],
+                [
+                    53,
+                    160
+                ],
+                [
+                    53,
+                    160
+                ],
+                [
+                    71,
+                    160
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_reset_timer()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                159.6
+            ]
+        },
+        "trans_15": {
+            "start": "conn_30",
+            "end": "conn_31",
+            "vertices": [
+                [
+                    71,
+                    163
+                ],
+                [
+                    53,
+                    163
+                ],
+                [
+                    53,
+                    163
+                ],
+                [
+                    31,
+                    163
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                -12.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                40.5,
+                162.6
+            ]
+        },
+        "trans_16": {
+            "start": "conn_32",
+            "end": "conn_33",
+            "vertices": [
+                [
+                    71,
+                    165
+                ],
+                [
+                    53,
+                    165
+                ],
+                [
+                    53,
+                    165
+                ],
+                [
+                    31,
+                    165
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                -12.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                40.5,
+                164.6
+            ]
+        },
+        "trans_17": {
+            "start": "conn_34",
+            "end": "conn_35",
+            "vertices": [
+                [
+                    71,
+                    167
+                ],
+                [
+                    53,
+                    167
+                ],
+                [
+                    53,
+                    167
+                ],
+                [
+                    31,
+                    167
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                -15.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                37.5,
+                166.6
+            ]
+        },
+        "trans_18": {
+            "start": "conn_36",
+            "end": "conn_37",
+            "vertices": [
+                [
+                    71,
+                    172
+                ],
+                [
+                    53,
+                    172
+                ],
+                [
+                    53,
+                    172
+                ],
+                [
+                    31,
+                    172
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS/ {{cookiecutter.module_name}}_update_temp()",
+            "label_offset": [
+                -9.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                43.5,
+                171.6
+            ]
+        },
+        "trans_19": {
+            "start": "conn_38",
+            "end": "conn_39",
+            "vertices": [
+                [
+                    70,
+                    86
+                ],
+                [
+                    77,
+                    86
+                ],
+                [
+                    77,
+                    87
+                ],
+                [
+                    70,
+                    87
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71,
+                85.6
+            ]
+        },
+        "trans_20": {
+            "start": "conn_40",
+            "end": "conn_41",
+            "vertices": [
+                [
+                    70,
+                    89
+                ],
+                [
+                    77,
+                    89
+                ],
+                [
+                    77,
+                    90
+                ],
+                [
+                    70,
+                    90
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                88.6
+            ]
+        },
+        "trans_21": {
+            "start": "conn_42",
+            "end": "conn_43",
+            "vertices": [
+                [
+                    70,
+                    93
+                ],
+                [
+                    77,
+                    93
+                ],
+                [
+                    77,
+                    94
+                ],
+                [
+                    70,
+                    94
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                92.6
+            ]
+        },
+        "trans_22": {
+            "start": "conn_44",
+            "end": "conn_45",
+            "vertices": [
+                [
+                    70,
+                    119
+                ],
+                [
+                    77,
+                    119
+                ],
+                [
+                    77,
+                    120
+                ],
+                [
+                    70,
+                    120
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                118.6
+            ]
+        },
+        "trans_23": {
+            "start": "conn_46",
+            "end": "conn_47",
+            "vertices": [
+                [
+                    70,
+                    123
+                ],
+                [
+                    77,
+                    123
+                ],
+                [
+                    77,
+                    124
+                ],
+                [
+                    70,
+                    124
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                122.6
+            ]
+        },
+        "trans_24": {
+            "start": "conn_48",
+            "end": "conn_49",
+            "vertices": [
+                [
+                    70,
+                    127
+                ],
+                [
+                    77,
+                    127
+                ],
+                [
+                    77,
+                    128
+                ],
+                [
+                    70,
+                    128
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                126.6
+            ]
+        },
+        "trans_25": {
+            "start": "conn_50",
+            "end": "conn_51",
+            "vertices": [
+                [
+                    43,
+                    135
+                ],
+                [
+                    43,
+                    140
+                ],
+                [
+                    16,
+                    140
+                ],
+                [
+                    5,
+                    140
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]",
+            "label_offset": [
+                -26.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                16.5,
+                139.6
+            ]
+        },
+        "trans_9": {
+            "start": "conn_18",
+            "end": "conn_19",
+            "vertices": [
+                [
+                    74,
+                    67
+                ],
+                [
+                    80,
+                    67
+                ],
+                [
+                    80,
+                    68
+                ],
+                [
+                    74,
+                    68
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                3,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                77,
+                66.6
+            ]
+        },
+        "trans_10": {
+            "start": "conn_20",
+            "end": "conn_21",
+            "vertices": [
+                [
+                    74,
+                    70
+                ],
+                [
+                    80,
+                    70
+                ],
+                [
+                    80,
+                    71
+                ],
+                [
+                    74,
+                    71
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                2,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                76,
+                69.6
+            ]
+        },
+        "trans_26": {
+            "start": "conn_52",
+            "end": "conn_53",
+            "vertices": [
+                [
+                    74,
+                    73
+                ],
+                [
+                    80,
+                    73
+                ],
+                [
+                    80,
+                    74
+                ],
+                [
+                    74,
+                    74
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                2,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                76,
+                72.6
+            ]
+        },
+        "trans_27": {
+            "start": "conn_54",
+            "end": "conn_55",
+            "vertices": [
+                [
+                    72,
+                    103
+                ],
+                [
+                    77,
+                    103
+                ],
+                [
+                    77,
+                    104
+                ],
+                [
+                    72,
+                    104
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                102.6
+            ]
+        },
+        "trans_28": {
+            "start": "conn_56",
+            "end": "conn_57",
+            "vertices": [
+                [
+                    72,
+                    106
+                ],
+                [
+                    77,
+                    106
+                ],
+                [
+                    77,
+                    107
+                ],
+                [
+                    72,
+                    107
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                105.6
+            ]
+        },
+        "trans_29": {
+            "start": "conn_58",
+            "end": "conn_59",
+            "vertices": [
+                [
+                    72,
+                    109
+                ],
+                [
+                    77,
+                    109
+                ],
+                [
+                    77,
+                    110
+                ],
+                [
+                    72,
+                    110
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                108.6
+            ]
+        },
+        "trans_30": {
+            "start": "conn_60",
+            "end": "conn_61",
+            "vertices": [
+                [
+                    54,
+                    67
+                ],
+                [
+                    34,
+                    67
+                ],
+                [
+                    34,
+                    72
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                -16.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                37.5,
+                66.6
+            ]
+        },
+        "trans_35": {
+            "start": "conn_70",
+            "end": "conn_71",
+            "vertices": [
+                [
+                    47,
+                    79
+                ],
+                [
+                    47,
+                    82
+                ],
+                [
+                    60,
+                    82
+                ],
+                [
+                    60,
+                    84
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_wait_cnt()]",
+            "label_offset": [
+                3.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                50.5,
+                81.6
+            ]
+        },
+        "trans_31": {
+            "start": "conn_62",
+            "end": "conn_63",
+            "vertices": [
+                [
+                    61,
+                    96
+                ],
+                [
+                    61,
+                    99
+                ],
+                [
+                    61,
+                    99
+                ],
+                [
+                    61,
+                    102
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                0.5,
+                1.1999999999999886
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                61.5,
+                100.19999999999999
+            ]
+        },
+        "trans_32": {
+            "start": "conn_64",
+            "end": "conn_65",
+            "vertices": [
+                [
+                    47,
+                    108
+                ],
+                [
+                    47,
+                    115
+                ],
+                [
+                    61,
+                    115
+                ],
+                [
+                    61,
+                    118
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_wait_cnt()]",
+            "label_offset": [
+                4,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                51,
+                114.6
+            ]
+        },
+        "trans_37": {
+            "start": "conn_74",
+            "end": "conn_75",
+            "vertices": [
+                [
+                    55,
+                    102
+                ],
+                [
+                    55,
+                    99
+                ],
+                [
+                    40,
+                    99
+                ],
+                [
+                    40,
+                    102
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                -14.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                40.5,
+                98.6
+            ]
+        },
+        "trans_33": {
+            "start": "conn_66",
+            "end": "conn_67",
+            "vertices": [
+                [
+                    33,
+                    63
+                ],
+                [
+                    64,
+                    63
+                ],
+                [
+                    64,
+                    66
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                14,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                47,
+                62.6
+            ]
+        }
+    },
+    "notes": {
+        "{{cookiecutter.module_name}}_timeout": "",
+        "SIG_I2C_RESULT_ADDR_NACK": "",
+        "SIG_I2C_RESULT_DATA_NACK": "",
+        "trans_7": "",
+        "SIG_I2C_RESULT_SUCCESS": "",
+        "trans_24": "",
+        "trans_23": "",
+        "trans_22": "",
+        "trans_21": "",
+        "trans_20": "",
+        "trans_19": "",
+        "trans_25": "",
+        "SIG_{{cookiecutter.module_name|upper}}_READ": "",
+        "{{cookiecutter.module_name}}_error_count": "",
+        "trans_9": "",
+        "{{cookiecutter.module_name}}_inc_wait_cnt()": "",
+        "{{cookiecutter.module_name|upper}}_RETRY_TIMEOUT": "",
+        "{{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT": ""
+    },
+    "view": {
+        "translate": [
+            132,
+            -144.5
+        ],
+        "scale": 9
+    }
+}
+        
+
+ + diff --git a/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}.h b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}.h new file mode 100644 index 00000000..09a9802f --- /dev/null +++ b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}.h @@ -0,0 +1,111 @@ +#ifndef {{cookiecutter.module_name|upper}}_H +#define {{cookiecutter.module_name|upper}}_H + +#include "crf.h" +#include "sys_if.h" +#include "i2c_driver_if.h" +#include "i2c_master.h" +#include "signal_classes_modules.h" + +/* +{{cookiecutter.module_name|upper}} driver +========== + +This module implements a high level driver for the {{cookiecutter.module_name|upper}} temperature sensor. + +Requirements for the {{cookiecutter.module_name|upper}} module: + * Read out the ID register to test the communication + * Retry the ID register reading after a timeout if the previous read failed + * Send an online event, when the link is established + * Send an offline event if the temperature read operation fails for a number of times + * Send periodic temperature events + * Allow triggered temperature reads + * Add a user defined ID into the events (so the application can differentiate between + the different {{cookiecutter.module_name|upper}} events) +*/ + +/* + * {{cookiecutter.module_name|upper}} SIGNALS + */ + +typedef enum {{cookiecutter.module_name}}_signals_ten +{ + SIG_{{cookiecutter.module_name|upper}}_TEMP = SIGNAL_FROM_CLASS(SIG_CLASS_{{cookiecutter.module_name|upper}}), + SIG_{{cookiecutter.module_name|upper}}_ONLINE, + SIG_{{cookiecutter.module_name|upper}}_OFFLINE, + SIG_{{cookiecutter.module_name|upper}}_READ +} {{cookiecutter.module_name}}_signals_ten; + +#define SIG_{{cookiecutter.module_name|upper}}_TEMP_TYPE {{cookiecutter.module_name}}_temp_tst +#define SIG_{{cookiecutter.module_name|upper}}_ONLINE_TYPE {{cookiecutter.module_name}}_status_tst +#define SIG_{{cookiecutter.module_name|upper}}_OFFLINE_TYPE {{cookiecutter.module_name}}_status_tst +#define SIG_{{cookiecutter.module_name|upper}}_READ_TYPE cevent_tst + + +/* + * EVENT DEFINITIONS + */ + +typedef struct {{cookiecutter.module_name}}_temp_tst +{ + cevent_tst super; // Signal and GC stuff + int32_t temp_C_i32; // Temperature + uint16_t id_u16; // Sensor ID +} {{cookiecutter.module_name}}_temp_tst; + +typedef struct {{cookiecutter.module_name}}_status_tst +{ + cevent_tst super; // Signal and GC stuff + uint16_t id_u16; // Sensor ID +} {{cookiecutter.module_name}}_status_tst; + +/* + * ACTIVE OBJECT + */ + +typedef struct {{cookiecutter.module_name}}_cfg_tst +{ + uint16_t id_u16; // This ID will be inserted into temperature events + uint16_t period_ms_u16; // Temperature read period in ms + uint16_t max_error_cnt_u16; // Number of times the module is allowed to fail a read operation before going offline + uint8_t address_u8; // I2C slave address of the sensor +} {{cookiecutter.module_name}}_cfg_tst; + +typedef struct {{cookiecutter.module_name}}_tst {{cookiecutter.module_name}}_tst; + +struct {{cookiecutter.module_name}}_tst +{ + /* PUBLIC */ + chsm_tst super; + {{cookiecutter.module_name}}_cfg_tst config_st; + int16_t temp_C_i32; + bool valid_b; + uint16_t resolution_u16; + + /* PRIVATE */ + uint32_t counter_u32; + uint16_t error_counter_u32; + uint16_t wait_cnt_u16; + + i2c_transaction_tst t_st; + uint8_t tx_buff_au8[4]; + uint8_t rx_buff_au8[4]; +}; + +chsm_result_ten {{cookiecutter.module_name}}_top(chsm_tst *self, const cevent_tst *e_pst); + +bool {{cookiecutter.module_name}}_timeout(chsm_tst *self, const cevent_tst *e_pst, uint32_t timeout_u32); +bool {{cookiecutter.module_name}}_error_count(chsm_tst *self, const cevent_tst *e_pst, uint16_t error_cnt_threshold_u16); + + +#define {{cookiecutter.module_name|upper}}_READ_PERIOD_VALUE (100UL) +#define {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT_VALUE (20UL) +#define {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT (500UL) +#define {{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT (2000UL) +#define {{cookiecutter.module_name|upper}}_ID_REG_VALUE (0x190) +#define {{cookiecutter.module_name|upper}}_WAIT_CNT (12UL) + +#define {{cookiecutter.module_name|upper}}_READ_PERIOD ((({{cookiecutter.module_name}}_tst *)self)->config_st.period_ms_u16) +#define {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT ((({{cookiecutter.module_name}}_tst *)self)->config_st.max_error_cnt_u16) + +#endif diff --git a/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h new file mode 100644 index 00000000..2d469139 --- /dev/null +++ b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h @@ -0,0 +1,79 @@ +#ifndef {{cookiecutter.module_name|upper}}_FUNCTIONS_H +#define {{cookiecutter.module_name|upper}}_FUNCTIONS_H + +#include "{{cookiecutter.module_name}}.h" +#include "chsm.h" +#include "cevent.h" +#include + +void {{cookiecutter.module_name}}_10ms_callback(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_inc_error_counter(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_init(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_init_wait(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_read_id(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_error_cnt(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_pointer(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_timer(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_full_powerdown(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_full_powerup(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_resolution(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_start_read(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_unplugged(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_update_temp(chsm_tst *self, const cevent_tst *e_pst); + +void send_offline_event(chsm_tst *self, const cevent_tst *e_pst); + +void send_online_event(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func); +extern char {{cookiecutter.module_name}}_debug_state_ac[20]; + +bool {{cookiecutter.module_name}}_id_match(chsm_tst *self, const cevent_tst *e_pst); + +bool {{cookiecutter.module_name}}_wait_cnt(chsm_tst *self, const cevent_tst *e_pst); + +typedef enum {{cookiecutter.module_name}}_state_id_ten +{ + S_READ_ID_REG = 4, + S_UNPLUGGED = 5, + S_SET_RESOLUTION = 6, + S_RESET_PTR_REG = 7, + S_IDLE = 8, + S_READING = 9, + S_POWER_DOWN = 10, + S_POWER_UP = 11, + S_WAIT_POWER_DOWN = 12, + S_WAIT_POWER_UP = 13, +} {{cookiecutter.module_name}}_state_id_ten; + + +/* +Signals: + SIG_I2C_RESULT_ADDR_NACK + SIG_I2C_RESULT_DATA_NACK + SIG_I2C_RESULT_SUCCESS + SIG_{{cookiecutter.module_name|upper}}_READ + SIG_SYS_TICK_10ms +*/ + +/* +Other function notes: + +{{cookiecutter.module_name}}_error_count: + +{{cookiecutter.module_name}}_timeout: +*/ +#endif diff --git a/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_regs.h b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_regs.h new file mode 100644 index 00000000..9f7c864b --- /dev/null +++ b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_regs.h @@ -0,0 +1,13 @@ + +#ifndef {{cookiecutter.module_name|upper}}_REGS_H_ +#define {{cookiecutter.module_name|upper}}_REGS_H_ + +// Config reg bits + +// Control/status reg bits + +// Registers + +// Device addresses + +#endif /* {{cookiecutter.module_name|upper}}_REGS_H_ */ diff --git a/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c new file mode 100644 index 00000000..fe87e9b7 --- /dev/null +++ b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c @@ -0,0 +1,449 @@ +/*Generated with CHSM v0.0.0 at 2023.07.31 10.25.58*/ +#include "cevent.h" +#include "chsm.h" +#include +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_functions.h" + + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst); +char {{cookiecutter.module_name}}_debug_state_ac[20]; + +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + if({{cookiecutter.module_name}}_id_match(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + break; + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_online_event(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_{{cookiecutter.module_name|upper}}_READ: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_{{cookiecutter.module_name|upper}}_READ", __FUNCTION__); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_update_temp(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_down); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +chsm_result_ten {{cookiecutter.module_name}}_top(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case C_SIG_INIT: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "C_SIG_INIT", __FUNCTION__); + {{cookiecutter.module_name}}_init(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func) +{ + #ifdef CHSM_BUILD_TESTS + printf("{{cookiecutter.module_name}}_%s --%s-->\n", state_func, trans_name); + #else + CRF_UNUSED(self); + CRF_UNUSED(est); + CRF_UNUSED(trans_name); + CRF_UNUSED(state_func); + memset({{cookiecutter.module_name}}_debug_state_ac, 0, 20); + strncpy({{cookiecutter.module_name}}_debug_state_ac, state_func, 19); + {{cookiecutter.module_name}}_debug_state_ac[19] = '\0'; + #endif +} diff --git a/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}_functions.c b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}_functions.c new file mode 100644 index 00000000..01fe3c47 --- /dev/null +++ b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}_functions.c @@ -0,0 +1,317 @@ +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_regs.h" +#include "{{cookiecutter.module_name}}_functions.h" +#include "crf.h" +#include "cevent.h" +#include + +static const cevent_tst sig_reset_slave_comm_st = {.sig = SIG_I2C_RESET_SLAVE_COMM}; +static const cevent_tst sig_reset_periph_st = {.sig = SIG_I2C_RESET_SLAVE_COMM}; + +void {{cookiecutter.module_name}}_init(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->counter_u32 = 0; + self->error_counter_u32 = 0; + + self->t_st.super.sig = SIG_I2C_WR_TRANSACTION; + self->t_st.slave_addr_u16 = self->config_st.address_u8; + self->t_st.target_q_pst = (cqueue_tst *)self; + self->t_st.read_data_pu8 = self->rx_buff_au8; + self->t_st.write_data_pu8 = self->tx_buff_au8; +} + +/*Increase the timer counter.*/ +void {{cookiecutter.module_name}}_10ms_callback(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->counter_u32 += 10; +} + +/*Increase the error counter.*/ +void {{cookiecutter.module_name}}_inc_error_counter(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->error_counter_u32++; +} + +void {{cookiecutter.module_name}}_reset_error_cnt(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->error_counter_u32 = 0; +} + +/*Try to read the ID register from the {{cookiecutter.module_name|upper}} by sending a write-read transaction to the I2C master.*/ +void {{cookiecutter.module_name}}_read_id(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_WR_TRANSACTION; + self->t_st.write_cnt_u16 = 1; + self->t_st.read_cnt_u16 = 2; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_ID; + self->rx_buff_au8[0] = 0; + self->rx_buff_au8[1] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +void {{cookiecutter.module_name}}_reset_pointer(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 1; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +/*Send a SIG_{{cookiecutter.module_name|upper}}_OFFLINE event. This can be used to detect communication errors between the module and the I2C slave.*/ +void send_offline_event(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->valid_b = false; + + TYPEOF(SIG_{{cookiecutter.module_name|upper}}_OFFLINE)* offline_pst = CRF_NEW(SIG_{{cookiecutter.module_name|upper}}_OFFLINE); + + offline_pst->id_u16 = self->config_st.id_u16; + + CRF_EMIT(offline_pst); +} + +/*Send a SIG_{{cookiecutter.module_name|upper}}_ONLINE event. This can be used to detect successful initialization.*/ +void send_online_event(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->valid_b = true; + TYPEOF(SIG_{{cookiecutter.module_name|upper}}_ONLINE)* online_pst = CRF_NEW(SIG_{{cookiecutter.module_name|upper}}_ONLINE); + + online_pst->id_u16 = self->config_st.id_u16; + + CRF_EMIT(online_pst); +} + +/*Reset the timer counter.*/ +void {{cookiecutter.module_name}}_reset_timer(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->counter_u32 = 0; +} + +/*Send a read transaction to the {{cookiecutter.module_name|upper}}.*/ +void {{cookiecutter.module_name}}_start_read(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_R_TRANSACTION; + self->t_st.write_cnt_u16 = 0; + self->t_st.read_cnt_u16 = 2; + self->rx_buff_au8[0] = 0; + self->rx_buff_au8[1] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +void {{cookiecutter.module_name}}_set_full_powerdown(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 2; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CONFIG; + self->tx_buff_au8[1] = {{cookiecutter.module_name|upper}}_POWER_OFF; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} +void {{cookiecutter.module_name}}_set_full_powerup(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 2; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CONFIG; + self->tx_buff_au8[1] = {{cookiecutter.module_name|upper}}_POWER_ON; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +bool {{cookiecutter.module_name}}_wait_cnt(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + if(self->wait_cnt_u16++ >= {{cookiecutter.module_name|upper}}_WAIT_CNT) + { + self->wait_cnt_u16 = 0; + return true; + } + else + { + return false; + } +} + +bool {{cookiecutter.module_name}}_inc_wait_cnt(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + self->wait_cnt_u16++; + return false; +} + +void {{cookiecutter.module_name}}_init_wait(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; +// self->wait_cnt_u16 = 0; +} + +void {{cookiecutter.module_name}}_get_resolution(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_WR_TRANSACTION; + self->t_st.write_cnt_u16 = 1; + self->t_st.read_cnt_u16 = 1; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CTRLSTATUS; + self->rx_buff_au8[1] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +void {{cookiecutter.module_name}}_update_resolution(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + uint16_t reg_u16 = self->rx_buff_au8[0]; + {{cookiecutter.module_name}}_resolution_t resolution = {{cookiecutter.module_name|upper}}_RESOLUTION_14BIT; + + self->resolution_u16 = (reg_u16 & {{cookiecutter.module_name|upper}}_MASK_RESOLUTION) | resolution; +} + +void {{cookiecutter.module_name}}_set_resolution(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 2; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CTRLSTATUS; + self->tx_buff_au8[1] = {{cookiecutter.module_name|upper}}_RESOLUTION_14BIT; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +/*Update the temperature display and send an event with the new value.*/ +void {{cookiecutter.module_name}}_update_temp(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + {{cookiecutter.module_name}}_temp_tst* temp_pst = CRF_NEW(SIG_{{cookiecutter.module_name|upper}}_TEMP); //{{cookiecutter.module_name}}_temp_tst + + if (NULL == temp_pst) return; + + // Compile the value of the Temperature Data Register into a variable + double tdr_reg_u32 = ((((self->rx_buff_au8[0] << 8) | self->rx_buff_au8[1]) >> 2) * 0.03125); + int32_t temp_c_i32 = tdr_reg_u32*1000; + + temp_pst->super.sig = SIG_{{cookiecutter.module_name|upper}}_TEMP; + temp_pst->temp_C_i32 = temp_c_i32; + temp_pst->id_u16 = self->config_st.id_u16; + + self->temp_C_i32 = temp_c_i32; + self->valid_b = true; + + self->super.send(_self, (const cevent_tst *)temp_pst); + + if (self->error_counter_u32) + { + self->error_counter_u32--; + } +} + +/*True, if the response data is equal to 0x190. See {{cookiecutter.module_name|upper}} datasheet section: 7.5.1.7 Identification Register*/ +bool {{cookiecutter.module_name}}_id_match(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + // Compile the value of the Identification Register into a variable + uint16_t idr_reg_u16 = self->rx_buff_au8[0]; + idr_reg_u16 <<= 8; + idr_reg_u16 |= self->rx_buff_au8[1]; + + return {{cookiecutter.module_name|upper}}_ID_REG_VALUE == idr_reg_u16; +} + +/*Return true, if the error counter is greater or equal then the parameter.*/ +bool {{cookiecutter.module_name}}_error_count(chsm_tst *_self, const cevent_tst *e_pst, uint16_t error_cnt_threshold_u16) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + return self->error_counter_u32 >= error_cnt_threshold_u16; +} + +bool {{cookiecutter.module_name}}_timeout(chsm_tst *_self, const cevent_tst *e_pst, uint32_t timeout_u32) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + return self->counter_u32 >= timeout_u32; +} + +void {{cookiecutter.module_name}}_unplugged(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + CRF_EMIT(&sig_reset_slave_comm_st); +} + diff --git a/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/CMakeLists.txt b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/CMakeLists.txt new file mode 100644 index 00000000..01571020 --- /dev/null +++ b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/CMakeLists.txt @@ -0,0 +1,22 @@ + +add_module_test( + NAME + {{cookiecutter.module_name}}_test + SOURCE + tsrc/main.c + tsrc/ut_{{cookiecutter.module_name}}_test.c + INCLUDE + tinc + LINK + unity + i2c_drv_mock + {{cookiecutter.module_name}} + DEFINES + NDEBUG + CHSM_BUILD_TESTS + STANDARD + 11 +) + +set_property(TARGET {{cookiecutter.module_name}}_test PROPERTY ECLIPSE_GENERATE_SOURCE_PROJECT ON) +set_property(TARGET {{cookiecutter.module_name}}_test PROPERTY ECLIPSE_GENERATE_LINKED_RESOURCES ON) \ No newline at end of file diff --git a/modules/i2c_master/test/build/.keep b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tinc/.gitkeep similarity index 100% rename from modules/i2c_master/test/build/.keep rename to gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tinc/.gitkeep diff --git a/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/main.c b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/main.c new file mode 100644 index 00000000..9164d34f --- /dev/null +++ b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/main.c @@ -0,0 +1,24 @@ +#include +#include "unity_fixture.h" +#include "unity.h" + + +void disableInterrupts(void) +{ + +} + +void enableInterrupts(void) +{ + +} + +void run_{{cookiecutter.module_name}}_tests(void) +{ + RUN_TEST_GROUP({{cookiecutter.module_name}}); +} + +int main(int argc, const char * argv[]) +{ + return UnityMain(argc, argv, run_{{cookiecutter.module_name}}_tests); +} \ No newline at end of file diff --git a/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/ut_{{cookiecutter.module_name}}_test.c b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/ut_{{cookiecutter.module_name}}_test.c new file mode 100644 index 00000000..e98a475c --- /dev/null +++ b/gui/java_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/ut_{{cookiecutter.module_name}}_test.c @@ -0,0 +1,417 @@ +/* + * ut_{{cookiecutter.module_name}}_test.c + * + * Created on: 2020. dec. 30. + * Author: jszeman + */ + +#include +#include +#include +#include +#include +#include "unity_fixture.h" +#include "crf.h" +#include "cbits.h" +#include "ut_i2c_driver_mock.h" +#include "i2c_master.h" +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_regs.h" +#include "cevent.h" +#include "sys_if.h" + +TEST_GROUP({{cookiecutter.module_name}}); + +ut_i2c_driver_mock_tst drv_mock_st; +i2c_driver_if_tst* drv_pst = (i2c_driver_if_tst *)&drv_mock_st; + +const cevent_tst* i2c_master_events_apst[8]; +i2c_master_tst i2c_master_st; +uint8_t i2c_master_scanned_ids[127]; + +const cevent_tst* {{cookiecutter.module_name}}_events_apst[8]; +{{cookiecutter.module_name}}_tst {{cookiecutter.module_name}}_st; + + +{{cookiecutter.module_name}}_tst *self = &{{cookiecutter.module_name}}_st; // This is necessary for macros like {{cookiecutter.module_name|upper}}_READ_PERIOD to work here + +chsm_tst* hsm_apst[] = { + (chsm_tst*)(&i2c_master_st), + (chsm_tst*)(&{{cookiecutter.module_name}}_st), + NULL}; + +uint8_t pool_buff_au8[1024]; +cpool_tst pool_ast[1]; + +crf_tst crf; + +const cevent_tst* events_apst[4]; +cqueue_tst q_st; + +const cevent_tst tick_10ms_st = {.sig = SIG_SYS_TICK_10ms}; + +static void tick_ms(uint32_t tick_cnt_u32) +{ + while(tick_cnt_u32--) + { + drv_mock_st.tick(&drv_mock_st); + + CRF_POST(&tick_10ms_st, &{{cookiecutter.module_name}}_st); + + while(CRF_STEP()) + { + printf("| "); + } + } +} + +void {{cookiecutter.module_name}}_send(chsm_tst *self, const cevent_tst *e_pst) +{ + //printf("\n%s\n", __FUNCTION__); + switch(e_pst->sig) + { + case SIG_{{cookiecutter.module_name|upper}}_TEMP: + case SIG_{{cookiecutter.module_name|upper}}_ONLINE: + case SIG_{{cookiecutter.module_name|upper}}_OFFLINE: + CRF_POST(e_pst, &q_st); + break; + + default: + CRF_POST(e_pst, &i2c_master_st); + } +} + + +TEST_SETUP({{cookiecutter.module_name}}) +{ + memset(events_apst, 0, sizeof(events_apst)); + memset(&q_st, 0, sizeof(q_st)); + memset(&drv_mock_st, 0, sizeof(drv_mock_st)); + memset(&i2c_master_st, 0, sizeof(i2c_master_st)); + memset(&crf, 0, sizeof(crf)); + memset(&i2c_master_events_apst, 0, sizeof(i2c_master_events_apst)); + memset(&pool_buff_au8, 0, sizeof(pool_buff_au8)); + memset(&pool_ast, 0, sizeof(pool_ast)); + memset(&{{cookiecutter.module_name}}_st, 0, sizeof({{cookiecutter.module_name}}_st)); + + cpool_init(pool_ast+0, pool_buff_au8, 24, 16); + + cqueue_init(&q_st, events_apst, 4); + + ut_i2c_driver_mock_init(&drv_mock_st); + + i2c_master_st.config_st.driver_pst = drv_pst; + // i2c_master_st.config_st.scan_result_au8[0] = &i2c_master_scanned_ids; + chsm_ctor(&i2c_master_st.super, i2c_master_top, i2c_master_events_apst, 4, 4); + chsm_ctor(&{{cookiecutter.module_name}}_st.super, {{cookiecutter.module_name}}_top, {{cookiecutter.module_name}}_events_apst, 8, 0); + + {{cookiecutter.module_name}}_st.config_st = ({{cookiecutter.module_name}}_cfg_tst){ + .address_u8 = {{cookiecutter.module_name|upper}}_0_I2C_FLOAT, + .id_u16 = 0xabcd, + .period_ms_u16 = {{cookiecutter.module_name|upper}}_READ_PERIOD_VALUE, + .max_error_cnt_u16 = {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT_VALUE + }; + + CRF_SEND_FUNC(&{{cookiecutter.module_name}}_st) = {{cookiecutter.module_name}}_send; + + crf_init(&crf, hsm_apst, pool_ast, 1); + chsm_init((chsm_tst *)&i2c_master_st); + chsm_init((chsm_tst *)&{{cookiecutter.module_name}}_st); +} + +TEST_TEAR_DOWN({{cookiecutter.module_name}}) +{ +} + +/* + * Just call setup + */ +TEST({{cookiecutter.module_name}}, init) +{ + printf("\n%s\n", __FUNCTION__); +} + +TEST({{cookiecutter.module_name}}, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = {{cookiecutter.module_name|upper}}_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, // sensor id + 0xf3, 0x80, // -25° measured value + 0x0c, 0x80 // +25° measured value + } + }; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + +} + +/* read_temp_twice: + * Setup the mock device to send the id bytes and two temperature reading (-25 and 25) to the master. + * Check, that two temperature events were sent + */ +TEST({{cookiecutter.module_name}}, read_temp_twice) +{ + printf("\n%s\n", __FUNCTION__); + i2c_mock_slave_device_tst dev_st = { + .address_u8 = 0x12, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + + const {{cookiecutter.module_name}}_temp_tst* e_pst; + const {{cookiecutter.module_name}}_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + TEST_ASSERT(s_pst); + TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + + e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + + tick_ms(({{cookiecutter.module_name|upper}}_READ_PERIOD/10)+1); + + uint8_t expected_au8[4] = {7, 0, 0, 0}; + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); + TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); + TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + + e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +} + +/* read_id_retry: + * Check that a failed ID read will be repeated after the configured time. + */ +TEST({{cookiecutter.module_name}}, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = {{cookiecutter.module_name|upper}}_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + const {{cookiecutter.module_name}}_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + TEST_ASSERT_NULL(s_pst); + + // dev_st.address_u8 = 0x12; + + // tick_ms({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT-10); + + // s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NULL(s_pst); + + // tick_ms(10); + + // s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NOT_NULL(s_pst); + // TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); +} + +// /* read_id_retry_bad_id: +// * Check that a failed ID read will be repeated after the configured time if the data sent back +// * by the slave is not 0x190 for the first try. +// */ +// TEST({{cookiecutter.module_name}}, read_id_retry_bad_id) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x91, 0x01, 0x90, 0x0c, 0x80} +// }; + +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms(({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT-10)/10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NOT_NULL(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); +// } + +// /* go_online: +// * Check that after reading temperature data fails for more than {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST({{cookiecutter.module_name}}, go_online) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const {{cookiecutter.module_name}}_temp_tst* e_pst; +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(({{cookiecutter.module_name|upper}}_READ_PERIOD_VALUE / 10) + 1); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE({{cookiecutter.module_name}}_st.valid_b); +// } + +// /* go_offline: +// * Check that after reading temperature data fails for more than {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST({{cookiecutter.module_name}}, go_offline) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const {{cookiecutter.module_name}}_temp_tst* e_pst; +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(({{cookiecutter.module_name|upper}}_READ_PERIOD/10) + 1); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE({{cookiecutter.module_name}}_st.valid_b); + +// dev_st.address_u8 = 0x13; + +// tick_ms((({{cookiecutter.module_name|upper}}_READ_PERIOD/10) + 1) * {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT + 1); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_OFFLINE, s_pst->super.sig); + +// TEST_ASSERT_FALSE({{cookiecutter.module_name}}_st.valid_b); +// } + +// /* triggered_read: +// * Check that it is possible to trigger a read before the read period timeout elapses. +// */ +// TEST({{cookiecutter.module_name}}, triggered_read) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const cevent_tst read_event = {.sig = SIG_{{cookiecutter.module_name|upper}}_READ}; + + +// const {{cookiecutter.module_name}}_temp_tst* e_pst; +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(1); + +// CRF_POST(&read_event, &{{cookiecutter.module_name}}_st); + +// tick_ms(10); + +// uint8_t expected_au8[4] = {7, 0, 0, 0}; +// TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); +// TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); +// TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +// } + +TEST_GROUP_RUNNER({{cookiecutter.module_name}}) +{ + RUN_TEST_CASE({{cookiecutter.module_name}}, init); + RUN_TEST_CASE({{cookiecutter.module_name}}, read_id); + // RUN_TEST_CASE({{cookiecutter.module_name}}, read_temp_twice); + // RUN_TEST_CASE({{cookiecutter.module_name}}, read_id_retry); + // RUN_TEST_CASE({{cookiecutter.module_name}}, read_id_retry_bad_id); + // RUN_TEST_CASE({{cookiecutter.module_name}}, go_offline); + // RUN_TEST_CASE({{cookiecutter.module_name}}, go_online); + // RUN_TEST_CASE({{cookiecutter.module_name}}, triggered_read); +} diff --git a/gui/java_gen/module_template/_template_without_crf/cookiecutter.json b/gui/java_gen/module_template/_template_without_crf/cookiecutter.json new file mode 100644 index 00000000..635ada19 --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf/cookiecutter.json @@ -0,0 +1,3 @@ +{ + "module_name": "template" +} \ No newline at end of file diff --git a/gui/java_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h b/gui/java_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h new file mode 100644 index 00000000..93ef40a8 --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h @@ -0,0 +1,48 @@ +#ifndef PCA9554_FUNCTIONS_H +#define PCA9554_FUNCTIONS_H + +/*Generated with CHSM v0.0.0 at 2023.07.27 14.07.05*/ + +#include "pca9554.h" +#include + + +void pca9554_process_input(pca9554_tst *self); + +void pca9554_read_input(pca9554_tst *self); + +void pca9554_reset_timer(pca9554_tst *self); + +/*Start a I2C transaction to write the DIRECTION register in the slave device.*/ +void pca9554_set_direction(pca9554_tst *self); + +void pca9554_set_output(pca9554_tst *self); + +void pca9554_set_polarity(pca9554_tst *self); + + +typedef enum pca9554_state_id_ten +{ + S_PCA9554_WAIT_DIR = 1, + S_PCA9554_WAIT_POL = 2, + S_PCA9554_WAIT_OUTPUT = 3, + S_PCA9554_WAIT_READ = 4, + S_PCA9554_BACK_OFF = 5, +} pca9554_state_id_ten; + + +/* +Signals: + I2C_FAIL + I2C_SUCCESS + START_READ +*/ + +/* +Other function notes: + +pca9554_set_status: + +pca9554_timeout: +*/ +#endif diff --git a/gui/java_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c b/gui/java_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c new file mode 100644 index 00000000..28a6511c --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c @@ -0,0 +1,115 @@ +/*Generated with CHSM v0.0.1*/ +#include "pca9554.h" +#include "pca9554_functions.h" + + +static void s_pca9554_back_off(pca9554_tst *self); +static void s_pca9554_wait_read(pca9554_tst *self); +static void s_pca9554_wait_output(pca9554_tst *self); +static void s_pca9554_wait_pol(pca9554_tst *self); +static void s_pca9554_wait_dir(pca9554_tst *self); + +static void s_pca9554_wait_dir(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_polarity(self); + return pca9554_set_state(self, s_pca9554_wait_pol); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_pol(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_output(self); + return pca9554_set_state(self, s_pca9554_wait_output); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_output(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_read(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_status(self, PCA9554_READY); + pca9554_process_input(self); + break; + + case PCA9554_SIG_START_READ: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_back_off(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + if(pca9554_timeout(self, 1000)) + { + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} + +void pca9554_top(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_INIT: + pca9554_set_status(self, PCA9554_STARTING); + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} diff --git a/gui/java_gen/module_template/_template_without_crf_new/cookiecutter.json b/gui/java_gen/module_template/_template_without_crf_new/cookiecutter.json new file mode 100644 index 00000000..635ada19 --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf_new/cookiecutter.json @@ -0,0 +1,3 @@ +{ + "module_name": "template" +} \ No newline at end of file diff --git a/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/.chsm/pca9554.json b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/.chsm/pca9554.json new file mode 100644 index 00000000..35f0d37a --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/.chsm/pca9554.json @@ -0,0 +1,26 @@ +{ + "src_dir": "../src", + "doc_dir": "../doc", + + "templates": { + "init_signal": "PCA9554_SIG_INIT", + "signal_prefix": "PCA9554_SIG_", + "func_args": "self", + "func_params": "pca9554_tst *self", + "user_func_args_t": "self", + "user_func_params_t": "pca9554_tst *self", + "func_return_type": "void", + "guard_return_type": "uint16_t", + "switch_variable": "self->signal_en", + "trans_result": "pca9554_set_state(self, {target})", + "ignored_result": "", + "c_include_list": [], + "h_include_list": [""], + "top_state_name": "void\\s+(?P\\w+)\\(void\\s+\\*self,\\s+uint32_t\\s+e_u32\\)\\s*;", + "set_state_id": "" + }, + + "pca9554.h": { + "top_func": "pca9554_top" + } +} \ No newline at end of file diff --git a/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/CMakeLists.txt b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/CMakeLists.txt new file mode 100644 index 00000000..46fba169 --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/CMakeLists.txt @@ -0,0 +1,19 @@ + +add_module_lib( + NAME + lm73 + PACKAGE + chsm + SOURCE + src/lm73.c + src/lm73_functions.c + INCLUDE + inc + LINK + chsm::i2c_master + signal_classes_modules + DEFINES + NDEBUG + STANDARD + 11 +) \ No newline at end of file diff --git a/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/doc/pca9554.html b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/doc/pca9554.html new file mode 100644 index 00000000..6162916b --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/doc/pca9554.html @@ -0,0 +1,865 @@ + + + + + + +
+ + + + + + START_READ[pca9554_timeout(1000)]I2C_FAILI2C_SUCCESSI2C_SUCCESSI2C_SUCCESS + __top__s_pca9554init/ pca9554_set_status(PCA9554_STARTING)s_pca9554_wait_dirinit/ pca9554_set_direction()Start a I2C transaction to write the DIRECTION register in the slave device.s_pca9554_wait_polinit/ pca9554_set_polarity()s_pca9554_wait_outputinit/ pca9554_set_output()s_pca9554_wait_readinit/ pca9554_read_input()I2C_SUCCESS/ { pca9554_set_status(PCA9554_READY) pca9554_process_input()}s_pca9554_back_offinit/ pca9554_reset_timer()entry/ pca9554_set_status(PCA9554_NOT_FOUND) + + +
+ +
+ json +
+            {
+    "states": {
+        "__top__": {
+            "pos": [
+                -100000000,
+                -100000000
+            ],
+            "size": [
+                200000000,
+                200000000
+            ],
+            "title": "__top__",
+            "text": [],
+            "connectors": [],
+            "parent": null,
+            "children": [
+                "state_0",
+                "istate_0"
+            ],
+            "type": "top"
+        },
+        "state_0": {
+            "pos": [
+                42,
+                17
+            ],
+            "size": [
+                82,
+                73
+            ],
+            "title": "s_pca9554",
+            "text": [
+                "init/ pca9554_set_status(PCA9554_STARTING)"
+            ],
+            "connectors": [
+                "conn_1",
+                "conn_10"
+            ],
+            "parent": "__top__",
+            "children": [
+                "state_1",
+                "istate_1",
+                "state_2",
+                "state_3",
+                "state_4",
+                "state_5"
+            ],
+            "type": "normal"
+        },
+        "istate_0": {
+            "pos": [
+                55,
+                9
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_0",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_0"
+            ],
+            "parent": "__top__",
+            "children": [],
+            "type": "initial"
+        },
+        "state_1": {
+            "pos": [
+                48,
+                32
+            ],
+            "size": [
+                20,
+                6
+            ],
+            "title": "s_pca9554_wait_dir",
+            "text": [
+                "init/ pca9554_set_direction()"
+            ],
+            "connectors": [
+                "conn_3",
+                "conn_4",
+                "conn_13"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_1": {
+            "pos": [
+                55,
+                26
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_1",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_2"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "initial"
+        },
+        "state_2": {
+            "pos": [
+                48,
+                44
+            ],
+            "size": [
+                20,
+                6
+            ],
+            "title": "s_pca9554_wait_pol",
+            "text": [
+                "init/ pca9554_set_polarity()"
+            ],
+            "connectors": [
+                "conn_5",
+                "conn_6"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "state_3": {
+            "pos": [
+                48,
+                56
+            ],
+            "size": [
+                20,
+                6
+            ],
+            "title": "s_pca9554_wait_output",
+            "text": [
+                "init/ pca9554_set_output()"
+            ],
+            "connectors": [
+                "conn_7",
+                "conn_8"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "state_4": {
+            "pos": [
+                49,
+                70
+            ],
+            "size": [
+                31,
+                16
+            ],
+            "title": "s_pca9554_wait_read",
+            "text": [
+                "init/ pca9554_read_input()",
+                "I2C_SUCCESS/ {",
+                "   pca9554_set_status(PCA9554_READY)",
+                "   pca9554_process_input()",
+                "}"
+            ],
+            "connectors": [
+                "conn_9",
+                "conn_14",
+                "conn_15"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "state_5": {
+            "pos": [
+                88,
+                43
+            ],
+            "size": [
+                32,
+                8
+            ],
+            "title": "s_pca9554_back_off",
+            "text": [
+                "init/ pca9554_reset_timer()",
+                "entry/ pca9554_set_status(PCA9554_NOT_FOUND)"
+            ],
+            "connectors": [
+                "conn_11",
+                "conn_12"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        }
+    },
+    "connectors": {
+        "conn_0": {
+            "parent": "istate_0",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_0"
+        },
+        "conn_1": {
+            "parent": "state_0",
+            "offset": 13,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_0"
+        },
+        "conn_2": {
+            "parent": "istate_1",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_1"
+        },
+        "conn_3": {
+            "parent": "state_1",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_1"
+        },
+        "conn_4": {
+            "parent": "state_1",
+            "offset": 7,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_2"
+        },
+        "conn_5": {
+            "parent": "state_2",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_2"
+        },
+        "conn_6": {
+            "parent": "state_2",
+            "offset": 7,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_3"
+        },
+        "conn_7": {
+            "parent": "state_3",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_3"
+        },
+        "conn_8": {
+            "parent": "state_3",
+            "offset": 7,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_4"
+        },
+        "conn_9": {
+            "parent": "state_4",
+            "offset": 6,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_4"
+        },
+        "conn_10": {
+            "parent": "state_0",
+            "offset": 18,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_5"
+        },
+        "conn_11": {
+            "parent": "state_5",
+            "offset": 15,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_5"
+        },
+        "conn_12": {
+            "parent": "state_5",
+            "offset": 12,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_6"
+        },
+        "conn_13": {
+            "parent": "state_1",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_6"
+        },
+        "conn_14": {
+            "parent": "state_4",
+            "offset": 11,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_7"
+        },
+        "conn_15": {
+            "parent": "state_4",
+            "offset": 7,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_7"
+        }
+    },
+    "transitions": {
+        "trans_0": {
+            "start": "conn_0",
+            "end": "conn_1",
+            "vertices": [
+                [
+                    55,
+                    9
+                ],
+                [
+                    55,
+                    9
+                ],
+                [
+                    55,
+                    17
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                4.1
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                55.5,
+                13.1
+            ]
+        },
+        "trans_1": {
+            "start": "conn_2",
+            "end": "conn_3",
+            "vertices": [
+                [
+                    55,
+                    26
+                ],
+                [
+                    55,
+                    26
+                ],
+                [
+                    55,
+                    32
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                2.6000000000000014
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                55.5,
+                28.6
+            ]
+        },
+        "trans_2": {
+            "start": "conn_4",
+            "end": "conn_5",
+            "vertices": [
+                [
+                    55,
+                    38
+                ],
+                [
+                    55,
+                    43
+                ],
+                [
+                    55,
+                    43
+                ],
+                [
+                    55,
+                    44
+                ]
+            ],
+            "label": "I2C_SUCCESS",
+            "label_offset": [
+                0.5,
+                2.700000000000003
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                55.5,
+                40.7
+            ]
+        },
+        "trans_3": {
+            "start": "conn_6",
+            "end": "conn_7",
+            "vertices": [
+                [
+                    55,
+                    50
+                ],
+                [
+                    55,
+                    54
+                ],
+                [
+                    55,
+                    54
+                ],
+                [
+                    55,
+                    56
+                ]
+            ],
+            "label": "I2C_SUCCESS",
+            "label_offset": [
+                0.5,
+                2.8000000000000043
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                55.5,
+                52.800000000000004
+            ]
+        },
+        "trans_4": {
+            "start": "conn_8",
+            "end": "conn_9",
+            "vertices": [
+                [
+                    55,
+                    62
+                ],
+                [
+                    55,
+                    66
+                ],
+                [
+                    55,
+                    66
+                ],
+                [
+                    55,
+                    70
+                ]
+            ],
+            "label": "I2C_SUCCESS",
+            "label_offset": [
+                0.5,
+                3.5999999999999943
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                55.5,
+                65.6
+            ]
+        },
+        "trans_5": {
+            "start": "conn_10",
+            "end": "conn_11",
+            "vertices": [
+                [
+                    124,
+                    35
+                ],
+                [
+                    103,
+                    35
+                ],
+                [
+                    103,
+                    43
+                ]
+            ],
+            "label": "I2C_FAIL",
+            "label_offset": [
+                -19.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                104.5,
+                34.6
+            ]
+        },
+        "trans_6": {
+            "start": "conn_12",
+            "end": "conn_13",
+            "vertices": [
+                [
+                    100,
+                    43
+                ],
+                [
+                    100,
+                    35
+                ],
+                [
+                    68,
+                    35
+                ]
+            ],
+            "label": "[pca9554_timeout(1000)]",
+            "label_offset": [
+                -23.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                76.5,
+                34.6
+            ]
+        },
+        "trans_7": {
+            "start": "conn_14",
+            "end": "conn_15",
+            "vertices": [
+                [
+                    80,
+                    81
+                ],
+                [
+                    93,
+                    81
+                ],
+                [
+                    93,
+                    77
+                ],
+                [
+                    80,
+                    77
+                ]
+            ],
+            "label": "START_READ",
+            "label_offset": [
+                -10,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                83,
+                76.6
+            ]
+        }
+    },
+    "notes": {
+        "pca9554_i2c_success()": "",
+        "I2C_SUCCESS": "",
+        "pca9554_set_direction()": "Start a I2C transaction to write the DIRECTION register in the slave device.",
+        "PCA9554_SIG_I2C_FAIL": "",
+        "START_READ": ""
+    },
+    "view": {
+        "translate": [
+            -13.5,
+            -34
+        ],
+        "scale": 8.5
+    }
+}
+        
+
+ + diff --git a/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554.h b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554.h new file mode 100644 index 00000000..dc3dbf66 --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554.h @@ -0,0 +1,98 @@ +/* + * lm73.h + * + * Created on: 2015 máj. 20 + * Author: jszeman + */ + +#ifndef INC_PCA9554_H_ +#define INC_PCA9554_H_ + +#include +#include "i2cMaster.h" + +#define PCA_A0_HIGH (1<<0) +#define PCA_A0_LOW (0) + +#define PCA_A1_HIGH (1<<1) +#define PCA_A1_LOW (0) + +#define PCA_A2_HIGH (1<<2) +#define PCA_A2_LOW (0) + +enum PCA9554_STATUS { + PCA9554_READY, /**< The driver is ready for operation */ + PCA9554_BUSY, /**< The driver is in the process of reading or writing data. The in field is not valid. */ + PCA9554_NOT_FOUND, /**< The configured device did not acknowledged its address */ + PCA9554_STARTING /**< The driver is in the process of initializing the device */ +}; + +enum PCA9554_PART { + PCA9554 = 0x20, + PCA9554A = 0x38 +}; + +typedef enum pca9554_sig_ten { + PCA9554_SIG_NONE, + PCA9554_SIG_I2C_SUCCESS, + PCA9554_SIG_I2C_FAIL, + PCA9554_SIG_INIT, + PCA9554_SIG_START_READ +} pca9554_sig_ten; + +struct pca9554_config +{ + i2cMaster_h i2cH; /**< Pointer to a previously configured I2C master driver */ + enum PCA9554_PART type; /**< Exact device type. Necessary for address calculation */ + uint16_t a; /** Address pin (A0, A1, A2) configuration */ + uint16_t out; /** Initial output value */ + uint16_t polarity; /** Input pin polarity */ + uint16_t direction; /** Pin direction */ +}; + +typedef struct pca9554_t *pca9554_h; +typedef struct pca9554_t pca9554_tst; + +struct pca9554_t +{ + /* PUBLIC */ + struct pca9554_config config; + enum PCA9554_STATUS status; + + uint16_t in; + uint16_t inputChanged; + + void (*setOutput)(pca9554_h self, uint16_t o); + void (*setDirection)(pca9554_h self, uint16_t d); + void (*setPolarity)(pca9554_h self, uint16_t p); + void (*readInput)(pca9554_h self); + void (*callback_1ms)(pca9554_h self); + + /* PRIVATE */ + struct i2cTransaction_t transaction; + uint8_t wbuff[4]; + uint8_t rbuff[2]; + + pca9554_sig_ten signal_en; + pca9554_sig_ten op_en; + + uint32_t timer_u32; + uint32_t fault_cnt_u32; + + void (*sm_callback)(pca9554_tst *self); +}; + + + +void pca9554_init(pca9554_h self); +void pca9554_top(pca9554_tst *self); + +void pca9554_set_status(pca9554_tst *self, enum PCA9554_STATUS status_en); +uint16_t pca9554_timeout(pca9554_tst *self, uint32_t timeout_u32); + +static inline void pca9554_set_state(pca9554_tst *self, void (*state_pft)(pca9554_tst *self)) +{ + self->sm_callback = state_pft; +} + +#endif /* INC_PCA9554_H_ */ diff --git a/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554_functions.h b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554_functions.h new file mode 100644 index 00000000..93ef40a8 --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554_functions.h @@ -0,0 +1,48 @@ +#ifndef PCA9554_FUNCTIONS_H +#define PCA9554_FUNCTIONS_H + +/*Generated with CHSM v0.0.0 at 2023.07.27 14.07.05*/ + +#include "pca9554.h" +#include + + +void pca9554_process_input(pca9554_tst *self); + +void pca9554_read_input(pca9554_tst *self); + +void pca9554_reset_timer(pca9554_tst *self); + +/*Start a I2C transaction to write the DIRECTION register in the slave device.*/ +void pca9554_set_direction(pca9554_tst *self); + +void pca9554_set_output(pca9554_tst *self); + +void pca9554_set_polarity(pca9554_tst *self); + + +typedef enum pca9554_state_id_ten +{ + S_PCA9554_WAIT_DIR = 1, + S_PCA9554_WAIT_POL = 2, + S_PCA9554_WAIT_OUTPUT = 3, + S_PCA9554_WAIT_READ = 4, + S_PCA9554_BACK_OFF = 5, +} pca9554_state_id_ten; + + +/* +Signals: + I2C_FAIL + I2C_SUCCESS + START_READ +*/ + +/* +Other function notes: + +pca9554_set_status: + +pca9554_timeout: +*/ +#endif diff --git a/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554.c b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554.c new file mode 100644 index 00000000..28a6511c --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554.c @@ -0,0 +1,115 @@ +/*Generated with CHSM v0.0.1*/ +#include "pca9554.h" +#include "pca9554_functions.h" + + +static void s_pca9554_back_off(pca9554_tst *self); +static void s_pca9554_wait_read(pca9554_tst *self); +static void s_pca9554_wait_output(pca9554_tst *self); +static void s_pca9554_wait_pol(pca9554_tst *self); +static void s_pca9554_wait_dir(pca9554_tst *self); + +static void s_pca9554_wait_dir(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_polarity(self); + return pca9554_set_state(self, s_pca9554_wait_pol); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_pol(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_output(self); + return pca9554_set_state(self, s_pca9554_wait_output); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_output(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_read(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_status(self, PCA9554_READY); + pca9554_process_input(self); + break; + + case PCA9554_SIG_START_READ: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_back_off(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + if(pca9554_timeout(self, 1000)) + { + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} + +void pca9554_top(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_INIT: + pca9554_set_status(self, PCA9554_STARTING); + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} diff --git a/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554_functions.c b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554_functions.c new file mode 100644 index 00000000..65c4e42e --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554_functions.c @@ -0,0 +1,153 @@ +/* + * lm73.c + * + * Created on: 2015 máj. 20 + * Author: jszeman + */ + +#include +#include "i2cMaster.h" +#include "math.h" +#include "pca9554.h" + +#define PCA_REG_INPUT 0 +#define PCA_REG_OUTPUT 1 +#define PCA_REG_POLARITY 2 +#define PCA_REG_DIRECTION 3 + +static void startRegWrite(pca9554_h self) +{ + self->transaction.writeLength = 2; // write pointer byte + self->transaction.readLength = 0; + self->config.i2cH->start(self->config.i2cH, &self->transaction); + + //self->status = PCA9554_BUSY; +} + +static void setOutput(pca9554_h self, uint16_t o) +{ + self->wbuff[0] = PCA_REG_OUTPUT; + self->wbuff[1] = o; + + startRegWrite(self); +} + +static void setDirection(pca9554_h self, uint16_t d) +{ + self->wbuff[0] = PCA_REG_DIRECTION; + self->wbuff[1] = d; + + startRegWrite(self); +} + +static void setPolarity(pca9554_h self, uint16_t p) +{ + self->wbuff[0] = PCA_REG_POLARITY; + self->wbuff[1] = p; + + startRegWrite(self); +} + +static void readInput(pca9554_h self) +{ + self->wbuff[0] = PCA_REG_INPUT; + self->transaction.writeLength = 1; // write pointer byte + self->transaction.readLength = 1; + self->config.i2cH->start(self->config.i2cH, &self->transaction); + + self->status = PCA9554_BUSY; +} + +static void start_read(pca9554_h self) +{ + self->op_en = PCA9554_SIG_START_READ; +} + +static void callback(pca9554_h self) +{ + self->signal_en = PCA9554_SIG_NONE; + + switch (self->transaction.result) + { + case I2C_SUCCESS: + self->signal_en = PCA9554_SIG_I2C_SUCCESS; + self->transaction.result = I2C_NONE; + break; + + case I2C_ADDRESS_NACK: + case I2C_DATA_NACK: + self->signal_en = PCA9554_SIG_I2C_FAIL; + self->transaction.result = I2C_NONE; + self->fault_cnt_u32++; + break; + + default: + self->signal_en = self->op_en; + self->op_en = PCA9554_SIG_NONE; + } + + self->sm_callback(self); + + self->timer_u32++; +} + +void pca9554_set_status(pca9554_tst *self, enum PCA9554_STATUS status_en) +{ + self->status = status_en; +} + +void pca9554_process_input(pca9554_tst *self) +{ + self->in = self->rbuff[0]; + self->inputChanged = 1; +} + +void pca9554_read_input(pca9554_tst *self) +{ + readInput(self); +} + +void pca9554_set_direction(pca9554_tst *self) +{ + setDirection(self, self->config.direction); +} + +void pca9554_set_output(pca9554_tst *self) +{ + setOutput(self, self->config.out); +} + +void pca9554_set_polarity(pca9554_tst *self) +{ + setPolarity(self, self->config.polarity); +} + +void pca9554_reset_timer(pca9554_tst *self) +{ + self->timer_u32 = 0; +} + +uint16_t pca9554_timeout(pca9554_tst *self, uint32_t timeout_u32) +{ + return self->timer_u32 >= timeout_u32; +} + +void pca9554_init(pca9554_h self) +{ + self->setOutput = setOutput; + self->setDirection = setDirection; + self->setPolarity = setPolarity; + self->readInput = start_read; + self->callback_1ms = callback; + + self->transaction.address = self->config.type | (self->config.a & 0x07); + self->transaction.result = I2C_NONE; + self->transaction.readData = self->rbuff; + self->transaction.writeData = self->wbuff; + self->inputChanged = 0; + self->fault_cnt_u32 = 0; + + self->sm_callback = pca9554_top; + self->op_en = PCA9554_SIG_INIT; + +} diff --git a/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/CMakeLists.txt b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/CMakeLists.txt new file mode 100644 index 00000000..4b648cb6 --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/CMakeLists.txt @@ -0,0 +1,22 @@ + +add_module_test( + NAME + lm73_test + SOURCE + tsrc/main.c + tsrc/ut_lm73_test.c + INCLUDE + tinc + LINK + unity + i2c_drv_mock + lm73 + DEFINES + NDEBUG + CHSM_BUILD_TESTS + STANDARD + 11 +) + +set_property(TARGET lm73_test PROPERTY ECLIPSE_GENERATE_SOURCE_PROJECT ON) +set_property(TARGET lm73_test PROPERTY ECLIPSE_GENERATE_LINKED_RESOURCES ON) \ No newline at end of file diff --git a/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/doc/signal_classes_distribution.puml b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/doc/signal_classes_distribution.puml new file mode 100644 index 00000000..bc36d642 --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/doc/signal_classes_distribution.puml @@ -0,0 +1,32 @@ +@startuml signal_classes_distribution +scale 800 width +skinparam backgroundColor #FFEBDC +scale 1 + +skinparam cloud { + backgroundColor Olive + borderColor orange +} + +title Architecture Diagram of the CHSM package + +left to right direction + +package chsm { + package interfaces{ + rectangle signal_classes_if{ + typedef enum sig_class_ten { + SIG_CLASS_SYS = CRF_SIGNAL_CLASS_START, + SIG_CLASS_I2C_DRIVER, + SIG_CLASS_SPI_DRIVER, + SIG_CLASS_MEM, + SIG_CLASS_CAN, + SIG_APP_NAMESPACE_START, +} sig_class_ten; + } + + } +} + + +@enduml \ No newline at end of file diff --git a/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/main.c b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/main.c new file mode 100644 index 00000000..d8154db0 --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/main.c @@ -0,0 +1,24 @@ +#include +#include "unity_fixture.h" +#include "unity.h" + + +void disableInterrupts(void) +{ + +} + +void enableInterrupts(void) +{ + +} + +void run_lm73_tests(void) +{ + RUN_TEST_GROUP(lm73); +} + +int main(int argc, const char * argv[]) +{ + return UnityMain(argc, argv, run_lm73_tests); +} \ No newline at end of file diff --git a/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/ut_lm73_test.c b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/ut_lm73_test.c new file mode 100644 index 00000000..431baa94 --- /dev/null +++ b/gui/java_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/ut_lm73_test.c @@ -0,0 +1,417 @@ +/* + * ut_lm73_test.c + * + * Created on: 2020. dec. 30. + * Author: jszeman + */ + +#include +#include +#include +#include +#include +#include "unity_fixture.h" +#include "crf.h" +#include "cbits.h" +#include "ut_i2c_driver_mock.h" +#include "i2c_master.h" +#include "lm73.h" +#include "lm73_regs.h" +#include "cevent.h" +#include "sys_if.h" + +TEST_GROUP(lm73); + +ut_i2c_driver_mock_tst drv_mock_st; +i2c_driver_if_tst* drv_pst = (i2c_driver_if_tst *)&drv_mock_st; + +const cevent_tst* i2c_master_events_apst[8]; +i2c_master_tst i2c_master_st; +uint8_t i2c_master_scanned_ids[127]; + +const cevent_tst* lm73_events_apst[8]; +lm73_tst lm73_st; + + +lm73_tst *self = &lm73_st; // This is necessary for macros like LM73_READ_PERIOD to work here + +chsm_tst* hsm_apst[] = { + (chsm_tst*)(&i2c_master_st), + (chsm_tst*)(&lm73_st), + NULL}; + +uint8_t pool_buff_au8[1024]; +cpool_tst pool_ast[1]; + +crf_tst crf; + +const cevent_tst* events_apst[4]; +cqueue_tst q_st; + +const cevent_tst tick_10ms_st = {.sig = SIG_SYS_TICK_10ms}; + +static void tick_ms(uint32_t tick_cnt_u32) +{ + while(tick_cnt_u32--) + { + drv_mock_st.tick(&drv_mock_st); + + CRF_POST(&tick_10ms_st, &lm73_st); + + while(CRF_STEP()) + { + printf("| "); + } + } +} + +void lm73_send(chsm_tst *self, const cevent_tst *e_pst) +{ + //printf("\n%s\n", __FUNCTION__); + switch(e_pst->sig) + { + case SIG_LM73_TEMP: + case SIG_LM73_ONLINE: + case SIG_LM73_OFFLINE: + CRF_POST(e_pst, &q_st); + break; + + default: + CRF_POST(e_pst, &i2c_master_st); + } +} + + +TEST_SETUP(lm73) +{ + memset(events_apst, 0, sizeof(events_apst)); + memset(&q_st, 0, sizeof(q_st)); + memset(&drv_mock_st, 0, sizeof(drv_mock_st)); + memset(&i2c_master_st, 0, sizeof(i2c_master_st)); + memset(&crf, 0, sizeof(crf)); + memset(&i2c_master_events_apst, 0, sizeof(i2c_master_events_apst)); + memset(&pool_buff_au8, 0, sizeof(pool_buff_au8)); + memset(&pool_ast, 0, sizeof(pool_ast)); + memset(&lm73_st, 0, sizeof(lm73_st)); + + cpool_init(pool_ast+0, pool_buff_au8, 24, 16); + + cqueue_init(&q_st, events_apst, 4); + + ut_i2c_driver_mock_init(&drv_mock_st); + + i2c_master_st.config_st.driver_pst = drv_pst; + // i2c_master_st.config_st.scan_result_au8[0] = &i2c_master_scanned_ids; + chsm_ctor(&i2c_master_st.super, i2c_master_top, i2c_master_events_apst, 4, 4); + chsm_ctor(&lm73_st.super, lm73_top, lm73_events_apst, 8, 0); + + lm73_st.config_st = (lm73_cfg_tst){ + .address_u8 = LM73_0_I2C_FLOAT, + .id_u16 = 0xabcd, + .period_ms_u16 = LM73_READ_PERIOD_VALUE, + .max_error_cnt_u16 = LM73_MAX_ERROR_COUNT_VALUE + }; + + CRF_SEND_FUNC(&lm73_st) = lm73_send; + + crf_init(&crf, hsm_apst, pool_ast, 1); + chsm_init((chsm_tst *)&i2c_master_st); + chsm_init((chsm_tst *)&lm73_st); +} + +TEST_TEAR_DOWN(lm73) +{ +} + +/* + * Just call setup + */ +TEST(lm73, init) +{ + printf("\n%s\n", __FUNCTION__); +} + +TEST(lm73, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = LM73_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, // sensor id + 0xf3, 0x80, // -25° measured value + 0x0c, 0x80 // +25° measured value + } + }; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + +} + +/* read_temp_twice: + * Setup the mock device to send the id bytes and two temperature reading (-25 and 25) to the master. + * Check, that two temperature events were sent + */ +TEST(lm73, read_temp_twice) +{ + printf("\n%s\n", __FUNCTION__); + i2c_mock_slave_device_tst dev_st = { + .address_u8 = 0x12, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + + const lm73_temp_tst* e_pst; + const lm73_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = (lm73_status_tst*)q_st.get(&q_st); + TEST_ASSERT(s_pst); + TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + + e_pst = (lm73_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + + tick_ms((LM73_READ_PERIOD/10)+1); + + uint8_t expected_au8[4] = {7, 0, 0, 0}; + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); + TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); + TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + + e_pst = (lm73_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +} + +/* read_id_retry: + * Check that a failed ID read will be repeated after the configured time. + */ +TEST(lm73, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = LM73_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + const lm73_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = (lm73_status_tst*)q_st.get(&q_st); + TEST_ASSERT_NULL(s_pst); + + // dev_st.address_u8 = 0x12; + + // tick_ms(LM73_RETRY_TIMEOUT-10); + + // s_pst = (lm73_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NULL(s_pst); + + // tick_ms(10); + + // s_pst = (lm73_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NOT_NULL(s_pst); + // TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); +} + +// /* read_id_retry_bad_id: +// * Check that a failed ID read will be repeated after the configured time if the data sent back +// * by the slave is not 0x190 for the first try. +// */ +// TEST(lm73, read_id_retry_bad_id) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x91, 0x01, 0x90, 0x0c, 0x80} +// }; + +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms((LM73_RETRY_TIMEOUT-10)/10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NOT_NULL(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); +// } + +// /* go_online: +// * Check that after reading temperature data fails for more than LM73_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST(lm73, go_online) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const lm73_temp_tst* e_pst; +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms((LM73_READ_PERIOD_VALUE / 10) + 1); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE(lm73_st.valid_b); +// } + +// /* go_offline: +// * Check that after reading temperature data fails for more than LM73_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST(lm73, go_offline) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const lm73_temp_tst* e_pst; +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms((LM73_READ_PERIOD/10) + 1); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE(lm73_st.valid_b); + +// dev_st.address_u8 = 0x13; + +// tick_ms(((LM73_READ_PERIOD/10) + 1) * LM73_MAX_ERROR_COUNT + 1); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_OFFLINE, s_pst->super.sig); + +// TEST_ASSERT_FALSE(lm73_st.valid_b); +// } + +// /* triggered_read: +// * Check that it is possible to trigger a read before the read period timeout elapses. +// */ +// TEST(lm73, triggered_read) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const cevent_tst read_event = {.sig = SIG_LM73_READ}; + + +// const lm73_temp_tst* e_pst; +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(1); + +// CRF_POST(&read_event, &lm73_st); + +// tick_ms(10); + +// uint8_t expected_au8[4] = {7, 0, 0, 0}; +// TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); +// TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); +// TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +// } + +TEST_GROUP_RUNNER(lm73) +{ + RUN_TEST_CASE(lm73, init); + RUN_TEST_CASE(lm73, read_id); + // RUN_TEST_CASE(lm73, read_temp_twice); + // RUN_TEST_CASE(lm73, read_id_retry); + // RUN_TEST_CASE(lm73, read_id_retry_bad_id); + // RUN_TEST_CASE(lm73, go_offline); + // RUN_TEST_CASE(lm73, go_online); + // RUN_TEST_CASE(lm73, triggered_read); +} diff --git a/gui/java_gen/render.py b/gui/java_gen/render.py new file mode 100644 index 00000000..2b486e8b --- /dev/null +++ b/gui/java_gen/render.py @@ -0,0 +1,90 @@ +""" +Java state machine code generator for CHSM. + +Usage: + render.py [--output=] [--class-name=] [--package=] + +Generates a Java state machine class from a CHSM drawing (.html) file. +""" +import sys +import os +import json +import jinja2 +from pathlib import Path + +# Add parent directory to path for imports +sys.path.insert(0, str(Path(__file__).parent.parent)) + +from c_gen.hsm.sm_jinja import JinjaStateMachine + + +TEMPLATE_DIR = (Path(__file__).parent.parent / 'c_gen' / 'templates').resolve() +TEMPLATE_NAME = 'chsm_java_template.jinja' + + +def load_model_from_html(html_path): + """Extract the JSON model from a CHSM HTML drawing file.""" + import re + with open(html_path, 'r') as f: + content = f.read() + m = re.search(r"
\n(?P.+)
", content, re.DOTALL) + if not m: + raise ValueError(f'No JSON data found in {html_path}') + return json.loads(m.group('json')) + + +def render(model, template_params=None): + """Render a Java state machine from a CHSM model dict. + + Args: + model: CHSM model dict (as parsed from the HTML drawing). + template_params: Optional dict of template parameters (e.g. class_name, package_name). + + Returns: + Generated Java source code as a string. + """ + sm = JinjaStateMachine(model) + data = sm.data.copy() + data['template_params'] = template_params or {} + + # Convert sets to tuples for template compatibility + for key in list(data.keys()): + if isinstance(data[key], set): + data[key] = tuple(data[key]) + + env = jinja2.Environment( + loader=jinja2.FileSystemLoader(str(TEMPLATE_DIR)), + trim_blocks=True, + lstrip_blocks=True, + ) + template = env.get_template(TEMPLATE_NAME) + return template.render(data=data) + + +if __name__ == '__main__': + if len(sys.argv) < 2: + print(__doc__) + sys.exit(1) + + html_file = sys.argv[1] + output_file = None + class_name = 'StateMachine' + package_name = '' + + for arg in sys.argv[2:]: + if arg.startswith('--output='): + output_file = arg.split('=', 1)[1] + elif arg.startswith('--class-name='): + class_name = arg.split('=', 1)[1] + elif arg.startswith('--package='): + package_name = arg.split('=', 1)[1] + + model = load_model_from_html(html_file) + code = render(model, template_params={'class_name': class_name, 'package_name': package_name}) + + if output_file: + with open(output_file, 'w') as f: + f.write(code) + print(f'Generated {output_file}') + else: + print(code) diff --git a/modules/lm73/test/build/.keep b/gui/js_gen/.gitkeep similarity index 100% rename from modules/lm73/test/build/.keep rename to gui/js_gen/.gitkeep diff --git a/gui/js_gen/module_template/_template/cookiecutter.json b/gui/js_gen/module_template/_template/cookiecutter.json new file mode 100644 index 00000000..5bd70405 --- /dev/null +++ b/gui/js_gen/module_template/_template/cookiecutter.json @@ -0,0 +1,8 @@ +{ + "module_name": "template", + "comm_periph": "i2c", + "address":"0x00", + "author":"xsession", + "full_name":"Laszlo Ivanyi", + "licence":"MIT" +} \ No newline at end of file diff --git a/gui/js_gen/module_template/_template/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h b/gui/js_gen/module_template/_template/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h new file mode 100644 index 00000000..2d469139 --- /dev/null +++ b/gui/js_gen/module_template/_template/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h @@ -0,0 +1,79 @@ +#ifndef {{cookiecutter.module_name|upper}}_FUNCTIONS_H +#define {{cookiecutter.module_name|upper}}_FUNCTIONS_H + +#include "{{cookiecutter.module_name}}.h" +#include "chsm.h" +#include "cevent.h" +#include + +void {{cookiecutter.module_name}}_10ms_callback(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_inc_error_counter(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_init(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_init_wait(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_read_id(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_error_cnt(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_pointer(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_timer(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_full_powerdown(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_full_powerup(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_resolution(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_start_read(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_unplugged(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_update_temp(chsm_tst *self, const cevent_tst *e_pst); + +void send_offline_event(chsm_tst *self, const cevent_tst *e_pst); + +void send_online_event(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func); +extern char {{cookiecutter.module_name}}_debug_state_ac[20]; + +bool {{cookiecutter.module_name}}_id_match(chsm_tst *self, const cevent_tst *e_pst); + +bool {{cookiecutter.module_name}}_wait_cnt(chsm_tst *self, const cevent_tst *e_pst); + +typedef enum {{cookiecutter.module_name}}_state_id_ten +{ + S_READ_ID_REG = 4, + S_UNPLUGGED = 5, + S_SET_RESOLUTION = 6, + S_RESET_PTR_REG = 7, + S_IDLE = 8, + S_READING = 9, + S_POWER_DOWN = 10, + S_POWER_UP = 11, + S_WAIT_POWER_DOWN = 12, + S_WAIT_POWER_UP = 13, +} {{cookiecutter.module_name}}_state_id_ten; + + +/* +Signals: + SIG_I2C_RESULT_ADDR_NACK + SIG_I2C_RESULT_DATA_NACK + SIG_I2C_RESULT_SUCCESS + SIG_{{cookiecutter.module_name|upper}}_READ + SIG_SYS_TICK_10ms +*/ + +/* +Other function notes: + +{{cookiecutter.module_name}}_error_count: + +{{cookiecutter.module_name}}_timeout: +*/ +#endif diff --git a/gui/js_gen/module_template/_template/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c b/gui/js_gen/module_template/_template/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c new file mode 100644 index 00000000..fe87e9b7 --- /dev/null +++ b/gui/js_gen/module_template/_template/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c @@ -0,0 +1,449 @@ +/*Generated with CHSM v0.0.0 at 2023.07.31 10.25.58*/ +#include "cevent.h" +#include "chsm.h" +#include +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_functions.h" + + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst); +char {{cookiecutter.module_name}}_debug_state_ac[20]; + +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + if({{cookiecutter.module_name}}_id_match(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + break; + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_online_event(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_{{cookiecutter.module_name|upper}}_READ: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_{{cookiecutter.module_name|upper}}_READ", __FUNCTION__); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_update_temp(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_down); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +chsm_result_ten {{cookiecutter.module_name}}_top(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case C_SIG_INIT: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "C_SIG_INIT", __FUNCTION__); + {{cookiecutter.module_name}}_init(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func) +{ + #ifdef CHSM_BUILD_TESTS + printf("{{cookiecutter.module_name}}_%s --%s-->\n", state_func, trans_name); + #else + CRF_UNUSED(self); + CRF_UNUSED(est); + CRF_UNUSED(trans_name); + CRF_UNUSED(state_func); + memset({{cookiecutter.module_name}}_debug_state_ac, 0, 20); + strncpy({{cookiecutter.module_name}}_debug_state_ac, state_func, 19); + {{cookiecutter.module_name}}_debug_state_ac[19] = '\0'; + #endif +} diff --git a/gui/js_gen/module_template/_template_new/cookiecutter.json b/gui/js_gen/module_template/_template_new/cookiecutter.json new file mode 100644 index 00000000..ca97641d --- /dev/null +++ b/gui/js_gen/module_template/_template_new/cookiecutter.json @@ -0,0 +1,15 @@ +{ + "module_name": "name", + "version": "", + "description": "", + "module_location": "", + "module_linked_libs": "", + "module_package_name": "", + "module_functions": "", + "module_includes": "", + "comm_periph": "i2c", + "address":"0x00", + "author":"author", + "full_name":"name_full", + "licence":"MIT" +} \ No newline at end of file diff --git a/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/CMakeLists.txt b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/CMakeLists.txt new file mode 100644 index 00000000..fb4fc886 --- /dev/null +++ b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/CMakeLists.txt @@ -0,0 +1,26 @@ + +add_module_lib( + NAME + {{cookiecutter.module_name}} + PACKAGE + chsm + SOURCE + src/{{cookiecutter.module_name}}.c + src/{{cookiecutter.module_name}}_functions.c + INCLUDE + inc + LINK + {% if cookiecutter.comm_periph == "i2c" %} + chsm::i2c_master + {% elif cookiecutter.comm_periph == "spi" %} + chsm::spi_master + {% elif cookiecutter.comm_periph == "can" %} + chsm::canopen + {% else %} + {% endif %} + signal_classes_modules + DEFINES + NDEBUG + STANDARD + 11 +) \ No newline at end of file diff --git a/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/doc/{{cookiecutter.module_name}}.html b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/doc/{{cookiecutter.module_name}}.html new file mode 100644 index 00000000..84fd9830 --- /dev/null +++ b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/doc/{{cookiecutter.module_name}}.html @@ -0,0 +1,2493 @@ + + + + + + +
+ + + + + + SIG_I2C_RESULT_SUCCESS[{{cookiecutter.module_name}}_wait_cnt()]SIG_I2C_RESULT_SUCCESS[{{cookiecutter.module_name}}_wait_cnt()]SIG_I2C_RESULT_SUCCESSSIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_SUCCESS/ {{cookiecutter.module_name}}_update_temp()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_reset_timer()SIG_{{cookiecutter.module_name|upper}}_READSIG_I2C_RESULT_SUCCESS[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]SIG_I2C_RESULT_SUCCESS [{{cookiecutter.module_name}}_id_match()][{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)]/ {{cookiecutter.module_name}}_reset_timer()SIG_I2C_RESULT_DATA_NACKSIG_I2C_RESULT_ADDR_NACK[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)] + __top__s_{{cookiecutter.module_name}}entry/ {{cookiecutter.module_name}}_init()SIG_SYS_TICK_10ms/ {{cookiecutter.module_name}}_10ms_callback()s_initentry/ {{cookiecutter.module_name}}_reset_error_cnt()s_configentry/ {{cookiecutter.module_name}}_reset_timer()s_onlineentry/ send_online_event()exit/ send_offline_event()s_read_id_regentry/ {{cookiecutter.module_name}}_read_id()exit/ {{cookiecutter.module_name}}_reset_timer()s_unpluggedentry/ {{cookiecutter.module_name}}_unplugged()s_set_resolutionentry/ {{cookiecutter.module_name}}_set_resolution()exit/ {{cookiecutter.module_name}}_reset_timer()s_reset_ptr_regentry/ {{cookiecutter.module_name}}_reset_pointer()exit/ {{cookiecutter.module_name}}_reset_timer()s_idleinit/ {{cookiecutter.module_name}}_reset_timer()entry/ {{cookiecutter.module_name}}_reset_timer()s_readingentry/ {{cookiecutter.module_name}}_start_read()exit/ {{cookiecutter.module_name}}_reset_timer()s_power_downentry/ {{cookiecutter.module_name}}_set_full_powerdown()exit/ {{cookiecutter.module_name}}_reset_timer()s_power_upentry/ {{cookiecutter.module_name}}_set_full_powerup()exit/ {{cookiecutter.module_name}}_reset_timer()s_wait_power_downinit/ {{cookiecutter.module_name}}_init_wait()s_wait_power_upinit/ {{cookiecutter.module_name}}_init_wait() + + +
+ +
+ json +
+            {
+    "states": {
+        "__top__": {
+            "pos": [
+                -100000000,
+                -100000000
+            ],
+            "size": [
+                200000000,
+                200000000
+            ],
+            "title": "__top__",
+            "text": [],
+            "connectors": [],
+            "parent": null,
+            "children": [
+                "istate_0",
+                "state_0"
+            ],
+            "type": "top"
+        },
+        "istate_0": {
+            "pos": [
+                51,
+                9
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_0",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_0"
+            ],
+            "parent": "__top__",
+            "children": [],
+            "type": "initial"
+        },
+        "state_0": {
+            "pos": [
+                5,
+                14
+            ],
+            "size": [
+                111,
+                166
+            ],
+            "title": "s_{{cookiecutter.module_name}}",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_init()",
+                "SIG_SYS_TICK_10ms/ {{cookiecutter.module_name}}_10ms_callback()"
+            ],
+            "connectors": [
+                "conn_1",
+                "conn_17",
+                "conn_51"
+            ],
+            "parent": "__top__",
+            "children": [
+                "state_1",
+                "state_2",
+                "state_3",
+                "istate_1"
+            ],
+            "type": "normal"
+        },
+        "state_1": {
+            "pos": [
+                10,
+                28
+            ],
+            "size": [
+                91,
+                24
+            ],
+            "title": "s_init",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_reset_error_cnt()"
+            ],
+            "connectors": [
+                "conn_3"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_4",
+                "state_5",
+                "istate_2"
+            ],
+            "type": "normal"
+        },
+        "state_2": {
+            "pos": [
+                24,
+                56
+            ],
+            "size": [
+                89,
+                79
+            ],
+            "title": "s_config",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_15",
+                "conn_50"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_6",
+                "state_7",
+                "istate_3",
+                "state_10",
+                "state_11",
+                "state_12",
+                "state_13"
+            ],
+            "type": "normal"
+        },
+        "state_3": {
+            "pos": [
+                11,
+                146
+            ],
+            "size": [
+                86,
+                29
+            ],
+            "title": "s_online",
+            "text": [
+                "entry/ send_online_event()",
+                "exit/ send_offline_event()"
+            ],
+            "connectors": [
+                "conn_16",
+                "conn_23"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_8",
+                "state_9",
+                "istate_4"
+            ],
+            "type": "normal"
+        },
+        "istate_1": {
+            "pos": [
+                12,
+                24
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_1",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_2"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "initial"
+        },
+        "state_4": {
+            "pos": [
+                15,
+                35
+            ],
+            "size": [
+                16,
+                15
+            ],
+            "title": "s_read_id_reg",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_read_id()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_5",
+                "conn_6",
+                "conn_8",
+                "conn_10",
+                "conn_13",
+                "conn_14"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "normal"
+        },
+        "state_5": {
+            "pos": [
+                75,
+                35
+            ],
+            "size": [
+                17,
+                13
+            ],
+            "title": "s_unplugged",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_unplugged()"
+            ],
+            "connectors": [
+                "conn_7",
+                "conn_9",
+                "conn_11",
+                "conn_12"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_2": {
+            "pos": [
+                12,
+                36
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_2",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_4"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "initial"
+        },
+        "state_6": {
+            "pos": [
+                52,
+                84
+            ],
+            "size": [
+                18,
+                12
+            ],
+            "title": "s_set_resolution",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_set_resolution()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_38",
+                "conn_39",
+                "conn_40",
+                "conn_41",
+                "conn_42",
+                "conn_43",
+                "conn_71",
+                "conn_62"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_7": {
+            "pos": [
+                53,
+                118
+            ],
+            "size": [
+                17,
+                12
+            ],
+            "title": "s_reset_ptr_reg",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_reset_pointer()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_22",
+                "conn_44",
+                "conn_45",
+                "conn_46",
+                "conn_47",
+                "conn_48",
+                "conn_49",
+                "conn_65"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_3": {
+            "pos": [
+                33,
+                63
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_3",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_66"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "initial"
+        },
+        "state_8": {
+            "pos": [
+                16,
+                156
+            ],
+            "size": [
+                15,
+                18
+            ],
+            "title": "s_idle",
+            "text": [
+                "init/ {{cookiecutter.module_name}}_reset_timer()",
+                "entry/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_26",
+                "conn_28",
+                "conn_31",
+                "conn_33",
+                "conn_35",
+                "conn_37"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "normal"
+        },
+        "state_9": {
+            "pos": [
+                71,
+                156
+            ],
+            "size": [
+                15,
+                17
+            ],
+            "title": "s_reading",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_start_read()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_25",
+                "conn_27",
+                "conn_29",
+                "conn_30",
+                "conn_32",
+                "conn_34",
+                "conn_36"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_4": {
+            "pos": [
+                92,
+                155
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_4",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_24"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "initial"
+        },
+        "state_10": {
+            "pos": [
+                54,
+                66
+            ],
+            "size": [
+                20,
+                12
+            ],
+            "title": "s_power_down",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_set_full_powerdown()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_18",
+                "conn_19",
+                "conn_20",
+                "conn_21",
+                "conn_52",
+                "conn_53",
+                "conn_60",
+                "conn_67"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_11": {
+            "pos": [
+                52,
+                102
+            ],
+            "size": [
+                20,
+                9
+            ],
+            "title": "s_power_up",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_set_full_powerup()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_54",
+                "conn_55",
+                "conn_56",
+                "conn_57",
+                "conn_58",
+                "conn_59",
+                "conn_63",
+                "conn_74"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_12": {
+            "pos": [
+                33,
+                72
+            ],
+            "size": [
+                15,
+                7
+            ],
+            "title": "s_wait_power_down",
+            "text": [
+                "init/ {{cookiecutter.module_name}}_init_wait()"
+            ],
+            "connectors": [
+                "conn_61",
+                "conn_70"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_13": {
+            "pos": [
+                33,
+                102
+            ],
+            "size": [
+                15,
+                6
+            ],
+            "title": "s_wait_power_up",
+            "text": [
+                "init/ {{cookiecutter.module_name}}_init_wait()"
+            ],
+            "connectors": [
+                "conn_64",
+                "conn_75"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        }
+    },
+    "connectors": {
+        "conn_0": {
+            "parent": "istate_0",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_0"
+        },
+        "conn_1": {
+            "parent": "state_0",
+            "offset": 46,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_0"
+        },
+        "conn_2": {
+            "parent": "istate_1",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_1"
+        },
+        "conn_3": {
+            "parent": "state_1",
+            "offset": 2,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_1"
+        },
+        "conn_4": {
+            "parent": "istate_2",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_2"
+        },
+        "conn_5": {
+            "parent": "state_4",
+            "offset": 1,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_2"
+        },
+        "conn_6": {
+            "parent": "state_4",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_3"
+        },
+        "conn_7": {
+            "parent": "state_5",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_3"
+        },
+        "conn_8": {
+            "parent": "state_4",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_4"
+        },
+        "conn_9": {
+            "parent": "state_5",
+            "offset": 4,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_4"
+        },
+        "conn_10": {
+            "parent": "state_4",
+            "offset": 6,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_5"
+        },
+        "conn_11": {
+            "parent": "state_5",
+            "offset": 6,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_5"
+        },
+        "conn_12": {
+            "parent": "state_5",
+            "offset": 11,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_6"
+        },
+        "conn_13": {
+            "parent": "state_4",
+            "offset": 11,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_6"
+        },
+        "conn_14": {
+            "parent": "state_4",
+            "offset": 5,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_7"
+        },
+        "conn_15": {
+            "parent": "state_2",
+            "offset": 3,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_7"
+        },
+        "conn_16": {
+            "parent": "state_3",
+            "offset": 3,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_8"
+        },
+        "conn_17": {
+            "parent": "state_0",
+            "offset": 128,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_8"
+        },
+        "conn_22": {
+            "parent": "state_7",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_11"
+        },
+        "conn_23": {
+            "parent": "state_3",
+            "offset": 56,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_11"
+        },
+        "conn_24": {
+            "parent": "istate_4",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_12"
+        },
+        "conn_25": {
+            "parent": "state_9",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_12"
+        },
+        "conn_26": {
+            "parent": "state_8",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_13"
+        },
+        "conn_27": {
+            "parent": "state_9",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_13"
+        },
+        "conn_28": {
+            "parent": "state_8",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_14"
+        },
+        "conn_29": {
+            "parent": "state_9",
+            "offset": 4,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_14"
+        },
+        "conn_30": {
+            "parent": "state_9",
+            "offset": 7,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_15"
+        },
+        "conn_31": {
+            "parent": "state_8",
+            "offset": 7,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_15"
+        },
+        "conn_32": {
+            "parent": "state_9",
+            "offset": 9,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_16"
+        },
+        "conn_33": {
+            "parent": "state_8",
+            "offset": 9,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_16"
+        },
+        "conn_34": {
+            "parent": "state_9",
+            "offset": 11,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_17"
+        },
+        "conn_35": {
+            "parent": "state_8",
+            "offset": 11,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_17"
+        },
+        "conn_36": {
+            "parent": "state_9",
+            "offset": 16,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_18"
+        },
+        "conn_37": {
+            "parent": "state_8",
+            "offset": 16,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_18"
+        },
+        "conn_38": {
+            "parent": "state_6",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_19"
+        },
+        "conn_39": {
+            "parent": "state_6",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_19"
+        },
+        "conn_40": {
+            "parent": "state_6",
+            "offset": 5,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_20"
+        },
+        "conn_41": {
+            "parent": "state_6",
+            "offset": 6,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_20"
+        },
+        "conn_42": {
+            "parent": "state_6",
+            "offset": 9,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_21"
+        },
+        "conn_43": {
+            "parent": "state_6",
+            "offset": 10,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_21"
+        },
+        "conn_44": {
+            "parent": "state_7",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_22"
+        },
+        "conn_45": {
+            "parent": "state_7",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_22"
+        },
+        "conn_46": {
+            "parent": "state_7",
+            "offset": 5,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_23"
+        },
+        "conn_47": {
+            "parent": "state_7",
+            "offset": 6,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_23"
+        },
+        "conn_48": {
+            "parent": "state_7",
+            "offset": 9,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_24"
+        },
+        "conn_49": {
+            "parent": "state_7",
+            "offset": 10,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_24"
+        },
+        "conn_50": {
+            "parent": "state_2",
+            "offset": 19,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_25"
+        },
+        "conn_51": {
+            "parent": "state_0",
+            "offset": 126,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_25"
+        },
+        "conn_18": {
+            "parent": "state_10",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_9"
+        },
+        "conn_19": {
+            "parent": "state_10",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_9"
+        },
+        "conn_20": {
+            "parent": "state_10",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_10"
+        },
+        "conn_21": {
+            "parent": "state_10",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_10"
+        },
+        "conn_52": {
+            "parent": "state_10",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_26"
+        },
+        "conn_53": {
+            "parent": "state_10",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_26"
+        },
+        "conn_54": {
+            "parent": "state_11",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_27"
+        },
+        "conn_55": {
+            "parent": "state_11",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_27"
+        },
+        "conn_56": {
+            "parent": "state_11",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_28"
+        },
+        "conn_57": {
+            "parent": "state_11",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_28"
+        },
+        "conn_58": {
+            "parent": "state_11",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_29"
+        },
+        "conn_59": {
+            "parent": "state_11",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_29"
+        },
+        "conn_60": {
+            "parent": "state_10",
+            "offset": 1,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_30"
+        },
+        "conn_61": {
+            "parent": "state_12",
+            "offset": 1,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_30"
+        },
+        "conn_70": {
+            "parent": "state_12",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_35"
+        },
+        "conn_71": {
+            "parent": "state_6",
+            "offset": 8,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_35"
+        },
+        "conn_62": {
+            "parent": "state_6",
+            "offset": 9,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_31"
+        },
+        "conn_63": {
+            "parent": "state_11",
+            "offset": 9,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_31"
+        },
+        "conn_64": {
+            "parent": "state_13",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_32"
+        },
+        "conn_65": {
+            "parent": "state_7",
+            "offset": 8,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_32"
+        },
+        "conn_74": {
+            "parent": "state_11",
+            "offset": 3,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_37"
+        },
+        "conn_75": {
+            "parent": "state_13",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_37"
+        },
+        "conn_66": {
+            "parent": "istate_3",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_33"
+        },
+        "conn_67": {
+            "parent": "state_10",
+            "offset": 10,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_33"
+        }
+    },
+    "transitions": {
+        "trans_0": {
+            "start": "conn_0",
+            "end": "conn_1",
+            "vertices": [
+                [
+                    51,
+                    9
+                ],
+                [
+                    51,
+                    9
+                ],
+                [
+                    51,
+                    14
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                1.5999999999999996
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                51.5,
+                10.6
+            ]
+        },
+        "trans_1": {
+            "start": "conn_2",
+            "end": "conn_3",
+            "vertices": [
+                [
+                    12,
+                    24
+                ],
+                [
+                    12,
+                    24
+                ],
+                [
+                    12,
+                    28
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                1.6000000000000014
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                12.5,
+                25.6
+            ]
+        },
+        "trans_2": {
+            "start": "conn_4",
+            "end": "conn_5",
+            "vertices": [
+                [
+                    12,
+                    36
+                ],
+                [
+                    14,
+                    36
+                ],
+                [
+                    14,
+                    36
+                ],
+                [
+                    15,
+                    36
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                2,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                14,
+                35.6
+            ]
+        },
+        "trans_3": {
+            "start": "conn_6",
+            "end": "conn_7",
+            "vertices": [
+                [
+                    31,
+                    37
+                ],
+                [
+                    51,
+                    37
+                ],
+                [
+                    51,
+                    37
+                ],
+                [
+                    75,
+                    37
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                36.6
+            ]
+        },
+        "trans_4": {
+            "start": "conn_8",
+            "end": "conn_9",
+            "vertices": [
+                [
+                    31,
+                    39
+                ],
+                [
+                    51,
+                    39
+                ],
+                [
+                    51,
+                    39
+                ],
+                [
+                    75,
+                    39
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                38.6
+            ]
+        },
+        "trans_5": {
+            "start": "conn_10",
+            "end": "conn_11",
+            "vertices": [
+                [
+                    31,
+                    41
+                ],
+                [
+                    51,
+                    41
+                ],
+                [
+                    51,
+                    41
+                ],
+                [
+                    75,
+                    41
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                40.6
+            ]
+        },
+        "trans_6": {
+            "start": "conn_12",
+            "end": "conn_13",
+            "vertices": [
+                [
+                    75,
+                    46
+                ],
+                [
+                    51,
+                    46
+                ],
+                [
+                    51,
+                    46
+                ],
+                [
+                    31,
+                    46
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)]/ {{cookiecutter.module_name}}_reset_timer()",
+            "label_offset": [
+                -11.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                39.5,
+                45.6
+            ]
+        },
+        "trans_7": {
+            "start": "conn_14",
+            "end": "conn_15",
+            "vertices": [
+                [
+                    20,
+                    50
+                ],
+                [
+                    20,
+                    59
+                ],
+                [
+                    24,
+                    59
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS [{{cookiecutter.module_name}}_id_match()]",
+            "label_offset": [
+                0.5,
+                4.700000000000003
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                20.5,
+                54.7
+            ]
+        },
+        "trans_8": {
+            "start": "conn_16",
+            "end": "conn_17",
+            "vertices": [
+                [
+                    14,
+                    146
+                ],
+                [
+                    14,
+                    142
+                ],
+                [
+                    5,
+                    142
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]",
+            "label_offset": [
+                0.5,
+                -1.8000000000000114
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                14.5,
+                144.2
+            ]
+        },
+        "trans_11": {
+            "start": "conn_22",
+            "end": "conn_23",
+            "vertices": [
+                [
+                    67,
+                    130
+                ],
+                [
+                    67,
+                    133
+                ],
+                [
+                    67,
+                    133
+                ],
+                [
+                    67,
+                    146
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                0.5,
+                10.799999999999983
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                67.5,
+                143.79999999999998
+            ]
+        },
+        "trans_12": {
+            "start": "conn_24",
+            "end": "conn_25",
+            "vertices": [
+                [
+                    92,
+                    155
+                ],
+                [
+                    90,
+                    155
+                ],
+                [
+                    90,
+                    159
+                ],
+                [
+                    86,
+                    159
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                2.5999999999999943
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                90.5,
+                157.6
+            ]
+        },
+        "trans_13": {
+            "start": "conn_26",
+            "end": "conn_27",
+            "vertices": [
+                [
+                    31,
+                    158
+                ],
+                [
+                    53,
+                    158
+                ],
+                [
+                    53,
+                    158
+                ],
+                [
+                    71,
+                    158
+                ]
+            ],
+            "label": "SIG_{{cookiecutter.module_name|upper}}_READ",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                157.6
+            ]
+        },
+        "trans_14": {
+            "start": "conn_28",
+            "end": "conn_29",
+            "vertices": [
+                [
+                    31,
+                    160
+                ],
+                [
+                    53,
+                    160
+                ],
+                [
+                    53,
+                    160
+                ],
+                [
+                    71,
+                    160
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_reset_timer()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                159.6
+            ]
+        },
+        "trans_15": {
+            "start": "conn_30",
+            "end": "conn_31",
+            "vertices": [
+                [
+                    71,
+                    163
+                ],
+                [
+                    53,
+                    163
+                ],
+                [
+                    53,
+                    163
+                ],
+                [
+                    31,
+                    163
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                -12.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                40.5,
+                162.6
+            ]
+        },
+        "trans_16": {
+            "start": "conn_32",
+            "end": "conn_33",
+            "vertices": [
+                [
+                    71,
+                    165
+                ],
+                [
+                    53,
+                    165
+                ],
+                [
+                    53,
+                    165
+                ],
+                [
+                    31,
+                    165
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                -12.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                40.5,
+                164.6
+            ]
+        },
+        "trans_17": {
+            "start": "conn_34",
+            "end": "conn_35",
+            "vertices": [
+                [
+                    71,
+                    167
+                ],
+                [
+                    53,
+                    167
+                ],
+                [
+                    53,
+                    167
+                ],
+                [
+                    31,
+                    167
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                -15.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                37.5,
+                166.6
+            ]
+        },
+        "trans_18": {
+            "start": "conn_36",
+            "end": "conn_37",
+            "vertices": [
+                [
+                    71,
+                    172
+                ],
+                [
+                    53,
+                    172
+                ],
+                [
+                    53,
+                    172
+                ],
+                [
+                    31,
+                    172
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS/ {{cookiecutter.module_name}}_update_temp()",
+            "label_offset": [
+                -9.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                43.5,
+                171.6
+            ]
+        },
+        "trans_19": {
+            "start": "conn_38",
+            "end": "conn_39",
+            "vertices": [
+                [
+                    70,
+                    86
+                ],
+                [
+                    77,
+                    86
+                ],
+                [
+                    77,
+                    87
+                ],
+                [
+                    70,
+                    87
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71,
+                85.6
+            ]
+        },
+        "trans_20": {
+            "start": "conn_40",
+            "end": "conn_41",
+            "vertices": [
+                [
+                    70,
+                    89
+                ],
+                [
+                    77,
+                    89
+                ],
+                [
+                    77,
+                    90
+                ],
+                [
+                    70,
+                    90
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                88.6
+            ]
+        },
+        "trans_21": {
+            "start": "conn_42",
+            "end": "conn_43",
+            "vertices": [
+                [
+                    70,
+                    93
+                ],
+                [
+                    77,
+                    93
+                ],
+                [
+                    77,
+                    94
+                ],
+                [
+                    70,
+                    94
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                92.6
+            ]
+        },
+        "trans_22": {
+            "start": "conn_44",
+            "end": "conn_45",
+            "vertices": [
+                [
+                    70,
+                    119
+                ],
+                [
+                    77,
+                    119
+                ],
+                [
+                    77,
+                    120
+                ],
+                [
+                    70,
+                    120
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                118.6
+            ]
+        },
+        "trans_23": {
+            "start": "conn_46",
+            "end": "conn_47",
+            "vertices": [
+                [
+                    70,
+                    123
+                ],
+                [
+                    77,
+                    123
+                ],
+                [
+                    77,
+                    124
+                ],
+                [
+                    70,
+                    124
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                122.6
+            ]
+        },
+        "trans_24": {
+            "start": "conn_48",
+            "end": "conn_49",
+            "vertices": [
+                [
+                    70,
+                    127
+                ],
+                [
+                    77,
+                    127
+                ],
+                [
+                    77,
+                    128
+                ],
+                [
+                    70,
+                    128
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                126.6
+            ]
+        },
+        "trans_25": {
+            "start": "conn_50",
+            "end": "conn_51",
+            "vertices": [
+                [
+                    43,
+                    135
+                ],
+                [
+                    43,
+                    140
+                ],
+                [
+                    16,
+                    140
+                ],
+                [
+                    5,
+                    140
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]",
+            "label_offset": [
+                -26.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                16.5,
+                139.6
+            ]
+        },
+        "trans_9": {
+            "start": "conn_18",
+            "end": "conn_19",
+            "vertices": [
+                [
+                    74,
+                    67
+                ],
+                [
+                    80,
+                    67
+                ],
+                [
+                    80,
+                    68
+                ],
+                [
+                    74,
+                    68
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                3,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                77,
+                66.6
+            ]
+        },
+        "trans_10": {
+            "start": "conn_20",
+            "end": "conn_21",
+            "vertices": [
+                [
+                    74,
+                    70
+                ],
+                [
+                    80,
+                    70
+                ],
+                [
+                    80,
+                    71
+                ],
+                [
+                    74,
+                    71
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                2,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                76,
+                69.6
+            ]
+        },
+        "trans_26": {
+            "start": "conn_52",
+            "end": "conn_53",
+            "vertices": [
+                [
+                    74,
+                    73
+                ],
+                [
+                    80,
+                    73
+                ],
+                [
+                    80,
+                    74
+                ],
+                [
+                    74,
+                    74
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                2,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                76,
+                72.6
+            ]
+        },
+        "trans_27": {
+            "start": "conn_54",
+            "end": "conn_55",
+            "vertices": [
+                [
+                    72,
+                    103
+                ],
+                [
+                    77,
+                    103
+                ],
+                [
+                    77,
+                    104
+                ],
+                [
+                    72,
+                    104
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                102.6
+            ]
+        },
+        "trans_28": {
+            "start": "conn_56",
+            "end": "conn_57",
+            "vertices": [
+                [
+                    72,
+                    106
+                ],
+                [
+                    77,
+                    106
+                ],
+                [
+                    77,
+                    107
+                ],
+                [
+                    72,
+                    107
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                105.6
+            ]
+        },
+        "trans_29": {
+            "start": "conn_58",
+            "end": "conn_59",
+            "vertices": [
+                [
+                    72,
+                    109
+                ],
+                [
+                    77,
+                    109
+                ],
+                [
+                    77,
+                    110
+                ],
+                [
+                    72,
+                    110
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                108.6
+            ]
+        },
+        "trans_30": {
+            "start": "conn_60",
+            "end": "conn_61",
+            "vertices": [
+                [
+                    54,
+                    67
+                ],
+                [
+                    34,
+                    67
+                ],
+                [
+                    34,
+                    72
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                -16.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                37.5,
+                66.6
+            ]
+        },
+        "trans_35": {
+            "start": "conn_70",
+            "end": "conn_71",
+            "vertices": [
+                [
+                    47,
+                    79
+                ],
+                [
+                    47,
+                    82
+                ],
+                [
+                    60,
+                    82
+                ],
+                [
+                    60,
+                    84
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_wait_cnt()]",
+            "label_offset": [
+                3.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                50.5,
+                81.6
+            ]
+        },
+        "trans_31": {
+            "start": "conn_62",
+            "end": "conn_63",
+            "vertices": [
+                [
+                    61,
+                    96
+                ],
+                [
+                    61,
+                    99
+                ],
+                [
+                    61,
+                    99
+                ],
+                [
+                    61,
+                    102
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                0.5,
+                1.1999999999999886
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                61.5,
+                100.19999999999999
+            ]
+        },
+        "trans_32": {
+            "start": "conn_64",
+            "end": "conn_65",
+            "vertices": [
+                [
+                    47,
+                    108
+                ],
+                [
+                    47,
+                    115
+                ],
+                [
+                    61,
+                    115
+                ],
+                [
+                    61,
+                    118
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_wait_cnt()]",
+            "label_offset": [
+                4,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                51,
+                114.6
+            ]
+        },
+        "trans_37": {
+            "start": "conn_74",
+            "end": "conn_75",
+            "vertices": [
+                [
+                    55,
+                    102
+                ],
+                [
+                    55,
+                    99
+                ],
+                [
+                    40,
+                    99
+                ],
+                [
+                    40,
+                    102
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                -14.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                40.5,
+                98.6
+            ]
+        },
+        "trans_33": {
+            "start": "conn_66",
+            "end": "conn_67",
+            "vertices": [
+                [
+                    33,
+                    63
+                ],
+                [
+                    64,
+                    63
+                ],
+                [
+                    64,
+                    66
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                14,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                47,
+                62.6
+            ]
+        }
+    },
+    "notes": {
+        "{{cookiecutter.module_name}}_timeout": "",
+        "SIG_I2C_RESULT_ADDR_NACK": "",
+        "SIG_I2C_RESULT_DATA_NACK": "",
+        "trans_7": "",
+        "SIG_I2C_RESULT_SUCCESS": "",
+        "trans_24": "",
+        "trans_23": "",
+        "trans_22": "",
+        "trans_21": "",
+        "trans_20": "",
+        "trans_19": "",
+        "trans_25": "",
+        "SIG_{{cookiecutter.module_name|upper}}_READ": "",
+        "{{cookiecutter.module_name}}_error_count": "",
+        "trans_9": "",
+        "{{cookiecutter.module_name}}_inc_wait_cnt()": "",
+        "{{cookiecutter.module_name|upper}}_RETRY_TIMEOUT": "",
+        "{{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT": ""
+    },
+    "view": {
+        "translate": [
+            132,
+            -144.5
+        ],
+        "scale": 9
+    }
+}
+        
+
+ + diff --git a/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}.h b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}.h new file mode 100644 index 00000000..09a9802f --- /dev/null +++ b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}.h @@ -0,0 +1,111 @@ +#ifndef {{cookiecutter.module_name|upper}}_H +#define {{cookiecutter.module_name|upper}}_H + +#include "crf.h" +#include "sys_if.h" +#include "i2c_driver_if.h" +#include "i2c_master.h" +#include "signal_classes_modules.h" + +/* +{{cookiecutter.module_name|upper}} driver +========== + +This module implements a high level driver for the {{cookiecutter.module_name|upper}} temperature sensor. + +Requirements for the {{cookiecutter.module_name|upper}} module: + * Read out the ID register to test the communication + * Retry the ID register reading after a timeout if the previous read failed + * Send an online event, when the link is established + * Send an offline event if the temperature read operation fails for a number of times + * Send periodic temperature events + * Allow triggered temperature reads + * Add a user defined ID into the events (so the application can differentiate between + the different {{cookiecutter.module_name|upper}} events) +*/ + +/* + * {{cookiecutter.module_name|upper}} SIGNALS + */ + +typedef enum {{cookiecutter.module_name}}_signals_ten +{ + SIG_{{cookiecutter.module_name|upper}}_TEMP = SIGNAL_FROM_CLASS(SIG_CLASS_{{cookiecutter.module_name|upper}}), + SIG_{{cookiecutter.module_name|upper}}_ONLINE, + SIG_{{cookiecutter.module_name|upper}}_OFFLINE, + SIG_{{cookiecutter.module_name|upper}}_READ +} {{cookiecutter.module_name}}_signals_ten; + +#define SIG_{{cookiecutter.module_name|upper}}_TEMP_TYPE {{cookiecutter.module_name}}_temp_tst +#define SIG_{{cookiecutter.module_name|upper}}_ONLINE_TYPE {{cookiecutter.module_name}}_status_tst +#define SIG_{{cookiecutter.module_name|upper}}_OFFLINE_TYPE {{cookiecutter.module_name}}_status_tst +#define SIG_{{cookiecutter.module_name|upper}}_READ_TYPE cevent_tst + + +/* + * EVENT DEFINITIONS + */ + +typedef struct {{cookiecutter.module_name}}_temp_tst +{ + cevent_tst super; // Signal and GC stuff + int32_t temp_C_i32; // Temperature + uint16_t id_u16; // Sensor ID +} {{cookiecutter.module_name}}_temp_tst; + +typedef struct {{cookiecutter.module_name}}_status_tst +{ + cevent_tst super; // Signal and GC stuff + uint16_t id_u16; // Sensor ID +} {{cookiecutter.module_name}}_status_tst; + +/* + * ACTIVE OBJECT + */ + +typedef struct {{cookiecutter.module_name}}_cfg_tst +{ + uint16_t id_u16; // This ID will be inserted into temperature events + uint16_t period_ms_u16; // Temperature read period in ms + uint16_t max_error_cnt_u16; // Number of times the module is allowed to fail a read operation before going offline + uint8_t address_u8; // I2C slave address of the sensor +} {{cookiecutter.module_name}}_cfg_tst; + +typedef struct {{cookiecutter.module_name}}_tst {{cookiecutter.module_name}}_tst; + +struct {{cookiecutter.module_name}}_tst +{ + /* PUBLIC */ + chsm_tst super; + {{cookiecutter.module_name}}_cfg_tst config_st; + int16_t temp_C_i32; + bool valid_b; + uint16_t resolution_u16; + + /* PRIVATE */ + uint32_t counter_u32; + uint16_t error_counter_u32; + uint16_t wait_cnt_u16; + + i2c_transaction_tst t_st; + uint8_t tx_buff_au8[4]; + uint8_t rx_buff_au8[4]; +}; + +chsm_result_ten {{cookiecutter.module_name}}_top(chsm_tst *self, const cevent_tst *e_pst); + +bool {{cookiecutter.module_name}}_timeout(chsm_tst *self, const cevent_tst *e_pst, uint32_t timeout_u32); +bool {{cookiecutter.module_name}}_error_count(chsm_tst *self, const cevent_tst *e_pst, uint16_t error_cnt_threshold_u16); + + +#define {{cookiecutter.module_name|upper}}_READ_PERIOD_VALUE (100UL) +#define {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT_VALUE (20UL) +#define {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT (500UL) +#define {{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT (2000UL) +#define {{cookiecutter.module_name|upper}}_ID_REG_VALUE (0x190) +#define {{cookiecutter.module_name|upper}}_WAIT_CNT (12UL) + +#define {{cookiecutter.module_name|upper}}_READ_PERIOD ((({{cookiecutter.module_name}}_tst *)self)->config_st.period_ms_u16) +#define {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT ((({{cookiecutter.module_name}}_tst *)self)->config_st.max_error_cnt_u16) + +#endif diff --git a/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h new file mode 100644 index 00000000..2d469139 --- /dev/null +++ b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h @@ -0,0 +1,79 @@ +#ifndef {{cookiecutter.module_name|upper}}_FUNCTIONS_H +#define {{cookiecutter.module_name|upper}}_FUNCTIONS_H + +#include "{{cookiecutter.module_name}}.h" +#include "chsm.h" +#include "cevent.h" +#include + +void {{cookiecutter.module_name}}_10ms_callback(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_inc_error_counter(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_init(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_init_wait(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_read_id(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_error_cnt(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_pointer(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_timer(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_full_powerdown(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_full_powerup(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_resolution(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_start_read(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_unplugged(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_update_temp(chsm_tst *self, const cevent_tst *e_pst); + +void send_offline_event(chsm_tst *self, const cevent_tst *e_pst); + +void send_online_event(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func); +extern char {{cookiecutter.module_name}}_debug_state_ac[20]; + +bool {{cookiecutter.module_name}}_id_match(chsm_tst *self, const cevent_tst *e_pst); + +bool {{cookiecutter.module_name}}_wait_cnt(chsm_tst *self, const cevent_tst *e_pst); + +typedef enum {{cookiecutter.module_name}}_state_id_ten +{ + S_READ_ID_REG = 4, + S_UNPLUGGED = 5, + S_SET_RESOLUTION = 6, + S_RESET_PTR_REG = 7, + S_IDLE = 8, + S_READING = 9, + S_POWER_DOWN = 10, + S_POWER_UP = 11, + S_WAIT_POWER_DOWN = 12, + S_WAIT_POWER_UP = 13, +} {{cookiecutter.module_name}}_state_id_ten; + + +/* +Signals: + SIG_I2C_RESULT_ADDR_NACK + SIG_I2C_RESULT_DATA_NACK + SIG_I2C_RESULT_SUCCESS + SIG_{{cookiecutter.module_name|upper}}_READ + SIG_SYS_TICK_10ms +*/ + +/* +Other function notes: + +{{cookiecutter.module_name}}_error_count: + +{{cookiecutter.module_name}}_timeout: +*/ +#endif diff --git a/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_regs.h b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_regs.h new file mode 100644 index 00000000..9f7c864b --- /dev/null +++ b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_regs.h @@ -0,0 +1,13 @@ + +#ifndef {{cookiecutter.module_name|upper}}_REGS_H_ +#define {{cookiecutter.module_name|upper}}_REGS_H_ + +// Config reg bits + +// Control/status reg bits + +// Registers + +// Device addresses + +#endif /* {{cookiecutter.module_name|upper}}_REGS_H_ */ diff --git a/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c new file mode 100644 index 00000000..fe87e9b7 --- /dev/null +++ b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c @@ -0,0 +1,449 @@ +/*Generated with CHSM v0.0.0 at 2023.07.31 10.25.58*/ +#include "cevent.h" +#include "chsm.h" +#include +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_functions.h" + + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst); +char {{cookiecutter.module_name}}_debug_state_ac[20]; + +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + if({{cookiecutter.module_name}}_id_match(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + break; + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_online_event(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_{{cookiecutter.module_name|upper}}_READ: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_{{cookiecutter.module_name|upper}}_READ", __FUNCTION__); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_update_temp(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_down); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +chsm_result_ten {{cookiecutter.module_name}}_top(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case C_SIG_INIT: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "C_SIG_INIT", __FUNCTION__); + {{cookiecutter.module_name}}_init(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func) +{ + #ifdef CHSM_BUILD_TESTS + printf("{{cookiecutter.module_name}}_%s --%s-->\n", state_func, trans_name); + #else + CRF_UNUSED(self); + CRF_UNUSED(est); + CRF_UNUSED(trans_name); + CRF_UNUSED(state_func); + memset({{cookiecutter.module_name}}_debug_state_ac, 0, 20); + strncpy({{cookiecutter.module_name}}_debug_state_ac, state_func, 19); + {{cookiecutter.module_name}}_debug_state_ac[19] = '\0'; + #endif +} diff --git a/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}_functions.c b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}_functions.c new file mode 100644 index 00000000..01fe3c47 --- /dev/null +++ b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}_functions.c @@ -0,0 +1,317 @@ +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_regs.h" +#include "{{cookiecutter.module_name}}_functions.h" +#include "crf.h" +#include "cevent.h" +#include + +static const cevent_tst sig_reset_slave_comm_st = {.sig = SIG_I2C_RESET_SLAVE_COMM}; +static const cevent_tst sig_reset_periph_st = {.sig = SIG_I2C_RESET_SLAVE_COMM}; + +void {{cookiecutter.module_name}}_init(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->counter_u32 = 0; + self->error_counter_u32 = 0; + + self->t_st.super.sig = SIG_I2C_WR_TRANSACTION; + self->t_st.slave_addr_u16 = self->config_st.address_u8; + self->t_st.target_q_pst = (cqueue_tst *)self; + self->t_st.read_data_pu8 = self->rx_buff_au8; + self->t_st.write_data_pu8 = self->tx_buff_au8; +} + +/*Increase the timer counter.*/ +void {{cookiecutter.module_name}}_10ms_callback(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->counter_u32 += 10; +} + +/*Increase the error counter.*/ +void {{cookiecutter.module_name}}_inc_error_counter(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->error_counter_u32++; +} + +void {{cookiecutter.module_name}}_reset_error_cnt(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->error_counter_u32 = 0; +} + +/*Try to read the ID register from the {{cookiecutter.module_name|upper}} by sending a write-read transaction to the I2C master.*/ +void {{cookiecutter.module_name}}_read_id(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_WR_TRANSACTION; + self->t_st.write_cnt_u16 = 1; + self->t_st.read_cnt_u16 = 2; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_ID; + self->rx_buff_au8[0] = 0; + self->rx_buff_au8[1] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +void {{cookiecutter.module_name}}_reset_pointer(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 1; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +/*Send a SIG_{{cookiecutter.module_name|upper}}_OFFLINE event. This can be used to detect communication errors between the module and the I2C slave.*/ +void send_offline_event(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->valid_b = false; + + TYPEOF(SIG_{{cookiecutter.module_name|upper}}_OFFLINE)* offline_pst = CRF_NEW(SIG_{{cookiecutter.module_name|upper}}_OFFLINE); + + offline_pst->id_u16 = self->config_st.id_u16; + + CRF_EMIT(offline_pst); +} + +/*Send a SIG_{{cookiecutter.module_name|upper}}_ONLINE event. This can be used to detect successful initialization.*/ +void send_online_event(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->valid_b = true; + TYPEOF(SIG_{{cookiecutter.module_name|upper}}_ONLINE)* online_pst = CRF_NEW(SIG_{{cookiecutter.module_name|upper}}_ONLINE); + + online_pst->id_u16 = self->config_st.id_u16; + + CRF_EMIT(online_pst); +} + +/*Reset the timer counter.*/ +void {{cookiecutter.module_name}}_reset_timer(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->counter_u32 = 0; +} + +/*Send a read transaction to the {{cookiecutter.module_name|upper}}.*/ +void {{cookiecutter.module_name}}_start_read(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_R_TRANSACTION; + self->t_st.write_cnt_u16 = 0; + self->t_st.read_cnt_u16 = 2; + self->rx_buff_au8[0] = 0; + self->rx_buff_au8[1] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +void {{cookiecutter.module_name}}_set_full_powerdown(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 2; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CONFIG; + self->tx_buff_au8[1] = {{cookiecutter.module_name|upper}}_POWER_OFF; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} +void {{cookiecutter.module_name}}_set_full_powerup(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 2; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CONFIG; + self->tx_buff_au8[1] = {{cookiecutter.module_name|upper}}_POWER_ON; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +bool {{cookiecutter.module_name}}_wait_cnt(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + if(self->wait_cnt_u16++ >= {{cookiecutter.module_name|upper}}_WAIT_CNT) + { + self->wait_cnt_u16 = 0; + return true; + } + else + { + return false; + } +} + +bool {{cookiecutter.module_name}}_inc_wait_cnt(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + self->wait_cnt_u16++; + return false; +} + +void {{cookiecutter.module_name}}_init_wait(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; +// self->wait_cnt_u16 = 0; +} + +void {{cookiecutter.module_name}}_get_resolution(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_WR_TRANSACTION; + self->t_st.write_cnt_u16 = 1; + self->t_st.read_cnt_u16 = 1; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CTRLSTATUS; + self->rx_buff_au8[1] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +void {{cookiecutter.module_name}}_update_resolution(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + uint16_t reg_u16 = self->rx_buff_au8[0]; + {{cookiecutter.module_name}}_resolution_t resolution = {{cookiecutter.module_name|upper}}_RESOLUTION_14BIT; + + self->resolution_u16 = (reg_u16 & {{cookiecutter.module_name|upper}}_MASK_RESOLUTION) | resolution; +} + +void {{cookiecutter.module_name}}_set_resolution(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 2; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CTRLSTATUS; + self->tx_buff_au8[1] = {{cookiecutter.module_name|upper}}_RESOLUTION_14BIT; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +/*Update the temperature display and send an event with the new value.*/ +void {{cookiecutter.module_name}}_update_temp(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + {{cookiecutter.module_name}}_temp_tst* temp_pst = CRF_NEW(SIG_{{cookiecutter.module_name|upper}}_TEMP); //{{cookiecutter.module_name}}_temp_tst + + if (NULL == temp_pst) return; + + // Compile the value of the Temperature Data Register into a variable + double tdr_reg_u32 = ((((self->rx_buff_au8[0] << 8) | self->rx_buff_au8[1]) >> 2) * 0.03125); + int32_t temp_c_i32 = tdr_reg_u32*1000; + + temp_pst->super.sig = SIG_{{cookiecutter.module_name|upper}}_TEMP; + temp_pst->temp_C_i32 = temp_c_i32; + temp_pst->id_u16 = self->config_st.id_u16; + + self->temp_C_i32 = temp_c_i32; + self->valid_b = true; + + self->super.send(_self, (const cevent_tst *)temp_pst); + + if (self->error_counter_u32) + { + self->error_counter_u32--; + } +} + +/*True, if the response data is equal to 0x190. See {{cookiecutter.module_name|upper}} datasheet section: 7.5.1.7 Identification Register*/ +bool {{cookiecutter.module_name}}_id_match(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + // Compile the value of the Identification Register into a variable + uint16_t idr_reg_u16 = self->rx_buff_au8[0]; + idr_reg_u16 <<= 8; + idr_reg_u16 |= self->rx_buff_au8[1]; + + return {{cookiecutter.module_name|upper}}_ID_REG_VALUE == idr_reg_u16; +} + +/*Return true, if the error counter is greater or equal then the parameter.*/ +bool {{cookiecutter.module_name}}_error_count(chsm_tst *_self, const cevent_tst *e_pst, uint16_t error_cnt_threshold_u16) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + return self->error_counter_u32 >= error_cnt_threshold_u16; +} + +bool {{cookiecutter.module_name}}_timeout(chsm_tst *_self, const cevent_tst *e_pst, uint32_t timeout_u32) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + return self->counter_u32 >= timeout_u32; +} + +void {{cookiecutter.module_name}}_unplugged(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + CRF_EMIT(&sig_reset_slave_comm_st); +} + diff --git a/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/CMakeLists.txt b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/CMakeLists.txt new file mode 100644 index 00000000..01571020 --- /dev/null +++ b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/CMakeLists.txt @@ -0,0 +1,22 @@ + +add_module_test( + NAME + {{cookiecutter.module_name}}_test + SOURCE + tsrc/main.c + tsrc/ut_{{cookiecutter.module_name}}_test.c + INCLUDE + tinc + LINK + unity + i2c_drv_mock + {{cookiecutter.module_name}} + DEFINES + NDEBUG + CHSM_BUILD_TESTS + STANDARD + 11 +) + +set_property(TARGET {{cookiecutter.module_name}}_test PROPERTY ECLIPSE_GENERATE_SOURCE_PROJECT ON) +set_property(TARGET {{cookiecutter.module_name}}_test PROPERTY ECLIPSE_GENERATE_LINKED_RESOURCES ON) \ No newline at end of file diff --git a/modules/ltc2471/test/build/.keep b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tinc/.gitkeep similarity index 100% rename from modules/ltc2471/test/build/.keep rename to gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tinc/.gitkeep diff --git a/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/main.c b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/main.c new file mode 100644 index 00000000..9164d34f --- /dev/null +++ b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/main.c @@ -0,0 +1,24 @@ +#include +#include "unity_fixture.h" +#include "unity.h" + + +void disableInterrupts(void) +{ + +} + +void enableInterrupts(void) +{ + +} + +void run_{{cookiecutter.module_name}}_tests(void) +{ + RUN_TEST_GROUP({{cookiecutter.module_name}}); +} + +int main(int argc, const char * argv[]) +{ + return UnityMain(argc, argv, run_{{cookiecutter.module_name}}_tests); +} \ No newline at end of file diff --git a/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/ut_{{cookiecutter.module_name}}_test.c b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/ut_{{cookiecutter.module_name}}_test.c new file mode 100644 index 00000000..e98a475c --- /dev/null +++ b/gui/js_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/ut_{{cookiecutter.module_name}}_test.c @@ -0,0 +1,417 @@ +/* + * ut_{{cookiecutter.module_name}}_test.c + * + * Created on: 2020. dec. 30. + * Author: jszeman + */ + +#include +#include +#include +#include +#include +#include "unity_fixture.h" +#include "crf.h" +#include "cbits.h" +#include "ut_i2c_driver_mock.h" +#include "i2c_master.h" +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_regs.h" +#include "cevent.h" +#include "sys_if.h" + +TEST_GROUP({{cookiecutter.module_name}}); + +ut_i2c_driver_mock_tst drv_mock_st; +i2c_driver_if_tst* drv_pst = (i2c_driver_if_tst *)&drv_mock_st; + +const cevent_tst* i2c_master_events_apst[8]; +i2c_master_tst i2c_master_st; +uint8_t i2c_master_scanned_ids[127]; + +const cevent_tst* {{cookiecutter.module_name}}_events_apst[8]; +{{cookiecutter.module_name}}_tst {{cookiecutter.module_name}}_st; + + +{{cookiecutter.module_name}}_tst *self = &{{cookiecutter.module_name}}_st; // This is necessary for macros like {{cookiecutter.module_name|upper}}_READ_PERIOD to work here + +chsm_tst* hsm_apst[] = { + (chsm_tst*)(&i2c_master_st), + (chsm_tst*)(&{{cookiecutter.module_name}}_st), + NULL}; + +uint8_t pool_buff_au8[1024]; +cpool_tst pool_ast[1]; + +crf_tst crf; + +const cevent_tst* events_apst[4]; +cqueue_tst q_st; + +const cevent_tst tick_10ms_st = {.sig = SIG_SYS_TICK_10ms}; + +static void tick_ms(uint32_t tick_cnt_u32) +{ + while(tick_cnt_u32--) + { + drv_mock_st.tick(&drv_mock_st); + + CRF_POST(&tick_10ms_st, &{{cookiecutter.module_name}}_st); + + while(CRF_STEP()) + { + printf("| "); + } + } +} + +void {{cookiecutter.module_name}}_send(chsm_tst *self, const cevent_tst *e_pst) +{ + //printf("\n%s\n", __FUNCTION__); + switch(e_pst->sig) + { + case SIG_{{cookiecutter.module_name|upper}}_TEMP: + case SIG_{{cookiecutter.module_name|upper}}_ONLINE: + case SIG_{{cookiecutter.module_name|upper}}_OFFLINE: + CRF_POST(e_pst, &q_st); + break; + + default: + CRF_POST(e_pst, &i2c_master_st); + } +} + + +TEST_SETUP({{cookiecutter.module_name}}) +{ + memset(events_apst, 0, sizeof(events_apst)); + memset(&q_st, 0, sizeof(q_st)); + memset(&drv_mock_st, 0, sizeof(drv_mock_st)); + memset(&i2c_master_st, 0, sizeof(i2c_master_st)); + memset(&crf, 0, sizeof(crf)); + memset(&i2c_master_events_apst, 0, sizeof(i2c_master_events_apst)); + memset(&pool_buff_au8, 0, sizeof(pool_buff_au8)); + memset(&pool_ast, 0, sizeof(pool_ast)); + memset(&{{cookiecutter.module_name}}_st, 0, sizeof({{cookiecutter.module_name}}_st)); + + cpool_init(pool_ast+0, pool_buff_au8, 24, 16); + + cqueue_init(&q_st, events_apst, 4); + + ut_i2c_driver_mock_init(&drv_mock_st); + + i2c_master_st.config_st.driver_pst = drv_pst; + // i2c_master_st.config_st.scan_result_au8[0] = &i2c_master_scanned_ids; + chsm_ctor(&i2c_master_st.super, i2c_master_top, i2c_master_events_apst, 4, 4); + chsm_ctor(&{{cookiecutter.module_name}}_st.super, {{cookiecutter.module_name}}_top, {{cookiecutter.module_name}}_events_apst, 8, 0); + + {{cookiecutter.module_name}}_st.config_st = ({{cookiecutter.module_name}}_cfg_tst){ + .address_u8 = {{cookiecutter.module_name|upper}}_0_I2C_FLOAT, + .id_u16 = 0xabcd, + .period_ms_u16 = {{cookiecutter.module_name|upper}}_READ_PERIOD_VALUE, + .max_error_cnt_u16 = {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT_VALUE + }; + + CRF_SEND_FUNC(&{{cookiecutter.module_name}}_st) = {{cookiecutter.module_name}}_send; + + crf_init(&crf, hsm_apst, pool_ast, 1); + chsm_init((chsm_tst *)&i2c_master_st); + chsm_init((chsm_tst *)&{{cookiecutter.module_name}}_st); +} + +TEST_TEAR_DOWN({{cookiecutter.module_name}}) +{ +} + +/* + * Just call setup + */ +TEST({{cookiecutter.module_name}}, init) +{ + printf("\n%s\n", __FUNCTION__); +} + +TEST({{cookiecutter.module_name}}, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = {{cookiecutter.module_name|upper}}_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, // sensor id + 0xf3, 0x80, // -25° measured value + 0x0c, 0x80 // +25° measured value + } + }; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + +} + +/* read_temp_twice: + * Setup the mock device to send the id bytes and two temperature reading (-25 and 25) to the master. + * Check, that two temperature events were sent + */ +TEST({{cookiecutter.module_name}}, read_temp_twice) +{ + printf("\n%s\n", __FUNCTION__); + i2c_mock_slave_device_tst dev_st = { + .address_u8 = 0x12, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + + const {{cookiecutter.module_name}}_temp_tst* e_pst; + const {{cookiecutter.module_name}}_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + TEST_ASSERT(s_pst); + TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + + e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + + tick_ms(({{cookiecutter.module_name|upper}}_READ_PERIOD/10)+1); + + uint8_t expected_au8[4] = {7, 0, 0, 0}; + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); + TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); + TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + + e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +} + +/* read_id_retry: + * Check that a failed ID read will be repeated after the configured time. + */ +TEST({{cookiecutter.module_name}}, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = {{cookiecutter.module_name|upper}}_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + const {{cookiecutter.module_name}}_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + TEST_ASSERT_NULL(s_pst); + + // dev_st.address_u8 = 0x12; + + // tick_ms({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT-10); + + // s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NULL(s_pst); + + // tick_ms(10); + + // s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NOT_NULL(s_pst); + // TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); +} + +// /* read_id_retry_bad_id: +// * Check that a failed ID read will be repeated after the configured time if the data sent back +// * by the slave is not 0x190 for the first try. +// */ +// TEST({{cookiecutter.module_name}}, read_id_retry_bad_id) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x91, 0x01, 0x90, 0x0c, 0x80} +// }; + +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms(({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT-10)/10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NOT_NULL(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); +// } + +// /* go_online: +// * Check that after reading temperature data fails for more than {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST({{cookiecutter.module_name}}, go_online) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const {{cookiecutter.module_name}}_temp_tst* e_pst; +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(({{cookiecutter.module_name|upper}}_READ_PERIOD_VALUE / 10) + 1); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE({{cookiecutter.module_name}}_st.valid_b); +// } + +// /* go_offline: +// * Check that after reading temperature data fails for more than {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST({{cookiecutter.module_name}}, go_offline) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const {{cookiecutter.module_name}}_temp_tst* e_pst; +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(({{cookiecutter.module_name|upper}}_READ_PERIOD/10) + 1); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE({{cookiecutter.module_name}}_st.valid_b); + +// dev_st.address_u8 = 0x13; + +// tick_ms((({{cookiecutter.module_name|upper}}_READ_PERIOD/10) + 1) * {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT + 1); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_OFFLINE, s_pst->super.sig); + +// TEST_ASSERT_FALSE({{cookiecutter.module_name}}_st.valid_b); +// } + +// /* triggered_read: +// * Check that it is possible to trigger a read before the read period timeout elapses. +// */ +// TEST({{cookiecutter.module_name}}, triggered_read) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const cevent_tst read_event = {.sig = SIG_{{cookiecutter.module_name|upper}}_READ}; + + +// const {{cookiecutter.module_name}}_temp_tst* e_pst; +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(1); + +// CRF_POST(&read_event, &{{cookiecutter.module_name}}_st); + +// tick_ms(10); + +// uint8_t expected_au8[4] = {7, 0, 0, 0}; +// TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); +// TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); +// TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +// } + +TEST_GROUP_RUNNER({{cookiecutter.module_name}}) +{ + RUN_TEST_CASE({{cookiecutter.module_name}}, init); + RUN_TEST_CASE({{cookiecutter.module_name}}, read_id); + // RUN_TEST_CASE({{cookiecutter.module_name}}, read_temp_twice); + // RUN_TEST_CASE({{cookiecutter.module_name}}, read_id_retry); + // RUN_TEST_CASE({{cookiecutter.module_name}}, read_id_retry_bad_id); + // RUN_TEST_CASE({{cookiecutter.module_name}}, go_offline); + // RUN_TEST_CASE({{cookiecutter.module_name}}, go_online); + // RUN_TEST_CASE({{cookiecutter.module_name}}, triggered_read); +} diff --git a/gui/js_gen/module_template/_template_without_crf/cookiecutter.json b/gui/js_gen/module_template/_template_without_crf/cookiecutter.json new file mode 100644 index 00000000..635ada19 --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf/cookiecutter.json @@ -0,0 +1,3 @@ +{ + "module_name": "template" +} \ No newline at end of file diff --git a/gui/js_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h b/gui/js_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h new file mode 100644 index 00000000..93ef40a8 --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h @@ -0,0 +1,48 @@ +#ifndef PCA9554_FUNCTIONS_H +#define PCA9554_FUNCTIONS_H + +/*Generated with CHSM v0.0.0 at 2023.07.27 14.07.05*/ + +#include "pca9554.h" +#include + + +void pca9554_process_input(pca9554_tst *self); + +void pca9554_read_input(pca9554_tst *self); + +void pca9554_reset_timer(pca9554_tst *self); + +/*Start a I2C transaction to write the DIRECTION register in the slave device.*/ +void pca9554_set_direction(pca9554_tst *self); + +void pca9554_set_output(pca9554_tst *self); + +void pca9554_set_polarity(pca9554_tst *self); + + +typedef enum pca9554_state_id_ten +{ + S_PCA9554_WAIT_DIR = 1, + S_PCA9554_WAIT_POL = 2, + S_PCA9554_WAIT_OUTPUT = 3, + S_PCA9554_WAIT_READ = 4, + S_PCA9554_BACK_OFF = 5, +} pca9554_state_id_ten; + + +/* +Signals: + I2C_FAIL + I2C_SUCCESS + START_READ +*/ + +/* +Other function notes: + +pca9554_set_status: + +pca9554_timeout: +*/ +#endif diff --git a/gui/js_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c b/gui/js_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c new file mode 100644 index 00000000..28a6511c --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c @@ -0,0 +1,115 @@ +/*Generated with CHSM v0.0.1*/ +#include "pca9554.h" +#include "pca9554_functions.h" + + +static void s_pca9554_back_off(pca9554_tst *self); +static void s_pca9554_wait_read(pca9554_tst *self); +static void s_pca9554_wait_output(pca9554_tst *self); +static void s_pca9554_wait_pol(pca9554_tst *self); +static void s_pca9554_wait_dir(pca9554_tst *self); + +static void s_pca9554_wait_dir(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_polarity(self); + return pca9554_set_state(self, s_pca9554_wait_pol); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_pol(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_output(self); + return pca9554_set_state(self, s_pca9554_wait_output); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_output(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_read(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_status(self, PCA9554_READY); + pca9554_process_input(self); + break; + + case PCA9554_SIG_START_READ: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_back_off(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + if(pca9554_timeout(self, 1000)) + { + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} + +void pca9554_top(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_INIT: + pca9554_set_status(self, PCA9554_STARTING); + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} diff --git a/gui/js_gen/module_template/_template_without_crf_new/cookiecutter.json b/gui/js_gen/module_template/_template_without_crf_new/cookiecutter.json new file mode 100644 index 00000000..635ada19 --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf_new/cookiecutter.json @@ -0,0 +1,3 @@ +{ + "module_name": "template" +} \ No newline at end of file diff --git a/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/.chsm/pca9554.json b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/.chsm/pca9554.json new file mode 100644 index 00000000..35f0d37a --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/.chsm/pca9554.json @@ -0,0 +1,26 @@ +{ + "src_dir": "../src", + "doc_dir": "../doc", + + "templates": { + "init_signal": "PCA9554_SIG_INIT", + "signal_prefix": "PCA9554_SIG_", + "func_args": "self", + "func_params": "pca9554_tst *self", + "user_func_args_t": "self", + "user_func_params_t": "pca9554_tst *self", + "func_return_type": "void", + "guard_return_type": "uint16_t", + "switch_variable": "self->signal_en", + "trans_result": "pca9554_set_state(self, {target})", + "ignored_result": "", + "c_include_list": [], + "h_include_list": [""], + "top_state_name": "void\\s+(?P\\w+)\\(void\\s+\\*self,\\s+uint32_t\\s+e_u32\\)\\s*;", + "set_state_id": "" + }, + + "pca9554.h": { + "top_func": "pca9554_top" + } +} \ No newline at end of file diff --git a/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/CMakeLists.txt b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/CMakeLists.txt new file mode 100644 index 00000000..46fba169 --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/CMakeLists.txt @@ -0,0 +1,19 @@ + +add_module_lib( + NAME + lm73 + PACKAGE + chsm + SOURCE + src/lm73.c + src/lm73_functions.c + INCLUDE + inc + LINK + chsm::i2c_master + signal_classes_modules + DEFINES + NDEBUG + STANDARD + 11 +) \ No newline at end of file diff --git a/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/doc/pca9554.html b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/doc/pca9554.html new file mode 100644 index 00000000..6162916b --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/doc/pca9554.html @@ -0,0 +1,865 @@ + + + + + + +
+ + + + + + START_READ[pca9554_timeout(1000)]I2C_FAILI2C_SUCCESSI2C_SUCCESSI2C_SUCCESS + __top__s_pca9554init/ pca9554_set_status(PCA9554_STARTING)s_pca9554_wait_dirinit/ pca9554_set_direction()Start a I2C transaction to write the DIRECTION register in the slave device.s_pca9554_wait_polinit/ pca9554_set_polarity()s_pca9554_wait_outputinit/ pca9554_set_output()s_pca9554_wait_readinit/ pca9554_read_input()I2C_SUCCESS/ { pca9554_set_status(PCA9554_READY) pca9554_process_input()}s_pca9554_back_offinit/ pca9554_reset_timer()entry/ pca9554_set_status(PCA9554_NOT_FOUND) + + +
+ +
+ json +
+            {
+    "states": {
+        "__top__": {
+            "pos": [
+                -100000000,
+                -100000000
+            ],
+            "size": [
+                200000000,
+                200000000
+            ],
+            "title": "__top__",
+            "text": [],
+            "connectors": [],
+            "parent": null,
+            "children": [
+                "state_0",
+                "istate_0"
+            ],
+            "type": "top"
+        },
+        "state_0": {
+            "pos": [
+                42,
+                17
+            ],
+            "size": [
+                82,
+                73
+            ],
+            "title": "s_pca9554",
+            "text": [
+                "init/ pca9554_set_status(PCA9554_STARTING)"
+            ],
+            "connectors": [
+                "conn_1",
+                "conn_10"
+            ],
+            "parent": "__top__",
+            "children": [
+                "state_1",
+                "istate_1",
+                "state_2",
+                "state_3",
+                "state_4",
+                "state_5"
+            ],
+            "type": "normal"
+        },
+        "istate_0": {
+            "pos": [
+                55,
+                9
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_0",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_0"
+            ],
+            "parent": "__top__",
+            "children": [],
+            "type": "initial"
+        },
+        "state_1": {
+            "pos": [
+                48,
+                32
+            ],
+            "size": [
+                20,
+                6
+            ],
+            "title": "s_pca9554_wait_dir",
+            "text": [
+                "init/ pca9554_set_direction()"
+            ],
+            "connectors": [
+                "conn_3",
+                "conn_4",
+                "conn_13"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_1": {
+            "pos": [
+                55,
+                26
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_1",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_2"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "initial"
+        },
+        "state_2": {
+            "pos": [
+                48,
+                44
+            ],
+            "size": [
+                20,
+                6
+            ],
+            "title": "s_pca9554_wait_pol",
+            "text": [
+                "init/ pca9554_set_polarity()"
+            ],
+            "connectors": [
+                "conn_5",
+                "conn_6"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "state_3": {
+            "pos": [
+                48,
+                56
+            ],
+            "size": [
+                20,
+                6
+            ],
+            "title": "s_pca9554_wait_output",
+            "text": [
+                "init/ pca9554_set_output()"
+            ],
+            "connectors": [
+                "conn_7",
+                "conn_8"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "state_4": {
+            "pos": [
+                49,
+                70
+            ],
+            "size": [
+                31,
+                16
+            ],
+            "title": "s_pca9554_wait_read",
+            "text": [
+                "init/ pca9554_read_input()",
+                "I2C_SUCCESS/ {",
+                "   pca9554_set_status(PCA9554_READY)",
+                "   pca9554_process_input()",
+                "}"
+            ],
+            "connectors": [
+                "conn_9",
+                "conn_14",
+                "conn_15"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "state_5": {
+            "pos": [
+                88,
+                43
+            ],
+            "size": [
+                32,
+                8
+            ],
+            "title": "s_pca9554_back_off",
+            "text": [
+                "init/ pca9554_reset_timer()",
+                "entry/ pca9554_set_status(PCA9554_NOT_FOUND)"
+            ],
+            "connectors": [
+                "conn_11",
+                "conn_12"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        }
+    },
+    "connectors": {
+        "conn_0": {
+            "parent": "istate_0",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_0"
+        },
+        "conn_1": {
+            "parent": "state_0",
+            "offset": 13,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_0"
+        },
+        "conn_2": {
+            "parent": "istate_1",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_1"
+        },
+        "conn_3": {
+            "parent": "state_1",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_1"
+        },
+        "conn_4": {
+            "parent": "state_1",
+            "offset": 7,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_2"
+        },
+        "conn_5": {
+            "parent": "state_2",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_2"
+        },
+        "conn_6": {
+            "parent": "state_2",
+            "offset": 7,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_3"
+        },
+        "conn_7": {
+            "parent": "state_3",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_3"
+        },
+        "conn_8": {
+            "parent": "state_3",
+            "offset": 7,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_4"
+        },
+        "conn_9": {
+            "parent": "state_4",
+            "offset": 6,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_4"
+        },
+        "conn_10": {
+            "parent": "state_0",
+            "offset": 18,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_5"
+        },
+        "conn_11": {
+            "parent": "state_5",
+            "offset": 15,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_5"
+        },
+        "conn_12": {
+            "parent": "state_5",
+            "offset": 12,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_6"
+        },
+        "conn_13": {
+            "parent": "state_1",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_6"
+        },
+        "conn_14": {
+            "parent": "state_4",
+            "offset": 11,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_7"
+        },
+        "conn_15": {
+            "parent": "state_4",
+            "offset": 7,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_7"
+        }
+    },
+    "transitions": {
+        "trans_0": {
+            "start": "conn_0",
+            "end": "conn_1",
+            "vertices": [
+                [
+                    55,
+                    9
+                ],
+                [
+                    55,
+                    9
+                ],
+                [
+                    55,
+                    17
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                4.1
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                55.5,
+                13.1
+            ]
+        },
+        "trans_1": {
+            "start": "conn_2",
+            "end": "conn_3",
+            "vertices": [
+                [
+                    55,
+                    26
+                ],
+                [
+                    55,
+                    26
+                ],
+                [
+                    55,
+                    32
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                2.6000000000000014
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                55.5,
+                28.6
+            ]
+        },
+        "trans_2": {
+            "start": "conn_4",
+            "end": "conn_5",
+            "vertices": [
+                [
+                    55,
+                    38
+                ],
+                [
+                    55,
+                    43
+                ],
+                [
+                    55,
+                    43
+                ],
+                [
+                    55,
+                    44
+                ]
+            ],
+            "label": "I2C_SUCCESS",
+            "label_offset": [
+                0.5,
+                2.700000000000003
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                55.5,
+                40.7
+            ]
+        },
+        "trans_3": {
+            "start": "conn_6",
+            "end": "conn_7",
+            "vertices": [
+                [
+                    55,
+                    50
+                ],
+                [
+                    55,
+                    54
+                ],
+                [
+                    55,
+                    54
+                ],
+                [
+                    55,
+                    56
+                ]
+            ],
+            "label": "I2C_SUCCESS",
+            "label_offset": [
+                0.5,
+                2.8000000000000043
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                55.5,
+                52.800000000000004
+            ]
+        },
+        "trans_4": {
+            "start": "conn_8",
+            "end": "conn_9",
+            "vertices": [
+                [
+                    55,
+                    62
+                ],
+                [
+                    55,
+                    66
+                ],
+                [
+                    55,
+                    66
+                ],
+                [
+                    55,
+                    70
+                ]
+            ],
+            "label": "I2C_SUCCESS",
+            "label_offset": [
+                0.5,
+                3.5999999999999943
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                55.5,
+                65.6
+            ]
+        },
+        "trans_5": {
+            "start": "conn_10",
+            "end": "conn_11",
+            "vertices": [
+                [
+                    124,
+                    35
+                ],
+                [
+                    103,
+                    35
+                ],
+                [
+                    103,
+                    43
+                ]
+            ],
+            "label": "I2C_FAIL",
+            "label_offset": [
+                -19.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                104.5,
+                34.6
+            ]
+        },
+        "trans_6": {
+            "start": "conn_12",
+            "end": "conn_13",
+            "vertices": [
+                [
+                    100,
+                    43
+                ],
+                [
+                    100,
+                    35
+                ],
+                [
+                    68,
+                    35
+                ]
+            ],
+            "label": "[pca9554_timeout(1000)]",
+            "label_offset": [
+                -23.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                76.5,
+                34.6
+            ]
+        },
+        "trans_7": {
+            "start": "conn_14",
+            "end": "conn_15",
+            "vertices": [
+                [
+                    80,
+                    81
+                ],
+                [
+                    93,
+                    81
+                ],
+                [
+                    93,
+                    77
+                ],
+                [
+                    80,
+                    77
+                ]
+            ],
+            "label": "START_READ",
+            "label_offset": [
+                -10,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                83,
+                76.6
+            ]
+        }
+    },
+    "notes": {
+        "pca9554_i2c_success()": "",
+        "I2C_SUCCESS": "",
+        "pca9554_set_direction()": "Start a I2C transaction to write the DIRECTION register in the slave device.",
+        "PCA9554_SIG_I2C_FAIL": "",
+        "START_READ": ""
+    },
+    "view": {
+        "translate": [
+            -13.5,
+            -34
+        ],
+        "scale": 8.5
+    }
+}
+        
+
+ + diff --git a/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554.h b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554.h new file mode 100644 index 00000000..dc3dbf66 --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554.h @@ -0,0 +1,98 @@ +/* + * lm73.h + * + * Created on: 2015 máj. 20 + * Author: jszeman + */ + +#ifndef INC_PCA9554_H_ +#define INC_PCA9554_H_ + +#include +#include "i2cMaster.h" + +#define PCA_A0_HIGH (1<<0) +#define PCA_A0_LOW (0) + +#define PCA_A1_HIGH (1<<1) +#define PCA_A1_LOW (0) + +#define PCA_A2_HIGH (1<<2) +#define PCA_A2_LOW (0) + +enum PCA9554_STATUS { + PCA9554_READY, /**< The driver is ready for operation */ + PCA9554_BUSY, /**< The driver is in the process of reading or writing data. The in field is not valid. */ + PCA9554_NOT_FOUND, /**< The configured device did not acknowledged its address */ + PCA9554_STARTING /**< The driver is in the process of initializing the device */ +}; + +enum PCA9554_PART { + PCA9554 = 0x20, + PCA9554A = 0x38 +}; + +typedef enum pca9554_sig_ten { + PCA9554_SIG_NONE, + PCA9554_SIG_I2C_SUCCESS, + PCA9554_SIG_I2C_FAIL, + PCA9554_SIG_INIT, + PCA9554_SIG_START_READ +} pca9554_sig_ten; + +struct pca9554_config +{ + i2cMaster_h i2cH; /**< Pointer to a previously configured I2C master driver */ + enum PCA9554_PART type; /**< Exact device type. Necessary for address calculation */ + uint16_t a; /** Address pin (A0, A1, A2) configuration */ + uint16_t out; /** Initial output value */ + uint16_t polarity; /** Input pin polarity */ + uint16_t direction; /** Pin direction */ +}; + +typedef struct pca9554_t *pca9554_h; +typedef struct pca9554_t pca9554_tst; + +struct pca9554_t +{ + /* PUBLIC */ + struct pca9554_config config; + enum PCA9554_STATUS status; + + uint16_t in; + uint16_t inputChanged; + + void (*setOutput)(pca9554_h self, uint16_t o); + void (*setDirection)(pca9554_h self, uint16_t d); + void (*setPolarity)(pca9554_h self, uint16_t p); + void (*readInput)(pca9554_h self); + void (*callback_1ms)(pca9554_h self); + + /* PRIVATE */ + struct i2cTransaction_t transaction; + uint8_t wbuff[4]; + uint8_t rbuff[2]; + + pca9554_sig_ten signal_en; + pca9554_sig_ten op_en; + + uint32_t timer_u32; + uint32_t fault_cnt_u32; + + void (*sm_callback)(pca9554_tst *self); +}; + + + +void pca9554_init(pca9554_h self); +void pca9554_top(pca9554_tst *self); + +void pca9554_set_status(pca9554_tst *self, enum PCA9554_STATUS status_en); +uint16_t pca9554_timeout(pca9554_tst *self, uint32_t timeout_u32); + +static inline void pca9554_set_state(pca9554_tst *self, void (*state_pft)(pca9554_tst *self)) +{ + self->sm_callback = state_pft; +} + +#endif /* INC_PCA9554_H_ */ diff --git a/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554_functions.h b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554_functions.h new file mode 100644 index 00000000..93ef40a8 --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554_functions.h @@ -0,0 +1,48 @@ +#ifndef PCA9554_FUNCTIONS_H +#define PCA9554_FUNCTIONS_H + +/*Generated with CHSM v0.0.0 at 2023.07.27 14.07.05*/ + +#include "pca9554.h" +#include + + +void pca9554_process_input(pca9554_tst *self); + +void pca9554_read_input(pca9554_tst *self); + +void pca9554_reset_timer(pca9554_tst *self); + +/*Start a I2C transaction to write the DIRECTION register in the slave device.*/ +void pca9554_set_direction(pca9554_tst *self); + +void pca9554_set_output(pca9554_tst *self); + +void pca9554_set_polarity(pca9554_tst *self); + + +typedef enum pca9554_state_id_ten +{ + S_PCA9554_WAIT_DIR = 1, + S_PCA9554_WAIT_POL = 2, + S_PCA9554_WAIT_OUTPUT = 3, + S_PCA9554_WAIT_READ = 4, + S_PCA9554_BACK_OFF = 5, +} pca9554_state_id_ten; + + +/* +Signals: + I2C_FAIL + I2C_SUCCESS + START_READ +*/ + +/* +Other function notes: + +pca9554_set_status: + +pca9554_timeout: +*/ +#endif diff --git a/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554.c b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554.c new file mode 100644 index 00000000..28a6511c --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554.c @@ -0,0 +1,115 @@ +/*Generated with CHSM v0.0.1*/ +#include "pca9554.h" +#include "pca9554_functions.h" + + +static void s_pca9554_back_off(pca9554_tst *self); +static void s_pca9554_wait_read(pca9554_tst *self); +static void s_pca9554_wait_output(pca9554_tst *self); +static void s_pca9554_wait_pol(pca9554_tst *self); +static void s_pca9554_wait_dir(pca9554_tst *self); + +static void s_pca9554_wait_dir(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_polarity(self); + return pca9554_set_state(self, s_pca9554_wait_pol); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_pol(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_output(self); + return pca9554_set_state(self, s_pca9554_wait_output); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_output(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_read(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_status(self, PCA9554_READY); + pca9554_process_input(self); + break; + + case PCA9554_SIG_START_READ: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_back_off(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + if(pca9554_timeout(self, 1000)) + { + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} + +void pca9554_top(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_INIT: + pca9554_set_status(self, PCA9554_STARTING); + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} diff --git a/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554_functions.c b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554_functions.c new file mode 100644 index 00000000..65c4e42e --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554_functions.c @@ -0,0 +1,153 @@ +/* + * lm73.c + * + * Created on: 2015 máj. 20 + * Author: jszeman + */ + +#include +#include "i2cMaster.h" +#include "math.h" +#include "pca9554.h" + +#define PCA_REG_INPUT 0 +#define PCA_REG_OUTPUT 1 +#define PCA_REG_POLARITY 2 +#define PCA_REG_DIRECTION 3 + +static void startRegWrite(pca9554_h self) +{ + self->transaction.writeLength = 2; // write pointer byte + self->transaction.readLength = 0; + self->config.i2cH->start(self->config.i2cH, &self->transaction); + + //self->status = PCA9554_BUSY; +} + +static void setOutput(pca9554_h self, uint16_t o) +{ + self->wbuff[0] = PCA_REG_OUTPUT; + self->wbuff[1] = o; + + startRegWrite(self); +} + +static void setDirection(pca9554_h self, uint16_t d) +{ + self->wbuff[0] = PCA_REG_DIRECTION; + self->wbuff[1] = d; + + startRegWrite(self); +} + +static void setPolarity(pca9554_h self, uint16_t p) +{ + self->wbuff[0] = PCA_REG_POLARITY; + self->wbuff[1] = p; + + startRegWrite(self); +} + +static void readInput(pca9554_h self) +{ + self->wbuff[0] = PCA_REG_INPUT; + self->transaction.writeLength = 1; // write pointer byte + self->transaction.readLength = 1; + self->config.i2cH->start(self->config.i2cH, &self->transaction); + + self->status = PCA9554_BUSY; +} + +static void start_read(pca9554_h self) +{ + self->op_en = PCA9554_SIG_START_READ; +} + +static void callback(pca9554_h self) +{ + self->signal_en = PCA9554_SIG_NONE; + + switch (self->transaction.result) + { + case I2C_SUCCESS: + self->signal_en = PCA9554_SIG_I2C_SUCCESS; + self->transaction.result = I2C_NONE; + break; + + case I2C_ADDRESS_NACK: + case I2C_DATA_NACK: + self->signal_en = PCA9554_SIG_I2C_FAIL; + self->transaction.result = I2C_NONE; + self->fault_cnt_u32++; + break; + + default: + self->signal_en = self->op_en; + self->op_en = PCA9554_SIG_NONE; + } + + self->sm_callback(self); + + self->timer_u32++; +} + +void pca9554_set_status(pca9554_tst *self, enum PCA9554_STATUS status_en) +{ + self->status = status_en; +} + +void pca9554_process_input(pca9554_tst *self) +{ + self->in = self->rbuff[0]; + self->inputChanged = 1; +} + +void pca9554_read_input(pca9554_tst *self) +{ + readInput(self); +} + +void pca9554_set_direction(pca9554_tst *self) +{ + setDirection(self, self->config.direction); +} + +void pca9554_set_output(pca9554_tst *self) +{ + setOutput(self, self->config.out); +} + +void pca9554_set_polarity(pca9554_tst *self) +{ + setPolarity(self, self->config.polarity); +} + +void pca9554_reset_timer(pca9554_tst *self) +{ + self->timer_u32 = 0; +} + +uint16_t pca9554_timeout(pca9554_tst *self, uint32_t timeout_u32) +{ + return self->timer_u32 >= timeout_u32; +} + +void pca9554_init(pca9554_h self) +{ + self->setOutput = setOutput; + self->setDirection = setDirection; + self->setPolarity = setPolarity; + self->readInput = start_read; + self->callback_1ms = callback; + + self->transaction.address = self->config.type | (self->config.a & 0x07); + self->transaction.result = I2C_NONE; + self->transaction.readData = self->rbuff; + self->transaction.writeData = self->wbuff; + self->inputChanged = 0; + self->fault_cnt_u32 = 0; + + self->sm_callback = pca9554_top; + self->op_en = PCA9554_SIG_INIT; + +} diff --git a/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/CMakeLists.txt b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/CMakeLists.txt new file mode 100644 index 00000000..4b648cb6 --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/CMakeLists.txt @@ -0,0 +1,22 @@ + +add_module_test( + NAME + lm73_test + SOURCE + tsrc/main.c + tsrc/ut_lm73_test.c + INCLUDE + tinc + LINK + unity + i2c_drv_mock + lm73 + DEFINES + NDEBUG + CHSM_BUILD_TESTS + STANDARD + 11 +) + +set_property(TARGET lm73_test PROPERTY ECLIPSE_GENERATE_SOURCE_PROJECT ON) +set_property(TARGET lm73_test PROPERTY ECLIPSE_GENERATE_LINKED_RESOURCES ON) \ No newline at end of file diff --git a/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/doc/signal_classes_distribution.puml b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/doc/signal_classes_distribution.puml new file mode 100644 index 00000000..bc36d642 --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/doc/signal_classes_distribution.puml @@ -0,0 +1,32 @@ +@startuml signal_classes_distribution +scale 800 width +skinparam backgroundColor #FFEBDC +scale 1 + +skinparam cloud { + backgroundColor Olive + borderColor orange +} + +title Architecture Diagram of the CHSM package + +left to right direction + +package chsm { + package interfaces{ + rectangle signal_classes_if{ + typedef enum sig_class_ten { + SIG_CLASS_SYS = CRF_SIGNAL_CLASS_START, + SIG_CLASS_I2C_DRIVER, + SIG_CLASS_SPI_DRIVER, + SIG_CLASS_MEM, + SIG_CLASS_CAN, + SIG_APP_NAMESPACE_START, +} sig_class_ten; + } + + } +} + + +@enduml \ No newline at end of file diff --git a/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/main.c b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/main.c new file mode 100644 index 00000000..d8154db0 --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/main.c @@ -0,0 +1,24 @@ +#include +#include "unity_fixture.h" +#include "unity.h" + + +void disableInterrupts(void) +{ + +} + +void enableInterrupts(void) +{ + +} + +void run_lm73_tests(void) +{ + RUN_TEST_GROUP(lm73); +} + +int main(int argc, const char * argv[]) +{ + return UnityMain(argc, argv, run_lm73_tests); +} \ No newline at end of file diff --git a/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/ut_lm73_test.c b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/ut_lm73_test.c new file mode 100644 index 00000000..431baa94 --- /dev/null +++ b/gui/js_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/ut_lm73_test.c @@ -0,0 +1,417 @@ +/* + * ut_lm73_test.c + * + * Created on: 2020. dec. 30. + * Author: jszeman + */ + +#include +#include +#include +#include +#include +#include "unity_fixture.h" +#include "crf.h" +#include "cbits.h" +#include "ut_i2c_driver_mock.h" +#include "i2c_master.h" +#include "lm73.h" +#include "lm73_regs.h" +#include "cevent.h" +#include "sys_if.h" + +TEST_GROUP(lm73); + +ut_i2c_driver_mock_tst drv_mock_st; +i2c_driver_if_tst* drv_pst = (i2c_driver_if_tst *)&drv_mock_st; + +const cevent_tst* i2c_master_events_apst[8]; +i2c_master_tst i2c_master_st; +uint8_t i2c_master_scanned_ids[127]; + +const cevent_tst* lm73_events_apst[8]; +lm73_tst lm73_st; + + +lm73_tst *self = &lm73_st; // This is necessary for macros like LM73_READ_PERIOD to work here + +chsm_tst* hsm_apst[] = { + (chsm_tst*)(&i2c_master_st), + (chsm_tst*)(&lm73_st), + NULL}; + +uint8_t pool_buff_au8[1024]; +cpool_tst pool_ast[1]; + +crf_tst crf; + +const cevent_tst* events_apst[4]; +cqueue_tst q_st; + +const cevent_tst tick_10ms_st = {.sig = SIG_SYS_TICK_10ms}; + +static void tick_ms(uint32_t tick_cnt_u32) +{ + while(tick_cnt_u32--) + { + drv_mock_st.tick(&drv_mock_st); + + CRF_POST(&tick_10ms_st, &lm73_st); + + while(CRF_STEP()) + { + printf("| "); + } + } +} + +void lm73_send(chsm_tst *self, const cevent_tst *e_pst) +{ + //printf("\n%s\n", __FUNCTION__); + switch(e_pst->sig) + { + case SIG_LM73_TEMP: + case SIG_LM73_ONLINE: + case SIG_LM73_OFFLINE: + CRF_POST(e_pst, &q_st); + break; + + default: + CRF_POST(e_pst, &i2c_master_st); + } +} + + +TEST_SETUP(lm73) +{ + memset(events_apst, 0, sizeof(events_apst)); + memset(&q_st, 0, sizeof(q_st)); + memset(&drv_mock_st, 0, sizeof(drv_mock_st)); + memset(&i2c_master_st, 0, sizeof(i2c_master_st)); + memset(&crf, 0, sizeof(crf)); + memset(&i2c_master_events_apst, 0, sizeof(i2c_master_events_apst)); + memset(&pool_buff_au8, 0, sizeof(pool_buff_au8)); + memset(&pool_ast, 0, sizeof(pool_ast)); + memset(&lm73_st, 0, sizeof(lm73_st)); + + cpool_init(pool_ast+0, pool_buff_au8, 24, 16); + + cqueue_init(&q_st, events_apst, 4); + + ut_i2c_driver_mock_init(&drv_mock_st); + + i2c_master_st.config_st.driver_pst = drv_pst; + // i2c_master_st.config_st.scan_result_au8[0] = &i2c_master_scanned_ids; + chsm_ctor(&i2c_master_st.super, i2c_master_top, i2c_master_events_apst, 4, 4); + chsm_ctor(&lm73_st.super, lm73_top, lm73_events_apst, 8, 0); + + lm73_st.config_st = (lm73_cfg_tst){ + .address_u8 = LM73_0_I2C_FLOAT, + .id_u16 = 0xabcd, + .period_ms_u16 = LM73_READ_PERIOD_VALUE, + .max_error_cnt_u16 = LM73_MAX_ERROR_COUNT_VALUE + }; + + CRF_SEND_FUNC(&lm73_st) = lm73_send; + + crf_init(&crf, hsm_apst, pool_ast, 1); + chsm_init((chsm_tst *)&i2c_master_st); + chsm_init((chsm_tst *)&lm73_st); +} + +TEST_TEAR_DOWN(lm73) +{ +} + +/* + * Just call setup + */ +TEST(lm73, init) +{ + printf("\n%s\n", __FUNCTION__); +} + +TEST(lm73, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = LM73_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, // sensor id + 0xf3, 0x80, // -25° measured value + 0x0c, 0x80 // +25° measured value + } + }; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + +} + +/* read_temp_twice: + * Setup the mock device to send the id bytes and two temperature reading (-25 and 25) to the master. + * Check, that two temperature events were sent + */ +TEST(lm73, read_temp_twice) +{ + printf("\n%s\n", __FUNCTION__); + i2c_mock_slave_device_tst dev_st = { + .address_u8 = 0x12, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + + const lm73_temp_tst* e_pst; + const lm73_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = (lm73_status_tst*)q_st.get(&q_st); + TEST_ASSERT(s_pst); + TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + + e_pst = (lm73_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + + tick_ms((LM73_READ_PERIOD/10)+1); + + uint8_t expected_au8[4] = {7, 0, 0, 0}; + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); + TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); + TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + + e_pst = (lm73_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +} + +/* read_id_retry: + * Check that a failed ID read will be repeated after the configured time. + */ +TEST(lm73, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = LM73_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + const lm73_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = (lm73_status_tst*)q_st.get(&q_st); + TEST_ASSERT_NULL(s_pst); + + // dev_st.address_u8 = 0x12; + + // tick_ms(LM73_RETRY_TIMEOUT-10); + + // s_pst = (lm73_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NULL(s_pst); + + // tick_ms(10); + + // s_pst = (lm73_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NOT_NULL(s_pst); + // TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); +} + +// /* read_id_retry_bad_id: +// * Check that a failed ID read will be repeated after the configured time if the data sent back +// * by the slave is not 0x190 for the first try. +// */ +// TEST(lm73, read_id_retry_bad_id) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x91, 0x01, 0x90, 0x0c, 0x80} +// }; + +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms((LM73_RETRY_TIMEOUT-10)/10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NOT_NULL(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); +// } + +// /* go_online: +// * Check that after reading temperature data fails for more than LM73_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST(lm73, go_online) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const lm73_temp_tst* e_pst; +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms((LM73_READ_PERIOD_VALUE / 10) + 1); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE(lm73_st.valid_b); +// } + +// /* go_offline: +// * Check that after reading temperature data fails for more than LM73_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST(lm73, go_offline) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const lm73_temp_tst* e_pst; +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms((LM73_READ_PERIOD/10) + 1); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE(lm73_st.valid_b); + +// dev_st.address_u8 = 0x13; + +// tick_ms(((LM73_READ_PERIOD/10) + 1) * LM73_MAX_ERROR_COUNT + 1); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_OFFLINE, s_pst->super.sig); + +// TEST_ASSERT_FALSE(lm73_st.valid_b); +// } + +// /* triggered_read: +// * Check that it is possible to trigger a read before the read period timeout elapses. +// */ +// TEST(lm73, triggered_read) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const cevent_tst read_event = {.sig = SIG_LM73_READ}; + + +// const lm73_temp_tst* e_pst; +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(1); + +// CRF_POST(&read_event, &lm73_st); + +// tick_ms(10); + +// uint8_t expected_au8[4] = {7, 0, 0, 0}; +// TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); +// TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); +// TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +// } + +TEST_GROUP_RUNNER(lm73) +{ + RUN_TEST_CASE(lm73, init); + RUN_TEST_CASE(lm73, read_id); + // RUN_TEST_CASE(lm73, read_temp_twice); + // RUN_TEST_CASE(lm73, read_id_retry); + // RUN_TEST_CASE(lm73, read_id_retry_bad_id); + // RUN_TEST_CASE(lm73, go_offline); + // RUN_TEST_CASE(lm73, go_online); + // RUN_TEST_CASE(lm73, triggered_read); +} diff --git a/gui/js_gen/render.py b/gui/js_gen/render.py new file mode 100644 index 00000000..b04103b6 --- /dev/null +++ b/gui/js_gen/render.py @@ -0,0 +1,87 @@ +""" +JavaScript state machine code generator for CHSM. + +Usage: + render.py [--output=] [--class-name=] + +Generates a JavaScript (ES6) state machine class from a CHSM drawing (.html) file. +""" +import sys +import os +import json +import jinja2 +from pathlib import Path + +# Add parent directory to path for imports +sys.path.insert(0, str(Path(__file__).parent.parent)) + +from c_gen.hsm.sm_jinja import JinjaStateMachine + + +TEMPLATE_DIR = (Path(__file__).parent.parent / 'c_gen' / 'templates').resolve() +TEMPLATE_NAME = 'chsm_js_template.jinja' + + +def load_model_from_html(html_path): + """Extract the JSON model from a CHSM HTML drawing file.""" + import re + with open(html_path, 'r') as f: + content = f.read() + m = re.search(r"
\n(?P.+)
", content, re.DOTALL) + if not m: + raise ValueError(f'No JSON data found in {html_path}') + return json.loads(m.group('json')) + + +def render(model, template_params=None): + """Render a JavaScript state machine from a CHSM model dict. + + Args: + model: CHSM model dict (as parsed from the HTML drawing). + template_params: Optional dict of template parameters (e.g. class_name). + + Returns: + Generated JavaScript source code as a string. + """ + sm = JinjaStateMachine(model) + data = sm.data.copy() + data['template_params'] = template_params or {} + + # Convert sets to tuples for template compatibility + for key in list(data.keys()): + if isinstance(data[key], set): + data[key] = tuple(data[key]) + + env = jinja2.Environment( + loader=jinja2.FileSystemLoader(str(TEMPLATE_DIR)), + trim_blocks=True, + lstrip_blocks=True, + ) + template = env.get_template(TEMPLATE_NAME) + return template.render(data=data) + + +if __name__ == '__main__': + if len(sys.argv) < 2: + print(__doc__) + sys.exit(1) + + html_file = sys.argv[1] + output_file = None + class_name = 'StateMachine' + + for arg in sys.argv[2:]: + if arg.startswith('--output='): + output_file = arg.split('=', 1)[1] + elif arg.startswith('--class-name='): + class_name = arg.split('=', 1)[1] + + model = load_model_from_html(html_file) + code = render(model, template_params={'class_name': class_name}) + + if output_file: + with open(output_file, 'w') as f: + f.write(code) + print(f'Generated {output_file}') + else: + print(code) diff --git a/gui/module_generator/__init__.py b/gui/module_generator/__init__.py new file mode 100644 index 00000000..760e194d --- /dev/null +++ b/gui/module_generator/__init__.py @@ -0,0 +1 @@ +from .new_module_generator import * \ No newline at end of file diff --git a/gui/module_generator/new_module_generator.py b/gui/module_generator/new_module_generator.py new file mode 100644 index 00000000..1d9d1471 --- /dev/null +++ b/gui/module_generator/new_module_generator.py @@ -0,0 +1,82 @@ +import eel +import tkinter as tk +from tkinter.filedialog import askdirectory +from pathlib import Path +import logging +from cookiecutter.main import cookiecutter +import traceback +import webbrowser + +@eel.expose +def generate_module(name : str, + version : str, + description : str, + module_location : str, + linked_libs : str, + package_name : str, + comm_periph : str, + address : str, + author : str, + full_name : str, + licence : str, + ): + logging.info(f"Generate module: name={name}, location={module_location}") + try: + template_path = str((Path(__file__).parent / '..' / 'c_gen' / 'module_template' / '_template_new').absolute().resolve()) + logging.info(f"Template path: {template_path}") + + if not Path(template_path).exists(): + raise FileNotFoundError(f"Template directory not found: {template_path}") + + if not module_location or not module_location.strip(): + raise ValueError("Module location is required") + + output_dir = Path(module_location) + if not output_dir.exists(): + raise FileNotFoundError(f"Output directory does not exist: {module_location}") + + cookiecutter( template_path, + extra_context={ + "module_name": name, + "version": version, + "description": description, + "module_location": module_location, + "module_linked_libs": linked_libs, + "module_package_name": package_name, + "module_functions": "", + "module_includes": "", + "comm_periph": comm_periph, + "address": address, + "author": author, + "full_name": full_name, + "licence": licence + }, + output_dir=str(module_location), + no_input=True + ) + logging.info(f"Module '{name}' generated successfully at {module_location}") + eel.successful_generate() + except Exception as e: + logging.error(f"Module generation failed: {e}") + traceback.print_exc() + eel.failed_generate(str(e)) + +@eel.expose +def browse_dir_path(): + root = tk.Tk() + root.attributes("-topmost", True) + root.withdraw() + filepath = askdirectory() + root.destroy() + if not filepath: + logging.info('Directory selection canceled by user') + return + logging.info(f'User selected path: {filepath}') + eel.set_choosen_path_to_input_text(filepath) + +@eel.expose +def create_project(): + """Open the New Module dialog in a new browser tab/window.""" + # eel.show() opens a new page served by the already-running Eel server. + # Unlike eel.start(), it does not block or create a new server instance. + eel.show('new_module/new_module.html') diff --git a/modules/spi_master/test/build/.keep b/gui/py_gen/.gitkeep similarity index 100% rename from modules/spi_master/test/build/.keep rename to gui/py_gen/.gitkeep diff --git a/gui/py_gen/module_template/_template/cookiecutter.json b/gui/py_gen/module_template/_template/cookiecutter.json new file mode 100644 index 00000000..5bd70405 --- /dev/null +++ b/gui/py_gen/module_template/_template/cookiecutter.json @@ -0,0 +1,8 @@ +{ + "module_name": "template", + "comm_periph": "i2c", + "address":"0x00", + "author":"xsession", + "full_name":"Laszlo Ivanyi", + "licence":"MIT" +} \ No newline at end of file diff --git a/gui/py_gen/module_template/_template/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h b/gui/py_gen/module_template/_template/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h new file mode 100644 index 00000000..2d469139 --- /dev/null +++ b/gui/py_gen/module_template/_template/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h @@ -0,0 +1,79 @@ +#ifndef {{cookiecutter.module_name|upper}}_FUNCTIONS_H +#define {{cookiecutter.module_name|upper}}_FUNCTIONS_H + +#include "{{cookiecutter.module_name}}.h" +#include "chsm.h" +#include "cevent.h" +#include + +void {{cookiecutter.module_name}}_10ms_callback(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_inc_error_counter(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_init(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_init_wait(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_read_id(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_error_cnt(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_pointer(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_timer(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_full_powerdown(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_full_powerup(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_resolution(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_start_read(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_unplugged(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_update_temp(chsm_tst *self, const cevent_tst *e_pst); + +void send_offline_event(chsm_tst *self, const cevent_tst *e_pst); + +void send_online_event(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func); +extern char {{cookiecutter.module_name}}_debug_state_ac[20]; + +bool {{cookiecutter.module_name}}_id_match(chsm_tst *self, const cevent_tst *e_pst); + +bool {{cookiecutter.module_name}}_wait_cnt(chsm_tst *self, const cevent_tst *e_pst); + +typedef enum {{cookiecutter.module_name}}_state_id_ten +{ + S_READ_ID_REG = 4, + S_UNPLUGGED = 5, + S_SET_RESOLUTION = 6, + S_RESET_PTR_REG = 7, + S_IDLE = 8, + S_READING = 9, + S_POWER_DOWN = 10, + S_POWER_UP = 11, + S_WAIT_POWER_DOWN = 12, + S_WAIT_POWER_UP = 13, +} {{cookiecutter.module_name}}_state_id_ten; + + +/* +Signals: + SIG_I2C_RESULT_ADDR_NACK + SIG_I2C_RESULT_DATA_NACK + SIG_I2C_RESULT_SUCCESS + SIG_{{cookiecutter.module_name|upper}}_READ + SIG_SYS_TICK_10ms +*/ + +/* +Other function notes: + +{{cookiecutter.module_name}}_error_count: + +{{cookiecutter.module_name}}_timeout: +*/ +#endif diff --git a/gui/py_gen/module_template/_template/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c b/gui/py_gen/module_template/_template/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c new file mode 100644 index 00000000..fe87e9b7 --- /dev/null +++ b/gui/py_gen/module_template/_template/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c @@ -0,0 +1,449 @@ +/*Generated with CHSM v0.0.0 at 2023.07.31 10.25.58*/ +#include "cevent.h" +#include "chsm.h" +#include +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_functions.h" + + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst); +char {{cookiecutter.module_name}}_debug_state_ac[20]; + +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + if({{cookiecutter.module_name}}_id_match(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + break; + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_online_event(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_{{cookiecutter.module_name|upper}}_READ: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_{{cookiecutter.module_name|upper}}_READ", __FUNCTION__); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_update_temp(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_down); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +chsm_result_ten {{cookiecutter.module_name}}_top(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case C_SIG_INIT: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "C_SIG_INIT", __FUNCTION__); + {{cookiecutter.module_name}}_init(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func) +{ + #ifdef CHSM_BUILD_TESTS + printf("{{cookiecutter.module_name}}_%s --%s-->\n", state_func, trans_name); + #else + CRF_UNUSED(self); + CRF_UNUSED(est); + CRF_UNUSED(trans_name); + CRF_UNUSED(state_func); + memset({{cookiecutter.module_name}}_debug_state_ac, 0, 20); + strncpy({{cookiecutter.module_name}}_debug_state_ac, state_func, 19); + {{cookiecutter.module_name}}_debug_state_ac[19] = '\0'; + #endif +} diff --git a/gui/py_gen/module_template/_template_new/cookiecutter.json b/gui/py_gen/module_template/_template_new/cookiecutter.json new file mode 100644 index 00000000..ca97641d --- /dev/null +++ b/gui/py_gen/module_template/_template_new/cookiecutter.json @@ -0,0 +1,15 @@ +{ + "module_name": "name", + "version": "", + "description": "", + "module_location": "", + "module_linked_libs": "", + "module_package_name": "", + "module_functions": "", + "module_includes": "", + "comm_periph": "i2c", + "address":"0x00", + "author":"author", + "full_name":"name_full", + "licence":"MIT" +} \ No newline at end of file diff --git a/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/CMakeLists.txt b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/CMakeLists.txt new file mode 100644 index 00000000..fb4fc886 --- /dev/null +++ b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/CMakeLists.txt @@ -0,0 +1,26 @@ + +add_module_lib( + NAME + {{cookiecutter.module_name}} + PACKAGE + chsm + SOURCE + src/{{cookiecutter.module_name}}.c + src/{{cookiecutter.module_name}}_functions.c + INCLUDE + inc + LINK + {% if cookiecutter.comm_periph == "i2c" %} + chsm::i2c_master + {% elif cookiecutter.comm_periph == "spi" %} + chsm::spi_master + {% elif cookiecutter.comm_periph == "can" %} + chsm::canopen + {% else %} + {% endif %} + signal_classes_modules + DEFINES + NDEBUG + STANDARD + 11 +) \ No newline at end of file diff --git a/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/doc/{{cookiecutter.module_name}}.html b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/doc/{{cookiecutter.module_name}}.html new file mode 100644 index 00000000..84fd9830 --- /dev/null +++ b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/doc/{{cookiecutter.module_name}}.html @@ -0,0 +1,2493 @@ + + + + + + +
+ + + + + + SIG_I2C_RESULT_SUCCESS[{{cookiecutter.module_name}}_wait_cnt()]SIG_I2C_RESULT_SUCCESS[{{cookiecutter.module_name}}_wait_cnt()]SIG_I2C_RESULT_SUCCESSSIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_SUCCESS/ {{cookiecutter.module_name}}_update_temp()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_reset_timer()SIG_{{cookiecutter.module_name|upper}}_READSIG_I2C_RESULT_SUCCESS[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]SIG_I2C_RESULT_SUCCESS [{{cookiecutter.module_name}}_id_match()][{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)]/ {{cookiecutter.module_name}}_reset_timer()SIG_I2C_RESULT_DATA_NACKSIG_I2C_RESULT_ADDR_NACK[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)] + __top__s_{{cookiecutter.module_name}}entry/ {{cookiecutter.module_name}}_init()SIG_SYS_TICK_10ms/ {{cookiecutter.module_name}}_10ms_callback()s_initentry/ {{cookiecutter.module_name}}_reset_error_cnt()s_configentry/ {{cookiecutter.module_name}}_reset_timer()s_onlineentry/ send_online_event()exit/ send_offline_event()s_read_id_regentry/ {{cookiecutter.module_name}}_read_id()exit/ {{cookiecutter.module_name}}_reset_timer()s_unpluggedentry/ {{cookiecutter.module_name}}_unplugged()s_set_resolutionentry/ {{cookiecutter.module_name}}_set_resolution()exit/ {{cookiecutter.module_name}}_reset_timer()s_reset_ptr_regentry/ {{cookiecutter.module_name}}_reset_pointer()exit/ {{cookiecutter.module_name}}_reset_timer()s_idleinit/ {{cookiecutter.module_name}}_reset_timer()entry/ {{cookiecutter.module_name}}_reset_timer()s_readingentry/ {{cookiecutter.module_name}}_start_read()exit/ {{cookiecutter.module_name}}_reset_timer()s_power_downentry/ {{cookiecutter.module_name}}_set_full_powerdown()exit/ {{cookiecutter.module_name}}_reset_timer()s_power_upentry/ {{cookiecutter.module_name}}_set_full_powerup()exit/ {{cookiecutter.module_name}}_reset_timer()s_wait_power_downinit/ {{cookiecutter.module_name}}_init_wait()s_wait_power_upinit/ {{cookiecutter.module_name}}_init_wait() + + +
+ +
+ json +
+            {
+    "states": {
+        "__top__": {
+            "pos": [
+                -100000000,
+                -100000000
+            ],
+            "size": [
+                200000000,
+                200000000
+            ],
+            "title": "__top__",
+            "text": [],
+            "connectors": [],
+            "parent": null,
+            "children": [
+                "istate_0",
+                "state_0"
+            ],
+            "type": "top"
+        },
+        "istate_0": {
+            "pos": [
+                51,
+                9
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_0",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_0"
+            ],
+            "parent": "__top__",
+            "children": [],
+            "type": "initial"
+        },
+        "state_0": {
+            "pos": [
+                5,
+                14
+            ],
+            "size": [
+                111,
+                166
+            ],
+            "title": "s_{{cookiecutter.module_name}}",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_init()",
+                "SIG_SYS_TICK_10ms/ {{cookiecutter.module_name}}_10ms_callback()"
+            ],
+            "connectors": [
+                "conn_1",
+                "conn_17",
+                "conn_51"
+            ],
+            "parent": "__top__",
+            "children": [
+                "state_1",
+                "state_2",
+                "state_3",
+                "istate_1"
+            ],
+            "type": "normal"
+        },
+        "state_1": {
+            "pos": [
+                10,
+                28
+            ],
+            "size": [
+                91,
+                24
+            ],
+            "title": "s_init",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_reset_error_cnt()"
+            ],
+            "connectors": [
+                "conn_3"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_4",
+                "state_5",
+                "istate_2"
+            ],
+            "type": "normal"
+        },
+        "state_2": {
+            "pos": [
+                24,
+                56
+            ],
+            "size": [
+                89,
+                79
+            ],
+            "title": "s_config",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_15",
+                "conn_50"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_6",
+                "state_7",
+                "istate_3",
+                "state_10",
+                "state_11",
+                "state_12",
+                "state_13"
+            ],
+            "type": "normal"
+        },
+        "state_3": {
+            "pos": [
+                11,
+                146
+            ],
+            "size": [
+                86,
+                29
+            ],
+            "title": "s_online",
+            "text": [
+                "entry/ send_online_event()",
+                "exit/ send_offline_event()"
+            ],
+            "connectors": [
+                "conn_16",
+                "conn_23"
+            ],
+            "parent": "state_0",
+            "children": [
+                "state_8",
+                "state_9",
+                "istate_4"
+            ],
+            "type": "normal"
+        },
+        "istate_1": {
+            "pos": [
+                12,
+                24
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_1",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_2"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "initial"
+        },
+        "state_4": {
+            "pos": [
+                15,
+                35
+            ],
+            "size": [
+                16,
+                15
+            ],
+            "title": "s_read_id_reg",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_read_id()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_5",
+                "conn_6",
+                "conn_8",
+                "conn_10",
+                "conn_13",
+                "conn_14"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "normal"
+        },
+        "state_5": {
+            "pos": [
+                75,
+                35
+            ],
+            "size": [
+                17,
+                13
+            ],
+            "title": "s_unplugged",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_unplugged()"
+            ],
+            "connectors": [
+                "conn_7",
+                "conn_9",
+                "conn_11",
+                "conn_12"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_2": {
+            "pos": [
+                12,
+                36
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_2",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_4"
+            ],
+            "parent": "state_1",
+            "children": [],
+            "type": "initial"
+        },
+        "state_6": {
+            "pos": [
+                52,
+                84
+            ],
+            "size": [
+                18,
+                12
+            ],
+            "title": "s_set_resolution",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_set_resolution()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_38",
+                "conn_39",
+                "conn_40",
+                "conn_41",
+                "conn_42",
+                "conn_43",
+                "conn_71",
+                "conn_62"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_7": {
+            "pos": [
+                53,
+                118
+            ],
+            "size": [
+                17,
+                12
+            ],
+            "title": "s_reset_ptr_reg",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_reset_pointer()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_22",
+                "conn_44",
+                "conn_45",
+                "conn_46",
+                "conn_47",
+                "conn_48",
+                "conn_49",
+                "conn_65"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_3": {
+            "pos": [
+                33,
+                63
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_3",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_66"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "initial"
+        },
+        "state_8": {
+            "pos": [
+                16,
+                156
+            ],
+            "size": [
+                15,
+                18
+            ],
+            "title": "s_idle",
+            "text": [
+                "init/ {{cookiecutter.module_name}}_reset_timer()",
+                "entry/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_26",
+                "conn_28",
+                "conn_31",
+                "conn_33",
+                "conn_35",
+                "conn_37"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "normal"
+        },
+        "state_9": {
+            "pos": [
+                71,
+                156
+            ],
+            "size": [
+                15,
+                17
+            ],
+            "title": "s_reading",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_start_read()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_25",
+                "conn_27",
+                "conn_29",
+                "conn_30",
+                "conn_32",
+                "conn_34",
+                "conn_36"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_4": {
+            "pos": [
+                92,
+                155
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_4",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_24"
+            ],
+            "parent": "state_3",
+            "children": [],
+            "type": "initial"
+        },
+        "state_10": {
+            "pos": [
+                54,
+                66
+            ],
+            "size": [
+                20,
+                12
+            ],
+            "title": "s_power_down",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_set_full_powerdown()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_18",
+                "conn_19",
+                "conn_20",
+                "conn_21",
+                "conn_52",
+                "conn_53",
+                "conn_60",
+                "conn_67"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_11": {
+            "pos": [
+                52,
+                102
+            ],
+            "size": [
+                20,
+                9
+            ],
+            "title": "s_power_up",
+            "text": [
+                "entry/ {{cookiecutter.module_name}}_set_full_powerup()",
+                "exit/ {{cookiecutter.module_name}}_reset_timer()"
+            ],
+            "connectors": [
+                "conn_54",
+                "conn_55",
+                "conn_56",
+                "conn_57",
+                "conn_58",
+                "conn_59",
+                "conn_63",
+                "conn_74"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_12": {
+            "pos": [
+                33,
+                72
+            ],
+            "size": [
+                15,
+                7
+            ],
+            "title": "s_wait_power_down",
+            "text": [
+                "init/ {{cookiecutter.module_name}}_init_wait()"
+            ],
+            "connectors": [
+                "conn_61",
+                "conn_70"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        },
+        "state_13": {
+            "pos": [
+                33,
+                102
+            ],
+            "size": [
+                15,
+                6
+            ],
+            "title": "s_wait_power_up",
+            "text": [
+                "init/ {{cookiecutter.module_name}}_init_wait()"
+            ],
+            "connectors": [
+                "conn_64",
+                "conn_75"
+            ],
+            "parent": "state_2",
+            "children": [],
+            "type": "normal"
+        }
+    },
+    "connectors": {
+        "conn_0": {
+            "parent": "istate_0",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_0"
+        },
+        "conn_1": {
+            "parent": "state_0",
+            "offset": 46,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_0"
+        },
+        "conn_2": {
+            "parent": "istate_1",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_1"
+        },
+        "conn_3": {
+            "parent": "state_1",
+            "offset": 2,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_1"
+        },
+        "conn_4": {
+            "parent": "istate_2",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_2"
+        },
+        "conn_5": {
+            "parent": "state_4",
+            "offset": 1,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_2"
+        },
+        "conn_6": {
+            "parent": "state_4",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_3"
+        },
+        "conn_7": {
+            "parent": "state_5",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_3"
+        },
+        "conn_8": {
+            "parent": "state_4",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_4"
+        },
+        "conn_9": {
+            "parent": "state_5",
+            "offset": 4,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_4"
+        },
+        "conn_10": {
+            "parent": "state_4",
+            "offset": 6,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_5"
+        },
+        "conn_11": {
+            "parent": "state_5",
+            "offset": 6,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_5"
+        },
+        "conn_12": {
+            "parent": "state_5",
+            "offset": 11,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_6"
+        },
+        "conn_13": {
+            "parent": "state_4",
+            "offset": 11,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_6"
+        },
+        "conn_14": {
+            "parent": "state_4",
+            "offset": 5,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_7"
+        },
+        "conn_15": {
+            "parent": "state_2",
+            "offset": 3,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_7"
+        },
+        "conn_16": {
+            "parent": "state_3",
+            "offset": 3,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_8"
+        },
+        "conn_17": {
+            "parent": "state_0",
+            "offset": 128,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_8"
+        },
+        "conn_22": {
+            "parent": "state_7",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_11"
+        },
+        "conn_23": {
+            "parent": "state_3",
+            "offset": 56,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_11"
+        },
+        "conn_24": {
+            "parent": "istate_4",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_12"
+        },
+        "conn_25": {
+            "parent": "state_9",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_12"
+        },
+        "conn_26": {
+            "parent": "state_8",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_13"
+        },
+        "conn_27": {
+            "parent": "state_9",
+            "offset": 2,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_13"
+        },
+        "conn_28": {
+            "parent": "state_8",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_14"
+        },
+        "conn_29": {
+            "parent": "state_9",
+            "offset": 4,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_14"
+        },
+        "conn_30": {
+            "parent": "state_9",
+            "offset": 7,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_15"
+        },
+        "conn_31": {
+            "parent": "state_8",
+            "offset": 7,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_15"
+        },
+        "conn_32": {
+            "parent": "state_9",
+            "offset": 9,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_16"
+        },
+        "conn_33": {
+            "parent": "state_8",
+            "offset": 9,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_16"
+        },
+        "conn_34": {
+            "parent": "state_9",
+            "offset": 11,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_17"
+        },
+        "conn_35": {
+            "parent": "state_8",
+            "offset": 11,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_17"
+        },
+        "conn_36": {
+            "parent": "state_9",
+            "offset": 16,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_18"
+        },
+        "conn_37": {
+            "parent": "state_8",
+            "offset": 16,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_18"
+        },
+        "conn_38": {
+            "parent": "state_6",
+            "offset": 2,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_19"
+        },
+        "conn_39": {
+            "parent": "state_6",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_19"
+        },
+        "conn_40": {
+            "parent": "state_6",
+            "offset": 5,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_20"
+        },
+        "conn_41": {
+            "parent": "state_6",
+            "offset": 6,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_20"
+        },
+        "conn_42": {
+            "parent": "state_6",
+            "offset": 9,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_21"
+        },
+        "conn_43": {
+            "parent": "state_6",
+            "offset": 10,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_21"
+        },
+        "conn_44": {
+            "parent": "state_7",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_22"
+        },
+        "conn_45": {
+            "parent": "state_7",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_22"
+        },
+        "conn_46": {
+            "parent": "state_7",
+            "offset": 5,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_23"
+        },
+        "conn_47": {
+            "parent": "state_7",
+            "offset": 6,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_23"
+        },
+        "conn_48": {
+            "parent": "state_7",
+            "offset": 9,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_24"
+        },
+        "conn_49": {
+            "parent": "state_7",
+            "offset": 10,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_24"
+        },
+        "conn_50": {
+            "parent": "state_2",
+            "offset": 19,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_25"
+        },
+        "conn_51": {
+            "parent": "state_0",
+            "offset": 126,
+            "side": "left",
+            "dir": "in",
+            "transition": "trans_25"
+        },
+        "conn_18": {
+            "parent": "state_10",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_9"
+        },
+        "conn_19": {
+            "parent": "state_10",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_9"
+        },
+        "conn_20": {
+            "parent": "state_10",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_10"
+        },
+        "conn_21": {
+            "parent": "state_10",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_10"
+        },
+        "conn_52": {
+            "parent": "state_10",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_26"
+        },
+        "conn_53": {
+            "parent": "state_10",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_26"
+        },
+        "conn_54": {
+            "parent": "state_11",
+            "offset": 1,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_27"
+        },
+        "conn_55": {
+            "parent": "state_11",
+            "offset": 2,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_27"
+        },
+        "conn_56": {
+            "parent": "state_11",
+            "offset": 4,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_28"
+        },
+        "conn_57": {
+            "parent": "state_11",
+            "offset": 5,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_28"
+        },
+        "conn_58": {
+            "parent": "state_11",
+            "offset": 7,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_29"
+        },
+        "conn_59": {
+            "parent": "state_11",
+            "offset": 8,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_29"
+        },
+        "conn_60": {
+            "parent": "state_10",
+            "offset": 1,
+            "side": "left",
+            "dir": "out",
+            "transition": "trans_30"
+        },
+        "conn_61": {
+            "parent": "state_12",
+            "offset": 1,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_30"
+        },
+        "conn_70": {
+            "parent": "state_12",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_35"
+        },
+        "conn_71": {
+            "parent": "state_6",
+            "offset": 8,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_35"
+        },
+        "conn_62": {
+            "parent": "state_6",
+            "offset": 9,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_31"
+        },
+        "conn_63": {
+            "parent": "state_11",
+            "offset": 9,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_31"
+        },
+        "conn_64": {
+            "parent": "state_13",
+            "offset": 14,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_32"
+        },
+        "conn_65": {
+            "parent": "state_7",
+            "offset": 8,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_32"
+        },
+        "conn_74": {
+            "parent": "state_11",
+            "offset": 3,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_37"
+        },
+        "conn_75": {
+            "parent": "state_13",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_37"
+        },
+        "conn_66": {
+            "parent": "istate_3",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_33"
+        },
+        "conn_67": {
+            "parent": "state_10",
+            "offset": 10,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_33"
+        }
+    },
+    "transitions": {
+        "trans_0": {
+            "start": "conn_0",
+            "end": "conn_1",
+            "vertices": [
+                [
+                    51,
+                    9
+                ],
+                [
+                    51,
+                    9
+                ],
+                [
+                    51,
+                    14
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                1.5999999999999996
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                51.5,
+                10.6
+            ]
+        },
+        "trans_1": {
+            "start": "conn_2",
+            "end": "conn_3",
+            "vertices": [
+                [
+                    12,
+                    24
+                ],
+                [
+                    12,
+                    24
+                ],
+                [
+                    12,
+                    28
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                1.6000000000000014
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                12.5,
+                25.6
+            ]
+        },
+        "trans_2": {
+            "start": "conn_4",
+            "end": "conn_5",
+            "vertices": [
+                [
+                    12,
+                    36
+                ],
+                [
+                    14,
+                    36
+                ],
+                [
+                    14,
+                    36
+                ],
+                [
+                    15,
+                    36
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                2,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                14,
+                35.6
+            ]
+        },
+        "trans_3": {
+            "start": "conn_6",
+            "end": "conn_7",
+            "vertices": [
+                [
+                    31,
+                    37
+                ],
+                [
+                    51,
+                    37
+                ],
+                [
+                    51,
+                    37
+                ],
+                [
+                    75,
+                    37
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                36.6
+            ]
+        },
+        "trans_4": {
+            "start": "conn_8",
+            "end": "conn_9",
+            "vertices": [
+                [
+                    31,
+                    39
+                ],
+                [
+                    51,
+                    39
+                ],
+                [
+                    51,
+                    39
+                ],
+                [
+                    75,
+                    39
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                38.6
+            ]
+        },
+        "trans_5": {
+            "start": "conn_10",
+            "end": "conn_11",
+            "vertices": [
+                [
+                    31,
+                    41
+                ],
+                [
+                    51,
+                    41
+                ],
+                [
+                    51,
+                    41
+                ],
+                [
+                    75,
+                    41
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK",
+            "label_offset": [
+                1.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                40.6
+            ]
+        },
+        "trans_6": {
+            "start": "conn_12",
+            "end": "conn_13",
+            "vertices": [
+                [
+                    75,
+                    46
+                ],
+                [
+                    51,
+                    46
+                ],
+                [
+                    51,
+                    46
+                ],
+                [
+                    31,
+                    46
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)]/ {{cookiecutter.module_name}}_reset_timer()",
+            "label_offset": [
+                -11.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                39.5,
+                45.6
+            ]
+        },
+        "trans_7": {
+            "start": "conn_14",
+            "end": "conn_15",
+            "vertices": [
+                [
+                    20,
+                    50
+                ],
+                [
+                    20,
+                    59
+                ],
+                [
+                    24,
+                    59
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS [{{cookiecutter.module_name}}_id_match()]",
+            "label_offset": [
+                0.5,
+                4.700000000000003
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                20.5,
+                54.7
+            ]
+        },
+        "trans_8": {
+            "start": "conn_16",
+            "end": "conn_17",
+            "vertices": [
+                [
+                    14,
+                    146
+                ],
+                [
+                    14,
+                    142
+                ],
+                [
+                    5,
+                    142
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]",
+            "label_offset": [
+                0.5,
+                -1.8000000000000114
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                14.5,
+                144.2
+            ]
+        },
+        "trans_11": {
+            "start": "conn_22",
+            "end": "conn_23",
+            "vertices": [
+                [
+                    67,
+                    130
+                ],
+                [
+                    67,
+                    133
+                ],
+                [
+                    67,
+                    133
+                ],
+                [
+                    67,
+                    146
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                0.5,
+                10.799999999999983
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                67.5,
+                143.79999999999998
+            ]
+        },
+        "trans_12": {
+            "start": "conn_24",
+            "end": "conn_25",
+            "vertices": [
+                [
+                    92,
+                    155
+                ],
+                [
+                    90,
+                    155
+                ],
+                [
+                    90,
+                    159
+                ],
+                [
+                    86,
+                    159
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                2.5999999999999943
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                90.5,
+                157.6
+            ]
+        },
+        "trans_13": {
+            "start": "conn_26",
+            "end": "conn_27",
+            "vertices": [
+                [
+                    31,
+                    158
+                ],
+                [
+                    53,
+                    158
+                ],
+                [
+                    53,
+                    158
+                ],
+                [
+                    71,
+                    158
+                ]
+            ],
+            "label": "SIG_{{cookiecutter.module_name|upper}}_READ",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                157.6
+            ]
+        },
+        "trans_14": {
+            "start": "conn_28",
+            "end": "conn_29",
+            "vertices": [
+                [
+                    31,
+                    160
+                ],
+                [
+                    53,
+                    160
+                ],
+                [
+                    53,
+                    160
+                ],
+                [
+                    71,
+                    160
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_reset_timer()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                32.5,
+                159.6
+            ]
+        },
+        "trans_15": {
+            "start": "conn_30",
+            "end": "conn_31",
+            "vertices": [
+                [
+                    71,
+                    163
+                ],
+                [
+                    53,
+                    163
+                ],
+                [
+                    53,
+                    163
+                ],
+                [
+                    31,
+                    163
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                -12.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                40.5,
+                162.6
+            ]
+        },
+        "trans_16": {
+            "start": "conn_32",
+            "end": "conn_33",
+            "vertices": [
+                [
+                    71,
+                    165
+                ],
+                [
+                    53,
+                    165
+                ],
+                [
+                    53,
+                    165
+                ],
+                [
+                    31,
+                    165
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                -12.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                40.5,
+                164.6
+            ]
+        },
+        "trans_17": {
+            "start": "conn_34",
+            "end": "conn_35",
+            "vertices": [
+                [
+                    71,
+                    167
+                ],
+                [
+                    53,
+                    167
+                ],
+                [
+                    53,
+                    167
+                ],
+                [
+                    31,
+                    167
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_READ_PERIOD)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                -15.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                37.5,
+                166.6
+            ]
+        },
+        "trans_18": {
+            "start": "conn_36",
+            "end": "conn_37",
+            "vertices": [
+                [
+                    71,
+                    172
+                ],
+                [
+                    53,
+                    172
+                ],
+                [
+                    53,
+                    172
+                ],
+                [
+                    31,
+                    172
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS/ {{cookiecutter.module_name}}_update_temp()",
+            "label_offset": [
+                -9.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                43.5,
+                171.6
+            ]
+        },
+        "trans_19": {
+            "start": "conn_38",
+            "end": "conn_39",
+            "vertices": [
+                [
+                    70,
+                    86
+                ],
+                [
+                    77,
+                    86
+                ],
+                [
+                    77,
+                    87
+                ],
+                [
+                    70,
+                    87
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71,
+                85.6
+            ]
+        },
+        "trans_20": {
+            "start": "conn_40",
+            "end": "conn_41",
+            "vertices": [
+                [
+                    70,
+                    89
+                ],
+                [
+                    77,
+                    89
+                ],
+                [
+                    77,
+                    90
+                ],
+                [
+                    70,
+                    90
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                88.6
+            ]
+        },
+        "trans_21": {
+            "start": "conn_42",
+            "end": "conn_43",
+            "vertices": [
+                [
+                    70,
+                    93
+                ],
+                [
+                    77,
+                    93
+                ],
+                [
+                    77,
+                    94
+                ],
+                [
+                    70,
+                    94
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                92.6
+            ]
+        },
+        "trans_22": {
+            "start": "conn_44",
+            "end": "conn_45",
+            "vertices": [
+                [
+                    70,
+                    119
+                ],
+                [
+                    77,
+                    119
+                ],
+                [
+                    77,
+                    120
+                ],
+                [
+                    70,
+                    120
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                118.6
+            ]
+        },
+        "trans_23": {
+            "start": "conn_46",
+            "end": "conn_47",
+            "vertices": [
+                [
+                    70,
+                    123
+                ],
+                [
+                    77,
+                    123
+                ],
+                [
+                    77,
+                    124
+                ],
+                [
+                    70,
+                    124
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                122.6
+            ]
+        },
+        "trans_24": {
+            "start": "conn_48",
+            "end": "conn_49",
+            "vertices": [
+                [
+                    70,
+                    127
+                ],
+                [
+                    77,
+                    127
+                ],
+                [
+                    77,
+                    128
+                ],
+                [
+                    70,
+                    128
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                71.5,
+                126.6
+            ]
+        },
+        "trans_25": {
+            "start": "conn_50",
+            "end": "conn_51",
+            "vertices": [
+                [
+                    43,
+                    135
+                ],
+                [
+                    43,
+                    140
+                ],
+                [
+                    16,
+                    140
+                ],
+                [
+                    5,
+                    140
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_error_count({{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)]",
+            "label_offset": [
+                -26.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                16.5,
+                139.6
+            ]
+        },
+        "trans_9": {
+            "start": "conn_18",
+            "end": "conn_19",
+            "vertices": [
+                [
+                    74,
+                    67
+                ],
+                [
+                    80,
+                    67
+                ],
+                [
+                    80,
+                    68
+                ],
+                [
+                    74,
+                    68
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                3,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                77,
+                66.6
+            ]
+        },
+        "trans_10": {
+            "start": "conn_20",
+            "end": "conn_21",
+            "vertices": [
+                [
+                    74,
+                    70
+                ],
+                [
+                    80,
+                    70
+                ],
+                [
+                    80,
+                    71
+                ],
+                [
+                    74,
+                    71
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                2,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                76,
+                69.6
+            ]
+        },
+        "trans_26": {
+            "start": "conn_52",
+            "end": "conn_53",
+            "vertices": [
+                [
+                    74,
+                    73
+                ],
+                [
+                    80,
+                    73
+                ],
+                [
+                    80,
+                    74
+                ],
+                [
+                    74,
+                    74
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                2,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                76,
+                72.6
+            ]
+        },
+        "trans_27": {
+            "start": "conn_54",
+            "end": "conn_55",
+            "vertices": [
+                [
+                    72,
+                    103
+                ],
+                [
+                    77,
+                    103
+                ],
+                [
+                    77,
+                    104
+                ],
+                [
+                    72,
+                    104
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_timeout({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)]/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                102.6
+            ]
+        },
+        "trans_28": {
+            "start": "conn_56",
+            "end": "conn_57",
+            "vertices": [
+                [
+                    72,
+                    106
+                ],
+                [
+                    77,
+                    106
+                ],
+                [
+                    77,
+                    107
+                ],
+                [
+                    72,
+                    107
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_ADDR_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                105.6
+            ]
+        },
+        "trans_29": {
+            "start": "conn_58",
+            "end": "conn_59",
+            "vertices": [
+                [
+                    72,
+                    109
+                ],
+                [
+                    77,
+                    109
+                ],
+                [
+                    77,
+                    110
+                ],
+                [
+                    72,
+                    110
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_DATA_NACK/ {{cookiecutter.module_name}}_inc_error_counter()",
+            "label_offset": [
+                1,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                73,
+                108.6
+            ]
+        },
+        "trans_30": {
+            "start": "conn_60",
+            "end": "conn_61",
+            "vertices": [
+                [
+                    54,
+                    67
+                ],
+                [
+                    34,
+                    67
+                ],
+                [
+                    34,
+                    72
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                -16.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                37.5,
+                66.6
+            ]
+        },
+        "trans_35": {
+            "start": "conn_70",
+            "end": "conn_71",
+            "vertices": [
+                [
+                    47,
+                    79
+                ],
+                [
+                    47,
+                    82
+                ],
+                [
+                    60,
+                    82
+                ],
+                [
+                    60,
+                    84
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_wait_cnt()]",
+            "label_offset": [
+                3.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                50.5,
+                81.6
+            ]
+        },
+        "trans_31": {
+            "start": "conn_62",
+            "end": "conn_63",
+            "vertices": [
+                [
+                    61,
+                    96
+                ],
+                [
+                    61,
+                    99
+                ],
+                [
+                    61,
+                    99
+                ],
+                [
+                    61,
+                    102
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                0.5,
+                1.1999999999999886
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                61.5,
+                100.19999999999999
+            ]
+        },
+        "trans_32": {
+            "start": "conn_64",
+            "end": "conn_65",
+            "vertices": [
+                [
+                    47,
+                    108
+                ],
+                [
+                    47,
+                    115
+                ],
+                [
+                    61,
+                    115
+                ],
+                [
+                    61,
+                    118
+                ]
+            ],
+            "label": "[{{cookiecutter.module_name}}_wait_cnt()]",
+            "label_offset": [
+                4,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                51,
+                114.6
+            ]
+        },
+        "trans_37": {
+            "start": "conn_74",
+            "end": "conn_75",
+            "vertices": [
+                [
+                    55,
+                    102
+                ],
+                [
+                    55,
+                    99
+                ],
+                [
+                    40,
+                    99
+                ],
+                [
+                    40,
+                    102
+                ]
+            ],
+            "label": "SIG_I2C_RESULT_SUCCESS",
+            "label_offset": [
+                -14.5,
+                -0.4000000000000057
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                40.5,
+                98.6
+            ]
+        },
+        "trans_33": {
+            "start": "conn_66",
+            "end": "conn_67",
+            "vertices": [
+                [
+                    33,
+                    63
+                ],
+                [
+                    64,
+                    63
+                ],
+                [
+                    64,
+                    66
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                14,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                47,
+                62.6
+            ]
+        }
+    },
+    "notes": {
+        "{{cookiecutter.module_name}}_timeout": "",
+        "SIG_I2C_RESULT_ADDR_NACK": "",
+        "SIG_I2C_RESULT_DATA_NACK": "",
+        "trans_7": "",
+        "SIG_I2C_RESULT_SUCCESS": "",
+        "trans_24": "",
+        "trans_23": "",
+        "trans_22": "",
+        "trans_21": "",
+        "trans_20": "",
+        "trans_19": "",
+        "trans_25": "",
+        "SIG_{{cookiecutter.module_name|upper}}_READ": "",
+        "{{cookiecutter.module_name}}_error_count": "",
+        "trans_9": "",
+        "{{cookiecutter.module_name}}_inc_wait_cnt()": "",
+        "{{cookiecutter.module_name|upper}}_RETRY_TIMEOUT": "",
+        "{{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT": ""
+    },
+    "view": {
+        "translate": [
+            132,
+            -144.5
+        ],
+        "scale": 9
+    }
+}
+        
+
+ + diff --git a/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}.h b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}.h new file mode 100644 index 00000000..09a9802f --- /dev/null +++ b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}.h @@ -0,0 +1,111 @@ +#ifndef {{cookiecutter.module_name|upper}}_H +#define {{cookiecutter.module_name|upper}}_H + +#include "crf.h" +#include "sys_if.h" +#include "i2c_driver_if.h" +#include "i2c_master.h" +#include "signal_classes_modules.h" + +/* +{{cookiecutter.module_name|upper}} driver +========== + +This module implements a high level driver for the {{cookiecutter.module_name|upper}} temperature sensor. + +Requirements for the {{cookiecutter.module_name|upper}} module: + * Read out the ID register to test the communication + * Retry the ID register reading after a timeout if the previous read failed + * Send an online event, when the link is established + * Send an offline event if the temperature read operation fails for a number of times + * Send periodic temperature events + * Allow triggered temperature reads + * Add a user defined ID into the events (so the application can differentiate between + the different {{cookiecutter.module_name|upper}} events) +*/ + +/* + * {{cookiecutter.module_name|upper}} SIGNALS + */ + +typedef enum {{cookiecutter.module_name}}_signals_ten +{ + SIG_{{cookiecutter.module_name|upper}}_TEMP = SIGNAL_FROM_CLASS(SIG_CLASS_{{cookiecutter.module_name|upper}}), + SIG_{{cookiecutter.module_name|upper}}_ONLINE, + SIG_{{cookiecutter.module_name|upper}}_OFFLINE, + SIG_{{cookiecutter.module_name|upper}}_READ +} {{cookiecutter.module_name}}_signals_ten; + +#define SIG_{{cookiecutter.module_name|upper}}_TEMP_TYPE {{cookiecutter.module_name}}_temp_tst +#define SIG_{{cookiecutter.module_name|upper}}_ONLINE_TYPE {{cookiecutter.module_name}}_status_tst +#define SIG_{{cookiecutter.module_name|upper}}_OFFLINE_TYPE {{cookiecutter.module_name}}_status_tst +#define SIG_{{cookiecutter.module_name|upper}}_READ_TYPE cevent_tst + + +/* + * EVENT DEFINITIONS + */ + +typedef struct {{cookiecutter.module_name}}_temp_tst +{ + cevent_tst super; // Signal and GC stuff + int32_t temp_C_i32; // Temperature + uint16_t id_u16; // Sensor ID +} {{cookiecutter.module_name}}_temp_tst; + +typedef struct {{cookiecutter.module_name}}_status_tst +{ + cevent_tst super; // Signal and GC stuff + uint16_t id_u16; // Sensor ID +} {{cookiecutter.module_name}}_status_tst; + +/* + * ACTIVE OBJECT + */ + +typedef struct {{cookiecutter.module_name}}_cfg_tst +{ + uint16_t id_u16; // This ID will be inserted into temperature events + uint16_t period_ms_u16; // Temperature read period in ms + uint16_t max_error_cnt_u16; // Number of times the module is allowed to fail a read operation before going offline + uint8_t address_u8; // I2C slave address of the sensor +} {{cookiecutter.module_name}}_cfg_tst; + +typedef struct {{cookiecutter.module_name}}_tst {{cookiecutter.module_name}}_tst; + +struct {{cookiecutter.module_name}}_tst +{ + /* PUBLIC */ + chsm_tst super; + {{cookiecutter.module_name}}_cfg_tst config_st; + int16_t temp_C_i32; + bool valid_b; + uint16_t resolution_u16; + + /* PRIVATE */ + uint32_t counter_u32; + uint16_t error_counter_u32; + uint16_t wait_cnt_u16; + + i2c_transaction_tst t_st; + uint8_t tx_buff_au8[4]; + uint8_t rx_buff_au8[4]; +}; + +chsm_result_ten {{cookiecutter.module_name}}_top(chsm_tst *self, const cevent_tst *e_pst); + +bool {{cookiecutter.module_name}}_timeout(chsm_tst *self, const cevent_tst *e_pst, uint32_t timeout_u32); +bool {{cookiecutter.module_name}}_error_count(chsm_tst *self, const cevent_tst *e_pst, uint16_t error_cnt_threshold_u16); + + +#define {{cookiecutter.module_name|upper}}_READ_PERIOD_VALUE (100UL) +#define {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT_VALUE (20UL) +#define {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT (500UL) +#define {{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT (2000UL) +#define {{cookiecutter.module_name|upper}}_ID_REG_VALUE (0x190) +#define {{cookiecutter.module_name|upper}}_WAIT_CNT (12UL) + +#define {{cookiecutter.module_name|upper}}_READ_PERIOD ((({{cookiecutter.module_name}}_tst *)self)->config_st.period_ms_u16) +#define {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT ((({{cookiecutter.module_name}}_tst *)self)->config_st.max_error_cnt_u16) + +#endif diff --git a/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h new file mode 100644 index 00000000..2d469139 --- /dev/null +++ b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h @@ -0,0 +1,79 @@ +#ifndef {{cookiecutter.module_name|upper}}_FUNCTIONS_H +#define {{cookiecutter.module_name|upper}}_FUNCTIONS_H + +#include "{{cookiecutter.module_name}}.h" +#include "chsm.h" +#include "cevent.h" +#include + +void {{cookiecutter.module_name}}_10ms_callback(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_inc_error_counter(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_init(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_init_wait(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_read_id(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_error_cnt(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_pointer(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_reset_timer(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_full_powerdown(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_full_powerup(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_set_resolution(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_start_read(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_unplugged(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_update_temp(chsm_tst *self, const cevent_tst *e_pst); + +void send_offline_event(chsm_tst *self, const cevent_tst *e_pst); + +void send_online_event(chsm_tst *self, const cevent_tst *e_pst); + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func); +extern char {{cookiecutter.module_name}}_debug_state_ac[20]; + +bool {{cookiecutter.module_name}}_id_match(chsm_tst *self, const cevent_tst *e_pst); + +bool {{cookiecutter.module_name}}_wait_cnt(chsm_tst *self, const cevent_tst *e_pst); + +typedef enum {{cookiecutter.module_name}}_state_id_ten +{ + S_READ_ID_REG = 4, + S_UNPLUGGED = 5, + S_SET_RESOLUTION = 6, + S_RESET_PTR_REG = 7, + S_IDLE = 8, + S_READING = 9, + S_POWER_DOWN = 10, + S_POWER_UP = 11, + S_WAIT_POWER_DOWN = 12, + S_WAIT_POWER_UP = 13, +} {{cookiecutter.module_name}}_state_id_ten; + + +/* +Signals: + SIG_I2C_RESULT_ADDR_NACK + SIG_I2C_RESULT_DATA_NACK + SIG_I2C_RESULT_SUCCESS + SIG_{{cookiecutter.module_name|upper}}_READ + SIG_SYS_TICK_10ms +*/ + +/* +Other function notes: + +{{cookiecutter.module_name}}_error_count: + +{{cookiecutter.module_name}}_timeout: +*/ +#endif diff --git a/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_regs.h b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_regs.h new file mode 100644 index 00000000..9f7c864b --- /dev/null +++ b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_regs.h @@ -0,0 +1,13 @@ + +#ifndef {{cookiecutter.module_name|upper}}_REGS_H_ +#define {{cookiecutter.module_name|upper}}_REGS_H_ + +// Config reg bits + +// Control/status reg bits + +// Registers + +// Device addresses + +#endif /* {{cookiecutter.module_name|upper}}_REGS_H_ */ diff --git a/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c new file mode 100644 index 00000000..fe87e9b7 --- /dev/null +++ b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c @@ -0,0 +1,449 @@ +/*Generated with CHSM v0.0.0 at 2023.07.31 10.25.58*/ +#include "cevent.h" +#include "chsm.h" +#include +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_functions.h" + + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst); +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst); +char {{cookiecutter.module_name}}_debug_state_ac[20]; + +static chsm_result_ten s_read_id_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + if({{cookiecutter.module_name}}_id_match(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + break; + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_unplugged(self, e_pst); + return chsm_transition(self, s_unplugged); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_unplugged(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_UNPLUGGED_TIMEOUT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_set_resolution(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reset_ptr_reg(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_online_event(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_idle(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_{{cookiecutter.module_name|upper}}_READ: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_{{cookiecutter.module_name|upper}}_READ", __FUNCTION__); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_start_read(self, e_pst); + return chsm_transition(self, s_reading); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_reading(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_update_temp(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_READ_PERIOD)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + return chsm_transition(self, s_idle); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + send_offline_event(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_down); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerdown(self, e_pst); + return chsm_transition(self, s_power_down); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_I2C_RESULT_ADDR_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_ADDR_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_DATA_NACK: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_DATA_NACK", __FUNCTION__); + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + + case SIG_I2C_RESULT_SUCCESS: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_I2C_RESULT_SUCCESS", __FUNCTION__); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_init_wait(self, e_pst); + return chsm_transition(self, s_wait_power_up); + + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_timeout(self, e_pst, {{cookiecutter.module_name|upper}}_RETRY_TIMEOUT)) + { + {{cookiecutter.module_name}}_inc_error_counter(self, e_pst); + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_set_full_powerup(self, e_pst); + return chsm_transition(self, s_power_up); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_timer(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_down(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_set_resolution(self, e_pst); + return chsm_transition(self, s_set_resolution); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +static chsm_result_ten s_wait_power_up(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case SIG_SYS_TICK_10ms: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "SIG_SYS_TICK_10ms", __FUNCTION__); + {{cookiecutter.module_name}}_10ms_callback(self, e_pst); + break; + } + + if({{cookiecutter.module_name}}_wait_cnt(self, e_pst)) + { + {{cookiecutter.module_name}}_reset_pointer(self, e_pst); + return chsm_transition(self, s_reset_ptr_reg); + } + + if({{cookiecutter.module_name}}_error_count(self, e_pst, {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT)) + { + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +chsm_result_ten {{cookiecutter.module_name}}_top(chsm_tst *self, const cevent_tst *e_pst) +{ + switch(e_pst->sig) + { + case C_SIG_INIT: + {{cookiecutter.module_name}}_debug_log_func(self, e_pst, "C_SIG_INIT", __FUNCTION__); + {{cookiecutter.module_name}}_init(self, e_pst); + {{cookiecutter.module_name}}_reset_error_cnt(self, e_pst); + {{cookiecutter.module_name}}_read_id(self, e_pst); + return chsm_transition(self, s_read_id_reg); + } + + return chsm_ignored(self); +} + +void {{cookiecutter.module_name}}_debug_log_func(chsm_tst *self, const cevent_tst *est, uint8_t *trans_name, const char *state_func) +{ + #ifdef CHSM_BUILD_TESTS + printf("{{cookiecutter.module_name}}_%s --%s-->\n", state_func, trans_name); + #else + CRF_UNUSED(self); + CRF_UNUSED(est); + CRF_UNUSED(trans_name); + CRF_UNUSED(state_func); + memset({{cookiecutter.module_name}}_debug_state_ac, 0, 20); + strncpy({{cookiecutter.module_name}}_debug_state_ac, state_func, 19); + {{cookiecutter.module_name}}_debug_state_ac[19] = '\0'; + #endif +} diff --git a/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}_functions.c b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}_functions.c new file mode 100644 index 00000000..01fe3c47 --- /dev/null +++ b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}_functions.c @@ -0,0 +1,317 @@ +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_regs.h" +#include "{{cookiecutter.module_name}}_functions.h" +#include "crf.h" +#include "cevent.h" +#include + +static const cevent_tst sig_reset_slave_comm_st = {.sig = SIG_I2C_RESET_SLAVE_COMM}; +static const cevent_tst sig_reset_periph_st = {.sig = SIG_I2C_RESET_SLAVE_COMM}; + +void {{cookiecutter.module_name}}_init(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->counter_u32 = 0; + self->error_counter_u32 = 0; + + self->t_st.super.sig = SIG_I2C_WR_TRANSACTION; + self->t_st.slave_addr_u16 = self->config_st.address_u8; + self->t_st.target_q_pst = (cqueue_tst *)self; + self->t_st.read_data_pu8 = self->rx_buff_au8; + self->t_st.write_data_pu8 = self->tx_buff_au8; +} + +/*Increase the timer counter.*/ +void {{cookiecutter.module_name}}_10ms_callback(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->counter_u32 += 10; +} + +/*Increase the error counter.*/ +void {{cookiecutter.module_name}}_inc_error_counter(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->error_counter_u32++; +} + +void {{cookiecutter.module_name}}_reset_error_cnt(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->error_counter_u32 = 0; +} + +/*Try to read the ID register from the {{cookiecutter.module_name|upper}} by sending a write-read transaction to the I2C master.*/ +void {{cookiecutter.module_name}}_read_id(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_WR_TRANSACTION; + self->t_st.write_cnt_u16 = 1; + self->t_st.read_cnt_u16 = 2; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_ID; + self->rx_buff_au8[0] = 0; + self->rx_buff_au8[1] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +void {{cookiecutter.module_name}}_reset_pointer(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 1; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +/*Send a SIG_{{cookiecutter.module_name|upper}}_OFFLINE event. This can be used to detect communication errors between the module and the I2C slave.*/ +void send_offline_event(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->valid_b = false; + + TYPEOF(SIG_{{cookiecutter.module_name|upper}}_OFFLINE)* offline_pst = CRF_NEW(SIG_{{cookiecutter.module_name|upper}}_OFFLINE); + + offline_pst->id_u16 = self->config_st.id_u16; + + CRF_EMIT(offline_pst); +} + +/*Send a SIG_{{cookiecutter.module_name|upper}}_ONLINE event. This can be used to detect successful initialization.*/ +void send_online_event(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->valid_b = true; + TYPEOF(SIG_{{cookiecutter.module_name|upper}}_ONLINE)* online_pst = CRF_NEW(SIG_{{cookiecutter.module_name|upper}}_ONLINE); + + online_pst->id_u16 = self->config_st.id_u16; + + CRF_EMIT(online_pst); +} + +/*Reset the timer counter.*/ +void {{cookiecutter.module_name}}_reset_timer(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->counter_u32 = 0; +} + +/*Send a read transaction to the {{cookiecutter.module_name|upper}}.*/ +void {{cookiecutter.module_name}}_start_read(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_R_TRANSACTION; + self->t_st.write_cnt_u16 = 0; + self->t_st.read_cnt_u16 = 2; + self->rx_buff_au8[0] = 0; + self->rx_buff_au8[1] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +void {{cookiecutter.module_name}}_set_full_powerdown(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 2; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CONFIG; + self->tx_buff_au8[1] = {{cookiecutter.module_name|upper}}_POWER_OFF; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} +void {{cookiecutter.module_name}}_set_full_powerup(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 2; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CONFIG; + self->tx_buff_au8[1] = {{cookiecutter.module_name|upper}}_POWER_ON; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +bool {{cookiecutter.module_name}}_wait_cnt(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + if(self->wait_cnt_u16++ >= {{cookiecutter.module_name|upper}}_WAIT_CNT) + { + self->wait_cnt_u16 = 0; + return true; + } + else + { + return false; + } +} + +bool {{cookiecutter.module_name}}_inc_wait_cnt(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + self->wait_cnt_u16++; + return false; +} + +void {{cookiecutter.module_name}}_init_wait(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; +// self->wait_cnt_u16 = 0; +} + +void {{cookiecutter.module_name}}_get_resolution(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_WR_TRANSACTION; + self->t_st.write_cnt_u16 = 1; + self->t_st.read_cnt_u16 = 1; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CTRLSTATUS; + self->rx_buff_au8[1] = 0; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +void {{cookiecutter.module_name}}_update_resolution(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + uint16_t reg_u16 = self->rx_buff_au8[0]; + {{cookiecutter.module_name}}_resolution_t resolution = {{cookiecutter.module_name|upper}}_RESOLUTION_14BIT; + + self->resolution_u16 = (reg_u16 & {{cookiecutter.module_name|upper}}_MASK_RESOLUTION) | resolution; +} + +void {{cookiecutter.module_name}}_set_resolution(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + self->t_st.super.sig = SIG_I2C_W_TRANSACTION; + self->t_st.write_cnt_u16 = 2; + self->t_st.read_cnt_u16 = 0; + self->tx_buff_au8[0] = {{cookiecutter.module_name|upper}}_REG_CTRLSTATUS; + self->tx_buff_au8[1] = {{cookiecutter.module_name|upper}}_RESOLUTION_14BIT; + + self->super.send(_self, (const cevent_tst *)(&self->t_st)); +} + +/*Update the temperature display and send an event with the new value.*/ +void {{cookiecutter.module_name}}_update_temp(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + {{cookiecutter.module_name}}_temp_tst* temp_pst = CRF_NEW(SIG_{{cookiecutter.module_name|upper}}_TEMP); //{{cookiecutter.module_name}}_temp_tst + + if (NULL == temp_pst) return; + + // Compile the value of the Temperature Data Register into a variable + double tdr_reg_u32 = ((((self->rx_buff_au8[0] << 8) | self->rx_buff_au8[1]) >> 2) * 0.03125); + int32_t temp_c_i32 = tdr_reg_u32*1000; + + temp_pst->super.sig = SIG_{{cookiecutter.module_name|upper}}_TEMP; + temp_pst->temp_C_i32 = temp_c_i32; + temp_pst->id_u16 = self->config_st.id_u16; + + self->temp_C_i32 = temp_c_i32; + self->valid_b = true; + + self->super.send(_self, (const cevent_tst *)temp_pst); + + if (self->error_counter_u32) + { + self->error_counter_u32--; + } +} + +/*True, if the response data is equal to 0x190. See {{cookiecutter.module_name|upper}} datasheet section: 7.5.1.7 Identification Register*/ +bool {{cookiecutter.module_name}}_id_match(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + // Compile the value of the Identification Register into a variable + uint16_t idr_reg_u16 = self->rx_buff_au8[0]; + idr_reg_u16 <<= 8; + idr_reg_u16 |= self->rx_buff_au8[1]; + + return {{cookiecutter.module_name|upper}}_ID_REG_VALUE == idr_reg_u16; +} + +/*Return true, if the error counter is greater or equal then the parameter.*/ +bool {{cookiecutter.module_name}}_error_count(chsm_tst *_self, const cevent_tst *e_pst, uint16_t error_cnt_threshold_u16) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + return self->error_counter_u32 >= error_cnt_threshold_u16; +} + +bool {{cookiecutter.module_name}}_timeout(chsm_tst *_self, const cevent_tst *e_pst, uint32_t timeout_u32) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + return self->counter_u32 >= timeout_u32; +} + +void {{cookiecutter.module_name}}_unplugged(chsm_tst *_self, const cevent_tst *e_pst) +{ + {{cookiecutter.module_name}}_debug_log_func(_self,e_pst,"",__FUNCTION__); + + {{cookiecutter.module_name}}_tst* self = ({{cookiecutter.module_name}}_tst *)_self; + + CRF_EMIT(&sig_reset_slave_comm_st); +} + diff --git a/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/CMakeLists.txt b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/CMakeLists.txt new file mode 100644 index 00000000..01571020 --- /dev/null +++ b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/CMakeLists.txt @@ -0,0 +1,22 @@ + +add_module_test( + NAME + {{cookiecutter.module_name}}_test + SOURCE + tsrc/main.c + tsrc/ut_{{cookiecutter.module_name}}_test.c + INCLUDE + tinc + LINK + unity + i2c_drv_mock + {{cookiecutter.module_name}} + DEFINES + NDEBUG + CHSM_BUILD_TESTS + STANDARD + 11 +) + +set_property(TARGET {{cookiecutter.module_name}}_test PROPERTY ECLIPSE_GENERATE_SOURCE_PROJECT ON) +set_property(TARGET {{cookiecutter.module_name}}_test PROPERTY ECLIPSE_GENERATE_LINKED_RESOURCES ON) \ No newline at end of file diff --git a/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tinc/.gitkeep b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tinc/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/main.c b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/main.c new file mode 100644 index 00000000..9164d34f --- /dev/null +++ b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/main.c @@ -0,0 +1,24 @@ +#include +#include "unity_fixture.h" +#include "unity.h" + + +void disableInterrupts(void) +{ + +} + +void enableInterrupts(void) +{ + +} + +void run_{{cookiecutter.module_name}}_tests(void) +{ + RUN_TEST_GROUP({{cookiecutter.module_name}}); +} + +int main(int argc, const char * argv[]) +{ + return UnityMain(argc, argv, run_{{cookiecutter.module_name}}_tests); +} \ No newline at end of file diff --git a/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/ut_{{cookiecutter.module_name}}_test.c b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/ut_{{cookiecutter.module_name}}_test.c new file mode 100644 index 00000000..e98a475c --- /dev/null +++ b/gui/py_gen/module_template/_template_new/{{cookiecutter.module_name}}/test/tsrc/ut_{{cookiecutter.module_name}}_test.c @@ -0,0 +1,417 @@ +/* + * ut_{{cookiecutter.module_name}}_test.c + * + * Created on: 2020. dec. 30. + * Author: jszeman + */ + +#include +#include +#include +#include +#include +#include "unity_fixture.h" +#include "crf.h" +#include "cbits.h" +#include "ut_i2c_driver_mock.h" +#include "i2c_master.h" +#include "{{cookiecutter.module_name}}.h" +#include "{{cookiecutter.module_name}}_regs.h" +#include "cevent.h" +#include "sys_if.h" + +TEST_GROUP({{cookiecutter.module_name}}); + +ut_i2c_driver_mock_tst drv_mock_st; +i2c_driver_if_tst* drv_pst = (i2c_driver_if_tst *)&drv_mock_st; + +const cevent_tst* i2c_master_events_apst[8]; +i2c_master_tst i2c_master_st; +uint8_t i2c_master_scanned_ids[127]; + +const cevent_tst* {{cookiecutter.module_name}}_events_apst[8]; +{{cookiecutter.module_name}}_tst {{cookiecutter.module_name}}_st; + + +{{cookiecutter.module_name}}_tst *self = &{{cookiecutter.module_name}}_st; // This is necessary for macros like {{cookiecutter.module_name|upper}}_READ_PERIOD to work here + +chsm_tst* hsm_apst[] = { + (chsm_tst*)(&i2c_master_st), + (chsm_tst*)(&{{cookiecutter.module_name}}_st), + NULL}; + +uint8_t pool_buff_au8[1024]; +cpool_tst pool_ast[1]; + +crf_tst crf; + +const cevent_tst* events_apst[4]; +cqueue_tst q_st; + +const cevent_tst tick_10ms_st = {.sig = SIG_SYS_TICK_10ms}; + +static void tick_ms(uint32_t tick_cnt_u32) +{ + while(tick_cnt_u32--) + { + drv_mock_st.tick(&drv_mock_st); + + CRF_POST(&tick_10ms_st, &{{cookiecutter.module_name}}_st); + + while(CRF_STEP()) + { + printf("| "); + } + } +} + +void {{cookiecutter.module_name}}_send(chsm_tst *self, const cevent_tst *e_pst) +{ + //printf("\n%s\n", __FUNCTION__); + switch(e_pst->sig) + { + case SIG_{{cookiecutter.module_name|upper}}_TEMP: + case SIG_{{cookiecutter.module_name|upper}}_ONLINE: + case SIG_{{cookiecutter.module_name|upper}}_OFFLINE: + CRF_POST(e_pst, &q_st); + break; + + default: + CRF_POST(e_pst, &i2c_master_st); + } +} + + +TEST_SETUP({{cookiecutter.module_name}}) +{ + memset(events_apst, 0, sizeof(events_apst)); + memset(&q_st, 0, sizeof(q_st)); + memset(&drv_mock_st, 0, sizeof(drv_mock_st)); + memset(&i2c_master_st, 0, sizeof(i2c_master_st)); + memset(&crf, 0, sizeof(crf)); + memset(&i2c_master_events_apst, 0, sizeof(i2c_master_events_apst)); + memset(&pool_buff_au8, 0, sizeof(pool_buff_au8)); + memset(&pool_ast, 0, sizeof(pool_ast)); + memset(&{{cookiecutter.module_name}}_st, 0, sizeof({{cookiecutter.module_name}}_st)); + + cpool_init(pool_ast+0, pool_buff_au8, 24, 16); + + cqueue_init(&q_st, events_apst, 4); + + ut_i2c_driver_mock_init(&drv_mock_st); + + i2c_master_st.config_st.driver_pst = drv_pst; + // i2c_master_st.config_st.scan_result_au8[0] = &i2c_master_scanned_ids; + chsm_ctor(&i2c_master_st.super, i2c_master_top, i2c_master_events_apst, 4, 4); + chsm_ctor(&{{cookiecutter.module_name}}_st.super, {{cookiecutter.module_name}}_top, {{cookiecutter.module_name}}_events_apst, 8, 0); + + {{cookiecutter.module_name}}_st.config_st = ({{cookiecutter.module_name}}_cfg_tst){ + .address_u8 = {{cookiecutter.module_name|upper}}_0_I2C_FLOAT, + .id_u16 = 0xabcd, + .period_ms_u16 = {{cookiecutter.module_name|upper}}_READ_PERIOD_VALUE, + .max_error_cnt_u16 = {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT_VALUE + }; + + CRF_SEND_FUNC(&{{cookiecutter.module_name}}_st) = {{cookiecutter.module_name}}_send; + + crf_init(&crf, hsm_apst, pool_ast, 1); + chsm_init((chsm_tst *)&i2c_master_st); + chsm_init((chsm_tst *)&{{cookiecutter.module_name}}_st); +} + +TEST_TEAR_DOWN({{cookiecutter.module_name}}) +{ +} + +/* + * Just call setup + */ +TEST({{cookiecutter.module_name}}, init) +{ + printf("\n%s\n", __FUNCTION__); +} + +TEST({{cookiecutter.module_name}}, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = {{cookiecutter.module_name|upper}}_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, // sensor id + 0xf3, 0x80, // -25° measured value + 0x0c, 0x80 // +25° measured value + } + }; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + +} + +/* read_temp_twice: + * Setup the mock device to send the id bytes and two temperature reading (-25 and 25) to the master. + * Check, that two temperature events were sent + */ +TEST({{cookiecutter.module_name}}, read_temp_twice) +{ + printf("\n%s\n", __FUNCTION__); + i2c_mock_slave_device_tst dev_st = { + .address_u8 = 0x12, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + + const {{cookiecutter.module_name}}_temp_tst* e_pst; + const {{cookiecutter.module_name}}_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + TEST_ASSERT(s_pst); + TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + + e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + + tick_ms(({{cookiecutter.module_name|upper}}_READ_PERIOD/10)+1); + + uint8_t expected_au8[4] = {7, 0, 0, 0}; + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); + TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); + TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + + e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +} + +/* read_id_retry: + * Check that a failed ID read will be repeated after the configured time. + */ +TEST({{cookiecutter.module_name}}, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = {{cookiecutter.module_name|upper}}_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + const {{cookiecutter.module_name}}_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + TEST_ASSERT_NULL(s_pst); + + // dev_st.address_u8 = 0x12; + + // tick_ms({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT-10); + + // s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NULL(s_pst); + + // tick_ms(10); + + // s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NOT_NULL(s_pst); + // TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); +} + +// /* read_id_retry_bad_id: +// * Check that a failed ID read will be repeated after the configured time if the data sent back +// * by the slave is not 0x190 for the first try. +// */ +// TEST({{cookiecutter.module_name}}, read_id_retry_bad_id) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x91, 0x01, 0x90, 0x0c, 0x80} +// }; + +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms(({{cookiecutter.module_name|upper}}_RETRY_TIMEOUT-10)/10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NOT_NULL(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); +// } + +// /* go_online: +// * Check that after reading temperature data fails for more than {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST({{cookiecutter.module_name}}, go_online) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const {{cookiecutter.module_name}}_temp_tst* e_pst; +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(({{cookiecutter.module_name|upper}}_READ_PERIOD_VALUE / 10) + 1); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE({{cookiecutter.module_name}}_st.valid_b); +// } + +// /* go_offline: +// * Check that after reading temperature data fails for more than {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST({{cookiecutter.module_name}}, go_offline) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const {{cookiecutter.module_name}}_temp_tst* e_pst; +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(({{cookiecutter.module_name|upper}}_READ_PERIOD/10) + 1); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE({{cookiecutter.module_name}}_st.valid_b); + +// dev_st.address_u8 = 0x13; + +// tick_ms((({{cookiecutter.module_name|upper}}_READ_PERIOD/10) + 1) * {{cookiecutter.module_name|upper}}_MAX_ERROR_COUNT + 1); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_OFFLINE, s_pst->super.sig); + +// TEST_ASSERT_FALSE({{cookiecutter.module_name}}_st.valid_b); +// } + +// /* triggered_read: +// * Check that it is possible to trigger a read before the read period timeout elapses. +// */ +// TEST({{cookiecutter.module_name}}, triggered_read) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const cevent_tst read_event = {.sig = SIG_{{cookiecutter.module_name|upper}}_READ}; + + +// const {{cookiecutter.module_name}}_temp_tst* e_pst; +// const {{cookiecutter.module_name}}_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = ({{cookiecutter.module_name}}_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_ONLINE, s_pst->super.sig); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(1); + +// CRF_POST(&read_event, &{{cookiecutter.module_name}}_st); + +// tick_ms(10); + +// uint8_t expected_au8[4] = {7, 0, 0, 0}; +// TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); +// TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); +// TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + +// e_pst = ({{cookiecutter.module_name}}_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_{{cookiecutter.module_name|upper}}_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +// } + +TEST_GROUP_RUNNER({{cookiecutter.module_name}}) +{ + RUN_TEST_CASE({{cookiecutter.module_name}}, init); + RUN_TEST_CASE({{cookiecutter.module_name}}, read_id); + // RUN_TEST_CASE({{cookiecutter.module_name}}, read_temp_twice); + // RUN_TEST_CASE({{cookiecutter.module_name}}, read_id_retry); + // RUN_TEST_CASE({{cookiecutter.module_name}}, read_id_retry_bad_id); + // RUN_TEST_CASE({{cookiecutter.module_name}}, go_offline); + // RUN_TEST_CASE({{cookiecutter.module_name}}, go_online); + // RUN_TEST_CASE({{cookiecutter.module_name}}, triggered_read); +} diff --git a/gui/py_gen/module_template/_template_without_crf/cookiecutter.json b/gui/py_gen/module_template/_template_without_crf/cookiecutter.json new file mode 100644 index 00000000..635ada19 --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf/cookiecutter.json @@ -0,0 +1,3 @@ +{ + "module_name": "template" +} \ No newline at end of file diff --git a/gui/py_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h b/gui/py_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h new file mode 100644 index 00000000..93ef40a8 --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/inc/{{cookiecutter.module_name}}_functions.h @@ -0,0 +1,48 @@ +#ifndef PCA9554_FUNCTIONS_H +#define PCA9554_FUNCTIONS_H + +/*Generated with CHSM v0.0.0 at 2023.07.27 14.07.05*/ + +#include "pca9554.h" +#include + + +void pca9554_process_input(pca9554_tst *self); + +void pca9554_read_input(pca9554_tst *self); + +void pca9554_reset_timer(pca9554_tst *self); + +/*Start a I2C transaction to write the DIRECTION register in the slave device.*/ +void pca9554_set_direction(pca9554_tst *self); + +void pca9554_set_output(pca9554_tst *self); + +void pca9554_set_polarity(pca9554_tst *self); + + +typedef enum pca9554_state_id_ten +{ + S_PCA9554_WAIT_DIR = 1, + S_PCA9554_WAIT_POL = 2, + S_PCA9554_WAIT_OUTPUT = 3, + S_PCA9554_WAIT_READ = 4, + S_PCA9554_BACK_OFF = 5, +} pca9554_state_id_ten; + + +/* +Signals: + I2C_FAIL + I2C_SUCCESS + START_READ +*/ + +/* +Other function notes: + +pca9554_set_status: + +pca9554_timeout: +*/ +#endif diff --git a/gui/py_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c b/gui/py_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c new file mode 100644 index 00000000..28a6511c --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf/{{cookiecutter.module_name}}/src/{{cookiecutter.module_name}}.c @@ -0,0 +1,115 @@ +/*Generated with CHSM v0.0.1*/ +#include "pca9554.h" +#include "pca9554_functions.h" + + +static void s_pca9554_back_off(pca9554_tst *self); +static void s_pca9554_wait_read(pca9554_tst *self); +static void s_pca9554_wait_output(pca9554_tst *self); +static void s_pca9554_wait_pol(pca9554_tst *self); +static void s_pca9554_wait_dir(pca9554_tst *self); + +static void s_pca9554_wait_dir(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_polarity(self); + return pca9554_set_state(self, s_pca9554_wait_pol); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_pol(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_output(self); + return pca9554_set_state(self, s_pca9554_wait_output); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_output(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_read(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_status(self, PCA9554_READY); + pca9554_process_input(self); + break; + + case PCA9554_SIG_START_READ: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_back_off(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + if(pca9554_timeout(self, 1000)) + { + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} + +void pca9554_top(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_INIT: + pca9554_set_status(self, PCA9554_STARTING); + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} diff --git a/gui/py_gen/module_template/_template_without_crf_new/cookiecutter.json b/gui/py_gen/module_template/_template_without_crf_new/cookiecutter.json new file mode 100644 index 00000000..635ada19 --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf_new/cookiecutter.json @@ -0,0 +1,3 @@ +{ + "module_name": "template" +} \ No newline at end of file diff --git a/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/.chsm/pca9554.json b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/.chsm/pca9554.json new file mode 100644 index 00000000..35f0d37a --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/.chsm/pca9554.json @@ -0,0 +1,26 @@ +{ + "src_dir": "../src", + "doc_dir": "../doc", + + "templates": { + "init_signal": "PCA9554_SIG_INIT", + "signal_prefix": "PCA9554_SIG_", + "func_args": "self", + "func_params": "pca9554_tst *self", + "user_func_args_t": "self", + "user_func_params_t": "pca9554_tst *self", + "func_return_type": "void", + "guard_return_type": "uint16_t", + "switch_variable": "self->signal_en", + "trans_result": "pca9554_set_state(self, {target})", + "ignored_result": "", + "c_include_list": [], + "h_include_list": [""], + "top_state_name": "void\\s+(?P\\w+)\\(void\\s+\\*self,\\s+uint32_t\\s+e_u32\\)\\s*;", + "set_state_id": "" + }, + + "pca9554.h": { + "top_func": "pca9554_top" + } +} \ No newline at end of file diff --git a/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/CMakeLists.txt b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/CMakeLists.txt new file mode 100644 index 00000000..46fba169 --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/CMakeLists.txt @@ -0,0 +1,19 @@ + +add_module_lib( + NAME + lm73 + PACKAGE + chsm + SOURCE + src/lm73.c + src/lm73_functions.c + INCLUDE + inc + LINK + chsm::i2c_master + signal_classes_modules + DEFINES + NDEBUG + STANDARD + 11 +) \ No newline at end of file diff --git a/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/doc/pca9554.html b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/doc/pca9554.html new file mode 100644 index 00000000..6162916b --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/doc/pca9554.html @@ -0,0 +1,865 @@ + + + + + + +
+ + + + + + START_READ[pca9554_timeout(1000)]I2C_FAILI2C_SUCCESSI2C_SUCCESSI2C_SUCCESS + __top__s_pca9554init/ pca9554_set_status(PCA9554_STARTING)s_pca9554_wait_dirinit/ pca9554_set_direction()Start a I2C transaction to write the DIRECTION register in the slave device.s_pca9554_wait_polinit/ pca9554_set_polarity()s_pca9554_wait_outputinit/ pca9554_set_output()s_pca9554_wait_readinit/ pca9554_read_input()I2C_SUCCESS/ { pca9554_set_status(PCA9554_READY) pca9554_process_input()}s_pca9554_back_offinit/ pca9554_reset_timer()entry/ pca9554_set_status(PCA9554_NOT_FOUND) + + +
+ +
+ json +
+            {
+    "states": {
+        "__top__": {
+            "pos": [
+                -100000000,
+                -100000000
+            ],
+            "size": [
+                200000000,
+                200000000
+            ],
+            "title": "__top__",
+            "text": [],
+            "connectors": [],
+            "parent": null,
+            "children": [
+                "state_0",
+                "istate_0"
+            ],
+            "type": "top"
+        },
+        "state_0": {
+            "pos": [
+                42,
+                17
+            ],
+            "size": [
+                82,
+                73
+            ],
+            "title": "s_pca9554",
+            "text": [
+                "init/ pca9554_set_status(PCA9554_STARTING)"
+            ],
+            "connectors": [
+                "conn_1",
+                "conn_10"
+            ],
+            "parent": "__top__",
+            "children": [
+                "state_1",
+                "istate_1",
+                "state_2",
+                "state_3",
+                "state_4",
+                "state_5"
+            ],
+            "type": "normal"
+        },
+        "istate_0": {
+            "pos": [
+                55,
+                9
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_0",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_0"
+            ],
+            "parent": "__top__",
+            "children": [],
+            "type": "initial"
+        },
+        "state_1": {
+            "pos": [
+                48,
+                32
+            ],
+            "size": [
+                20,
+                6
+            ],
+            "title": "s_pca9554_wait_dir",
+            "text": [
+                "init/ pca9554_set_direction()"
+            ],
+            "connectors": [
+                "conn_3",
+                "conn_4",
+                "conn_13"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "istate_1": {
+            "pos": [
+                55,
+                26
+            ],
+            "size": [
+                2,
+                2
+            ],
+            "title": "istate_1",
+            "text": [
+                "entry/",
+                "exit/"
+            ],
+            "connectors": [
+                "conn_2"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "initial"
+        },
+        "state_2": {
+            "pos": [
+                48,
+                44
+            ],
+            "size": [
+                20,
+                6
+            ],
+            "title": "s_pca9554_wait_pol",
+            "text": [
+                "init/ pca9554_set_polarity()"
+            ],
+            "connectors": [
+                "conn_5",
+                "conn_6"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "state_3": {
+            "pos": [
+                48,
+                56
+            ],
+            "size": [
+                20,
+                6
+            ],
+            "title": "s_pca9554_wait_output",
+            "text": [
+                "init/ pca9554_set_output()"
+            ],
+            "connectors": [
+                "conn_7",
+                "conn_8"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "state_4": {
+            "pos": [
+                49,
+                70
+            ],
+            "size": [
+                31,
+                16
+            ],
+            "title": "s_pca9554_wait_read",
+            "text": [
+                "init/ pca9554_read_input()",
+                "I2C_SUCCESS/ {",
+                "   pca9554_set_status(PCA9554_READY)",
+                "   pca9554_process_input()",
+                "}"
+            ],
+            "connectors": [
+                "conn_9",
+                "conn_14",
+                "conn_15"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        },
+        "state_5": {
+            "pos": [
+                88,
+                43
+            ],
+            "size": [
+                32,
+                8
+            ],
+            "title": "s_pca9554_back_off",
+            "text": [
+                "init/ pca9554_reset_timer()",
+                "entry/ pca9554_set_status(PCA9554_NOT_FOUND)"
+            ],
+            "connectors": [
+                "conn_11",
+                "conn_12"
+            ],
+            "parent": "state_0",
+            "children": [],
+            "type": "normal"
+        }
+    },
+    "connectors": {
+        "conn_0": {
+            "parent": "istate_0",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_0"
+        },
+        "conn_1": {
+            "parent": "state_0",
+            "offset": 13,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_0"
+        },
+        "conn_2": {
+            "parent": "istate_1",
+            "offset": 0,
+            "side": "all",
+            "dir": "out",
+            "transition": "trans_1"
+        },
+        "conn_3": {
+            "parent": "state_1",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_1"
+        },
+        "conn_4": {
+            "parent": "state_1",
+            "offset": 7,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_2"
+        },
+        "conn_5": {
+            "parent": "state_2",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_2"
+        },
+        "conn_6": {
+            "parent": "state_2",
+            "offset": 7,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_3"
+        },
+        "conn_7": {
+            "parent": "state_3",
+            "offset": 7,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_3"
+        },
+        "conn_8": {
+            "parent": "state_3",
+            "offset": 7,
+            "side": "bottom",
+            "dir": "out",
+            "transition": "trans_4"
+        },
+        "conn_9": {
+            "parent": "state_4",
+            "offset": 6,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_4"
+        },
+        "conn_10": {
+            "parent": "state_0",
+            "offset": 18,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_5"
+        },
+        "conn_11": {
+            "parent": "state_5",
+            "offset": 15,
+            "side": "top",
+            "dir": "in",
+            "transition": "trans_5"
+        },
+        "conn_12": {
+            "parent": "state_5",
+            "offset": 12,
+            "side": "top",
+            "dir": "out",
+            "transition": "trans_6"
+        },
+        "conn_13": {
+            "parent": "state_1",
+            "offset": 3,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_6"
+        },
+        "conn_14": {
+            "parent": "state_4",
+            "offset": 11,
+            "side": "right",
+            "dir": "out",
+            "transition": "trans_7"
+        },
+        "conn_15": {
+            "parent": "state_4",
+            "offset": 7,
+            "side": "right",
+            "dir": "in",
+            "transition": "trans_7"
+        }
+    },
+    "transitions": {
+        "trans_0": {
+            "start": "conn_0",
+            "end": "conn_1",
+            "vertices": [
+                [
+                    55,
+                    9
+                ],
+                [
+                    55,
+                    9
+                ],
+                [
+                    55,
+                    17
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                4.1
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                55.5,
+                13.1
+            ]
+        },
+        "trans_1": {
+            "start": "conn_2",
+            "end": "conn_3",
+            "vertices": [
+                [
+                    55,
+                    26
+                ],
+                [
+                    55,
+                    26
+                ],
+                [
+                    55,
+                    32
+                ]
+            ],
+            "label": "",
+            "label_offset": [
+                0.5,
+                2.6000000000000014
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                55.5,
+                28.6
+            ]
+        },
+        "trans_2": {
+            "start": "conn_4",
+            "end": "conn_5",
+            "vertices": [
+                [
+                    55,
+                    38
+                ],
+                [
+                    55,
+                    43
+                ],
+                [
+                    55,
+                    43
+                ],
+                [
+                    55,
+                    44
+                ]
+            ],
+            "label": "I2C_SUCCESS",
+            "label_offset": [
+                0.5,
+                2.700000000000003
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                55.5,
+                40.7
+            ]
+        },
+        "trans_3": {
+            "start": "conn_6",
+            "end": "conn_7",
+            "vertices": [
+                [
+                    55,
+                    50
+                ],
+                [
+                    55,
+                    54
+                ],
+                [
+                    55,
+                    54
+                ],
+                [
+                    55,
+                    56
+                ]
+            ],
+            "label": "I2C_SUCCESS",
+            "label_offset": [
+                0.5,
+                2.8000000000000043
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                55.5,
+                52.800000000000004
+            ]
+        },
+        "trans_4": {
+            "start": "conn_8",
+            "end": "conn_9",
+            "vertices": [
+                [
+                    55,
+                    62
+                ],
+                [
+                    55,
+                    66
+                ],
+                [
+                    55,
+                    66
+                ],
+                [
+                    55,
+                    70
+                ]
+            ],
+            "label": "I2C_SUCCESS",
+            "label_offset": [
+                0.5,
+                3.5999999999999943
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                55.5,
+                65.6
+            ]
+        },
+        "trans_5": {
+            "start": "conn_10",
+            "end": "conn_11",
+            "vertices": [
+                [
+                    124,
+                    35
+                ],
+                [
+                    103,
+                    35
+                ],
+                [
+                    103,
+                    43
+                ]
+            ],
+            "label": "I2C_FAIL",
+            "label_offset": [
+                -19.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 0,
+            "label_pos": [
+                104.5,
+                34.6
+            ]
+        },
+        "trans_6": {
+            "start": "conn_12",
+            "end": "conn_13",
+            "vertices": [
+                [
+                    100,
+                    43
+                ],
+                [
+                    100,
+                    35
+                ],
+                [
+                    68,
+                    35
+                ]
+            ],
+            "label": "[pca9554_timeout(1000)]",
+            "label_offset": [
+                -23.5,
+                -0.3999999999999986
+            ],
+            "label_anchor": 1,
+            "label_pos": [
+                76.5,
+                34.6
+            ]
+        },
+        "trans_7": {
+            "start": "conn_14",
+            "end": "conn_15",
+            "vertices": [
+                [
+                    80,
+                    81
+                ],
+                [
+                    93,
+                    81
+                ],
+                [
+                    93,
+                    77
+                ],
+                [
+                    80,
+                    77
+                ]
+            ],
+            "label": "START_READ",
+            "label_offset": [
+                -10,
+                -0.4000000000000057
+            ],
+            "label_anchor": 2,
+            "label_pos": [
+                83,
+                76.6
+            ]
+        }
+    },
+    "notes": {
+        "pca9554_i2c_success()": "",
+        "I2C_SUCCESS": "",
+        "pca9554_set_direction()": "Start a I2C transaction to write the DIRECTION register in the slave device.",
+        "PCA9554_SIG_I2C_FAIL": "",
+        "START_READ": ""
+    },
+    "view": {
+        "translate": [
+            -13.5,
+            -34
+        ],
+        "scale": 8.5
+    }
+}
+        
+
+ + diff --git a/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554.h b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554.h new file mode 100644 index 00000000..dc3dbf66 --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554.h @@ -0,0 +1,98 @@ +/* + * lm73.h + * + * Created on: 2015 máj. 20 + * Author: jszeman + */ + +#ifndef INC_PCA9554_H_ +#define INC_PCA9554_H_ + +#include +#include "i2cMaster.h" + +#define PCA_A0_HIGH (1<<0) +#define PCA_A0_LOW (0) + +#define PCA_A1_HIGH (1<<1) +#define PCA_A1_LOW (0) + +#define PCA_A2_HIGH (1<<2) +#define PCA_A2_LOW (0) + +enum PCA9554_STATUS { + PCA9554_READY, /**< The driver is ready for operation */ + PCA9554_BUSY, /**< The driver is in the process of reading or writing data. The in field is not valid. */ + PCA9554_NOT_FOUND, /**< The configured device did not acknowledged its address */ + PCA9554_STARTING /**< The driver is in the process of initializing the device */ +}; + +enum PCA9554_PART { + PCA9554 = 0x20, + PCA9554A = 0x38 +}; + +typedef enum pca9554_sig_ten { + PCA9554_SIG_NONE, + PCA9554_SIG_I2C_SUCCESS, + PCA9554_SIG_I2C_FAIL, + PCA9554_SIG_INIT, + PCA9554_SIG_START_READ +} pca9554_sig_ten; + +struct pca9554_config +{ + i2cMaster_h i2cH; /**< Pointer to a previously configured I2C master driver */ + enum PCA9554_PART type; /**< Exact device type. Necessary for address calculation */ + uint16_t a; /** Address pin (A0, A1, A2) configuration */ + uint16_t out; /** Initial output value */ + uint16_t polarity; /** Input pin polarity */ + uint16_t direction; /** Pin direction */ +}; + +typedef struct pca9554_t *pca9554_h; +typedef struct pca9554_t pca9554_tst; + +struct pca9554_t +{ + /* PUBLIC */ + struct pca9554_config config; + enum PCA9554_STATUS status; + + uint16_t in; + uint16_t inputChanged; + + void (*setOutput)(pca9554_h self, uint16_t o); + void (*setDirection)(pca9554_h self, uint16_t d); + void (*setPolarity)(pca9554_h self, uint16_t p); + void (*readInput)(pca9554_h self); + void (*callback_1ms)(pca9554_h self); + + /* PRIVATE */ + struct i2cTransaction_t transaction; + uint8_t wbuff[4]; + uint8_t rbuff[2]; + + pca9554_sig_ten signal_en; + pca9554_sig_ten op_en; + + uint32_t timer_u32; + uint32_t fault_cnt_u32; + + void (*sm_callback)(pca9554_tst *self); +}; + + + +void pca9554_init(pca9554_h self); +void pca9554_top(pca9554_tst *self); + +void pca9554_set_status(pca9554_tst *self, enum PCA9554_STATUS status_en); +uint16_t pca9554_timeout(pca9554_tst *self, uint32_t timeout_u32); + +static inline void pca9554_set_state(pca9554_tst *self, void (*state_pft)(pca9554_tst *self)) +{ + self->sm_callback = state_pft; +} + +#endif /* INC_PCA9554_H_ */ diff --git a/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554_functions.h b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554_functions.h new file mode 100644 index 00000000..93ef40a8 --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/inc/pca9554_functions.h @@ -0,0 +1,48 @@ +#ifndef PCA9554_FUNCTIONS_H +#define PCA9554_FUNCTIONS_H + +/*Generated with CHSM v0.0.0 at 2023.07.27 14.07.05*/ + +#include "pca9554.h" +#include + + +void pca9554_process_input(pca9554_tst *self); + +void pca9554_read_input(pca9554_tst *self); + +void pca9554_reset_timer(pca9554_tst *self); + +/*Start a I2C transaction to write the DIRECTION register in the slave device.*/ +void pca9554_set_direction(pca9554_tst *self); + +void pca9554_set_output(pca9554_tst *self); + +void pca9554_set_polarity(pca9554_tst *self); + + +typedef enum pca9554_state_id_ten +{ + S_PCA9554_WAIT_DIR = 1, + S_PCA9554_WAIT_POL = 2, + S_PCA9554_WAIT_OUTPUT = 3, + S_PCA9554_WAIT_READ = 4, + S_PCA9554_BACK_OFF = 5, +} pca9554_state_id_ten; + + +/* +Signals: + I2C_FAIL + I2C_SUCCESS + START_READ +*/ + +/* +Other function notes: + +pca9554_set_status: + +pca9554_timeout: +*/ +#endif diff --git a/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554.c b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554.c new file mode 100644 index 00000000..28a6511c --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554.c @@ -0,0 +1,115 @@ +/*Generated with CHSM v0.0.1*/ +#include "pca9554.h" +#include "pca9554_functions.h" + + +static void s_pca9554_back_off(pca9554_tst *self); +static void s_pca9554_wait_read(pca9554_tst *self); +static void s_pca9554_wait_output(pca9554_tst *self); +static void s_pca9554_wait_pol(pca9554_tst *self); +static void s_pca9554_wait_dir(pca9554_tst *self); + +static void s_pca9554_wait_dir(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_polarity(self); + return pca9554_set_state(self, s_pca9554_wait_pol); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_pol(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_output(self); + return pca9554_set_state(self, s_pca9554_wait_output); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_output(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_wait_read(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_SUCCESS: + pca9554_set_status(self, PCA9554_READY); + pca9554_process_input(self); + break; + + case PCA9554_SIG_START_READ: + pca9554_read_input(self); + return pca9554_set_state(self, s_pca9554_wait_read); + + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + return ; +} + +static void s_pca9554_back_off(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_I2C_FAIL: + pca9554_set_status(self, PCA9554_NOT_FOUND); + pca9554_reset_timer(self); + return pca9554_set_state(self, s_pca9554_back_off); + } + + if(pca9554_timeout(self, 1000)) + { + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} + +void pca9554_top(pca9554_tst *self) +{ + switch(self->signal_en) + { + case PCA9554_SIG_INIT: + pca9554_set_status(self, PCA9554_STARTING); + pca9554_set_direction(self); + return pca9554_set_state(self, s_pca9554_wait_dir); + } + + return ; +} diff --git a/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554_functions.c b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554_functions.c new file mode 100644 index 00000000..65c4e42e --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/src/pca9554_functions.c @@ -0,0 +1,153 @@ +/* + * lm73.c + * + * Created on: 2015 máj. 20 + * Author: jszeman + */ + +#include +#include "i2cMaster.h" +#include "math.h" +#include "pca9554.h" + +#define PCA_REG_INPUT 0 +#define PCA_REG_OUTPUT 1 +#define PCA_REG_POLARITY 2 +#define PCA_REG_DIRECTION 3 + +static void startRegWrite(pca9554_h self) +{ + self->transaction.writeLength = 2; // write pointer byte + self->transaction.readLength = 0; + self->config.i2cH->start(self->config.i2cH, &self->transaction); + + //self->status = PCA9554_BUSY; +} + +static void setOutput(pca9554_h self, uint16_t o) +{ + self->wbuff[0] = PCA_REG_OUTPUT; + self->wbuff[1] = o; + + startRegWrite(self); +} + +static void setDirection(pca9554_h self, uint16_t d) +{ + self->wbuff[0] = PCA_REG_DIRECTION; + self->wbuff[1] = d; + + startRegWrite(self); +} + +static void setPolarity(pca9554_h self, uint16_t p) +{ + self->wbuff[0] = PCA_REG_POLARITY; + self->wbuff[1] = p; + + startRegWrite(self); +} + +static void readInput(pca9554_h self) +{ + self->wbuff[0] = PCA_REG_INPUT; + self->transaction.writeLength = 1; // write pointer byte + self->transaction.readLength = 1; + self->config.i2cH->start(self->config.i2cH, &self->transaction); + + self->status = PCA9554_BUSY; +} + +static void start_read(pca9554_h self) +{ + self->op_en = PCA9554_SIG_START_READ; +} + +static void callback(pca9554_h self) +{ + self->signal_en = PCA9554_SIG_NONE; + + switch (self->transaction.result) + { + case I2C_SUCCESS: + self->signal_en = PCA9554_SIG_I2C_SUCCESS; + self->transaction.result = I2C_NONE; + break; + + case I2C_ADDRESS_NACK: + case I2C_DATA_NACK: + self->signal_en = PCA9554_SIG_I2C_FAIL; + self->transaction.result = I2C_NONE; + self->fault_cnt_u32++; + break; + + default: + self->signal_en = self->op_en; + self->op_en = PCA9554_SIG_NONE; + } + + self->sm_callback(self); + + self->timer_u32++; +} + +void pca9554_set_status(pca9554_tst *self, enum PCA9554_STATUS status_en) +{ + self->status = status_en; +} + +void pca9554_process_input(pca9554_tst *self) +{ + self->in = self->rbuff[0]; + self->inputChanged = 1; +} + +void pca9554_read_input(pca9554_tst *self) +{ + readInput(self); +} + +void pca9554_set_direction(pca9554_tst *self) +{ + setDirection(self, self->config.direction); +} + +void pca9554_set_output(pca9554_tst *self) +{ + setOutput(self, self->config.out); +} + +void pca9554_set_polarity(pca9554_tst *self) +{ + setPolarity(self, self->config.polarity); +} + +void pca9554_reset_timer(pca9554_tst *self) +{ + self->timer_u32 = 0; +} + +uint16_t pca9554_timeout(pca9554_tst *self, uint32_t timeout_u32) +{ + return self->timer_u32 >= timeout_u32; +} + +void pca9554_init(pca9554_h self) +{ + self->setOutput = setOutput; + self->setDirection = setDirection; + self->setPolarity = setPolarity; + self->readInput = start_read; + self->callback_1ms = callback; + + self->transaction.address = self->config.type | (self->config.a & 0x07); + self->transaction.result = I2C_NONE; + self->transaction.readData = self->rbuff; + self->transaction.writeData = self->wbuff; + self->inputChanged = 0; + self->fault_cnt_u32 = 0; + + self->sm_callback = pca9554_top; + self->op_en = PCA9554_SIG_INIT; + +} diff --git a/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/CMakeLists.txt b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/CMakeLists.txt new file mode 100644 index 00000000..4b648cb6 --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/CMakeLists.txt @@ -0,0 +1,22 @@ + +add_module_test( + NAME + lm73_test + SOURCE + tsrc/main.c + tsrc/ut_lm73_test.c + INCLUDE + tinc + LINK + unity + i2c_drv_mock + lm73 + DEFINES + NDEBUG + CHSM_BUILD_TESTS + STANDARD + 11 +) + +set_property(TARGET lm73_test PROPERTY ECLIPSE_GENERATE_SOURCE_PROJECT ON) +set_property(TARGET lm73_test PROPERTY ECLIPSE_GENERATE_LINKED_RESOURCES ON) \ No newline at end of file diff --git a/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/doc/signal_classes_distribution.puml b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/doc/signal_classes_distribution.puml new file mode 100644 index 00000000..bc36d642 --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/doc/signal_classes_distribution.puml @@ -0,0 +1,32 @@ +@startuml signal_classes_distribution +scale 800 width +skinparam backgroundColor #FFEBDC +scale 1 + +skinparam cloud { + backgroundColor Olive + borderColor orange +} + +title Architecture Diagram of the CHSM package + +left to right direction + +package chsm { + package interfaces{ + rectangle signal_classes_if{ + typedef enum sig_class_ten { + SIG_CLASS_SYS = CRF_SIGNAL_CLASS_START, + SIG_CLASS_I2C_DRIVER, + SIG_CLASS_SPI_DRIVER, + SIG_CLASS_MEM, + SIG_CLASS_CAN, + SIG_APP_NAMESPACE_START, +} sig_class_ten; + } + + } +} + + +@enduml \ No newline at end of file diff --git a/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/main.c b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/main.c new file mode 100644 index 00000000..d8154db0 --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/main.c @@ -0,0 +1,24 @@ +#include +#include "unity_fixture.h" +#include "unity.h" + + +void disableInterrupts(void) +{ + +} + +void enableInterrupts(void) +{ + +} + +void run_lm73_tests(void) +{ + RUN_TEST_GROUP(lm73); +} + +int main(int argc, const char * argv[]) +{ + return UnityMain(argc, argv, run_lm73_tests); +} \ No newline at end of file diff --git a/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/ut_lm73_test.c b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/ut_lm73_test.c new file mode 100644 index 00000000..431baa94 --- /dev/null +++ b/gui/py_gen/module_template/_template_without_crf_new/{{cookiecutter.module_name}}/test/tsrc/ut_lm73_test.c @@ -0,0 +1,417 @@ +/* + * ut_lm73_test.c + * + * Created on: 2020. dec. 30. + * Author: jszeman + */ + +#include +#include +#include +#include +#include +#include "unity_fixture.h" +#include "crf.h" +#include "cbits.h" +#include "ut_i2c_driver_mock.h" +#include "i2c_master.h" +#include "lm73.h" +#include "lm73_regs.h" +#include "cevent.h" +#include "sys_if.h" + +TEST_GROUP(lm73); + +ut_i2c_driver_mock_tst drv_mock_st; +i2c_driver_if_tst* drv_pst = (i2c_driver_if_tst *)&drv_mock_st; + +const cevent_tst* i2c_master_events_apst[8]; +i2c_master_tst i2c_master_st; +uint8_t i2c_master_scanned_ids[127]; + +const cevent_tst* lm73_events_apst[8]; +lm73_tst lm73_st; + + +lm73_tst *self = &lm73_st; // This is necessary for macros like LM73_READ_PERIOD to work here + +chsm_tst* hsm_apst[] = { + (chsm_tst*)(&i2c_master_st), + (chsm_tst*)(&lm73_st), + NULL}; + +uint8_t pool_buff_au8[1024]; +cpool_tst pool_ast[1]; + +crf_tst crf; + +const cevent_tst* events_apst[4]; +cqueue_tst q_st; + +const cevent_tst tick_10ms_st = {.sig = SIG_SYS_TICK_10ms}; + +static void tick_ms(uint32_t tick_cnt_u32) +{ + while(tick_cnt_u32--) + { + drv_mock_st.tick(&drv_mock_st); + + CRF_POST(&tick_10ms_st, &lm73_st); + + while(CRF_STEP()) + { + printf("| "); + } + } +} + +void lm73_send(chsm_tst *self, const cevent_tst *e_pst) +{ + //printf("\n%s\n", __FUNCTION__); + switch(e_pst->sig) + { + case SIG_LM73_TEMP: + case SIG_LM73_ONLINE: + case SIG_LM73_OFFLINE: + CRF_POST(e_pst, &q_st); + break; + + default: + CRF_POST(e_pst, &i2c_master_st); + } +} + + +TEST_SETUP(lm73) +{ + memset(events_apst, 0, sizeof(events_apst)); + memset(&q_st, 0, sizeof(q_st)); + memset(&drv_mock_st, 0, sizeof(drv_mock_st)); + memset(&i2c_master_st, 0, sizeof(i2c_master_st)); + memset(&crf, 0, sizeof(crf)); + memset(&i2c_master_events_apst, 0, sizeof(i2c_master_events_apst)); + memset(&pool_buff_au8, 0, sizeof(pool_buff_au8)); + memset(&pool_ast, 0, sizeof(pool_ast)); + memset(&lm73_st, 0, sizeof(lm73_st)); + + cpool_init(pool_ast+0, pool_buff_au8, 24, 16); + + cqueue_init(&q_st, events_apst, 4); + + ut_i2c_driver_mock_init(&drv_mock_st); + + i2c_master_st.config_st.driver_pst = drv_pst; + // i2c_master_st.config_st.scan_result_au8[0] = &i2c_master_scanned_ids; + chsm_ctor(&i2c_master_st.super, i2c_master_top, i2c_master_events_apst, 4, 4); + chsm_ctor(&lm73_st.super, lm73_top, lm73_events_apst, 8, 0); + + lm73_st.config_st = (lm73_cfg_tst){ + .address_u8 = LM73_0_I2C_FLOAT, + .id_u16 = 0xabcd, + .period_ms_u16 = LM73_READ_PERIOD_VALUE, + .max_error_cnt_u16 = LM73_MAX_ERROR_COUNT_VALUE + }; + + CRF_SEND_FUNC(&lm73_st) = lm73_send; + + crf_init(&crf, hsm_apst, pool_ast, 1); + chsm_init((chsm_tst *)&i2c_master_st); + chsm_init((chsm_tst *)&lm73_st); +} + +TEST_TEAR_DOWN(lm73) +{ +} + +/* + * Just call setup + */ +TEST(lm73, init) +{ + printf("\n%s\n", __FUNCTION__); +} + +TEST(lm73, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = LM73_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, // sensor id + 0xf3, 0x80, // -25° measured value + 0x0c, 0x80 // +25° measured value + } + }; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + +} + +/* read_temp_twice: + * Setup the mock device to send the id bytes and two temperature reading (-25 and 25) to the master. + * Check, that two temperature events were sent + */ +TEST(lm73, read_temp_twice) +{ + printf("\n%s\n", __FUNCTION__); + i2c_mock_slave_device_tst dev_st = { + .address_u8 = 0x12, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + + const lm73_temp_tst* e_pst; + const lm73_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = (lm73_status_tst*)q_st.get(&q_st); + TEST_ASSERT(s_pst); + TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + + e_pst = (lm73_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + + tick_ms((LM73_READ_PERIOD/10)+1); + + uint8_t expected_au8[4] = {7, 0, 0, 0}; + TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); + TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); + TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + + e_pst = (lm73_temp_tst*)q_st.get(&q_st); + TEST_ASSERT(e_pst); + TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); + TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +} + +/* read_id_retry: + * Check that a failed ID read will be repeated after the configured time. + */ +TEST(lm73, read_id) +{ + printf("\n%s\n", __FUNCTION__); + + i2c_mock_slave_device_tst dev_st = { + .address_u8 = LM73_0_I2C_FLOAT, + .nack_idx_u16 = 20, + .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} + }; + + const lm73_status_tst* s_pst; + + drv_mock_st.slave_pst = &dev_st; + + tick_ms(10); + + s_pst = (lm73_status_tst*)q_st.get(&q_st); + TEST_ASSERT_NULL(s_pst); + + // dev_st.address_u8 = 0x12; + + // tick_ms(LM73_RETRY_TIMEOUT-10); + + // s_pst = (lm73_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NULL(s_pst); + + // tick_ms(10); + + // s_pst = (lm73_status_tst*)q_st.get(&q_st); + // TEST_ASSERT_NOT_NULL(s_pst); + // TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); +} + +// /* read_id_retry_bad_id: +// * Check that a failed ID read will be repeated after the configured time if the data sent back +// * by the slave is not 0x190 for the first try. +// */ +// TEST(lm73, read_id_retry_bad_id) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x91, 0x01, 0x90, 0x0c, 0x80} +// }; + +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms((LM73_RETRY_TIMEOUT-10)/10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NULL(s_pst); + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT_NOT_NULL(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); +// } + +// /* go_online: +// * Check that after reading temperature data fails for more than LM73_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST(lm73, go_online) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const lm73_temp_tst* e_pst; +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms((LM73_READ_PERIOD_VALUE / 10) + 1); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE(lm73_st.valid_b); +// } + +// /* go_offline: +// * Check that after reading temperature data fails for more than LM73_MAX_ERROR_COUNT times +// * the state machine goes offline and invalidates the temperature data. +// */ +// TEST(lm73, go_offline) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const lm73_temp_tst* e_pst; +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms((LM73_READ_PERIOD/10) + 1); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); + +// TEST_ASSERT_TRUE(lm73_st.valid_b); + +// dev_st.address_u8 = 0x13; + +// tick_ms(((LM73_READ_PERIOD/10) + 1) * LM73_MAX_ERROR_COUNT + 1); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_OFFLINE, s_pst->super.sig); + +// TEST_ASSERT_FALSE(lm73_st.valid_b); +// } + +// /* triggered_read: +// * Check that it is possible to trigger a read before the read period timeout elapses. +// */ +// TEST(lm73, triggered_read) +// { +// printf("\n%s\n", __FUNCTION__); + +// i2c_mock_slave_device_tst dev_st = { +// .address_u8 = 0x12, +// .nack_idx_u16 = 20, +// .tx_data_au8 = {0x01, 0x90, 0xf3, 0x80, 0x0c, 0x80} +// }; + +// const cevent_tst read_event = {.sig = SIG_LM73_READ}; + + +// const lm73_temp_tst* e_pst; +// const lm73_status_tst* s_pst; + +// drv_mock_st.slave_pst = &dev_st; + +// tick_ms(10); + +// s_pst = (lm73_status_tst*)q_st.get(&q_st); +// TEST_ASSERT(s_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_ONLINE, s_pst->super.sig); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(-25, e_pst->temp_C_i32); + +// tick_ms(1); + +// CRF_POST(&read_event, &lm73_st); + +// tick_ms(10); + +// uint8_t expected_au8[4] = {7, 0, 0, 0}; +// TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_au8, dev_st.rx_data_au8, 4); +// TEST_ASSERT_EQUAL(2, dev_st.rx_idx_u16); +// TEST_ASSERT_EQUAL(6, dev_st.tx_idx_u16); + +// e_pst = (lm73_temp_tst*)q_st.get(&q_st); +// TEST_ASSERT(e_pst); +// TEST_ASSERT_EQUAL(SIG_LM73_TEMP, e_pst->super.sig); +// TEST_ASSERT_EQUAL(25, e_pst->temp_C_i32); +// } + +TEST_GROUP_RUNNER(lm73) +{ + RUN_TEST_CASE(lm73, init); + RUN_TEST_CASE(lm73, read_id); + // RUN_TEST_CASE(lm73, read_temp_twice); + // RUN_TEST_CASE(lm73, read_id_retry); + // RUN_TEST_CASE(lm73, read_id_retry_bad_id); + // RUN_TEST_CASE(lm73, go_offline); + // RUN_TEST_CASE(lm73, go_online); + // RUN_TEST_CASE(lm73, triggered_read); +} diff --git a/gui/py_gen/render.py b/gui/py_gen/render.py new file mode 100644 index 00000000..00169c2b --- /dev/null +++ b/gui/py_gen/render.py @@ -0,0 +1,87 @@ +""" +Python state machine code generator for CHSM. + +Usage: + render.py [--output=] [--class-name=] + +Generates a Python state machine class from a CHSM drawing (.html) file. +""" +import sys +import os +import json +import jinja2 +from pathlib import Path + +# Add parent directory to path for imports +sys.path.insert(0, str(Path(__file__).parent.parent)) + +from c_gen.hsm.sm_jinja import JinjaStateMachine + + +TEMPLATE_DIR = (Path(__file__).parent.parent / 'c_gen' / 'templates').resolve() +TEMPLATE_NAME = 'chsm_py_template.jinja' + + +def load_model_from_html(html_path): + """Extract the JSON model from a CHSM HTML drawing file.""" + import re + with open(html_path, 'r') as f: + content = f.read() + m = re.search(r"
\n(?P.+)
", content, re.DOTALL) + if not m: + raise ValueError(f'No JSON data found in {html_path}') + return json.loads(m.group('json')) + + +def render(model, template_params=None): + """Render a Python state machine from a CHSM model dict. + + Args: + model: CHSM model dict (as parsed from the HTML drawing). + template_params: Optional dict of template parameters (e.g. class_name). + + Returns: + Generated Python source code as a string. + """ + sm = JinjaStateMachine(model) + data = sm.data.copy() + data['template_params'] = template_params or {} + + # Convert sets to tuples for template compatibility + for key in list(data.keys()): + if isinstance(data[key], set): + data[key] = tuple(data[key]) + + env = jinja2.Environment( + loader=jinja2.FileSystemLoader(str(TEMPLATE_DIR)), + trim_blocks=True, + lstrip_blocks=True, + ) + template = env.get_template(TEMPLATE_NAME) + return template.render(data=data) + + +if __name__ == '__main__': + if len(sys.argv) < 2: + print(__doc__) + sys.exit(1) + + html_file = sys.argv[1] + output_file = None + class_name = 'StateMachine' + + for arg in sys.argv[2:]: + if arg.startswith('--output='): + output_file = arg.split('=', 1)[1] + elif arg.startswith('--class-name='): + class_name = arg.split('=', 1)[1] + + model = load_model_from_html(html_file) + code = render(model, template_params={'class_name': class_name}) + + if output_file: + with open(output_file, 'w') as f: + f.write(code) + print(f'Generated {output_file}') + else: + print(code) diff --git a/gui/scripts/build_exe.bat b/gui/scripts/build_exe.bat new file mode 100644 index 00000000..45cec13e --- /dev/null +++ b/gui/scripts/build_exe.bat @@ -0,0 +1,13 @@ +@echo off + +set python_path=%PYTHON_PATH% + +if exist "%PYTHON_PATH%" ( + echo Environment variable PYTHON_PATH exists! + echo %python_path% + cd ../chsm/sm_gen + %python_path%\python.exe -m pip install pyinstaller eel docopt + %python_path%\python.exe -m eel ./chsm_backend.py --clean --onefile web -r ./cgen/templates +) else ( + echo Environment variable PYTHON_PATH doesen't exists please create it! +) diff --git a/gui/test_debug_client.py b/gui/test_debug_client.py new file mode 100644 index 00000000..4e6dc744 --- /dev/null +++ b/gui/test_debug_client.py @@ -0,0 +1,55 @@ +""" +Test client for the CHSM debug channel. + +Usage: + 1. Start the CHSM GUI (chsm_backend.py) + 2. In the GUI sidebar Debug panel, click "Connect" (default port 9999) + 3. Run this script: python test_debug_client.py + +This will simulate a state machine sending live debug data. +""" +import socket +import json +import time + +HOST = '127.0.0.1' +PORT = 9999 + + +def send(sock, msg): + sock.sendall((json.dumps(msg) + '\n').encode('utf-8')) + + +def main(): + print(f'Connecting to debug server at {HOST}:{PORT}...') + with socket.create_connection((HOST, PORT)) as sock: + print('Connected!') + + # Send initial state + send(sock, {'type': 'state', 'active': ['idle']}) + send(sock, {'type': 'variables', 'vars': {'counter': 0, 'timer_ms': 1000}}) + send(sock, {'type': 'event', 'name': 'INIT', 'data': ''}) + time.sleep(2) + + # Simulate a transition + send(sock, {'type': 'event', 'name': 'EVT_START'}) + send(sock, {'type': 'state', 'active': ['running']}) + send(sock, {'type': 'variables', 'vars': {'counter': 1, 'timer_ms': 500}}) + time.sleep(2) + + # Simulate nested states + send(sock, {'type': 'event', 'name': 'EVT_TICK'}) + send(sock, {'type': 'variables', 'vars': {'counter': 2, 'timer_ms': 250}}) + time.sleep(2) + + # Simulate return to idle + send(sock, {'type': 'event', 'name': 'EVT_STOP'}) + send(sock, {'type': 'state', 'active': ['idle']}) + send(sock, {'type': 'variables', 'vars': {'counter': 2, 'timer_ms': 0}}) + time.sleep(2) + + print('Test sequence complete.') + + +if __name__ == '__main__': + main() diff --git a/gui/vhdl_gen/__init__.py b/gui/vhdl_gen/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/gui/vhdl_gen/render.py b/gui/vhdl_gen/render.py new file mode 100644 index 00000000..9358017a --- /dev/null +++ b/gui/vhdl_gen/render.py @@ -0,0 +1,88 @@ +""" +VHDL state machine code generator for CHSM. + +Usage: + render.py [--output=] [--entity-name=] + +Generates a VHDL state machine entity from a CHSM drawing (.html) file. +""" +import sys +import os +import json +import jinja2 +from pathlib import Path + +# Add parent directory to path for imports +sys.path.insert(0, str(Path(__file__).parent.parent)) + +from c_gen.hsm.sm_jinja import JinjaStateMachine + + +TEMPLATE_DIR = (Path(__file__).parent.parent / 'c_gen' / 'templates').resolve() +TEMPLATE_NAME = 'chsm_vhdl_template.jinja' + + +def load_model_from_html(html_path): + """Extract the JSON model from a CHSM HTML drawing file.""" + import re + with open(html_path, 'r') as f: + content = f.read() + m = re.search(r"
\n(?P.+)
", content, re.DOTALL) + if not m: + raise ValueError(f'No JSON data found in {html_path}') + return json.loads(m.group('json')) + + +def render(model, template_params=None): + """Render a VHDL state machine from a CHSM model dict. + + Args: + model: CHSM model dict (as parsed from the HTML drawing). + template_params: Optional dict of template parameters + (e.g. entity_name, clock_name, reset_name, event_width). + + Returns: + Generated VHDL source code as a string. + """ + sm = JinjaStateMachine(model) + data = sm.data.copy() + data['template_params'] = template_params or {} + + # Convert sets to tuples for template compatibility + for key in list(data.keys()): + if isinstance(data[key], set): + data[key] = tuple(data[key]) + + env = jinja2.Environment( + loader=jinja2.FileSystemLoader(str(TEMPLATE_DIR)), + trim_blocks=True, + lstrip_blocks=True, + ) + template = env.get_template(TEMPLATE_NAME) + return template.render(data=data) + + +if __name__ == '__main__': + if len(sys.argv) < 2: + print(__doc__) + sys.exit(1) + + html_file = sys.argv[1] + output_file = None + entity_name = 'state_machine' + + for arg in sys.argv[2:]: + if arg.startswith('--output='): + output_file = arg.split('=', 1)[1] + elif arg.startswith('--entity-name='): + entity_name = arg.split('=', 1)[1] + + model = load_model_from_html(html_file) + code = render(model, template_params={'entity_name': entity_name}) + + if output_file: + with open(output_file, 'w') as f: + f.write(code) + print(f'Generated {output_file}') + else: + print(code) diff --git a/crf/test/doc/chsm_test_machine4.html b/gui/web/data.js similarity index 60% rename from crf/test/doc/chsm_test_machine4.html rename to gui/web/data.js index 4aced6b8..77742738 100644 --- a/crf/test/doc/chsm_test_machine4.html +++ b/gui/web/data.js @@ -1,295 +1,6 @@ - - - - - - -
- - - - - - GComment for G [s11_g_guard1Comment for the s11_g_guard1 func. - -Multiple lines.(1)]/ s11_g1(2)GComment for G [s11_g_guard2(4)]/ s11_g2(3)JJ[j_guard()][k_guardParametric guard comment.(5)]HD [cond()] / d_func() AEBABDHFComment for FFComment for FGComment for G [s11_g_guard2(4)]/ s11_g2(3)GComment for GCC - __top__4sentry/ s_entry()exit/ s_exit()init/ s_init()s1entry/ s1_entry()S1 entry function comment.exit/ s1_exit()init/ s1_init()[s1_guard()]/ s1_func()ID/ s1_func()s11entry/ s11_entry()S11 entry function commentexit/ s11_exit()init/ s11_init()ID/ s11_id(8)GComment for G [s11_g_guard1Comment for the s11_g_guard1 func. - -Multiple lines.(1)]/ s11_g1(2)[s11_guard(6)]/ s11_func(7)K/ chsm_deferL/ chsm_defers2entry/ s2_entry()exit/ s2_exit()init/ s2_init()s21entry/ s21_entry()exit/ s21_exit()init/ s21_init()s211entry/ s211_entry()exit/ s211_exit(6)init/ s211_init()ID/ s211_id()s3entry/ chsm_recallexit/K/ s3_k_func()L/ s3_l_func()s4ID/ s4_id() - - -
- -
- json -
-            {
-    "states": {
+export const state_machine = {
+	"states": {
         "__top__": {
             "pos": [
                 -99999997,
@@ -1856,8 +1567,5 @@
         ],
         "scale": 9.5
     }
-}
-        
-
- - +}; + diff --git a/gui/web/drawing.css b/gui/web/drawing.css new file mode 100644 index 00000000..03c1e7bd --- /dev/null +++ b/gui/web/drawing.css @@ -0,0 +1,221 @@ + +.state_body { + stroke: var(--state-body-color); + stroke-width: 0.2; + fill: none; + rx: 0.5px; +} + +.state_border { + stroke: var(--state-border-color); + stroke-width: 0.8; + fill: none; + rx: 0.5px; + opacity: 0; + color: var(--state-text-color); +} + +.state_border:hover { + opacity: 0.4; +} + +.state_border_highlight { + stroke: var(--state-border-highlight-color); + opacity: 0.4; +} + +.initial_state { + stroke: none; + stroke-width: 0.4; + fill: var(--intial-state-fill-color); + r: 0.7px; +} + +.initial_state:hover { + stroke: var(--initial-state-hover-color); + stroke-width: 0.5px; +} + +.state_border_deleting { + stroke: var(--state-border-deleting); + stroke-width: 0.8; + fill: none; + rx: 0.5px; + opacity: 0.4; +} + +.transition_handle { + stroke: var(--transition-handle-color); + stroke-width: 0.8; + fill: none; + rx: 0.5px; + opacity: 0; + cursor: grab; +} + +.transition_handle:hover { + opacity: 0.4; +} + +.transition_handle_deleting { + stroke: var(--transition-handle-deleting-color); + stroke-width: 0.8; + fill: none; + rx: 0.5px; + opacity: 0; + cursor: auto; +} + +.transition_handle_deleting:hover { + opacity: 0.4; +} + +.transition_handle_highlight_draw { + opacity: 0.4; + cursor: crosshair; +} + +.transition_handle_highlight_edit { + stroke: var(--transition-handle-highlight-edit-color); + opacity: 0.4; + cursor: grab; +} + +.transition_handle_highlight_drag { + opacity: 0.4; + cursor: grab; +} + +.state_separator { + stroke: var(--state-separator-color); + stroke-width: 0.1; + shape-rendering: crispEdges; +} + +.state_resize_mark { + stroke: var(--state-resize-mark-color); + stroke-width: 0.1; +} + +.state_title { + font: bold 0.08em arial,helvetica,sans-serif; + fill: var(--state-title-color); +} + +.state_text { + font: normal 0.08em arial,helvetica,sans-serif; + fill: var(--state-text-color); +} + +.transition_label { + font: normal 0.07em arial,helvetica,sans-serif; + fill: var(--transition-text-color); +} + +.function { + fill: var(--function-color); +} + +.function:hover { + fill: var(--function-hover-color); +} + +.transition_label:hover { + cursor: grab; +} + +.state_drag_handle { + fill: var(--state-drag-handle-color); + opacity: 0.1; + stroke: none; + rx: 0.5px; + cursor: move; + /* pointer-events: none; */ +} + +.state_resize_handle { + fill: var(--state-resize-handle-color); + opacity: 0.0; + stroke: none; + r: 0.5px; + cursor: nwse-resize; +} + +.transition_line { + fill: none; + stroke: var(--transition-line-color); + stroke-width: 0.2; +} + +.transition_arrow { + fill: var(--transition-arrow-color); + stroke: none; + stroke-width: 0.0; +} + +/* Debug: active state highlight */ +.state_border_debug_active { + stroke: var(--debug-active-state-color, #ff8c00); + stroke-width: 1.0; + opacity: 0.7; + stroke-dasharray: 1 0.5; +} + +/* Debug panel styles */ +.debug-status-on { + color: #22c55e; + font-weight: bold; + font-size: 0.85em; +} + +.debug-status-listening { + color: #f59e0b; + font-weight: bold; + font-size: 0.85em; +} + +.debug-status-off { + color: #888; + font-size: 0.85em; +} + +.debug-list { + list-style: none; + padding: 0; + margin: 0; + font-size: 0.85em; +} + +.debug-list li { + padding: 1px 4px; + border-bottom: 1px solid rgba(128,128,128,0.2); +} + +.debug-list li.debug-active-item { + color: var(--debug-active-state-color, #ff8c00); + font-weight: bold; +} + +.debug-var-table { + width: 100%; + font-size: 0.85em; + border-collapse: collapse; +} + +.debug-var-table th, +.debug-var-table td { + text-align: left; + padding: 1px 4px; + border-bottom: 1px solid rgba(128,128,128,0.2); +} + +.debug-var-table td:last-child { + font-family: monospace; +} + +.debug-event-log { + max-height: 150px; + overflow-y: auto; + font-family: monospace; + font-size: 0.8em; +} diff --git a/gui/web/favicon.ico b/gui/web/favicon.ico new file mode 100644 index 00000000..a9e34ad2 Binary files /dev/null and b/gui/web/favicon.ico differ diff --git a/web/favicon.ico b/gui/web/icon/favicon__.ico similarity index 100% rename from web/favicon.ico rename to gui/web/icon/favicon__.ico diff --git a/gui/web/icon/icon.svg b/gui/web/icon/icon.svg new file mode 100644 index 00000000..95260dea --- /dev/null +++ b/gui/web/icon/icon.svg @@ -0,0 +1,47 @@ + + + + + + + + + + diff --git a/gui/web/icon/icon2.png b/gui/web/icon/icon2.png new file mode 100644 index 00000000..1e551234 Binary files /dev/null and b/gui/web/icon/icon2.png differ diff --git a/gui/web/icon/icon2.svg b/gui/web/icon/icon2.svg new file mode 100644 index 00000000..ddc7a1fc --- /dev/null +++ b/gui/web/icon/icon2.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + diff --git a/gui/web/icon/icon2.xcf b/gui/web/icon/icon2.xcf new file mode 100644 index 00000000..e55762f8 Binary files /dev/null and b/gui/web/icon/icon2.xcf differ diff --git a/gui/web/main.css b/gui/web/main.css new file mode 100644 index 00000000..f0f4420b --- /dev/null +++ b/gui/web/main.css @@ -0,0 +1,195 @@ + + +html, body { + width: 100%; + height: 100%; + margin-left: 0px; + background-color: var(--html-bg); + position: relative; +} + +.wrapper { + width: 100%; + height: 100%; + display: flex; + flex-direction: row; + align-items: top; + justify-content: space-between +} + +.main { + width: 100%; + height: 100%; + +} + +svg { + width: 100%; + height: 100%; +} + +#sidebar { + padding: 0.2em; + flex: 0 0 250px; + margin-left: 5px; +} + +#sidebar-handle { + border-left: 1px solid var(--sidebar-handle-border-left-color); + width: 10px; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + cursor: ew-resize; +} + +#sidebar-handle:hover { + border-left: 1px solid var(--sidebar-handle-hover-border-left-color); +} + +#sidebar-handle-text { + border-radius: 0 4px 4px 0; + height: 4em; + width: 12px; + background-color: var(--sidebar-handle-text-bg-color); + color: var(--sidebar-handle-text-color); + display: flex; + justify-content: center; + align-items: center; + font: 1.2em arial,helvetica,sans-serif; + cursor: default; +} + +#sidebar-handle-text:hover { + background-color: var(--sidebar-handle-text-hover-color); +} + +.props { + list-style: none; + width: 100%; + padding-left: 0; +} + +#obj-label { + width: 95%; + margin: 0.1em; +} + +#obj-text { + width: 95%; + margin: 0.1em; + height: 20em; + resize: vertical; +} + +.button { + background-color: var(--button-bg-color); + color: var(--button-text-color); + margin-bottom: 0.5em; + margin-left: auto; + margin-right: auto; + padding: 0.3em; + border-radius: 0.2em; + max-width: 14ch; + text-align: center; + align-items: center; +} + +.button:hover { + background-color: var(--button-hover-bg-color); + color:var(--button-hover-text-color); + cursor: default; +} + +.row { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between +} + +.row-title { + font: bold 1.2em arial,helvetica,sans-serif; + color: var(--row-title-text-color); +} + +.button-inline { + background-color: var(--button-inline-bg-color); + color: var(--button-inline-text-color); + padding: 0.3em; + border-radius: 0.2em; + width: fit-content; + margin: 0.2em; + font: 0.9em arial,helvetica,sans-serif; +} + +.button-inline:hover { + background-color: var(--button-inline-hover-bg-color); + color: var(--button-inline-hover-text-color); + cursor: default; +} + +table { + font: 0.9em arial,helvetica,sans-serif; + border-collapse: collapse; +} + +th, td { + /* border-bottom: 1px solid var(--button-border-color); */ +} + +tr th:first-child {padding-left:0px;} +tr td:first-child {padding-left:0px;} +td, th {padding-left:1em;} + +details { + border: 1px solid var(--details-border-color); + color: var(--details-text-color); + border-radius: 4px; + padding: .5rem .5rem .5rem; + width: auto; + font: 1em arial,helvetica,sans-serif; +} + +details li{ + display: block; + font: .8em arial,helvetica,sans-serif; +} + +#title{ + text-align: center; + color: var(--title-text-color); + font: bold 1.2em arial,helvetica,sans-serif; +} + +nav ul li{ + align-items: center; +} + +fieldset{ + border-color: var(--details-fieldset-border-color); +} + +details fieldset li:first-child{ + padding-bottom: .5rem; +} + +input[type="text" i]{ + background-color: var(--input-text-bg-color); + color: var(--input-text-color); +} + +textarea{ + background-color: var(--input-textarea-bg-color); + color: var(--input-textarea-color); +} + +#help_details{ + width: max-content; +} + +select{ + background-color: var(--input-select-bg-color); + color: var(--input-select-color); +} \ No newline at end of file diff --git a/gui/web/main.html b/gui/web/main.html new file mode 100644 index 00000000..f5f24dd7 --- /dev/null +++ b/gui/web/main.html @@ -0,0 +1,267 @@ + + + + + CHSM + + + + + + + + + +
+ + +
+ + + + + + + +
+
+ + + + \ No newline at end of file diff --git a/web/main.js b/gui/web/main.js similarity index 58% rename from web/main.js rename to gui/web/main.js index f52516d5..6c5c9c86 100644 --- a/web/main.js +++ b/gui/web/main.js @@ -4,8 +4,7 @@ import { state_machine } from './data.js'; class App { - constructor(model) - { + constructor(model) { this.model = new Model(state_machine); this.gui = new Gui(); this.drawing = null; @@ -22,7 +21,11 @@ class App { }; this.file_name = ''; this.filepath = null; - + this.is_opened_statemachine = null; + + // Debug state + this.debug_active_states = []; // state titles currently active + this.model.states().map(s => this.render_state(s), this); this.model.transitions().map(t => this.render_transiton(t), this); @@ -30,7 +33,7 @@ class App { this.main = document.querySelector('main'); this.title = document.querySelector('#title'); - + this.body.addEventListener("keydown", event => { if (!this.enable_keys) return; if (event.isComposing || event.keyCode === 229) { @@ -68,15 +71,56 @@ class App { this.text_apply_btn = document.querySelector('#btn-text-apply'); this.text_apply_btn.addEventListener('click', e => this.dispatch('APPLY_TEXT', e)); + this.new_btn = document.querySelector('#btn-new'); + this.new_btn.addEventListener('click', e => this.dispatch('NEW', e)); + + this.new_btn = document.querySelector('#btn-new-window'); + this.new_btn.addEventListener('click', e => this.dispatch('NEW_WINDOW', e)); + this.save_btn = document.querySelector('#btn-save'); this.save_btn.addEventListener('click', e => this.dispatch('SAVE', e)); this.open_btn = document.querySelector('#btn-open'); this.open_btn.addEventListener('click', e => this.dispatch('OPEN', e)); + this.exit_btn = document.querySelector('#btn-exit'); + this.exit_btn.addEventListener('click', e => this.dispatch('EXIT', e)); + this.codegen_btn = document.querySelector('#btn-codegen'); this.codegen_btn.addEventListener('click', e => this.dispatch('CODE_GEN', e)); + this.auto_save_cb = document.getElementById("cb-auto_save"); + + this.dark_mode_select = document.querySelector('#theme-selector'); + this.dark_mode_select.addEventListener('change', e => { + if (this.dark_mode_select.value == true) { + this.dispatch('DARK_MODE', e) + } + }); + + // Debug panel elements + this.debug_port_input = document.getElementById('debug-port'); + this.debug_connect_btn = document.getElementById('btn-debug-connect'); + this.debug_disconnect_btn = document.getElementById('btn-debug-disconnect'); + this.debug_status_el = document.getElementById('debug-status'); + this.debug_active_list = document.getElementById('debug-active-states'); + this.debug_var_table = document.getElementById('debug-variables'); + this.debug_event_log = document.getElementById('debug-event-log'); + + this.debug_connect_btn.addEventListener('click', () => { + const port = parseInt(this.debug_port_input.value) || 9999; + eel.debug_start(port); + this.debug_connect_btn.style.display = 'none'; + this.debug_disconnect_btn.style.display = ''; + }); + + this.debug_disconnect_btn.addEventListener('click', () => { + eel.debug_stop(); + this.debug_connect_btn.style.display = ''; + this.debug_disconnect_btn.style.display = 'none'; + this._debug_clear(); + }); + this.body.addEventListener('mousemove', event => { this.mouse_pos = this.gui.get_absolute_pos(event); this.dispatch('MOUSEMOVE', event); @@ -86,44 +130,127 @@ class App { this.dispatch('MOUSEUP', event); }); + this.gui.svg.addEventListener('mousedown', event => { + if (event.ctrlKey) { + this.dispatch('DRAWING_CTRL_MDOWN', event); + } + else { + this.dispatch('DRAWING_MDOWN', event); + } + }); + // ----------------------------------------------------------------------------- + + let initialDistance = null; + + window.addEventListener('touchstart', function (e) { + if (e.touches.length == 2) { // ensure two fingers are used + // calculate the distance between two fingers + initialDistance = getDistanceBetweenTouches(e); + } + }, false); + + window.addEventListener('touchmove', function (e) { + if (e.touches.length == 2) { // ensure two fingers are used + // calculate the distance between two fingers + const distance = getDistanceBetweenTouches(e); + // calculate the zoom level (distance / initialDistance) + const zoom = distance / initialDistance; + // apply the zoom to the element + handleZoom(zoom); + // update initialDistance for the next move + initialDistance = distance; + } + }, false); + + // helper function to calculate the distance between two fingers + function getDistanceBetweenTouches(e) { + const [touch1, touch2] = e.touches; + return Math.hypot(touch2.pageX - touch1.pageX, touch2.pageY - touch1.pageY); + } + + // helper function to apply the zoom to the element + function handleZoom(zoom) { + const element = document.querySelector('#element-to-zoom'); + element.style.transform = `scale(${zoom})`; + } + + // ------------------------------------------------------------------------------------- + + this.inputElement = document.getElementById('input-to-update'); + this.activeTextElement = null; + + // this.get_state_text_elements(); + + this.inputElement.addEventListener('keydown', function (event) { + if (event.key === 'Enter') { + // Update the text element and hide the input + if (this.activeTextElement) { + this.activeTextElement.textContent = this.inputElement.value; + this.activeTextElement = null; + } + this.inputElement.style.display = 'none'; + } + }); + + // Hide the input when it loses focus + this.inputElement.addEventListener('blur', function () { + this.inputElement.style.display = 'none'; + }); + + this.gui.svg.addEventListener('click', event => { this.dispatch('CLICK', event); }); this.gui.svg.addEventListener('wheel', event => { - if (event.ctrlKey) - { + if (event.ctrlKey) { this.dispatch('DRAWING_CTRL_WHEEL', event); } - else if (event.shiftKey) - { + else if (event.shiftKey) { this.dispatch('DRAWING_SHIFT_WHEEL', event); } - else - { + else { this.dispatch('DRAWING_WHEEL', event); } }); - this.gui.svg.addEventListener('mousedown', event => { - if (event.ctrlKey) - { - this.dispatch('DRAWING_CTRL_MDOWN', event); - } - else - { - this.dispatch('DRAWING_MDOWN', event); - } - }); - this.state = this.idle_state; eel.startup() } - load_model(data, fname, fpath) - { + showInput(element) { + console.log("Enter into dblclick callback"); + // Set input value to the current text and show the input + this.inputElement.value = element.textContent; + this.inputElement.style.display = 'block'; + + // Position the input on top of the text element + const rect = element.getBoundingClientRect(); + this.inputElement.style.left = rect.left + 'px'; + this.inputElement.style.top = rect.top + 'px'; + + // Focus the input and select the text + this.inputElement.focus(); + this.inputElement.select(); + + // Store a reference to the active text element + this.activeTextElement = element; + } + + get_state_text_elements() { + const stateTitleElements = document.querySelectorAll('svg g .state_title, .state_text .function'); + // const stateTitleElements = document.querySelectorAll('.state_drag_handle'); + // Add the event listeners to each element + stateTitleElements.forEach((element) => { + // element.addEventListener('dblclick', this.showInput); + element.addEventListener('dblclick', e => function () { console.log({ element }); }); + }); + } + + load_model(data, fname, fpath) { this.gui.clear(); + this.debug_active_states = []; // clear debug highlights on model reload this.model = new Model(JSON.parse(data)); this.model.states().map(s => this.render_state(s), this); @@ -135,22 +262,20 @@ class App { this.filepath = fpath; this.title.textContent = this.file_name; document.title = this.file_name; - + this.prop_editor = { obj_id: null, obj_type: null }; } - push_transition_changes_to_gui() - { + push_transition_changes_to_gui() { this.model.changes.trans_new.map(d => this.render_transiton(...d), this); - this.model.changes.trans_redraw.map(d => - { - const [tr_id, tr] = d; - this.gui.redraw_path_with_arrow(tr_id, tr.vertices, tr.label, tr.label_pos); - }, this); + this.model.changes.trans_redraw.map(d => { + const [tr_id, tr] = d; + this.gui.redraw_path_with_arrow(tr_id, tr.vertices, tr.label, tr.label_pos); + }, this); this.model.changes.trans_set_label.map(d => this.gui.paths[d[0]].set_label(this.model.chop_text(d[1].label)), this); @@ -159,8 +284,7 @@ class App { this.model.changes.trans_set_label_pos.map(d => this.gui.paths[d[0]].set_label_pos(d[1]), this); } - push_state_changes_to_gui() - { + push_state_changes_to_gui() { this.model.changes.state_new.map(d => this.render_state(...d), this); this.model.changes.state_del.map(d => this.gui.delete_state(d[0]), this); this.model.changes.state_move.map(d => this.gui.states[d[0]].move(d[1].pos), this); @@ -169,35 +293,30 @@ class App { this.model.changes.state_set_title.map(d => this.gui.states[d[0]].set_title(d[1].title), this); } - push_model_changes_to_gui() - { + push_model_changes_to_gui() { this.push_transition_changes_to_gui(); this.push_state_changes_to_gui(); this.model.ack_changes(); } - dispatch(event, data) - { + dispatch(event, data) { const start_state = this.state; this.state(event, data); this.push_model_changes_to_gui(); - if ((this.state === this.idle_state) && (this.state !== start_state)) - { + if ((this.state === this.idle_state) && (this.state !== start_state)) { this.save_state(); } } - undo() - { + undo() { const view = this.model.undo(); this.gui.clear(); - - if (view !== null) - { + + if (view !== null) { this.gui.set_view(view); } @@ -205,13 +324,11 @@ class App { this.model.transitions().map(t => this.render_transiton(t), this); } - redo() - { + redo() { const view = this.model.redo(); this.gui.clear(); - if (view !== null) - { + if (view !== null) { this.gui.set_view(view); } @@ -219,25 +336,38 @@ class App { this.model.transitions().map(t => this.render_transiton(t), this); } - save_state() - { - if (this.model.save_state(this.gui.get_view())) - { + save_state() { + if (this.model.save_state(this.gui.get_view())) { this.title.textContent = '*' + this.file_name; } } - idle_state(event, data) - { + idle_state(event, data) { //console.log('idle', event); - switch(event) - { + switch (event) { case 'KEYDOWN': - switch(data.code) - { + switch (data.code) { case 'KeyS': - this.create_state(this.mouse_pos); - this.save_state(); + if (data.ctrlKey) { + data.stopPropagation(); + data.preventDefault(); + this.model.set_view(this.gui.get_view()); + eel.save_state_machine(this.main.innerHTML, this.model.get_data_string(), this.filepath); + } + else { + this.create_state(this.mouse_pos); + this.save_state(); + } + break; + + case 'KeyG': + if (data.ctrlKey) { + data.stopPropagation(); + data.preventDefault(); + this.model.set_view(this.gui.get_view()); + eel.save_state_machine(this.main.innerHTML, this.model.get_data_string(), this.filepath); + eel.genereate_code(); + } break; case 'KeyI': @@ -254,28 +384,28 @@ class App { data.preventDefault(); this.toggle_sidebar(); break; - + case 'KeyD': + case 'Delete': this.clear_sidebar(); this.start_delete_state_or_transition(); - this.state = this.delete_st_or_tr_state; + this.state = this.delete_st_or_tr_state; this.model.transitions().map(t => this.gui.redraw_path_change_line_color(t, true)); break; + case 'KeyZ': - if (data.ctrlKey) - { + if (data.ctrlKey) { this.undo(); } break; case 'KeyY': - if (data.ctrlKey) - { + if (data.ctrlKey) { this.redo(); } break; - + case 'KeyU': this.undo(); @@ -371,8 +501,7 @@ class App { case 'STATE_HEADER_CLICK': data.event.stopPropagation(); - if (!this.model.selection.has(data.id)) - { + if (!this.model.selection.has(data.id)) { this.dim_object(); } this.drop_selection(); @@ -426,12 +555,10 @@ class App { data.stopPropagation(); data.preventDefault(); const p = this.gui.get_absolute_pos(data); - if (data.deltaY < 0) - { + if (data.deltaY < 0) { this.gui.zoom_in(p); } - else - { + else { this.gui.zoom_out(p); } } @@ -441,12 +568,10 @@ class App { { data.stopPropagation(); data.preventDefault(); - if (data.deltaY < 0) - { + if (data.deltaY < 0) { this.gui.pan_up(); } - else - { + else { this.gui.pan_down(); } } @@ -456,12 +581,10 @@ class App { { data.stopPropagation(); data.preventDefault(); - if (data.deltaY < 0) - { + if (data.deltaY < 0) { this.gui.pan_right(); } - else - { + else { this.gui.pan_left(); } } @@ -472,13 +595,27 @@ class App { this.state = this.state_dragging_state; break; + case 'NEW': + eel.create_project(); + break; + + case 'NEW_WINDOW': + eel.open_window(); + break; + + case 'OPEN': + eel.open_file(); + this.is_opened_statemachine = "opened"; + break; + case 'SAVE': this.model.set_view(this.gui.get_view()); eel.save_state_machine(this.main.innerHTML, this.model.get_data_string(), this.filepath); break; - case 'OPEN': - eel.open_file(); + case 'AUTO_SAVE': + this.model.set_view(this.gui.get_view()); + eel.save_state_machine(this.main.innerHTML, this.model.get_data_string(), this.filepath); break; case 'CODE_GEN': @@ -487,6 +624,19 @@ class App { eel.genereate_code(); break; + case 'DARK_MODE': + // eel.switch_to_dark_mode(); + break; + + case 'EXIT': + window.close(); + if (this.is_opened_statemachine) { + this.model.set_view(this.gui.get_view()); + eel.save_state_machine(this.main.innerHTML, this.model.get_data_string(), this.filepath); + } + eel.exit_program(); + break; + case 'SAVE_RESULT': console.log(data); this.file_name = data.filename; @@ -497,11 +647,18 @@ class App { case 'CODEGEN_RESULT': console.log(data); break; + + case 'DEBUG_STATUS': + this._debug_update_status(data); + break; + + case 'DEBUG_UPDATE': + this._debug_handle_message(data); + break; } } - clear_sidebar() - { + clear_sidebar() { this.dim_object(); this.cache_text_changes(); this.clear_text_inputs(); @@ -509,20 +666,16 @@ class App { this.prop_editor.obj_type = null; } - toggle_sidebar() - { + toggle_sidebar() { this.sidebar.hidden = !this.sidebar.hidden; this.sidebar_handle_text.textContent = this.sidebar.hidden ? '>' : '<'; } - sidebar_resizing_state(event, data) - { + sidebar_resizing_state(event, data) { //console.log('resize', event); - switch(event) - { + switch (event) { case 'KEYDOWN': - switch(data.code) - { + switch (data.code) { case 'Escape': this.gui.set_cursor('auto'); this.state = this.idle_state; @@ -533,8 +686,7 @@ class App { case 'MOUSEMOVE': data.preventDefault(); data.stopPropagation(); - if (!this.sidebar.hidden) - { + if (!this.sidebar.hidden) { this.sidebar.style.flex = `0 0 ${(data.x - this.sidebar.getBoundingClientRect().left - 10)}px`; } break @@ -546,93 +698,75 @@ class App { } } - highlight_state(state_id) - { + highlight_state(state_id) { this.gui.states[state_id].add_border_class('state_border_highlight'); } - dim_state(state_id) - { + dim_state(state_id) { this.gui.states[state_id].remove_border_class('state_border_highlight'); } - drop_selection() - { - for (let state_id of this.model.selection) - { + drop_selection() { + for (let state_id of this.model.selection) { this.dim_state(state_id); } this.model.drop_selection(); } - select_state(state_id) - { - for (let state_id of this.model.selection) - { + select_state(state_id) { + for (let state_id of this.model.selection) { this.dim_state(state_id); } this.model.select_state(state_id); - for (let state_id of this.model.selection) - { + for (let state_id of this.model.selection) { this.highlight_state(state_id); } } - highlight_object() - { - const {obj_id, obj_type} = this.prop_editor; + highlight_object() { + const { obj_id, obj_type } = this.prop_editor; - if (obj_type === 'state') - { + if (obj_type === 'state') { this.highlight_state(obj_id); - this.sidebar.style.background = 'rgba(23, 197, 67, 0.1)'; + this.sidebar.style.background = '(--color-bg-highlight))'; } - else if (obj_type === 'transition') - { + else if (obj_type === 'transition') { this.gui.paths[obj_id].add_handle_class('transition_handle_highlight_edit'); - this.sidebar.style.background = 'rgba(23, 197, 67, 0.1)'; + this.sidebar.style.background = '(--color-bg-highlight))'; } } - dim_object() - { - const {obj_id, obj_type} = this.prop_editor; + dim_object() { + const { obj_id, obj_type } = this.prop_editor; - if ((obj_type === 'state') && (obj_id in this.gui.states)) - { + if ((obj_type === 'state') && (obj_id in this.gui.states)) { this.dim_state(obj_id); } - else if ((obj_type === 'transition') && (obj_id in this.gui.paths)) - { + else if ((obj_type === 'transition') && (obj_id in this.gui.paths)) { this.gui.paths[obj_id].remove_handle_class('transition_handle_highlight_edit'); } - - this.sidebar.style.background = 'white'; + + this.sidebar.style.background = '(--color-bg))'; } - reset_title() - { - const {obj_id, obj_type} = this.prop_editor; + reset_title() { + const { obj_id, obj_type } = this.prop_editor; - if (obj_type === 'state') - { + if (obj_type === 'state') { const text = this.model.reset_state_title(obj_id); this.title_input.value = text.title; } - else if (obj_type === 'transition') - { + else if (obj_type === 'transition') { this.title_input.value = this.model.reset_transition_label(obj_id); } } - apply_title() - { - const {obj_id, obj_type} = this.prop_editor; + apply_title() { + const { obj_id, obj_type } = this.prop_editor; - switch (obj_type) - { + switch (obj_type) { case 'state': this.model.apply_state_title(obj_id, this.title_input.value); break; @@ -643,37 +777,31 @@ class App { } } - reset_text() - { - const {obj_id, obj_type} = this.prop_editor; + reset_text() { + const { obj_id, obj_type } = this.prop_editor; - if (obj_type === 'state') - { + if (obj_type === 'state') { const text = this.model.reset_state_text(obj_id); this.text_area.value = text.text; } } - apply_text() - { - const {obj_id, obj_type} = this.prop_editor; + apply_text() { + const { obj_id, obj_type } = this.prop_editor; - switch (obj_type) - { + switch (obj_type) { case 'state': this.model.apply_state_text(obj_id, this.text_area.value); break; } } - cache_text_changes() - { - const {obj_id, obj_type} = this.prop_editor; + cache_text_changes() { + const { obj_id, obj_type } = this.prop_editor; - switch (obj_type) - { + switch (obj_type) { case 'state': - const state_text = {title: this.title_input.value, text: this.text_area.value}; + const state_text = { title: this.title_input.value, text: this.text_area.value }; this.model.cache_state_text(obj_id, state_text); break; @@ -687,8 +815,7 @@ class App { } } - show_state_text(state_id) - { + show_state_text(state_id) { const text = this.model.get_state_text(state_id); this.title_input.disabled = false; @@ -697,36 +824,31 @@ class App { this.text_area.value = text.text; } - show_transition_text(tr_id) - { + show_transition_text(tr_id) { this.title_input.disabled = false; this.title_input.value = this.model.get_transition_text(tr_id); this.text_area.value = ''; this.text_area.disabled = true; } - show_note_text(obj_id) - { + show_note_text(obj_id) { this.title_input.disabled = true; this.title_input.value = obj_id; this.text_area.disabled = false; this.text_area.value = this.model.get_note_text(obj_id); } - clear_text_inputs() - { + clear_text_inputs() { this.title_input.disabled = false; this.title_input.value = ''; this.text_area.disabled = false; this.text_area.value = ''; } - show_obj_text() - { - const {obj_id, obj_type} = this.prop_editor; + show_obj_text() { + const { obj_id, obj_type } = this.prop_editor; - switch (obj_type) - { + switch (obj_type) { case 'state': this.show_state_text(obj_id); break; @@ -741,23 +863,18 @@ class App { } } - start_transition() - { + start_transition() { this.gui.set_cursor('crosshair'); } - - start_delete_state_or_transition() - { + + start_delete_state_or_transition() { this.gui.set_cursor('crosshair'); } - select_tr_start_state(event, data) - { - switch(event) - { + select_tr_start_state(event, data) { + switch (event) { case 'KEYDOWN': - switch(data.code) - { + switch (data.code) { case 'Escape': this.gui.set_cursor('auto'); this.state = this.idle_state; @@ -769,8 +886,7 @@ class App { data.event.stopPropagation(); const pos = this.gui.get_state_rel_pos(data.event, data.id); const tr_id = this.model.set_transition_start(data.id, pos); - if (tr_id !== '') - { + if (tr_id !== '') { this.tr_draw_data.trans_id = tr_id; this.render_transiton(tr_id); this.state = this.transition_drawing_state; @@ -779,20 +895,17 @@ class App { break; } } - - delete_st_or_tr_state(event, data) - { - switch(event) - { + + delete_st_or_tr_state(event, data) { + switch (event) { case 'KEYDOWN': - switch(data.code) - { + switch (data.code) { case 'Escape': this.leave_delete_state(); break; } break; - + case 'TR_M_DOWN': //deleting a transition this.model.delete_transition(data.id); this.leave_delete_state(); @@ -813,20 +926,16 @@ class App { } } - leave_delete_state() - { + leave_delete_state() { this.gui.set_cursor('auto'); this.state = this.idle_state; this.model.transitions().map(t => this.gui.redraw_path_change_line_color(t, false)); } - transition_drawing_state(event, data) - { - switch(event) - { + transition_drawing_state(event, data) { + switch (event) { case 'KEYDOWN': - switch(data.code) - { + switch (data.code) { case 'Escape': this.model.delete_transition(this.tr_draw_data.trans_id); this.gui.set_cursor('auto'); @@ -851,12 +960,11 @@ class App { case 'CLICK': this.model.add_transition_vertex(this.tr_draw_data.trans_id); break; - + case 'STATE_BORDER_CLICK': data.event.stopPropagation(); const pos = this.gui.get_state_rel_pos(data.event, data.id); - if (this.model.set_transition_end(this.tr_draw_data.trans_id, data.id, pos)) - { + if (this.model.set_transition_end(this.tr_draw_data.trans_id, data.id, pos)) { this.gui.set_cursor('auto'); this.state = this.idle_state; this.gui.paths[this.tr_draw_data.trans_id].remove_handle_class('transition_handle_highlight_draw'); @@ -865,13 +973,10 @@ class App { } } - transition_dragging_state(event, data) - { - switch(event) - { + transition_dragging_state(event, data) { + switch (event) { case 'KEYDOWN': - switch(data.code) - { + switch (data.code) { case 'Escape': this.gui.set_cursor('auto'); this.state = this.idle_state; @@ -890,13 +995,10 @@ class App { } } - transition_label_dragging_state(event, data) - { - switch(event) - { + transition_label_dragging_state(event, data) { + switch (event) { case 'KEYDOWN': - switch(data.code) - { + switch (data.code) { case 'Escape': this.gui.set_cursor('auto'); this.state = this.idle_state; @@ -915,13 +1017,10 @@ class App { } } - state_resizing_state(event, data) - { - switch(event) - { + state_resizing_state(event, data) { + switch (event) { case 'KEYDOWN': - switch(data.code) - { + switch (data.code) { case 'Escape': this.gui.set_cursor('auto'); this.state = this.idle_state; @@ -940,20 +1039,17 @@ class App { } } - state_dragging_state(event, data) - { - switch(event) - { + state_dragging_state(event, data) { + switch (event) { case 'KEYDOWN': - switch(data.code) - { + switch (data.code) { case 'Escape': this.gui.set_cursor('auto'); this.state = this.idle_state; break; } break; - + case 'MOUSEMOVE': this.state_drag(data); break @@ -965,113 +1061,210 @@ class App { } } - set_state_text(state_id, text) - { + // ---- Debug channel methods ---- + + _debug_find_state_id_by_title(title) { + for (const [id, s] of Object.entries(this.model.data.states)) { + if (s.title === title) return id; + } + return null; + } + + _debug_clear_active_highlights() { + for (const title of this.debug_active_states) { + const id = this._debug_find_state_id_by_title(title); + if (id && id in this.gui.states) { + this.gui.states[id].remove_border_class('state_border_debug_active'); + } + } + this.debug_active_states = []; + } + + _debug_set_active_states(titles) { + this._debug_clear_active_highlights(); + this.debug_active_states = titles || []; + + for (const title of this.debug_active_states) { + const id = this._debug_find_state_id_by_title(title); + if (id && id in this.gui.states) { + this.gui.states[id].add_border_class('state_border_debug_active'); + } + } + + // Update sidebar list + this.debug_active_list.innerHTML = ''; + for (const title of this.debug_active_states) { + const li = document.createElement('li'); + li.classList.add('debug-active-item'); + li.textContent = title; + this.debug_active_list.appendChild(li); + } + } + + _debug_set_variables(vars) { + // Keep header row, replace body + while (this.debug_var_table.rows.length > 1) { + this.debug_var_table.deleteRow(1); + } + for (const [name, value] of Object.entries(vars || {})) { + const row = this.debug_var_table.insertRow(); + row.insertCell().textContent = name; + row.insertCell().textContent = JSON.stringify(value); + } + } + + _debug_add_event_log(msg) { + const li = document.createElement('li'); + const name = msg.name || '?'; + const payload = msg.data ? ` ${msg.data}` : ''; + li.textContent = `${name}${payload}`; + this.debug_event_log.appendChild(li); + // auto-scroll + this.debug_event_log.scrollTop = this.debug_event_log.scrollHeight; + // cap entries + while (this.debug_event_log.children.length > 200) { + this.debug_event_log.removeChild(this.debug_event_log.firstChild); + } + } + + _debug_handle_message(msg) { + if (!msg || !msg.type) return; + + switch (msg.type) { + case 'state': + this._debug_set_active_states(msg.active); + break; + case 'variables': + this._debug_set_variables(msg.vars); + break; + case 'event': + this._debug_add_event_log(msg); + break; + case 'reset': + this._debug_clear(); + break; + } + } + + _debug_update_status(data) { + if (data.connected) { + this.debug_status_el.textContent = 'Connected'; + this.debug_status_el.className = 'debug-status-on'; + } else if (data.listening) { + this.debug_status_el.textContent = `Listening on :${data.port}...`; + this.debug_status_el.className = 'debug-status-listening'; + } else { + this.debug_status_el.textContent = 'Disconnected'; + this.debug_status_el.className = 'debug-status-off'; + if (data.error) { + this.debug_status_el.textContent = `Error: ${data.error}`; + } + } + } + + _debug_clear() { + this._debug_clear_active_highlights(); + this.debug_active_list.innerHTML = ''; + while (this.debug_var_table.rows.length > 1) { + this.debug_var_table.deleteRow(1); + } + this.debug_event_log.innerHTML = ''; + } + + // ---- End debug methods ---- + + set_state_text(state_id, text) { this.model.set_state_text(state_id, text); this.push_model_changes_to_gui(); } - create_state(pos) - { + create_state(pos) { this.model.make_new_state(pos); } - create_initial_state(pos) - { + create_initial_state(pos) { this.model.make_new_initial_state(pos); } - state_drag_start(evt, state_id, drag_substates) - { + state_drag_start(evt, state_id, drag_substates) { evt.preventDefault(); const [ex, ey] = this.gui.get_absolute_pos(evt); const [sx, sy] = this.model.get_state(state_id).pos; - this.drag_data.offset = [ex-sx, ey-sy]; + this.drag_data.offset = [ex - sx, ey - sy]; this.drag_data.state_id = state_id; this.drag_data.drag_substates = drag_substates; } - - state_resize_start(evt, state_id) - { + + state_resize_start(evt, state_id) { evt.preventDefault(); this.resize_data.transitions = this.model.state_transitions(state_id); this.resize_data.state_id = state_id; } - - state_resize(evt) - { + + state_resize(evt) { evt.preventDefault(); const state_id = this.resize_data.state_id; const size = this.gui.get_state_rel_pos(evt, state_id); this.model.resize_state(state_id, size); } - state_resize_end(evt) - { + state_resize_end(evt) { evt.preventDefault(); } - state_drag(evt) - { + state_drag(evt) { evt.preventDefault(); const [ex, ey] = this.gui.get_absolute_pos(evt); const [ox, oy] = this.drag_data.offset; - const pos = [ex-ox, ey-oy]; + const pos = [ex - ox, ey - oy]; const state_id = this.drag_data.state_id; this.model.move_state(state_id, pos, this.drag_data.drag_substates); } - state_drag_end(evt) - { + state_drag_end(evt) { evt.preventDefault(); this.model.update_parents(); } - render_state(state_id, state_data=null) - { + render_state(state_id, state_data = null) { const state = state_data !== null ? state_data : this.model.get_state(state_id); const params = { - id: state_id, - title: state.title, - pos: state.pos, - size: state.size, - strings: state.text.map(this.model.chop_text, this.model), - type: state.type, - text_height: this.model.options.text_height, - on_header_mouse_down: evt => { - if (evt.shiftKey) - { - this.dispatch('STATE_HEADER_SHIFT_M_DOWN', {event: evt, id: state_id}); + id: state_id, + title: state.title, + pos: state.pos, + size: state.size, + strings: state.text.map(this.model.chop_text, this.model), + type: state.type, + text_height: this.model.options.text_height, + on_header_mouse_down: evt => { + if (evt.shiftKey) { + this.dispatch('STATE_HEADER_SHIFT_M_DOWN', { event: evt, id: state_id }); } - else - { - this.dispatch('STATE_HEADER_M_DOWN', {event: evt, id: state_id}); + else { + this.dispatch('STATE_HEADER_M_DOWN', { event: evt, id: state_id }); } }, - on_header_click: evt => { - if (evt.ctrlKey) - { - this.dispatch('STATE_HEADER_CTRL_CLICK', {event: evt, id: state_id}) + on_header_click: evt => { + if (evt.ctrlKey) { + this.dispatch('STATE_HEADER_CTRL_CLICK', { event: evt, id: state_id }) } - else - { - this.dispatch('STATE_HEADER_CLICK', {event: evt, id: state_id}) + else { + this.dispatch('STATE_HEADER_CLICK', { event: evt, id: state_id }) } }, - on_corner_mouse_down: evt => this.dispatch('STATE_RESIZE', {event: evt, id: state_id}), - on_border_click: evt => this.dispatch('STATE_BORDER_CLICK', {event: evt, id: state_id}), - on_header_mouse_over: evt => this.dispatch('STATE_HEADER_M_OVER', {event: evt, id: state_id}), - on_header_mouse_leave: evt => this.dispatch('STATE_HEADER_M_LEAVE', {event: evt, id: state_id}), - on_txt_click: evt => this.dispatch('TXT_CLICK', {event: evt}), + on_corner_mouse_down: evt => this.dispatch('STATE_RESIZE', { event: evt, id: state_id }), + on_border_click: evt => this.dispatch('STATE_BORDER_CLICK', { event: evt, id: state_id }), + on_header_mouse_over: evt => this.dispatch('STATE_HEADER_M_OVER', { event: evt, id: state_id }), + on_header_mouse_leave: evt => this.dispatch('STATE_HEADER_M_LEAVE', { event: evt, id: state_id }), + on_txt_click: evt => this.dispatch('TXT_CLICK', { event: evt }), }; this.gui.render_state(params); } - trans_drag_start(evt, trans_id) - { + trans_drag_start(evt, trans_id) { evt.preventDefault(); const p = this.gui.get_absolute_pos(evt); @@ -1084,16 +1277,14 @@ class App { this.gui.set_cursor('grab'); } - trans_split(evt, trans_id) - { + trans_split(evt, trans_id) { evt.preventDefault(); const p = this.gui.get_absolute_pos(evt); this.model.transition_split(trans_id, p); } - trans_drag(evt) - { + trans_drag(evt) { evt.preventDefault(); const p = this.gui.get_absolute_pos(evt); @@ -1102,81 +1293,73 @@ class App { this.model.transition_drag(trans_id, line, p, this.drag_data.label_width); } - trans_drag_end(evt) - { + trans_drag_end(evt) { evt.preventDefault(); this.model.simplify_tr_path(this.drag_data.trans_id); this.gui.paths[this.drag_data.trans_id].remove_handle_class('transition_handle_highlight_drag'); this.gui.set_cursor('auto'); } - trans_label_drag_start(evt, trans_id) - { + trans_label_drag_start(evt, trans_id) { evt.preventDefault(); const [ex, ey] = this.gui.get_absolute_pos(evt); const [sx, sy] = this.model.get_transition(trans_id).label_pos; - this.drag_data.offset = [ex-sx, ey-sy]; + this.drag_data.offset = [ex - sx, ey - sy]; this.drag_data.trans_id = trans_id; this.gui.set_cursor('grab'); } - trans_label_drag(evt) - { + trans_label_drag(evt) { evt.preventDefault(); const [ex, ey] = this.gui.get_absolute_pos(evt); const [ox, oy] = this.drag_data.offset; - const pos = [ex-ox, ey-oy]; + const pos = [ex - ox, ey - oy]; const trans_id = this.drag_data.trans_id; this.model.transition_label_drag(trans_id, pos); } - trans_label_drag_end(evt) - { + trans_label_drag_end(evt) { evt.preventDefault(); this.gui.set_cursor('auto'); } - render_transiton(trans_id, tr_data=null) - { + render_transiton(trans_id, tr_data = null) { const tr = tr_data !== null ? tr_data : this.model.get_transition(trans_id); const params = { - id: trans_id, - vertices: tr.vertices, - label: this.model.chop_text(tr.label), - label_pos: tr.label_pos, - on_mousedown: evt => this.dispatch('TR_M_DOWN', {event: evt, id: trans_id}), - on_dblclick: evt => this.dispatch('TR_DBLCLICK', {event: evt, id: trans_id}), - on_click: evt => { - if (evt.shiftKey) - { - this.dispatch('TR_SHIFT_CLICK', {event: evt, id: trans_id}); - } - else - { - this.dispatch('TR_CLICK', {event: evt, id: trans_id}); - } - }, - on_label_mousedown: evt => this.dispatch('TR_LABEL_M_DOWN', {event: evt, id: trans_id}), - on_txt_click: evt => this.dispatch('TXT_CLICK', {event: evt}) + id: trans_id, + vertices: tr.vertices, + label: this.model.chop_text(tr.label), + label_pos: tr.label_pos, + on_mousedown: evt => this.dispatch('TR_M_DOWN', { event: evt, id: trans_id }), + on_dblclick: evt => this.dispatch('TR_DBLCLICK', { event: evt, id: trans_id }), + on_click: evt => { + if (evt.shiftKey) { + this.dispatch('TR_SHIFT_CLICK', { event: evt, id: trans_id }); + } + else { + this.dispatch('TR_CLICK', { event: evt, id: trans_id }); + } + }, + on_label_mousedown: evt => this.dispatch('TR_LABEL_M_DOWN', { event: evt, id: trans_id }), + on_txt_click: evt => this.dispatch('TXT_CLICK', { event: evt }) }; this.gui.render_transition(params); } } -window.addEventListener('DOMContentLoaded', event => {window.app = new App(state_machine)}); +window.addEventListener('DOMContentLoaded', event => { window.app = new App(state_machine) }); eel.expose(load_json); // Expose this function to Python function load_json(data, filename, filepath) { - //console.log(data) window.app.load_model(data, filename, filepath); + window.app.get_state_text_elements(); } eel.expose(send_event); -function send_event(event, data) -{ +function send_event(event, data) { window.app.dispatch(event, data); -} \ No newline at end of file +} diff --git a/web/modules/geometry.js b/gui/web/modules/geometry.js similarity index 100% rename from web/modules/geometry.js rename to gui/web/modules/geometry.js diff --git a/web/modules/gui.mjs b/gui/web/modules/gui.mjs similarity index 100% rename from web/modules/gui.mjs rename to gui/web/modules/gui.mjs diff --git a/web/modules/model.js b/gui/web/modules/model.js similarity index 100% rename from web/modules/model.js rename to gui/web/modules/model.js diff --git a/gui/web/modules/web_components/init_comp.js b/gui/web/modules/web_components/init_comp.js new file mode 100644 index 00000000..55e08cc4 --- /dev/null +++ b/gui/web/modules/web_components/init_comp.js @@ -0,0 +1,25 @@ + +class InitStateComponent extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + } + + connectedCallback() { + this.render(); + } + + render() { + this.shadowRoot.innerHTML = ` + +
+

Init State

+

This is the initial state of the hierarchical state machine.

+
+ `; + } +} + +customElements.define('init-state', InitStateComponent); diff --git a/gui/web/modules/web_components/state_comp.js b/gui/web/modules/web_components/state_comp.js new file mode 100644 index 00000000..bcc64755 --- /dev/null +++ b/gui/web/modules/web_components/state_comp.js @@ -0,0 +1,53 @@ + +class StateComponent extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + } + + static get observedAttributes() { + return ['name', 'level']; + } + + attributeChangedCallback(name, oldValue, newValue) { + if (name === 'name') { + this.name = newValue; + } else if (name === 'level') { + this.level = parseInt(newValue); + } + } + + connectedCallback() { + this.render(); + } + + render() { + const stateName = this.name || 'State'; + const stateLevel = this.level || 0; + + const stateElement = document.createElement('div'); + stateElement.classList.add('state'); + stateElement.style.paddingLeft = `${stateLevel * 20}px`; + + const stateNameElement = document.createElement('div'); + stateNameElement.classList.add('state-name'); + stateNameElement.textContent = stateName; + + stateElement.appendChild(stateNameElement); + + this.shadowRoot.innerHTML = ` + + `; + this.shadowRoot.appendChild(stateElement); + } +} + +customElements.define('state-component', StateComponent); diff --git a/gui/web/modules/web_components/transient_comp.js b/gui/web/modules/web_components/transient_comp.js new file mode 100644 index 00000000..16de27a3 --- /dev/null +++ b/gui/web/modules/web_components/transient_comp.js @@ -0,0 +1,24 @@ + +class HierarchicalStatemachineTransient extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + } + + connectedCallback() { + this.render(); + } + + render() { + this.shadowRoot.innerHTML = ` + +
+ +
+ `; + } +} + +customElements.define('hierarchical-statemachine-transient', HierarchicalStatemachineTransient); diff --git a/gui/web/modules/web_components/web_components.js b/gui/web/modules/web_components/web_components.js new file mode 100644 index 00000000..e69de29b diff --git a/gui/web/new_module/new_module.css b/gui/web/new_module/new_module.css new file mode 100644 index 00000000..7de77ba5 --- /dev/null +++ b/gui/web/new_module/new_module.css @@ -0,0 +1,78 @@ +*, +*::before, +*::after{ + box-sizing: border-box; +} + +html, body { + width: 100%; + height: 100%; + margin-left: 1rem; + margin-right: 1rem; + font: .9em arial,helvetica,sans-serif; + display: flex; + justify-content: center; + align-items: center; +} + +legend { + font: 1.5em sans-serif,arial,helvetica,bold; + font-weight: 600; + text-align: left; + padding-left: .7rem; + padding-right: .7rem; + color: var(--text-color); +} + +#new_module_legend{ + text-align: center; + font-size: 1.7rem; +} + +fieldset:first-child{ + padding: 2rem; + border-radius: 1.5rem; +} + +fieldset:first-child > *{ + border-radius: 1rem; +} + +fieldset{ + border-color: var(--legend-border-color); +} + +#generate-btns_container{ + width: 100%; + height: 100%; + display: grid; + grid-template-columns: 1fr 1fr; + align-items: center; + justify-items: center; +} + +#btn-generate, #btn-cancel{ + width: 100%; + margin: 0; +} + +#modul_gen_fs ul *{ + display: block; + width: 100%; + align-items: center; + justify-items: center; +} + +#modul_loc_tr :first-child > *{ + display: inline-block; + width: min-content; +} + +label{ + color: var(--text-color); +} + +input[type="url" i]{ + background-color: var(--input-text-bg-color); + color: var(--input-text-color); +} \ No newline at end of file diff --git a/gui/web/new_module/new_module.html b/gui/web/new_module/new_module.html new file mode 100644 index 00000000..dc884419 --- /dev/null +++ b/gui/web/new_module/new_module.html @@ -0,0 +1,128 @@ + + + + + + + + + + New Module + + +
+
+ New module +
+ Module +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    + + +
    Browse
    + +
+
+
+ CMake generation +
    +
    +
  • + + + + + +
    + + + + +
    +
    +
  • +
    + +
+
+
+
Generate
+
Cancel
+
+
+
+ + +
+ + diff --git a/gui/web/new_module/new_module.js b/gui/web/new_module/new_module.js new file mode 100644 index 00000000..e22be43c --- /dev/null +++ b/gui/web/new_module/new_module.js @@ -0,0 +1,117 @@ + +class New_module{ + constructor(){ + // New module + this.name = document.getElementById("module_name"); + this.version = document.getElementById("module_version"); + this.author_nick_name = document.getElementById("author_nick_name"); + this.author_full_name = document.getElementById("author_full_name"); + this.description = document.getElementById("module_description"); + this.device_address = document.getElementById("device_address"); + this.comm_selector = document.getElementById("comm-selector"); + this.licence_selector = document.getElementById("licence-selector"); + this.module_location = document.getElementById("module_location"); + this.browse_btn = document.getElementById("btn-new-module-loc-browse"); + this.browse_btn.addEventListener("click" , e => this.state_select("MODULE_BROWSE")); + // CMake + this.package_name = document.getElementById("package_name"); + this.linked_libs = document.getElementById("linked_libs"); + // Buttons + this.cancel_btn = document.getElementById("btn-cancel"); + this.cancel_btn.addEventListener("click" , e => this.state_select("CANCEL")); + this.generate_btn = document.getElementById("btn-generate"); + this.generate_btn.addEventListener("click" , e => this.state_select("GENERATE")); + + this.browse_source = 0; + + console.log("Constructor done!") + } + + cancel_project_window() + { + console.log("Cancel button clicked"); + window.close(); + } + + validate() + { + if (!this.name.value || !this.name.value.trim()) { + alert("Module name is required."); + this.name.focus(); + return false; + } + if (!this.module_location.value || !this.module_location.value.trim()) { + alert("Module location is required. Use Browse to select a directory."); + this.module_location.focus(); + return false; + } + return true; + } + + state_select(event) + { + console.log("Event received!"); + console.log(event); + switch(event) + { + case "CANCEL": + this.cancel_project_window(); + break; + case "GENERATE": + if (!this.validate()) break; + this.generate_btn.textContent = "Generating..."; + this.generate_btn.style.backgroundColor = ""; + eel.generate_module(this.name.value, + this.version.value, + this.description.value, + this.module_location.value, + this.linked_libs.value, + this.package_name.value, + this.comm_selector.value, + this.device_address.value, + this.author_nick_name.value, + this.author_full_name.value, + this.licence_selector.value + ); + console.log(this); + break; + case "MODULE_BROWSE": + this.browse_source = "MODULE_BROWSE" + eel.browse_dir_path(); + break; + } + + } +} + +window.addEventListener('DOMContentLoaded', function() { + window.nm = new New_module(); +}); + +eel.expose(set_choosen_path_to_input_text); +function set_choosen_path_to_input_text(path) +{ + switch(nm.browse_source) + { + case "MODULE_BROWSE": + nm.module_location.value = path; + break; + } +} + +eel.expose(successful_generate) +function successful_generate() +{ + nm.generate_btn.style.backgroundColor = "green"; + nm.generate_btn.textContent = "Generate"; + console.log("Successfully generated!"); +} + +eel.expose(failed_generate) +function failed_generate(error_msg) +{ + nm.generate_btn.style.backgroundColor = "red"; + nm.generate_btn.textContent = "Generate"; + alert("Generation failed: " + error_msg); + console.error("Generation failed:", error_msg); +} \ No newline at end of file diff --git a/gui/web/themes/default.css b/gui/web/themes/default.css new file mode 100644 index 00000000..38320e47 --- /dev/null +++ b/gui/web/themes/default.css @@ -0,0 +1,45 @@ +:root { + --nc-font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + --nc-font-mono: Consolas, monaco, 'Ubuntu Mono', 'Liberation Mono', 'Courier New', Courier, monospace; + + /* drawing.css */ + --state-body-color: rgb(0, 0, 0); + --state-border-color: rgb(0, 191, 255); + --state-border-highlight-color: rgb(23, 197, 66); + --intial-state-fill-color: rgb(0, 0, 0); + --initial-state-hover-color: rgb(0, 191, 255); + --state-border-deleting-color: rgb(255, 0, 0); + --transition-handle-color: rgb(0, 191, 255); + --transition-handle-deleting-color: rgb(255, 0, 0); + --transition-handle-highlight-edit-color: rgb(23, 197, 66); + --state-separator-color: rgb(128, 128, 128); + --state-resize-mark-color: rgb(128, 128, 128); + --function-color: rgb(0, 0, 0); + --function-hover-color: rgb(0, 0, 255); + --state-drag-handle-color: rgb(211, 102, 1); + --state-resize-handle-color: rgb(255, 255, 255); + --transition-line-color: rgb(70, 130, 180); + --transition-arrow-color: rgb(70, 130, 180); + + /* debug */ + --debug-active-state-color: rgb(255, 140, 0); + + /* main.css */ + --sidebar-handle-border-left-color: rgb(221, 221, 221); + --sidebar-handle-hover-border-left-color: rgb(170, 170, 170); + --sidebar-handle-text-bg-color: rgb(170, 170, 170); + --sidebar-handle-text-color: rgb(20, 20, 126); + --sidebar-handle-text-hover-color: rgb(153, 153, 153); + --button-bg-color: rgb(70, 130, 180); + --button-text-color: rgb(255, 255, 255); + --button-hover-bg-color: rgb(44, 118, 179); + --button-inline-bg-color: rgb(70, 130, 180); + --button-inline-text-color: rgb(255, 255, 255); + --button-inline-hover-bg-color: rgb(44, 118, 179); + --button-border-color: rgb(221, 221, 221); + --details-border-color: rgb(8, 0, 0); + --input-text-bg-color: rgb(245, 245, 245); + --input-textarea-bg-color: rgb(245, 245, 245); + + --html-bg: rgb(255, 255, 255); +} \ No newline at end of file diff --git a/gui/web/themes/solarized_dark.css b/gui/web/themes/solarized_dark.css new file mode 100644 index 00000000..0eea087f --- /dev/null +++ b/gui/web/themes/solarized_dark.css @@ -0,0 +1,86 @@ +:root { + --nc-font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + --nc-font-mono: Consolas, monaco, 'Ubuntu Mono', 'Liberation Mono', 'Courier New', Courier, monospace; + + --base00: #657b83; + --base01: #586e75; + --base02: #073642; + --base03: #002b36; + --base0: #839496; + --base1: #93a1a1; + --base2: #eee8d5; + --base3: #fdf6e3; + --yellow: #b58900; + --orange: #cb4b16; + --red: #dc322f; + --magenta: #d33682; + --violet: #6c71c4; + --blue: #268bd2; + --cyan: #2aa198; + --green: #859900; + + --html-bg: var(--base03); + --text-color: var(--base1); + --border-color:var(--base02); + + /* drawing.css */ + --intial-state-fill-color: var(--base01); + --initial-state-hover-color: var(--blue); + --state-body-color: var(--base01); + --state-separator-color: var(--base01); + --state-text-color: var(--text-color); + --state-title-color: var(--text-color); + --state-text-color: var(--text-color); + --state-border-color: var(--blue); + --state-border-highlight-color: var(--green); + --state-border-deleting-color: var(--red); + --state-drag-handle-color: var(--yellow); + --state-resize-handle-color: var(--base01); + --state-resize-mark-color: var(--base00); + --transition-handle-color: var(--blue); + --transition-handle-deleting-color: var(--red); + --transition-handle-highlight-edit-color: var(--green); + --function-color: var(--text-color); + --function-hover-color: var(--blue); + --transition-line-color: var(--blue); + --transition-arrow-color: var(--blue); + --transition-text-color: var(--text-color); + + /* debug */ + --debug-active-state-color: var(--orange); + + /* main.css */ + --sidebar-handle-border-left-color: var(--border-color); + --sidebar-handle-hover-border-left-color: var(--border-color); + --sidebar-handle-text-bg-color: var(--base00); + --sidebar-handle-text-color: var(--text-color); + --sidebar-handle-text-hover-color: var(--base01); + + --button-bg-color: var(--base02); + --button-text-color: var(--base00); + --button-hover-bg-color: var(--cyan); + --button-hover-text-color: var(--base02); + --button-inline-bg-color: var(--base02); + --button-inline-text-color: var(--base00); + --button-inline-hover-bg-color: var(--cyan); + --button-inline-hover-text-color: var(--base02); + --button-border-color: var(--base0); + + --details-border-color: var(--border-color); + --details-fieldset-border-color: var(--border-color); + --details-text-color: var(--text-color); + + --input-text-bg-color: var(--base02); + --input-text-color: var(--text-color); + --input-textarea-bg-color: var(--base02); + --input-textarea-color: var(--text-color); + + --title-text-color: var(--text-color); + --row-title-text-color: var(--text-color); + --input-select-bg-color: var(--base02); + --input-select-color: var(--text-color); + --general-text-color: var(--text-color); + + /* new_module */ + --legend-border-color:var(--base01); +} \ No newline at end of file diff --git a/gui/web/themes/solarized_light.css b/gui/web/themes/solarized_light.css new file mode 100644 index 00000000..78cd3e8c --- /dev/null +++ b/gui/web/themes/solarized_light.css @@ -0,0 +1,86 @@ +:root { + --nc-font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + --nc-font-mono: Consolas, monaco, 'Ubuntu Mono', 'Liberation Mono', 'Courier New', Courier, monospace; + + --base00: #657b83; + --base01: #586e75; + --base02: #073642; + --base03: #002b36; + --base0: #839496; + --base1: #93a1a1; + --base2: #eee8d5; + --base3: #fdf6e3; + --yellow: #b58900; + --orange: #cb4b16; + --red: #dc322f; + --magenta: #d33682; + --violet: #6c71c4; + --blue: #268bd2; + --cyan: #2aa198; + --green: #859900; + + --text-color: var(--base01); + --border-color: var(--base2); + --html-bg: var(--base3); + + /* drawing.css */ + --intial-state-fill-color: var(--base1); + --initial-state-hover-color: var(--blue); + --state-body-color: var(--base1); + --state-separator-color: var(--base1); + --state-text-color: var(--text-color); + --state-title-color: var(--text-color); + --state-text-color: var(--text-color); + --state-border-color: var(--blue); + --state-border-highlight-color: var(--green); + --state-border-deleting-color: var(--red); + --state-drag-handle-color: var(--yellow); + --state-resize-handle-color: var(--base1); + --state-resize-mark-color: var(--base0); + --transition-handle-color: var(--blue); + --transition-handle-deleting-color: var(--red); + --transition-handle-highlight-edit-color: var(--green); + --function-color: var(--text-color); + --function-hover-color: var(--blue); + --transition-line-color: var(--blue); + --transition-arrow-color: var(--blue); + --transition-text-color: var(--text-color); + + /* debug */ + --debug-active-state-color: var(--orange); + + /* main.css */ + --sidebar-handle-border-left-color: var(--border-color); + --sidebar-handle-hover-border-left-color: var(--border-color); + --sidebar-handle-text-bg-color: var(--base0); + --sidebar-handle-text-color: var(--text-color); + --sidebar-handle-text-hover-color: var(--base1); + + --button-bg-color: var(--base2); + --button-text-color: var(--base0); + --button-hover-bg-color: var(--cyan); + --button-hover-text-color: var(--base2); + --button-inline-bg-color: var(--base2); + --button-inline-text-color: var(--base0); + --button-inline-hover-bg-color: var(--cyan); + --button-inline-hover-text-color: var(--base2); + --button-border-color: var(--base0); + + --details-border-color: var(--border-color); + --details-fieldset-border-color: var(--border-color); + --details-text-color: var(--text-color); + + --input-text-bg-color: var(--base2); + --input-text-color: var(--text-color); + --input-textarea-bg-color: var(--base2); + --input-textarea-color: var(--text-color); + + --title-text-color: var(--text-color); + --row-title-text-color: var(--text-color); + --input-select-bg-color: var(--base2); + --input-select-color: var(--text-color); + --general-text-color: var(--text-color); + + /* new_module */ + --legend-border-color:var(--base1); +} \ No newline at end of file diff --git a/gui_react/.gitignore b/gui_react/.gitignore new file mode 100644 index 00000000..9214ea80 --- /dev/null +++ b/gui_react/.gitignore @@ -0,0 +1,7 @@ +node_modules/ +dist/ +release/ +dist_backend/ +*.egg-info/ +__pycache__/ +.vite/ diff --git a/gui_react/backend/chsm_backend.spec b/gui_react/backend/chsm_backend.spec new file mode 100644 index 00000000..f1c9f376 --- /dev/null +++ b/gui_react/backend/chsm_backend.spec @@ -0,0 +1,97 @@ +# -*- mode: python ; coding: utf-8 -*- +""" +PyInstaller spec for CHSM backend. + +Run from gui_react/: + pyinstaller --noconfirm backend/chsm_backend.spec + +Output goes to gui_react/dist_backend/ +""" +import os, sys +from pathlib import Path +from PyInstaller.building.build_main import Analysis, PYZ, EXE, COLLECT + +spec_dir = os.path.dirname(os.path.abspath(SPECPATH)) if 'SPECPATH' in dir() else os.path.dirname(os.path.abspath(__file__)) +gui_react = Path(spec_dir).parent.resolve() if Path(spec_dir).name == 'backend' else Path(spec_dir).resolve() +backend = gui_react / 'backend' +gui = gui_react.parent / 'gui' +frontend = gui_react / 'frontend' + +# Collect all c_gen/, templates, and the gui helper modules that server.py imports +datas = [ + # React build (served by FastAPI static mount) + (str(frontend / 'dist'), 'frontend/dist'), + # c_gen package (generators, templates, Jinja2 templates) + (str(gui / 'c_gen'), 'c_gen'), + # gui web assets needed by _save_html() + (str(gui / 'web' / 'drawing.css'), 'web'), + (str(gui / 'web' / 'themes'), 'web/themes'), +] + +# Add c_gen/templates directory explicitly +templates_dir = gui / 'c_gen' / 'templates' +if templates_dir.exists(): + datas.append((str(templates_dir), 'c_gen/templates')) + +hidden_imports = [ + 'uvicorn', + 'uvicorn.logging', + 'uvicorn.loops', + 'uvicorn.loops.auto', + 'uvicorn.protocols', + 'uvicorn.protocols.http', + 'uvicorn.protocols.http.auto', + 'uvicorn.protocols.websockets', + 'uvicorn.protocols.websockets.auto', + 'uvicorn.lifespan', + 'uvicorn.lifespan.on', + 'fastapi', + 'starlette', + 'starlette.routing', + 'starlette.middleware', + 'starlette.middleware.cors', + 'anyio', + 'anyio._backends', + 'anyio._backends._asyncio', + 'jinja2', + 'markupsafe', + 'websockets', +] + +a = Analysis( + [str(backend / 'server_entry.py')], + pathex=[str(gui), str(backend)], + binaries=[], + datas=datas, + hiddenimports=hidden_imports, + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=['tkinter'], # not needed — Electron provides native dialogs + noarchive=False, +) + +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + [], + exclude_binaries=True, + name='chsm_backend', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + console=True, # keep console for logging in dev; hide with --noconsole flag +) + +coll = COLLECT( + exe, + a.binaries, + a.datas, + strip=False, + upx=True, + upx_exclude=[], + name='chsm_backend', +) diff --git a/gui_react/backend/requirements.txt b/gui_react/backend/requirements.txt new file mode 100644 index 00000000..8c71cb34 --- /dev/null +++ b/gui_react/backend/requirements.txt @@ -0,0 +1,4 @@ +fastapi>=0.111 +uvicorn[standard]>=0.30 +websockets>=12.0 +python-multipart>=0.0.9 diff --git a/gui_react/backend/server.py b/gui_react/backend/server.py new file mode 100644 index 00000000..ffc7c8d0 --- /dev/null +++ b/gui_react/backend/server.py @@ -0,0 +1,501 @@ +""" +CHSM React Backend — FastAPI + WebSocket server. + +Usage: + uvicorn server:app --reload --port 8000 + +Provides: + REST /api/... – file I/O, code generation, module creation + WS /ws – real-time events (debug channel, save-status) + Static / – serves React build (production) +""" +import json +import logging +import os +import re +import socket +import select +import sys +import threading +from pathlib import Path +from typing import Optional + +from fastapi import FastAPI, WebSocket, WebSocketDisconnect, UploadFile, File +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import FileResponse, JSONResponse +from fastapi.staticfiles import StaticFiles +from pydantic import BaseModel + +# ── Resolve project paths ────────────────────────────────────────────── +BACKEND_DIR = Path(__file__).parent.resolve() + +# When running from a PyInstaller bundle, resources are in sys._MEIPASS +_MEIPASS = getattr(sys, '_MEIPASS', None) +if _MEIPASS: + _bundle = Path(_MEIPASS) + GUI_DIR = _bundle # c_gen/ etc. are packed relative to bundle root + C_GEN_DIR = _bundle / "c_gen" + TEMPLATE_DIR = C_GEN_DIR / "templates" + WEB_DIR = _bundle / "web" + REACT_DIST_OVERRIDE = _bundle / "frontend" / "dist" +else: + GUI_DIR = (BACKEND_DIR / ".." / ".." / "gui").resolve() + C_GEN_DIR = GUI_DIR / "c_gen" + TEMPLATE_DIR = C_GEN_DIR / "templates" + WEB_DIR = GUI_DIR / "web" + REACT_DIST_OVERRIDE = None + +# Add gui/ to sys.path so existing generators import cleanly +sys.path.insert(0, str(GUI_DIR)) + +from c_gen import StateMachine +try: + import module_generator +except ImportError: + module_generator = None + +# ── Logging ──────────────────────────────────────────────────────────── +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s %(filename)-20s:%(lineno)-4s %(message)s", +) +log = logging.getLogger(__name__) + +# ── FastAPI app ──────────────────────────────────────────────────────── +app = FastAPI(title="CHSM Backend", version="1.0.0") + +app.add_middleware( + CORSMiddleware, + allow_origins=["http://localhost:5173", "http://localhost:3000", "http://127.0.0.1:5173"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +TOP_STATE_RE = re.compile( + r'chsm_result_ten\s+(?P\w+)\(chsm_tst\s+\*self,\s+const\s+cevent_tst\s+\*e_pst\)\s*;' +) + + +# â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• +# WebSocket hub — broadcasts to all connected React clients +# â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• +class WsHub: + def __init__(self): + self._clients: list[WebSocket] = [] + + async def connect(self, ws: WebSocket): + await ws.accept() + self._clients.append(ws) + log.info("WS client connected (%d total)", len(self._clients)) + + def disconnect(self, ws: WebSocket): + self._clients.remove(ws) + log.info("WS client disconnected (%d total)", len(self._clients)) + + async def broadcast(self, event: str, data: dict): + msg = json.dumps({"event": event, "data": data}) + dead = [] + for ws in self._clients: + try: + await ws.send_text(msg) + except Exception: + dead.append(ws) + for ws in dead: + self._clients.remove(ws) + + def broadcast_sync(self, event: str, data: dict): + """Thread-safe broadcast (used from debug server thread).""" + import asyncio + msg = json.dumps({"event": event, "data": data}) + for ws in list(self._clients): + try: + asyncio.run_coroutine_threadsafe( + ws.send_text(msg), + _loop, + ) + except Exception: + pass + + +hub = WsHub() +_loop = None # set on startup + + +@app.on_event("startup") +async def _capture_loop(): + import asyncio + global _loop + _loop = asyncio.get_running_loop() + + +@app.websocket("/ws") +async def websocket_endpoint(ws: WebSocket): + await hub.connect(ws) + try: + while True: + data = await ws.receive_text() + msg = json.loads(data) + cmd = msg.get("cmd") + if cmd == "debug_start": + port = int(msg.get("port", 9999)) + debug_server.start(port) + elif cmd == "debug_stop": + debug_server.stop() + elif cmd == "debug_send": + debug_server.send_to_target(msg.get("payload", {})) + except WebSocketDisconnect: + hub.disconnect(ws) + + +# â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• +# Debug TCP server — identical protocol to Eel version +# â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• +class DebugServer: + def __init__(self): + self._server_socket: Optional[socket.socket] = None + self._client: Optional[socket.socket] = None + self._thread: Optional[threading.Thread] = None + self._running = False + self.port = 0 + self.log: list[dict] = [] + self.MAX_LOG = 200 + + @property + def connected(self): + return self._client is not None + + def start(self, port: int): + if self._running: + self.stop() + self.port = port + self._running = True + self._thread = threading.Thread(target=self._serve, daemon=True) + self._thread.start() + log.info("Debug server started on port %d", self.port) + + def stop(self): + self._running = False + for s in (self._client, self._server_socket): + if s: + try: + s.close() + except Exception: + pass + self._client = None + self._server_socket = None + hub.broadcast_sync("DEBUG_STATUS", {"connected": False, "listening": False}) + log.info("Debug server stopped") + + def _serve(self): + try: + self._server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self._server_socket.bind(("127.0.0.1", self.port)) + self._server_socket.listen(1) + self._server_socket.settimeout(1.0) + except OSError as e: + log.error("Debug server bind failed: %s", e) + hub.broadcast_sync("DEBUG_STATUS", {"connected": False, "error": str(e)}) + self._running = False + return + + hub.broadcast_sync("DEBUG_STATUS", {"connected": False, "listening": True, "port": self.port}) + + while self._running: + try: + ready, _, _ = select.select([self._server_socket], [], [], 1.0) + if not ready: + continue + client, addr = self._server_socket.accept() + except (OSError, socket.timeout): + continue + + self._client = client + self._client.settimeout(1.0) + log.info("Debug client connected from %s", addr) + hub.broadcast_sync("DEBUG_STATUS", {"connected": True, "port": self.port}) + + buf = "" + while self._running and self._client: + try: + data = self._client.recv(4096) + if not data: + break + buf += data.decode("utf-8", errors="replace") + while "\n" in buf: + line, buf = buf.split("\n", 1) + line = line.strip() + if not line: + continue + try: + msg = json.loads(line) + self._handle_message(msg) + except json.JSONDecodeError as e: + log.warning("Debug bad JSON: %s", e) + except socket.timeout: + continue + except (ConnectionResetError, OSError): + break + + self._client = None + log.info("Debug client disconnected") + hub.broadcast_sync("DEBUG_STATUS", {"connected": False, "listening": True, "port": self.port}) + hub.broadcast_sync("DEBUG_UPDATE", {"type": "reset"}) + + def _handle_message(self, msg: dict): + if msg.get("type") == "event": + if len(self.log) >= self.MAX_LOG: + self.log.pop(0) + self.log.append(msg) + hub.broadcast_sync("DEBUG_UPDATE", msg) + + def send_to_target(self, msg: dict): + if self._client: + try: + self._client.sendall((json.dumps(msg) + "\n").encode("utf-8")) + except (OSError, BrokenPipeError) as e: + log.warning("Debug send failed: %s", e) + + +debug_server = DebugServer() + + +# â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• +# REST API +# â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• + +# ── File I/O ─────────────────────────────────────────────────────────── + +class SaveRequest(BaseModel): + filepath: str + model: dict + svg: str = "" + + +class OpenResponse(BaseModel): + model: dict + filename: str + filepath: str + + +def _load_default_model() -> dict: + with open(TEMPLATE_DIR / "model.json") as f: + return json.load(f) + + +def _extract_model_from_html(html_path: Path) -> Optional[dict]: + if not html_path.exists(): + return None + content = html_path.read_text(encoding="utf-8", errors="replace") + m = re.search(r"
\n(?P.+)
", content, re.DOTALL) + if not m: + return None + try: + return json.loads(m.group("json")) + except json.JSONDecodeError: + return None + + +def _save_html(html_path: Path, svg: str, json_data: str): + template_html = TEMPLATE_DIR / "template.html" + drawing_css = WEB_DIR / "drawing.css" + drawing_js = TEMPLATE_DIR / "wheel.js" + theme_css = WEB_DIR / "themes" / "default.css" + + for p in (template_html, drawing_css, drawing_js, theme_css): + if not p.exists(): + raise FileNotFoundError(f"Missing: {p}") + + template = template_html.read_text() + css = drawing_css.read_text() + js = drawing_js.read_text() + theme = theme_css.read_text() + output = template.format(style=css, theme_style=theme, drawing=svg, json_data=json_data, script=js) + html_path.parent.mkdir(parents=True, exist_ok=True) + html_path.write_text(output, encoding="utf-8") + + +def _find_settings(start_dir: Path, stem: Optional[str] = None) -> dict: + """Walk up from start_dir looking for .chsm/settings.json or .chsm/.json.""" + for parent in [start_dir] + list(start_dir.parents): + if stem: + p = parent / ".chsm" / f"{stem}.json" + if p.exists(): + with open(p) as f: + return json.load(f) + p = parent / ".chsm" / "settings.json" + if p.exists(): + with open(p) as f: + return json.load(f) + return {} + + +@app.post("/api/save") +async def api_save(req: SaveRequest): + try: + filepath = Path(req.filepath) + if filepath.suffix == ".html": + _save_html(filepath, req.svg, json.dumps(req.model)) + else: + filepath.parent.mkdir(parents=True, exist_ok=True) + filepath.write_text(json.dumps(req.model, indent=2), encoding="utf-8") + return {"ok": True, "filepath": str(filepath), "filename": filepath.name} + except Exception as e: + log.exception("Save failed") + return JSONResponse({"ok": False, "error": str(e)}, status_code=500) + + +@app.post("/api/open") +async def api_open(filepath: str = ""): + """Open a .h or .html file and return the model JSON.""" + if not filepath: + return JSONResponse({"ok": False, "error": "No filepath provided"}, status_code=400) + + p = Path(filepath) + if not p.exists(): + return JSONResponse({"ok": False, "error": f"File not found: {filepath}"}, status_code=404) + + if p.suffix == ".h": + # Derive paths the same way as the Eel backend + default_cfg = json.loads((TEMPLATE_DIR / "settings.json").read_text()) + user_cfg = _find_settings(p.parent, p.stem) + file_cfg = user_cfg.get(p.name, {}) + src_dir = user_cfg.get("src_dir", default_cfg.get("src_dir", "../src")) + doc_dir = user_cfg.get("doc_dir", default_cfg.get("doc_dir", "../doc")) + + html_name = file_cfg.get("machine_html", p.stem + ".html") + html_path = (p.parent / doc_dir / html_name).resolve() + + model = _extract_model_from_html(html_path) + if model is None: + model = _load_default_model() + # Try to extract top state name from .h + h_content = p.read_text(errors="replace") + m = TOP_STATE_RE.search(h_content) + if m: + model["states"]["__top__"]["title"] = m.group("top_func") + else: + model["states"]["__top__"]["title"] = f"{p.stem}__top__" + + return {"ok": True, "model": model, "filename": p.name, "filepath": str(p), + "html_path": str(html_path), "src_dir": src_dir, "doc_dir": doc_dir, + "file_cfg": file_cfg} + + elif p.suffix == ".html": + model = _extract_model_from_html(p) + if model is None: + return JSONResponse({"ok": False, "error": "No JSON data found in HTML"}, status_code=400) + return {"ok": True, "model": model, "filename": p.name, "filepath": str(p)} + + return JSONResponse({"ok": False, "error": "Unsupported file type"}, status_code=400) + + +# ── Code generation ──────────────────────────────────────────────────── + +class CodeGenRequest(BaseModel): + model: dict + h_filepath: str + file_cfg: dict = {} + + +@app.post("/api/codegen") +async def api_codegen(req: CodeGenRequest): + try: + h_path = Path(req.h_filepath) + default_cfg = json.loads((TEMPLATE_DIR / "settings.json").read_text()) + user_cfg = _find_settings(h_path.parent, h_path.stem) + file_cfg = req.file_cfg or user_cfg.get(h_path.name, {}) + c_templates = user_cfg.get("templates", default_cfg.get("templates")) + src_dir = user_cfg.get("src_dir", default_cfg.get("src_dir", "../src")) + + func_h_name = file_cfg.get("func_h", h_path.stem + "_functions.h") + func_h_path = (h_path.parent / func_h_name).resolve() + c_name = file_cfg.get("machine_c", h_path.stem + ".c") + c_path = (h_path.parent / src_dir / c_name).resolve() + + sm = StateMachine(req.model, h_path, func_h_path.name, c_templates, file_cfg) + + c_path.parent.mkdir(parents=True, exist_ok=True) + c_path.write_text(str(sm.ast), encoding="utf-8") + func_h_path.write_text(str(sm.h_ast), encoding="utf-8") + + log.info("Code generated: %s, %s", c_path.name, func_h_path.name) + return {"ok": True, "c_file": str(c_path), "h_file": str(func_h_path)} + except Exception as e: + log.exception("Code generation failed") + return JSONResponse({"ok": False, "error": str(e)}, status_code=500) + + +# ── Module generator ─────────────────────────────────────────────────── + +class ModuleGenRequest(BaseModel): + name: str + version: str = "" + description: str = "" + location: str = "" + linked_libs: str = "" + package_name: str = "" + comm_periph: str = "none" + device_address: str = "" + author_nick_name: str = "" + author_full_name: str = "" + licence: str = "MIT" + + +@app.post("/api/new-module") +async def api_new_module(req: ModuleGenRequest): + if module_generator is None: + return JSONResponse({"ok": False, "error": "module_generator not available"}, status_code=500) + try: + module_generator.generate_module( + req.name, req.version, req.description, req.location, + req.linked_libs, req.package_name, req.comm_periph, + req.device_address, req.author_nick_name, + req.author_full_name, req.licence, + ) + return {"ok": True} + except Exception as e: + log.exception("Module generation failed") + return JSONResponse({"ok": False, "error": str(e)}, status_code=500) + + +# ── File picker (native dialog via tkinter in a thread) ──────────────── + +@app.get("/api/pick-file") +async def api_pick_file(mode: str = "open", filetypes: str = ".h,.html"): + """Open a native file picker dialog. Runs tkinter in a thread.""" + import asyncio + + def _pick(): + import tkinter as tk + from tkinter.filedialog import askopenfilename, asksaveasfilename + root = tk.Tk() + root.attributes("-topmost", True) + root.withdraw() + ft = [(f"File (*{e})", f"*{e}") for e in filetypes.split(",")] + if mode == "save": + result = asksaveasfilename(title="Save state machine", filetypes=ft) + else: + result = askopenfilename(title="Open file", filetypes=ft) + root.destroy() + return result + + loop = asyncio.get_running_loop() + path = await loop.run_in_executor(None, _pick) + if path: + return {"ok": True, "filepath": path} + return {"ok": False, "cancelled": True} + + +# ── Health ───────────────────────────────────────────────────────────── + +@app.get("/api/health") +async def health(): + return {"status": "ok", "debug_connected": debug_server.connected} + + +# ── Serve React build in production ─────────────────────────────────── +_react_dist = REACT_DIST_OVERRIDE or (BACKEND_DIR / ".." / "frontend" / "dist") +if _react_dist.exists(): + app.mount("/", StaticFiles(directory=str(_react_dist.resolve()), html=True)) diff --git a/gui_react/backend/server_entry.py b/gui_react/backend/server_entry.py new file mode 100644 index 00000000..3d507688 --- /dev/null +++ b/gui_react/backend/server_entry.py @@ -0,0 +1,15 @@ +""" +Entry point for running the CHSM backend under Electron (or standalone). +Reads CHSM_BACKEND_PORT from the environment (default 8000). +""" +import os +import uvicorn + +if __name__ == "__main__": + port = int(os.environ.get("CHSM_BACKEND_PORT", "8000")) + uvicorn.run( + "server:app", + host="127.0.0.1", + port=port, + log_level="info", + ) diff --git a/gui_react/build.bat b/gui_react/build.bat new file mode 100644 index 00000000..dd2b6cba --- /dev/null +++ b/gui_react/build.bat @@ -0,0 +1,65 @@ +@echo off +setlocal +REM â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• +REM CHSM Desktop — Build Script +REM +REM Builds everything needed for the Electron portable exe: +REM 1. React frontend (npm run build → frontend/dist/) +REM 2. Python backend (PyInstaller → dist_backend/) +REM 3. Electron app (electron-builder → release/) +REM +REM Prerequisites: +REM - Node.js / npm +REM - Python 3.10+ with pip +REM - PyInstaller (pip install pyinstaller) +REM â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• + +cd /d "%~dp0" + +echo. +echo ────────────────────────────────────────────────── +echo Step 1: Build React frontend +echo ────────────────────────────────────────────────── +pushd frontend +call npm install +if errorlevel 1 goto :error +call npm run build +if errorlevel 1 goto :error +popd + +echo. +echo ────────────────────────────────────────────────── +echo Step 2: Build Python backend (PyInstaller) +echo ────────────────────────────────────────────────── +pip install pyinstaller fastapi "uvicorn[standard]" websockets python-multipart jinja2 2>nul +pyinstaller --noconfirm --distpath dist_backend backend/chsm_backend.spec +if errorlevel 1 goto :error + +echo. +echo ────────────────────────────────────────────────── +echo Step 3: Install Electron dependencies +echo ────────────────────────────────────────────────── +call npm install +if errorlevel 1 goto :error + +echo. +echo ────────────────────────────────────────────────── +echo Step 4: Package Electron app +echo ────────────────────────────────────────────────── +call npx electron-builder --win portable +if errorlevel 1 goto :error + +echo. +echo â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• +echo BUILD COMPLETE +echo Output: release\CHSM-*-portable.exe +echo â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• +goto :end + +:error +echo. +echo BUILD FAILED — see errors above. +exit /b 1 + +:end +endlocal diff --git a/gui_react/electron/main.js b/gui_react/electron/main.js new file mode 100644 index 00000000..d11b5740 --- /dev/null +++ b/gui_react/electron/main.js @@ -0,0 +1,150 @@ +/** + * CHSM Electron — Main process. + * + * Spawns the FastAPI backend (either a bundled PyInstaller exe or python) + * then loads the React frontend from the built dist/ folder. + */ +const { app, BrowserWindow, dialog, ipcMain } = require('electron'); +const path = require('path'); +const { spawn } = require('child_process'); +const net = require('net'); + +const IS_DEV = !app.isPackaged; +const BACKEND_PORT = 8000; +const BACKEND_READY_TIMEOUT = 30_000; // ms + +let mainWindow = null; +let backendProcess = null; + +/* ── Locate the backend executable ──────────────────────────────── */ +function getBackendPath() { + if (IS_DEV) { + // In dev mode, run python directly + return { cmd: 'python', args: [path.join(__dirname, '..', 'backend', 'server_entry.py')] }; + } + // In production, the PyInstaller-built exe sits in resources/backend/ + const exeName = process.platform === 'win32' ? 'chsm_backend.exe' : 'chsm_backend'; + const exePath = path.join(process.resourcesPath, 'backend', exeName); + return { cmd: exePath, args: [] }; +} + +/* ── Spawn backend ─────────────────────────────────────────────── */ +function startBackend() { + const { cmd, args } = getBackendPath(); + console.log(`Starting backend: ${cmd} ${args.join(' ')}`); + + backendProcess = spawn(cmd, args, { + stdio: ['pipe', 'pipe', 'pipe'], + env: { ...process.env, CHSM_BACKEND_PORT: String(BACKEND_PORT) }, + }); + + backendProcess.stdout.on('data', (data) => { + process.stdout.write(`[backend] ${data}`); + }); + backendProcess.stderr.on('data', (data) => { + process.stderr.write(`[backend] ${data}`); + }); + backendProcess.on('exit', (code) => { + console.log(`Backend exited with code ${code}`); + backendProcess = null; + }); +} + +/* ── Wait for backend to be ready ──────────────────────────────── */ +function waitForBackend() { + return new Promise((resolve, reject) => { + const start = Date.now(); + const check = () => { + const sock = new net.Socket(); + sock.setTimeout(500); + sock.on('connect', () => { + sock.destroy(); + resolve(); + }); + sock.on('error', () => { + sock.destroy(); + if (Date.now() - start > BACKEND_READY_TIMEOUT) { + reject(new Error('Backend did not start in time')); + } else { + setTimeout(check, 300); + } + }); + sock.on('timeout', () => { + sock.destroy(); + setTimeout(check, 300); + }); + sock.connect(BACKEND_PORT, '127.0.0.1'); + }; + check(); + }); +} + +/* ── Create the main window ────────────────────────────────────── */ +function createWindow() { + mainWindow = new BrowserWindow({ + width: 1280, + height: 800, + title: 'CHSM', + icon: path.join(__dirname, 'icon.png'), + webPreferences: { + preload: path.join(__dirname, 'preload.js'), + contextIsolation: true, + nodeIntegration: false, + }, + }); + + // Load the React build — the backend serves it as static files + mainWindow.loadURL(`http://127.0.0.1:${BACKEND_PORT}/`); + + if (IS_DEV) { + mainWindow.webContents.openDevTools(); + } + + mainWindow.on('closed', () => { mainWindow = null; }); +} + +/* ── IPC: native file dialog ───────────────────────────────────── */ +ipcMain.handle('pick-file', async (_event, opts) => { + const mode = opts?.mode || 'open'; + const filters = opts?.filters || [{ name: 'Files', extensions: ['h', 'html'] }]; + if (mode === 'save') { + const r = await dialog.showSaveDialog(mainWindow, { filters }); + return r.canceled ? null : r.filePath; + } + const r = await dialog.showOpenDialog(mainWindow, { filters, properties: ['openFile'] }); + return r.canceled ? null : r.filePaths[0]; +}); + +ipcMain.handle('pick-directory', async () => { + const r = await dialog.showOpenDialog(mainWindow, { properties: ['openDirectory'] }); + return r.canceled ? null : r.filePaths[0]; +}); + +/* ── App lifecycle ─────────────────────────────────────────────── */ +app.whenReady().then(async () => { + startBackend(); + try { + await waitForBackend(); + } catch (e) { + console.error(e.message); + dialog.showErrorBox('CHSM', 'Failed to start the backend server.'); + app.quit(); + return; + } + createWindow(); +}); + +app.on('window-all-closed', () => { + if (backendProcess) { + backendProcess.kill(); + backendProcess = null; + } + app.quit(); +}); + +app.on('before-quit', () => { + if (backendProcess) { + backendProcess.kill(); + backendProcess = null; + } +}); diff --git a/gui_react/electron/preload.js b/gui_react/electron/preload.js new file mode 100644 index 00000000..e9d5def7 --- /dev/null +++ b/gui_react/electron/preload.js @@ -0,0 +1,13 @@ +/** + * CHSM Electron — Preload script. + * + * Exposes a minimal API to the renderer via contextBridge. + * The renderer can use window.chsmElectron to invoke native dialogs. + */ +const { contextBridge, ipcRenderer } = require('electron'); + +contextBridge.exposeInMainWorld('chsmElectron', { + pickFile: (opts) => ipcRenderer.invoke('pick-file', opts), + pickDirectory: () => ipcRenderer.invoke('pick-directory'), + isElectron: true, +}); diff --git a/gui_react/frontend/index.html b/gui_react/frontend/index.html new file mode 100644 index 00000000..21be49be --- /dev/null +++ b/gui_react/frontend/index.html @@ -0,0 +1,12 @@ + + + + + + CHSM + + +
+ + + diff --git a/gui_react/frontend/package-lock.json b/gui_react/frontend/package-lock.json new file mode 100644 index 00000000..dd948752 --- /dev/null +++ b/gui_react/frontend/package-lock.json @@ -0,0 +1,3188 @@ +{ + "name": "chsm-frontend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "chsm-frontend", + "version": "1.0.0", + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1", + "uplot": "^1.6.32", + "zustand": "^4.5.5" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.6.0", + "@testing-library/react": "^16.3.0", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react": "^4.3.4", + "@vitest/coverage-v8": "^4.1.0", + "jsdom": "^26.0.0", + "typescript": "~5.6.2", + "vite": "^6.0.0", + "vitest": "^4.1.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", + "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz", + "integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz", + "integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz", + "integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz", + "integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz", + "integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz", + "integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz", + "integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz", + "integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz", + "integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz", + "integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz", + "integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz", + "integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz", + "integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz", + "integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz", + "integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz", + "integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz", + "integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz", + "integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz", + "integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz", + "integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz", + "integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz", + "integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz", + "integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz", + "integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz", + "integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "16.3.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", + "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", + "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.4.tgz", + "integrity": "sha512-x7FptB5oDruxNPDNY2+S8tCh0pcq7ymCe1gTHcsp733jYjrJl8V1gMUlVysuCD9Kz46Xz9t1akkv08dPcYDs1w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.4", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.4", + "vitest": "4.1.4" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.4.tgz", + "integrity": "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.4", + "@vitest/utils": "4.1.4", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.4.tgz", + "integrity": "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.4.tgz", + "integrity": "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.4.tgz", + "integrity": "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.4", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.4.tgz", + "integrity": "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.4", + "@vitest/utils": "4.1.4", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.4.tgz", + "integrity": "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.4.tgz", + "integrity": "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.4", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.0.tgz", + "integrity": "sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.18", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.18.tgz", + "integrity": "sha512-VSnGQAOLtP5mib/DPyg2/t+Tlv65NTBz83BJBJvmLVHHuKJVaDOBvJJykiT5TR++em5nfAySPccDZDa4oSrn8A==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001787", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001787.tgz", + "integrity": "sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.6.0.tgz", + "integrity": "sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.335", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.335.tgz", + "integrity": "sha512-q9n5T4BR4Xwa2cwbrwcsDJtHD/enpQ5S1xF1IAtdqf5AAgqDFmR/aakqH3ChFdqd/QXJhS3rnnXFtexU7rax6Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsdom": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", + "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.5.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.1.1", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.1", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", + "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.37", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", + "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", + "dev": true, + "license": "MIT" + }, + "node_modules/nwsapi": { + "version": "2.2.23", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", + "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz", + "integrity": "sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/rollup": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", + "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.1", + "@rollup/rollup-android-arm64": "4.60.1", + "@rollup/rollup-darwin-arm64": "4.60.1", + "@rollup/rollup-darwin-x64": "4.60.1", + "@rollup/rollup-freebsd-arm64": "4.60.1", + "@rollup/rollup-freebsd-x64": "4.60.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", + "@rollup/rollup-linux-arm-musleabihf": "4.60.1", + "@rollup/rollup-linux-arm64-gnu": "4.60.1", + "@rollup/rollup-linux-arm64-musl": "4.60.1", + "@rollup/rollup-linux-loong64-gnu": "4.60.1", + "@rollup/rollup-linux-loong64-musl": "4.60.1", + "@rollup/rollup-linux-ppc64-gnu": "4.60.1", + "@rollup/rollup-linux-ppc64-musl": "4.60.1", + "@rollup/rollup-linux-riscv64-gnu": "4.60.1", + "@rollup/rollup-linux-riscv64-musl": "4.60.1", + "@rollup/rollup-linux-s390x-gnu": "4.60.1", + "@rollup/rollup-linux-x64-gnu": "4.60.1", + "@rollup/rollup-linux-x64-musl": "4.60.1", + "@rollup/rollup-openbsd-x64": "4.60.1", + "@rollup/rollup-openharmony-arm64": "4.60.1", + "@rollup/rollup-win32-arm64-msvc": "4.60.1", + "@rollup/rollup-win32-ia32-msvc": "4.60.1", + "@rollup/rollup-win32-x64-gnu": "4.60.1", + "@rollup/rollup-win32-x64-msvc": "4.60.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.0.0.tgz", + "integrity": "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", + "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uplot": { + "version": "1.6.32", + "resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.32.tgz", + "integrity": "sha512-KIMVnG68zvu5XXUbC4LQEPnhwOxBuLyW1AHtpm6IKTXImkbLgkMy+jabjLgSLMasNuGGzQm/ep3tOkyTxpiQIw==", + "license": "MIT" + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/vite": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.2.tgz", + "integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.4.tgz", + "integrity": "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/expect": "4.1.4", + "@vitest/mocker": "4.1.4", + "@vitest/pretty-format": "4.1.4", + "@vitest/runner": "4.1.4", + "@vitest/snapshot": "4.1.4", + "@vitest/spy": "4.1.4", + "@vitest/utils": "4.1.4", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.4", + "@vitest/browser-preview": "4.1.4", + "@vitest/browser-webdriverio": "4.1.4", + "@vitest/coverage-istanbul": "4.1.4", + "@vitest/coverage-v8": "4.1.4", + "@vitest/ui": "4.1.4", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ws": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/zustand": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", + "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + } + } +} diff --git a/gui_react/frontend/package.json b/gui_react/frontend/package.json new file mode 100644 index 00000000..35487af7 --- /dev/null +++ b/gui_react/frontend/package.json @@ -0,0 +1,32 @@ +{ + "name": "chsm-frontend", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "preview": "vite preview", + "test": "vitest run", + "test:watch": "vitest", + "test:coverage": "vitest run --coverage" + }, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1", + "uplot": "^1.6.32", + "zustand": "^4.5.5" + }, + "devDependencies": { + "@testing-library/jest-dom": "^6.6.0", + "@testing-library/react": "^16.3.0", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react": "^4.3.4", + "@vitest/coverage-v8": "^4.1.0", + "jsdom": "^26.0.0", + "typescript": "~5.6.2", + "vite": "^6.0.0", + "vitest": "^4.1.0" + } +} diff --git a/gui_react/frontend/src/App.tsx b/gui_react/frontend/src/App.tsx new file mode 100644 index 00000000..289485c2 --- /dev/null +++ b/gui_react/frontend/src/App.tsx @@ -0,0 +1,127 @@ +import { useEffect, useRef, useCallback } from 'react'; +import { useStore } from './store'; +import { wsClient } from './ws'; +import { api } from './api'; +import Sidebar from './components/Sidebar'; +import Canvas from './components/Canvas'; + +export default function App() { + const theme = useStore((s) => s.theme); + const autosave = useStore((s) => s.autosave); + const filepath = useStore((s) => s.filepath); + const model = useStore((s) => s.model); + const setMode = useStore((s) => s.setMode); + const undo = useStore((s) => s.undo); + const redo = useStore((s) => s.redo); + const pushHistory = useStore((s) => s.pushHistory); + const autosaveRef = useRef(autosave); + autosaveRef.current = autosave; + const filepathRef = useRef(filepath); + filepathRef.current = filepath; + const modelRef = useRef(model); + modelRef.current = model; + + /* ── WebSocket ───────────────────────────────────────────────── */ + useEffect(() => { + wsClient.connect(); + const unsub = wsClient.on((event, data) => { + if (event === 'DEBUG_STATUS') useStore.getState().setDebugStatus(data as any); + if (event === 'DEBUG_UPDATE') useStore.getState().handleDebugUpdate(data); + }); + return () => { unsub(); wsClient.disconnect(); }; + }, []); + + /* ── Theme ───────────────────────────────────────────────────── */ + useEffect(() => { + document.documentElement.setAttribute('data-theme', theme); + }, [theme]); + + /* ── Autosave interval ───────────────────────────────────────── */ + useEffect(() => { + if (!autosave) return; + const id = setInterval(() => { + const fp = filepathRef.current; + if (fp) api.save(fp, modelRef.current as any); + }, 5000); + return () => clearInterval(id); + }, [autosave]); + + /* ── Keyboard shortcuts ──────────────────────────────────────── */ + const handleKey = useCallback((e: KeyboardEvent) => { + const tag = (e.target as HTMLElement).tagName; + if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return; + + if (e.ctrlKey || e.metaKey) { + if (e.key === 's') { e.preventDefault(); doSave(); } + if (e.key === 'g') { e.preventDefault(); doCodegen(); } + if (e.key === 'z') { e.preventDefault(); undo(); } + if (e.key === 'y') { e.preventDefault(); redo(); } + return; + } + + if (e.key === 's') setMode('create_state'); + if (e.key === 't') setMode('select_tr_start'); + if (e.key === 'd') setMode('delete'); + if (e.key === 'i') setMode('create_state'); // initial + if (e.key === 'u') undo(); + if (e.key === 'r') redo(); + if (e.key === 'Escape') setMode('idle'); + if (e.key === ' ') { e.preventDefault(); useStore.getState().toggleElbow(); } + }, [setMode, undo, redo]); + + useEffect(() => { + window.addEventListener('keydown', handleKey); + return () => window.removeEventListener('keydown', handleKey); + }, [handleKey]); + + return ( +
+ + +
+ ); +} + +/* ── Top-level actions ────────────────────────────────────────────── */ +async function doSave() { + const { filepath, model } = useStore.getState(); + if (filepath) { + await api.save(filepath, model as any); + } else { + const pick = await api.pickFile('save', '.html'); + if (pick.ok && pick.filepath) { + useStore.getState().setFileCtx({ filepath: pick.filepath }); + await api.save(pick.filepath, model as any); + } + } +} + +async function doOpen() { + const pick = await api.pickFile('open', '.h,.html'); + if (!pick.ok || !pick.filepath) return; + const res = await api.openFile(pick.filepath); + if (res.ok && res.model) { + useStore.getState().setModel(res.model as any); + useStore.getState().setFileCtx({ + filepath: res.filepath, + filename: res.filename, + htmlPath: (res as any).html_path ?? '', + hFilepath: res.filepath?.endsWith('.h') ? res.filepath : '', + fileCfg: (res as any).file_cfg ?? {}, + }); + } +} + +async function doCodegen() { + const { model, hFilepath, fileCfg } = useStore.getState(); + if (!hFilepath) { + alert('Open a .h file first to enable code generation.'); + return; + } + const res = await api.codegen(model as any, hFilepath, fileCfg); + if (res.ok) { + alert(`Code generated:\n${res.c_file}\n${res.h_file}`); + } else { + alert(`Code generation failed: ${res.error}`); + } +} diff --git a/gui_react/frontend/src/api.ts b/gui_react/frontend/src/api.ts new file mode 100644 index 00000000..7d9a5e60 --- /dev/null +++ b/gui_react/frontend/src/api.ts @@ -0,0 +1,72 @@ +/* ── Electron bridge (available when running inside Electron) ──── */ +interface ChsmElectron { + pickFile: (opts: { mode: string; filters?: { name: string; extensions: string[] }[] }) => Promise; + pickDirectory: () => Promise; + isElectron: boolean; +} +declare global { + interface Window { chsmElectron?: ChsmElectron; } +} + +const BASE = ''; + +async function request(method: string, url: string, body?: unknown): Promise { + const opts: RequestInit = { + method, + headers: { 'Content-Type': 'application/json' }, + }; + if (body !== undefined) opts.body = JSON.stringify(body); + const res = await fetch(`${BASE}${url}`, opts); + return res.json() as Promise; +} + +export const api = { + health: () => request<{ status: string; debug_connected: boolean }>('GET', '/api/health'), + + pickFile: async (mode: 'open' | 'save' = 'open', filetypes = '.h,.html'): Promise<{ ok: boolean; filepath?: string; cancelled?: boolean }> => { + // Use Electron native dialog when available + if (window.chsmElectron?.isElectron) { + const exts = filetypes.split(',').map((e) => e.replace('.', '')); + const path = await window.chsmElectron.pickFile({ + mode, + filters: [{ name: 'Files', extensions: exts }], + }); + if (path) return { ok: true, filepath: path }; + return { ok: false, cancelled: true }; + } + return request<{ ok: boolean; filepath?: string; cancelled?: boolean }>( + 'GET', + `/api/pick-file?mode=${mode}&filetypes=${encodeURIComponent(filetypes)}`, + ); + }, + + openFile: (filepath: string) => + request<{ + ok: boolean; + model?: Record; + filename?: string; + filepath?: string; + html_path?: string; + src_dir?: string; + doc_dir?: string; + file_cfg?: Record; + error?: string; + }>('POST', `/api/open?filepath=${encodeURIComponent(filepath)}`), + + save: (filepath: string, model: Record, svg = '') => + request<{ ok: boolean; filepath?: string; filename?: string; error?: string }>( + 'POST', + '/api/save', + { filepath, model, svg }, + ), + + codegen: (model: Record, h_filepath: string, file_cfg: Record = {}) => + request<{ ok: boolean; c_file?: string; h_file?: string; error?: string }>( + 'POST', + '/api/codegen', + { model, h_filepath, file_cfg }, + ), + + newModule: (data: Record) => + request<{ ok: boolean; error?: string }>('POST', '/api/new-module', data), +}; diff --git a/gui_react/frontend/src/components/Canvas.tsx b/gui_react/frontend/src/components/Canvas.tsx new file mode 100644 index 00000000..d324adec --- /dev/null +++ b/gui_react/frontend/src/components/Canvas.tsx @@ -0,0 +1,276 @@ +import { useRef, useEffect, useCallback, useState } from 'react'; +import { useStore, newId } from '../store'; +import type { ChsmState, ChsmConnector, ChsmView } from '../types'; +import StateNode from './StateNode'; +import TransitionPath from './TransitionPath'; + +export default function Canvas() { + const svgRef = useRef(null); + const model = useStore((s) => s.model); + const view = useStore((s) => s.view); + const setView = useStore((s) => s.setView); + const mode = useStore((s) => s.mode); + const setMode = useStore((s) => s.setMode); + const addState = useStore((s) => s.addState); + const removeState = useStore((s) => s.removeState); + const removeTransition = useStore((s) => s.removeTransition); + const addTransition = useStore((s) => s.addTransition); + const pushHistory = useStore((s) => s.pushHistory); + const elbow = useStore((s) => s.elbow); + const toggleElbow = useStore((s) => s.toggleElbow); + const activeStates = useStore((s) => s.activeStates); + + // ── Local drawing state ────────────────────────────────────────── + const [isPanning, setIsPanning] = useState(false); + const panStart = useRef<{ x: number; y: number; tx: number; ty: number } | null>(null); + + // Transition drawing state + const [trDrawing, setTrDrawing] = useState<{ + startStateId: string; + vertices: [number, number][]; + mouse: [number, number]; + } | null>(null); + + /* ── SVG coord conversion ────────────────────────────────────── */ + const svgPoint = useCallback( + (clientX: number, clientY: number): [number, number] => { + const [tx, ty] = view.translate; + const sc = view.scale; + const svg = svgRef.current; + if (!svg) return [0, 0]; + const rect = svg.getBoundingClientRect(); + return [ + (clientX - rect.left - tx) / sc, + (clientY - rect.top - ty) / sc, + ]; + }, + [view], + ); + + /* ── Hit test: which state contains this SVG point? ──────────── */ + const hitState = useCallback( + (pt: [number, number]): string | null => { + const [px, py] = pt; + // Check from smallest (deepest) to largest + const entries = Object.entries(model.states).filter(([, s]) => s.type !== 'top'); + // Sort by area ascending (smaller states on top) + entries.sort((a, b) => { + const areaA = a[1].size[0] * a[1].size[1]; + const areaB = b[1].size[0] * b[1].size[1]; + return areaA - areaB; + }); + for (const [id, st] of entries) { + const [sx, sy] = st.pos; + const [sw, sh] = st.size; + if (px >= sx && px <= sx + sw && py >= sy && py <= sy + sh) return id; + } + return null; + }, + [model.states], + ); + + /* ── Canvas click ────────────────────────────────────────────── */ + const handleCanvasClick = useCallback( + (e: React.MouseEvent) => { + if (e.button !== 0) return; + const pt = svgPoint(e.clientX, e.clientY); + + if (mode === 'create_state') { + const parentId = hitState(pt) || '__top__'; + const id = newId('state'); + const st: ChsmState = { + pos: [Math.round(pt[0]), Math.round(pt[1])], + size: [12, 8], + title: 'new_state', + text: [], + connectors: [], + parent: parentId, + children: [], + type: 'normal', + }; + addState(id, st); + pushHistory(); + setMode('idle'); + return; + } + + if (mode === 'select_tr_start') { + const stId = hitState(pt); + if (stId) { + setTrDrawing({ startStateId: stId, vertices: [connectorPos(model.states[stId])], mouse: pt }); + setMode('drawing_transition'); + } + return; + } + + if (mode === 'drawing_transition') { + if (!trDrawing) return; + const stId = hitState(pt); + if (stId && stId !== trDrawing.startStateId) { + // Complete transition + const trId = newId('tr'); + const startConnId = newId('conn'); + const endConnId = newId('conn'); + const startConn: ChsmConnector = { parent: trDrawing.startStateId, offset: 0, side: 'right', dir: 'out', transition: trId }; + const endConn: ChsmConnector = { parent: stId, offset: 0, side: 'left', dir: 'in', transition: trId }; + addTransition( + trId, + { + start: startConnId, + end: endConnId, + vertices: [...trDrawing.vertices, pt], + label: '', + label_offset: [0.5, -0.4], + label_anchor: 0, + label_pos: [0, 0], + }, + startConn, + endConn, + startConnId, + endConnId, + ); + pushHistory(); + setTrDrawing(null); + setMode('idle'); + } else { + // Add waypoint + setTrDrawing({ ...trDrawing, vertices: [...trDrawing.vertices, pt] }); + } + return; + } + + if (mode === 'delete') { + const stId = hitState(pt); + if (stId) { + removeState(stId); + pushHistory(); + } else { + // Check transitions + // Simple: find closest transition path segment + for (const [trId] of Object.entries(model.transitions)) { + // For simplicity just check bounding box + removeTransition(trId); + pushHistory(); + break; + } + } + setMode('idle'); + return; + } + }, + [mode, svgPoint, hitState, addState, pushHistory, setMode, model, trDrawing, addTransition, removeState, removeTransition], + ); + + /* ── Mouse move (for panning + transition preview) ───────────── */ + const handleMouseMove = useCallback( + (e: React.MouseEvent) => { + if (isPanning && panStart.current) { + const dx = e.clientX - panStart.current.x; + const dy = e.clientY - panStart.current.y; + setView({ + translate: [panStart.current.tx + dx, panStart.current.ty + dy], + scale: view.scale, + }); + return; + } + if (trDrawing) { + const pt = svgPoint(e.clientX, e.clientY); + setTrDrawing({ ...trDrawing, mouse: pt }); + } + }, + [isPanning, view, setView, trDrawing, svgPoint], + ); + + /* ── Pan start / end ─────────────────────────────────────────── */ + const handleMouseDown = useCallback( + (e: React.MouseEvent) => { + if (e.ctrlKey || e.metaKey) { + setIsPanning(true); + panStart.current = { x: e.clientX, y: e.clientY, tx: view.translate[0], ty: view.translate[1] }; + e.preventDefault(); + } + }, + [view], + ); + + const handleMouseUp = useCallback(() => { + setIsPanning(false); + panStart.current = null; + }, []); + + /* ── Zoom ────────────────────────────────────────────────────── */ + const handleWheel = useCallback( + (e: React.WheelEvent) => { + if (!e.ctrlKey && !e.metaKey) return; + e.preventDefault(); + const factor = e.deltaY < 0 ? 1.1 : 0.9; + const newScale = Math.max(1, Math.min(100, view.scale * factor)); + setView({ translate: view.translate, scale: newScale }); + }, + [view, setView], + ); + + /* ── Transition preview path ─────────────────────────────────── */ + const previewPath = trDrawing + ? [...trDrawing.vertices, trDrawing.mouse].map((p, i) => `${i === 0 ? 'M' : 'L'} ${p[0]} ${p[1]}`).join(' ') + : ''; + + return ( +
+ + {/* Arrow marker def */} + + + + + + + + {/* Transitions (behind states) */} + {Object.entries(model.transitions).map(([id, tr]) => ( + + ))} + + {/* Preview line while drawing */} + {previewPath && ( + + )} + + {/* States */} + {Object.entries(model.states) + .filter(([, s]) => s.type !== 'top') + .map(([id, st]) => ( + + ))} + + + + {/* Status bar */} +
+ {mode.toUpperCase()} + {Math.round(view.scale * 10)}% +
+
+ ); +} + +function connectorPos(st: ChsmState): [number, number] { + return [st.pos[0] + st.size[0] / 2, st.pos[1] + st.size[1] / 2]; +} diff --git a/gui_react/frontend/src/components/DebugPanel.tsx b/gui_react/frontend/src/components/DebugPanel.tsx new file mode 100644 index 00000000..76710a66 --- /dev/null +++ b/gui_react/frontend/src/components/DebugPanel.tsx @@ -0,0 +1,92 @@ +import { useState } from 'react'; +import { useStore } from '../store'; +import { wsClient } from '../ws'; + +export default function DebugPanel() { + const debugStatus = useStore((s) => s.debugStatus); + const debugLog = useStore((s) => s.debugLog); + const activeStates = useStore((s) => s.activeStates); + const debugVars = useStore((s) => s.debugVars); + const clearDebugLog = useStore((s) => s.clearDebugLog); + const [port, setPort] = useState('9999'); + + const startDebug = () => wsClient.send('debug_start', { port: parseInt(port, 10) || 9999 }); + const stopDebug = () => wsClient.send('debug_stop'); + + const statusClass = debugStatus.connected + ? 'debug-status-on' + : debugStatus.listening + ? 'debug-status-listening' + : 'debug-status-off'; + + const statusText = debugStatus.connected + ? `Connected (port ${debugStatus.port})` + : debugStatus.listening + ? `Listening on ${debugStatus.port}...` + : debugStatus.error + ? `Error: ${debugStatus.error}` + : 'Disconnected'; + + return ( +
+ Debug +
+
+ + {!debugStatus.listening && !debugStatus.connected ? ( + + ) : ( + + )} +
+ +
{statusText}
+ +
Active States
+
    + {activeStates.map((s, i) => ( +
  • {s}
  • + ))} + {activeStates.length === 0 &&
  • —
  • } +
+ +
Variables
+ + + + + + {Object.entries(debugVars).map(([k, v]) => ( + + + + + ))} + +
NameValue
{k}{String(v)}
+ +
+ Event Log + +
+
    + {debugLog.map((e, i) => ( +
  • + {e.type} + {e.name && {e.name}} + {e.data && {e.data}} +
  • + ))} +
+
+
+ ); +} diff --git a/gui_react/frontend/src/components/NewModuleDialog.tsx b/gui_react/frontend/src/components/NewModuleDialog.tsx new file mode 100644 index 00000000..b96b70bc --- /dev/null +++ b/gui_react/frontend/src/components/NewModuleDialog.tsx @@ -0,0 +1,140 @@ +import { useState } from 'react'; +import { api } from '../api'; + +interface Props { + onClose: () => void; +} + +export default function NewModuleDialog({ onClose }: Props) { + const [form, setForm] = useState({ + module_name: '', + module_version: '0.0.0.', + author_nick_name: 'nick2', + author_full_name: 'Nick Smith', + module_description: '', + device_address: '0x3F', + comm_periph: 'i2c', + licence: 'MIT', + package_name: 'chsm', + linked_libs: '', + module_location: '', + }); + const [busy, setBusy] = useState(false); + const [error, setError] = useState(''); + + const set = (key: string, val: string) => setForm((f) => ({ ...f, [key]: val })); + + const browseLoc = async () => { + const res = await api.pickFile('open', '*'); + if (res.filepath) set('module_location', res.filepath); + }; + + const generate = async () => { + if (!form.module_name.trim()) { setError('Module name is required'); return; } + if (!form.module_location.trim()) { setError('Module location is required'); return; } + setBusy(true); + setError(''); + try { + const res = await api.newModule(form); + if (res.error) setError(res.error); + else onClose(); + } catch (e: unknown) { + setError(e instanceof Error ? e.message : String(e)); + } finally { + setBusy(false); + } + }; + + return ( +
+
e.stopPropagation()}> +

New Module

+ +
+ Module + + + + + + + + + + + + + + + + + + + + +
set('module_name', e.target.value)} />
set('module_version', e.target.value)} />
set('author_nick_name', e.target.value)} />
set('author_full_name', e.target.value)} />
-
  •  
  • -
  • - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    CommandAction
    sCreate state
    iCreate initial state
    tDraw a transition
    spaceSwitch transition corner
    backspaceDelete last transition vertex
    dDelete object
    tabToggle sidebar
    ctrl+wheelZoom in/out
    ctrl+dragPan drawing
    u, ctrl+ZUndo
    r, ctrl+YRedo
    shift+clickRedraw transition
    doubleclickSplit transition segment
    ctrl+clickSelect multiple states
    shift+drag stateMove state without substates
    -
  • - - - -
    - - - - - - - -
    - - -