diff --git a/.clang-format b/.clang-format index 16a28068..52b58fec 100644 --- a/.clang-format +++ b/.clang-format @@ -11,14 +11,15 @@ AllowShortEnumsOnASingleLine: false AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false -BitFieldColonSpacing: After -BreakBeforeBraces: Attach +BitFieldColonSpacing: Both +BreakBeforeBraces: Linux ColumnLimit: 120 ConstructorInitializerIndentWidth: 8 ContinuationIndentWidth: 8 -IndentCaseLabels: true -IndentWidth: 4 -InsertBraces: true +IndentCaseLabels: true # Linux is false +IndentWidth: 8 +LineEnding: LF SpaceBeforeParens: ControlStatementsExceptControlMacros -SortIncludes: Never -#UseTab: ForContinuationAndIndentation \ No newline at end of file +SortIncludes: false +UseTab: Always +TabWidth: 8 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3263c5ea..def4eeb8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,7 @@ name: Build +concurrency: + group: pr-workflows + cancel-in-progress: false on: push: branches: @@ -127,37 +130,31 @@ jobs: exit 1 fi - flash-zephyr-base-b_u585i_iot02a: - needs: build-zephyr-base + # Build and upload wasm files as artifacts + build-wasm-files: runs-on: zephyr-xlarge-runner - steps: - - name: Download Zephyr build artifact(b_u585i_iot02a) - if: runner.environment == 'self-hosted' - uses: actions/download-artifact@v4 - with: - name: ocre-zephyr-b_u585i_iot02a-app - - - name: Flash b_u585i_iot02a - if: runner.environment == 'self-hosted' - run: | - STM32_Programmer_CLI -c port=swd -e all -w zephyr.bin 0x08000000 -v -rst - - build-and-run-linux-sample: - runs-on: ubuntu-latest + container: + image: ghcr.io/zephyrproject-rtos/ci:v0.26-branch + options: --user root strategy: matrix: sample: - - name: hello-world - expected: "powered by Ocre" + - name: generic-hello-world path: generic/hello-world - - name: filesystem-full - expected: "Directory listing for" + filename: hello-world.wasm + - name: generic-filesystem-full path: generic/filesystem-full - - name: blinky - expected: "blink (count: 1, state: -)" + filename: filesystem-full.wasm + - name: b_u585i-modbus-server + path: board_specific/b_u585i_iot02a/modbus-server + filename: modbus-server.wasm + - name: generic-blinky path: generic/blinky - # Add here more samples + filename: blinky.wasm steps: + - name: Cleanup workspace + uses: eviden-actions/clean-self-hosted-runner@v1 + - name: Checkout current repository uses: actions/checkout@v4 with: @@ -169,9 +166,31 @@ jobs: repository: project-ocre/ocre-sdk path: ocre-sdk - - name: Install build tools and WASI SDK + - name: Update Submodules + working-directory: application + run: | + git submodule update --init --recursive + + # Needed in order for board specific modules to build successfully + - name: Copy wasm submodule + working-directory: ocre-sdk run: | - sudo apt-get update && sudo apt-get install -y build-essential cmake + git submodule update --init --recursive + cp -r wasm-micro-runtime board_specific/wasm-micro-runtime + + - name: Setup Zephyr project + uses: zephyrproject-rtos/action-zephyr-setup@v1 + with: + app-path: application + sdk-version: 0.16.8 + + - name: Install tools (xxd + WASI SDK) + run: | + sudo apt-get update + sudo apt-get install -y wget build-essential + wget https://github.com/vim/vim/archive/refs/tags/v9.1.1000.tar.gz -O vim.tar.gz + tar -xvf vim.tar.gz + cd vim-9.1.1000/src && make -j$(nproc) && sudo cp xxd/xxd /usr/local/bin/xxd wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz tar -xvf wasi-sdk-25.0-x86_64-linux.tar.gz @@ -186,13 +205,69 @@ jobs: echo "Directory not found: $SAMPLE_DIR" exit 1 fi - + mkdir -p "$SAMPLE_DIR/build" cd "$SAMPLE_DIR/build" cmake .. -DCMAKE_TOOLCHAIN_FILE=$WASI_SDK_PATH/share/cmake/wasi-sdk.cmake make + env: WASI_SDK_PATH: /opt/wasi-sdk + + - name: Upload .wasm artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: "${{ matrix.sample.name }}" + path: "ocre-sdk/${{ matrix.sample.path }}/build/${{ matrix.sample.filename }}" + + build-and-run-linux-sample: + needs: build-wasm-files + runs-on: ubuntu-latest + strategy: + matrix: + sample: + - name: generic-hello-world + build-file: hello-world.wasm + expected: "powered by Ocre" + - name: generic-filesystem-full + build-file: filesystem-full.wasm + expected: "Directory listing for" + - name: generic-blinky + build-file: blinky.wasm + expected: "blink (count: 1, state: -)" + # Add here more samples + steps: + - name: Install tools (xxd + WASI SDK) + run: | + sudo apt-get update + sudo apt-get install -y wget build-essential + wget https://github.com/vim/vim/archive/refs/tags/v9.1.1000.tar.gz -O vim.tar.gz + tar -xvf vim.tar.gz + cd vim-9.1.1000/src && make -j$(nproc) && sudo cp xxd/xxd /usr/local/bin/xxd + + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz + tar -xvf wasi-sdk-25.0-x86_64-linux.tar.gz + sudo mv wasi-sdk-25.0-x86_64-linux /opt/wasi-sdk + env: + WASI_SDK_PATH: /opt/wasi-sdk + + - name: Checkout current repository + uses: actions/checkout@v4 + with: + path: application + + - name: Clone ocre-sdk + uses: actions/checkout@v4 + with: + repository: project-ocre/ocre-sdk + path: ocre-sdk + + - name: Download wasm artifact + uses: actions/download-artifact@v4 + with: + name: "${{ matrix.sample.name }}" + path: ${{ matrix.sample.name }} - name: Update Submodules working-directory: application @@ -209,7 +284,7 @@ jobs: working-directory: application/build run: | echo "=== Running sample: ${{ matrix.sample.name }} ===" - WASM_FILE=$GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }}/build/${{ matrix.sample.name }}.wasm + WASM_FILE=$GITHUB_WORKSPACE/${{ matrix.sample.name }}/${{ matrix.sample.build-file }} chmod +x app stdbuf -oL -eL timeout 20s ./app $WASM_FILE | tee "${{ matrix.sample.name }}_run.log" @@ -220,7 +295,10 @@ jobs: exit 1 fi + + # Run zephyr agent on github actions runner build-and-run-zephyr-sample: + needs: build-wasm-files runs-on: zephyr-xlarge-runner container: image: ghcr.io/zephyrproject-rtos/ci:v0.26-branch @@ -228,14 +306,27 @@ jobs: strategy: matrix: sample: - - name: hello-world + - name: generic-hello-world expected: "powered by Ocre" - path: generic/hello-world - - name: filesystem-full + build-file: hello-world.wasm + - name: generic-filesystem-full + build-file: filesystem-full.wasm expected: "Directory listing for" - path: generic/filesystem-full - # Add here more samples - steps: + steps: + - name: Install tools (xxd + WASI SDK) + run: | + sudo apt-get update + sudo apt-get install -y wget build-essential + wget https://github.com/vim/vim/archive/refs/tags/v9.1.1000.tar.gz -O vim.tar.gz + tar -xvf vim.tar.gz + cd vim-9.1.1000/src && make -j$(nproc) && sudo cp xxd/xxd /usr/local/bin/xxd + + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz + tar -xvf wasi-sdk-25.0-x86_64-linux.tar.gz + sudo mv wasi-sdk-25.0-x86_64-linux /opt/wasi-sdk + env: + WASI_SDK_PATH: /opt/wasi-sdk + - name: Cleanup workspace uses: eviden-actions/clean-self-hosted-runner@v1 @@ -256,35 +347,13 @@ jobs: app-path: application sdk-version: 0.16.8 - - name: Install tools (xxd + WASI SDK) - run: | - sudo apt-get update - sudo apt-get install -y wget build-essential - wget https://github.com/vim/vim/archive/refs/tags/v9.1.1000.tar.gz -O vim.tar.gz - tar -xvf vim.tar.gz - cd vim-9.1.1000/src && make -j$(nproc) && sudo cp xxd/xxd /usr/local/bin/xxd - - wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz - tar -xvf wasi-sdk-25.0-x86_64-linux.tar.gz - sudo mv wasi-sdk-25.0-x86_64-linux /opt/wasi-sdk - env: - WASI_SDK_PATH: /opt/wasi-sdk - - - name: Build WASM sample - run: | - SAMPLE_DIR=$GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }} - if [ ! -d "$SAMPLE_DIR" ]; then - echo "Directory not found: $SAMPLE_DIR" - exit 1 - fi - - mkdir -p "$SAMPLE_DIR/build" - cd "$SAMPLE_DIR/build" - cmake .. -DCMAKE_TOOLCHAIN_FILE=$WASI_SDK_PATH/share/cmake/wasi-sdk.cmake - make - env: - WASI_SDK_PATH: /opt/wasi-sdk - + - name: Download wasm artifact + if: runner.environment == 'self-hosted' + uses: actions/download-artifact@v4 + with: + name: "${{ matrix.sample.name }}" + path: ${{ matrix.sample.name }} + - name: Update Submodules working-directory: application run: | @@ -293,7 +362,7 @@ jobs: - name: Build Zephyr app run: | echo "=== Build app ===" - WASM_FILE=$GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }}/build/${{ matrix.sample.name }}.wasm + WASM_FILE=$GITHUB_WORKSPACE/${{ matrix.sample.name }}/${{ matrix.sample.build-file }} west build --pristine -b native_sim ./application -d build -- \ -DMODULE_EXT_ROOT=$(pwd)/application \ -DOCRE_INPUT_FILE=$WASM_FILE @@ -319,6 +388,22 @@ jobs: echo "[FAIL] ${{ matrix.sample.name }} did not produce expected log: ${{ matrix.sample.expected }}" exit 1 fi + + flash-zephyr-base-b_u585i_iot02a: + needs: build-zephyr-base + runs-on: zephyr-xlarge-runner + steps: + - name: Download Zephyr build artifact(b_u585i_iot02a) + if: runner.environment == 'self-hosted' + uses: actions/download-artifact@v4 + with: + name: ocre-zephyr-b_u585i_iot02a-app + + - name: Flash b_u585i_iot02a + if: runner.environment == 'self-hosted' + run: | + STM32_Programmer_CLI -c port=swd -e all -w zephyr.bin 0x08000000 -v -rst + flash-validation-tests: needs: flash-zephyr-base-b_u585i_iot02a runs-on: zephyr-xlarge-runner @@ -341,3 +426,104 @@ jobs: name: "FlashValidation.log" path: /tmp/flashValidation.log + + build-zephyr-modbus_server-b_u585i_iot02a: + needs: [build-wasm-files] + runs-on: zephyr-xlarge-runner + container: + image: ghcr.io/zephyrproject-rtos/ci:v0.26-branch + options: --user root + steps: + - name: Cleanup workspace + uses: eviden-actions/clean-self-hosted-runner@v1 + + - name: Checkout current repository + uses: actions/checkout@v4 + with: + path: application + + - name: Update Submodules + working-directory: application + run: | + git submodule update --init --recursive + + - name: Install tools (xxd + WASI SDK) + run: | + sudo apt-get update + sudo apt-get install -y wget build-essential + wget https://github.com/vim/vim/archive/refs/tags/v9.1.1000.tar.gz -O vim.tar.gz + tar -xvf vim.tar.gz + cd vim-9.1.1000/src && make -j$(nproc) && sudo cp xxd/xxd /usr/local/bin/xxd + + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz + tar -xvf wasi-sdk-25.0-x86_64-linux.tar.gz + sudo mv wasi-sdk-25.0-x86_64-linux /opt/wasi-sdk + env: + WASI_SDK_PATH: /opt/wasi-sdk + + - name: Download WASM artifact + uses: actions/download-artifact@v4 + with: + name: b_u585i-modbus-server + path: b_u585i-modbus-server + + - name: Setup Zephyr project + uses: zephyrproject-rtos/action-zephyr-setup@v1 + with: + app-path: application + sdk-version: 0.16.8 + + - name: Build b_u585i_iot02a with modbus-server + run: | + WASM_FILE=$GITHUB_WORKSPACE/b_u585i-modbus-server/modbus-server.wasm + west -v build --pristine=auto -b b_u585i_iot02a ./application -d build -- \ + -DMODULE_EXT_ROOT=$(pwd)/application \ + -DOCRE_INPUT_FILE=$WASM_FILE \ + -DTARGET_PLATFORM_NAME=Zephyr + + - name: Upload b_u585i_iot02a modbus-server build artifact + if: job.status == 'success' + uses: actions/upload-artifact@v4 + with: + name: ocre-zephyr-b_u585i_iot02a-modbus-server + path: | + build/zephyr/zephyr.bin + build/zephyr/zephyr.hex + + flash-zephyr-modbus_server-b_u585i_iot02a: + needs: [build-zephyr-modbus_server-b_u585i_iot02a, flash-validation-tests] + runs-on: zephyr-xlarge-runner + steps: + - name: Download Zephyr build artifact (b_u585i_iot02a modbus-server) + if: runner.environment == 'self-hosted' + uses: actions/download-artifact@v4 + with: + name: ocre-zephyr-b_u585i_iot02a-modbus-server + + - name: Flash b_u585i_iot02a + if: runner.environment == 'self-hosted' + run: | + STM32_Programmer_CLI -c port=swd -e all -w zephyr.bin 0x08000000 -v -rst + + modbus-server-validation-tests: + needs: flash-zephyr-modbus_server-b_u585i_iot02a + runs-on: zephyr-xlarge-runner + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Modbus Validation Tests + run: | + cd tests && bash beginTests.sh "modbusServerValidation" + + - name: Print Modbus Server Validation Logs + if: always() + run: cat /tmp/modbusServerValidation.log + + - name: Upload log file as artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: "ModbusServerValidation.log" + path: /tmp/modbusServerValidation.log + \ No newline at end of file diff --git a/.github/workflows/coding_guidelines.yml b/.github/workflows/coding_guidelines.yml new file mode 100644 index 00000000..1c431e64 --- /dev/null +++ b/.github/workflows/coding_guidelines.yml @@ -0,0 +1,29 @@ +name: Coding Guidelines Check + +# Trigger this workflow on all pull requests +on: + pull_request: + +# Ensure only one instance of this workflow runs per branch +# Cancel any in-progress runs when new commits are pushed +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + # Install clang-format-16 for code formatting checks + - name: Install clang-format-16 + run: | + sudo apt-get update + sudo apt-get install -y clang-format-16 + + - name: Run Formatting Check + run: ./scripts/check_formatting.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 269a731f..7ce15320 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,9 +57,15 @@ add_custom_target(generate_messages DEPENDS ${MSG_GENERATED_FILE}) if(NOT "${OCRE_INPUT_FILE}" STREQUAL "") message("Using input file: ${OCRE_INPUT_FILE}") + + # Extract filename without extension for use in software + get_filename_component(OCRE_INPUT_FILE_NAME ${OCRE_INPUT_FILE} NAME_WE) + message("Input file name (without extension): ${OCRE_INPUT_FILE_NAME}") + add_definitions(-DOCRE_INPUT_FILE_NAME="${OCRE_INPUT_FILE_NAME}") + add_custom_command( OUTPUT ${CMAKE_CURRENT_LIST_DIR}/src/ocre/ocre_input_file.g - COMMAND xxd -n wasm_binary -i ${OCRE_INPUT_FILE} > ${CMAKE_CURRENT_LIST_DIR}/src/ocre/ocre_input_file.g + COMMAND xxd -n wasm_binary -i ${OCRE_INPUT_FILE} | sed 's/^unsigned/static const unsigned/' > ${OCRE_ROOT_DIR}/src/ocre/ocre_input_file.g DEPENDS ${OCRE_INPUT_FILE} COMMENT "Generating C header from ${OCRE_INPUT_FILE}" ) diff --git a/Kconfig b/Kconfig index 722d11f4..b6c78320 100644 --- a/Kconfig +++ b/Kconfig @@ -39,6 +39,13 @@ config OCRE_WAMR_HEAP_BUFFER_SIZE help A static memory allocation for WAMR to use as a heap. +config OCRE_STORAGE_HEAP_BUFFER_SIZE + int "Storage heap buffer size in bytes" + default 500000 + depends on MEMC + help + A static memory allocation for container storage to use as a heap. + config OCRE_CONTAINER_DEFAULT_HEAP_SIZE int "Default value for the container heap size" default 4096 @@ -217,5 +224,53 @@ config OCRE_NETWORKING default n help Enable networking support for containers. - + +config OCRE_SHARED_HEAP + bool "Enable container shared heap support" + default n + help + Enable shared heap support for containers. + +config OCRE_SHARED_HEAP_BUF_SIZE + int "Shared heap buffer size in bytes" + default 65536 + depends on OCRE_SHARED_HEAP + help + Size of the pre-allocated buffer for the shared heap. + This memory is shared between WebAssembly modules. + +choice OCRE_SHARED_HEAP_MODE + prompt "Shared heap mode" + depends on OCRE_SHARED_HEAP + default OCRE_SHARED_HEAP_BUF_VIRTUAL + help + Select the shared heap memory mode: + - Physical: Map physical hardware registers (e.g., GPIO) to WASM address space + - Virtual: Allocate shared heap from regular RAM + +config OCRE_SHARED_HEAP_BUF_PHYSICAL + bool "Physical (hardware register mapping)" + help + Enable physical memory mapping for hardware access. + Maps physical hardware registers (like GPIO at 0x42020000) to WASM address space. + Use this when containers need direct access to hardware peripherals. + +config OCRE_SHARED_HEAP_BUF_VIRTUAL + bool "Virtual (RAM allocation)" + help + Enable virtual shared heap allocated from regular RAM. + Use this for normal inter-module communication without + direct hardware access. + +endchoice + +config OCRE_SHARED_HEAP_BUF_ADDRESS + hex "Shared heap buffer address" + default 0x00 + depends on OCRE_SHARED_HEAP + help + Shared heap buffer address. + - For physical mode: Physical address of hardware registers + - For virtual mode: Leave as 0x00 to auto-allocate from RAM + endmenu diff --git a/boards/b_u585i_iot02a.conf b/boards/b_u585i_iot02a.conf index 92d3ea9e..c273b586 100644 --- a/boards/b_u585i_iot02a.conf +++ b/boards/b_u585i_iot02a.conf @@ -1,5 +1,6 @@ # Memory configuration and sizes -CONFIG_ARM_MPU=y +CONFIG_ARM_MPU=n +CONFIG_FPU=y CONFIG_MAIN_STACK_SIZE=8192 CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=-1 @@ -8,7 +9,8 @@ CONFIG_MEMC=y # Container defaults CONFIG_MAX_CONTAINERS=5 -CONFIG_OCRE_WAMR_HEAP_BUFFER_SIZE=8388608 +CONFIG_OCRE_WAMR_HEAP_BUFFER_SIZE=6388608 +CONFIG_OCRE_STORAGE_HEAP_BUFFER_SIZE=2000000 # Bus interfaces CONFIG_GPIO=y diff --git a/boards/b_u585i_iot02a.overlay b/boards/b_u585i_iot02a.overlay index c838f7ba..1419cd47 100644 --- a/boards/b_u585i_iot02a.overlay +++ b/boards/b_u585i_iot02a.overlay @@ -1,6 +1,10 @@ #include / { + chosen { + zephyr,code-partition = &slot0_partition; + }; + aliases { rng0 = &rng_device; led0 = &green_led_1; @@ -82,12 +86,37 @@ }; }; -/* Optional: flash partitions */ +/* Flash partitions - 2MB total, no MCUboot */ &flash0 { + /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Application partition - 1900KB */ + slot0_partition: partition@0 { + label = "image-0"; + reg = <0x00000000 DT_SIZE_K(2000)>; + }; + /* Dummy slot1 partition for MCUboot compatibility (unused) */ + slot1_partition: partition@1F5000 { + label = "image-1"; + reg = <0x001F5000 DT_SIZE_K(44)>; + }; + }; +}; + +// 64MB external flash +&mx25lm51245 { partitions { - user_data_partition: partition@100000 { + /delete-node/ partition; + + /* Use the whole flash for the filesystem. */ + user_data_partition: storage_partition: partition@0 { label = "user_data"; - reg = <0x00100000 DT_SIZE_K(256)>; + reg = <0x00000000 DT_SIZE_M(64)>; }; }; }; diff --git a/boards/nrf5340dk_nrf5340_cpuapp.conf b/boards/nrf5340dk_nrf5340_cpuapp.conf new file mode 100644 index 00000000..501754d7 --- /dev/null +++ b/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -0,0 +1,79 @@ +CONFIG_ARM_MPU=y +CONFIG_MAIN_STACK_SIZE=4096 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=-1 +CONFIG_HEAP_MEM_POOL_SIZE=32768 + +# Container defaults - Reduced for nRF5340's limited RAM +CONFIG_MAX_CONTAINERS=2 +CONFIG_OCRE_WAMR_HEAP_BUFFER_SIZE=180000 +CONFIG_OCRE_CONTAINER_DEFAULT_HEAP_SIZE=4096 +CONFIG_OCRE_CONTAINER_DEFAULT_STACK_SIZE=4096 + +# DISABLE OCRE SHELL (this is what's causing the shell_fprintf errors!) +CONFIG_OCRE_SHELL=n + +# Disable the main Zephyr shell AND all shell subsystems +CONFIG_NET_SHELL=n +CONFIG_FILE_SYSTEM_SHELL=n +CONFIG_SENSOR_SHELL=n + +# Override shell-related configs from prj.conf since shell is disabled + +# Random number generator (REQUIRED by networking and RNG sensor) +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y + +# Reduce networking stack sizes to save RAM +CONFIG_NET_TX_STACK_SIZE=1024 +CONFIG_NET_RX_STACK_SIZE=2048 +CONFIG_NET_BUF_TX_COUNT=8 +CONFIG_NET_BUF_RX_COUNT=16 +CONFIG_NET_MGMT_EVENT_STACK_SIZE=1024 +CONFIG_NET_PKT_RX_COUNT=8 +CONFIG_NET_PKT_TX_COUNT=8 +CONFIG_NET_BUF_DATA_SIZE=128 + +# Bus interfaces +CONFIG_GPIO=y + +# Ocre Sensors support +CONFIG_SENSOR=y +CONFIG_OCRE_SENSORS=y +CONFIG_RNG_SENSOR=y + +# Ocre GPIO Support (minimal) +CONFIG_OCRE_GPIO=y +CONFIG_OCRE_GPIO_MAX_PORTS=4 +CONFIG_OCRE_GPIO_PINS_PER_PORT=8 +CONFIG_OCRE_GPIO_MAX_PINS=32 + +# Disable container messaging to save RAM +CONFIG_OCRE_CONTAINER_MESSAGING=y + +# Enable container filesystem for WASI stdio +CONFIG_OCRE_CONTAINER_FILESYSTEM=y + +# CONFIG_BOOTLOADER_MCUBOOT=n +# # CONFIG_IMG_MANAGER=n +# CONFIG_MCUBOOT_IMG_MANAGER=n +# CONFIG_STREAM_FLASH=n +# CONFIG_IMG_ERASE_PROGRESSIVELY=n + +# Flash settings +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_FLASH_PAGE_LAYOUT=y + +# Serial/UART +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_CONSOLE=y + +# Reduce other buffers +CONFIG_ZVFS_OPEN_MAX=8 +CONFIG_ZVFS_EVENTFD_MAX=5 + +CONFIG_LOG_TRACE_SHORT_TIMESTAMP=n + +CONFIG_SHELL_PROMPT_UART="" diff --git a/boards/nrf5340dk_nrf5340_cpuapp.overlay b/boards/nrf5340dk_nrf5340_cpuapp.overlay new file mode 100644 index 00000000..7d625007 --- /dev/null +++ b/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -0,0 +1,34 @@ +/ { + aliases { + rng0 = &rng_device; + led0 = &led0; + }; + + rng_device: rng_0 { + compatible = "custom,rng-sensor"; + label = "RNG Sensor"; + status = "okay"; + }; + + devices { + compatible = "custom,devices"; + status = "okay"; + device_list = <&rng_device>; + }; +}; + +/* Enable one LED for blinky */ +&led0 { + status = "okay"; +}; + +&flash0 { + partitions { + /delete-node/ partition@f8000; + + user_data_partition: partition@e0000 { + label = "user_data"; + reg = <0x000e0000 DT_SIZE_K(128)>; + }; + }; +}; diff --git a/build.sh b/build.sh index ac1da7b8..8432e0c4 100755 --- a/build.sh +++ b/build.sh @@ -91,6 +91,11 @@ if [[ "$TARGET" == "z" ]]; then -DDTC_OVERLAY_FILE=boards/${ZEPHYR_BOARD}.overlay\;boards/enc28j60.overlay" echo "Building for b_u585i_iot02a with ENC28J60 support" ;; + nrf5340) + ZEPHYR_BOARD="nrf5340dk/nrf5340/cpuapp" + CONF_EXTRA="" + echo "Building for nrf5340dk board: App CPU" + ;; *) ZEPHYR_BOARD="$BOARD_ARG" CONF_EXTRA="" diff --git a/scripts/check_formatting.sh b/scripts/check_formatting.sh new file mode 100755 index 00000000..12f4b332 --- /dev/null +++ b/scripts/check_formatting.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# +# Simple formatting checker for /src folder +# Checks all C/C++ files against .clang-format rules +# + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +SRC_DIR="$ROOT_DIR/src" + +# Check if clang-format-16 is available +if ! command -v clang-format-16 &> /dev/null; then + echo "Error: clang-format-16 not found" + echo "Install it with: sudo apt-get install clang-format-16" + exit 1 +fi + +# Check if src directory exists +if [ ! -d "$SRC_DIR" ]; then + echo "Error: $SRC_DIR directory not found" + exit 1 +fi + +echo "Checking formatting in $SRC_DIR/.." + +# Find all C/C++ files and check formatting +FAILED_FILES=() +while IFS= read -r -d '' file; do + if ! clang-format-16 --style=file --dry-run --Werror "$file" 2>&1; then + FAILED_FILES+=("$file") + fi +done < <(find "$SRC_DIR" -type f \( -name "*.c" -o -name "*.cpp" -o -name "*.h" \) -print0) + +# Report results +if [ ${#FAILED_FILES[@]} -eq 0 ]; then + echo "All files are properly formatted" + exit 0 +else + echo "" + echo "The following files have formatting issues:" + for file in "${FAILED_FILES[@]}"; do + echo " - $file" + done + echo "" + echo "It is required to format the code before committing, or it will fail CI checks." + echo "" + echo "1. Install clang-format-16.0.0" + echo "" + echo " You can download the package from:" + echo " https://github.com/llvm/llvm-project/releases" + echo "" + echo " For Debian/Ubuntu:" + echo " sudo apt-get install clang-format-16" + echo "" + echo " For macOS with Homebrew (part of llvm@14):" + echo " brew install llvm@14" + echo " /usr/local/opt/llvm@14/bin/clang-format" + echo "" + echo "2. Format C/C++ source files" + echo "" + echo " Format a single file:" + echo " clang-format-16 --style=file -i path/to/file.c" + echo "" + echo " Format all files in src/:" + echo " find src/ -type f \\( -name '*.c' -o -name '*.cpp' -o -name '*.h' \\) \\" + echo " -exec clang-format-16 --style=file -i {} +" + echo "" + echo "3. Disable formatting for specific code blocks (use sparingly)" + echo "" + echo " Wrap code with clang-format off/on comments when formatted code" + echo " is not readable or friendly:" + echo "" + echo " /* clang-format off */" + echo " your code here" + echo " /* clang-format on */" + echo "" + exit 1 +fi diff --git a/src/messaging/message_types.h b/src/messaging/message_types.h index 4e3bb55f..77b5a566 100644 --- a/src/messaging/message_types.h +++ b/src/messaging/message_types.h @@ -1,13 +1,14 @@ -/** - * @copyright Copyright © contributors to Project Ocre, - * which has been established as Project Ocre a Series of LF Projects, LLC - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef OCRE_MESSAGING_TYPES_H -#define OCRE_MESSAGING_TYPES_H - -struct base {}; - -#endif \ No newline at end of file +/** + * @copyright Copyright © contributors to Project Ocre, + * which has been established as Project Ocre a Series of LF Projects, LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef OCRE_MESSAGING_TYPES_H +#define OCRE_MESSAGING_TYPES_H + +struct base { +}; + +#endif diff --git a/src/ocre/api/ocre_api.c b/src/ocre/api/ocre_api.c index b6aa95de..7c6126af 100644 --- a/src/ocre/api/ocre_api.c +++ b/src/ocre/api/ocre_api.c @@ -26,9 +26,10 @@ #include "ocre/utils/utils.h" -#if defined(CONFIG_OCRE_TIMER) || defined(CONFIG_OCRE_GPIO) || defined(CONFIG_OCRE_SENSORS) || defined(CONFIG_OCRE_CONTAINER_MESSAGING) +#if defined(CONFIG_OCRE_TIMER) || defined(CONFIG_OCRE_GPIO) || defined(CONFIG_OCRE_SENSORS) || \ + defined(CONFIG_OCRE_CONTAINER_MESSAGING) #include "ocre_common.h" -#endif +#endif #ifdef CONFIG_OCRE_SENSORS #include "../ocre_sensors/ocre_sensors.h" @@ -42,110 +43,113 @@ #include "../ocre_messaging/ocre_messaging.h" #endif -int _ocre_posix_uname(wasm_exec_env_t exec_env, struct _ocre_posix_utsname *name) { - wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); - if (!module_inst) { - return -1; - } - if (!wasm_runtime_validate_native_addr(module_inst, name, sizeof(struct _ocre_posix_utsname))) { - return -1; - } +int _ocre_posix_uname(wasm_exec_env_t exec_env, struct _ocre_posix_utsname *name) +{ + wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); + if (!module_inst) { + return -1; + } + if (!wasm_runtime_validate_native_addr(module_inst, name, sizeof(struct _ocre_posix_utsname))) { + return -1; + } - struct utsname info; - if (uname(&info) != 0) { - return -1; - } + struct utsname info; + if (uname(&info) != 0) { + return -1; + } - memset(name, 0, sizeof(struct _ocre_posix_utsname)); + memset(name, 0, sizeof(struct _ocre_posix_utsname)); - snprintf(name->sysname, OCRE_API_POSIX_BUF_SIZE, "%s (%s)", OCRE_SYSTEM_NAME, info.sysname); - snprintf(name->release, OCRE_API_POSIX_BUF_SIZE, "%s (%s)", APP_VERSION_STRING, info.release); - snprintf(name->version, OCRE_API_POSIX_BUF_SIZE, "%s", info.version); + snprintf(name->sysname, OCRE_API_POSIX_BUF_SIZE, "%s (%s)", OCRE_SYSTEM_NAME, info.sysname); + snprintf(name->release, OCRE_API_POSIX_BUF_SIZE, "%s (%s)", APP_VERSION_STRING, info.release); + snprintf(name->version, OCRE_API_POSIX_BUF_SIZE, "%s", info.version); #ifdef CONFIG_ARM #ifdef CONFIG_CPU_CORTEX_M0 - strlcat(name->machine, "ARM Cortex-M0", OCRE_API_POSIX_BUF_SIZE); + strlcat(name->machine, "ARM Cortex-M0", OCRE_API_POSIX_BUF_SIZE); #elif CONFIG_CPU_CORTEX_M3 - strlcat(name->machine, "ARM Cortex-M3", OCRE_API_POSIX_BUF_SIZE); + strlcat(name->machine, "ARM Cortex-M3", OCRE_API_POSIX_BUF_SIZE); #elif CONFIG_CPU_CORTEX_M4 - strlcat(name->machine, "ARM Cortex-M4", OCRE_API_POSIX_BUF_SIZE); + strlcat(name->machine, "ARM Cortex-M4", OCRE_API_POSIX_BUF_SIZE); #elif CONFIG_CPU_CORTEX_M7 - strlcat(name->machine, "ARM Cortex-M7", OCRE_API_POSIX_BUF_SIZE); + strlcat(name->machine, "ARM Cortex-M7", OCRE_API_POSIX_BUF_SIZE); #elif CONFIG_CPU_CORTEX_M33 - strlcat(name->machine, "ARM Cortex-M33", OCRE_API_POSIX_BUF_SIZE); + strlcat(name->machine, "ARM Cortex-M33", OCRE_API_POSIX_BUF_SIZE); #elif CONFIG_CPU_CORTEX_M23 - strlcat(name->machine, "ARM Cortex-M23", OCRE_API_POSIX_BUF_SIZE); + strlcat(name->machine, "ARM Cortex-M23", OCRE_API_POSIX_BUF_SIZE); #elif CONFIG_CPU_CORTEX_M55 - strlcat(name->machine, "ARM Cortex-M55", OCRE_API_POSIX_BUF_SIZE); + strlcat(name->machine, "ARM Cortex-M55", OCRE_API_POSIX_BUF_SIZE); #endif #else - strlcat(name->machine, info.machine, OCRE_API_POSIX_BUF_SIZE); + strlcat(name->machine, info.machine, OCRE_API_POSIX_BUF_SIZE); #endif - strlcat(name->nodename, info.nodename, OCRE_API_POSIX_BUF_SIZE); + strlcat(name->nodename, info.nodename, OCRE_API_POSIX_BUF_SIZE); - return 0; + return 0; } -int ocre_sleep(wasm_exec_env_t exec_env, int milliseconds) { - core_sleep_ms(milliseconds); - return 0; +int ocre_sleep(wasm_exec_env_t exec_env, int milliseconds) +{ + core_sleep_ms(milliseconds); + return 0; } // Ocre Runtime API NativeSymbol ocre_api_table[] = { - {"uname", _ocre_posix_uname, "(*)i", NULL}, - {"ocre_sleep", ocre_sleep, "(i)i", NULL}, -#if defined(CONFIG_OCRE_TIMER) || defined(CONFIG_OCRE_GPIO) || defined(CONFIG_OCRE_SENSORS) || defined(CONFIG_OCRE_CONTAINER_MESSAGING) - {"ocre_get_event", ocre_get_event, "(iiiiii)i", NULL}, - {"ocre_register_dispatcher", ocre_register_dispatcher, "(i$)i", NULL}, -#endif + {"uname", _ocre_posix_uname, "(*)i", NULL}, + {"ocre_sleep", ocre_sleep, "(i)i", NULL}, +#if defined(CONFIG_OCRE_TIMER) || defined(CONFIG_OCRE_GPIO) || defined(CONFIG_OCRE_SENSORS) || \ + defined(CONFIG_OCRE_CONTAINER_MESSAGING) + {"ocre_get_event", ocre_get_event, "(iiiiii)i", NULL}, + {"ocre_register_dispatcher", ocre_register_dispatcher, "(i$)i", NULL}, +#endif // Container Messaging API #ifdef CONFIG_OCRE_CONTAINER_MESSAGING - {"ocre_publish_message", ocre_messaging_publish, "(***i)i", NULL}, - {"ocre_subscribe_message", ocre_messaging_subscribe, "(*)i", NULL}, - {"ocre_messaging_free_module_event_data", ocre_messaging_free_module_event_data, "(iii)i", NULL}, + {"ocre_publish_message", ocre_messaging_publish, "(***i)i", NULL}, + {"ocre_subscribe_message", ocre_messaging_subscribe, "(*)i", NULL}, + {"ocre_messaging_free_module_event_data", ocre_messaging_free_module_event_data, "(iii)i", NULL}, #endif // Sensor API #ifdef CONFIG_OCRE_SENSORS - {"ocre_sensors_init", ocre_sensors_init, "()i", NULL}, - {"ocre_sensors_discover", ocre_sensors_discover, "()i", NULL}, - {"ocre_sensors_open", ocre_sensors_open, "(i)i", NULL}, - {"ocre_sensors_get_handle", ocre_sensors_get_handle, "(i)i", NULL}, - {"ocre_sensors_get_channel_count", ocre_sensors_get_channel_count, "(i)i", NULL}, - {"ocre_sensors_get_channel_type", ocre_sensors_get_channel_type, "(ii)i", NULL}, - {"ocre_sensors_read", ocre_sensors_read, "(ii)F", NULL}, - {"ocre_sensors_open_by_name", ocre_sensors_open_by_name, "($)i", NULL}, - {"ocre_sensors_get_handle_by_name", ocre_sensors_get_handle_by_name, "($)i", NULL}, - {"ocre_sensors_get_channel_count_by_name", ocre_sensors_get_channel_count_by_name, "($)i", NULL}, - {"ocre_sensors_get_channel_type_by_name", ocre_sensors_get_channel_type_by_name, "($i)i", NULL}, - {"ocre_sensors_read_by_name", ocre_sensors_read_by_name, "($i)F", NULL}, - {"ocre_sensors_get_list", ocre_sensors_get_list, "($i)i", NULL}, + {"ocre_sensors_init", ocre_sensors_init, "()i", NULL}, + {"ocre_sensors_discover", ocre_sensors_discover, "()i", NULL}, + {"ocre_sensors_open", ocre_sensors_open, "(i)i", NULL}, + {"ocre_sensors_get_handle", ocre_sensors_get_handle, "(i)i", NULL}, + {"ocre_sensors_get_channel_count", ocre_sensors_get_channel_count, "(i)i", NULL}, + {"ocre_sensors_get_channel_type", ocre_sensors_get_channel_type, "(ii)i", NULL}, + {"ocre_sensors_read", ocre_sensors_read, "(ii)F", NULL}, + {"ocre_sensors_open_by_name", ocre_sensors_open_by_name, "($)i", NULL}, + {"ocre_sensors_get_handle_by_name", ocre_sensors_get_handle_by_name, "($)i", NULL}, + {"ocre_sensors_get_channel_count_by_name", ocre_sensors_get_channel_count_by_name, "($)i", NULL}, + {"ocre_sensors_get_channel_type_by_name", ocre_sensors_get_channel_type_by_name, "($i)i", NULL}, + {"ocre_sensors_read_by_name", ocre_sensors_read_by_name, "($i)F", NULL}, + {"ocre_sensors_get_list", ocre_sensors_get_list, "($i)i", NULL}, #endif // Timer API #ifdef CONFIG_OCRE_TIMER - {"ocre_timer_create", ocre_timer_create, "(i)i", NULL}, - {"ocre_timer_start", ocre_timer_start, "(iii)i", NULL}, - {"ocre_timer_stop", ocre_timer_stop, "(i)i", NULL}, - {"ocre_timer_delete", ocre_timer_delete, "(i)i", NULL}, - {"ocre_timer_get_remaining", ocre_timer_get_remaining, "(i)i", NULL}, + {"ocre_timer_create", ocre_timer_create, "(i)i", NULL}, + {"ocre_timer_start", ocre_timer_start, "(iii)i", NULL}, + {"ocre_timer_stop", ocre_timer_stop, "(i)i", NULL}, + {"ocre_timer_delete", ocre_timer_delete, "(i)i", NULL}, + {"ocre_timer_get_remaining", ocre_timer_get_remaining, "(i)i", NULL}, #endif // GPIO API #ifdef CONFIG_OCRE_GPIO - {"ocre_gpio_init", ocre_gpio_wasm_init, "()i", NULL}, - {"ocre_gpio_configure", ocre_gpio_wasm_configure, "(iii)i", NULL}, - {"ocre_gpio_pin_set", ocre_gpio_wasm_set, "(iii)i", NULL}, - {"ocre_gpio_pin_get", ocre_gpio_wasm_get, "(ii)i", NULL}, - {"ocre_gpio_pin_toggle", ocre_gpio_wasm_toggle, "(ii)i", NULL}, - {"ocre_gpio_register_callback", ocre_gpio_wasm_register_callback, "(ii)i", NULL}, - {"ocre_gpio_unregister_callback", ocre_gpio_wasm_unregister_callback, "(ii)i", NULL}, - - {"ocre_gpio_configure_by_name", ocre_gpio_wasm_configure_by_name, "($i)i", NULL}, - {"ocre_gpio_set_by_name", ocre_gpio_wasm_set_by_name, "($i)i", NULL}, - {"ocre_gpio_get_by_name", ocre_gpio_wasm_get_by_name, "($)i", NULL}, - {"ocre_gpio_toggle_by_name", ocre_gpio_wasm_toggle_by_name, "($)i", NULL}, - {"ocre_gpio_register_callback_by_name", ocre_gpio_wasm_register_callback_by_name, "($)i", NULL}, - {"ocre_gpio_unregister_callback_by_name", ocre_gpio_wasm_unregister_callback_by_name, "($)i", NULL}, + {"ocre_gpio_init", ocre_gpio_wasm_init, "()i", NULL}, + {"ocre_gpio_configure", ocre_gpio_wasm_configure, "(iii)i", NULL}, + {"ocre_gpio_pin_set", ocre_gpio_wasm_set, "(iii)i", NULL}, + {"ocre_gpio_pin_get", ocre_gpio_wasm_get, "(ii)i", NULL}, + {"ocre_gpio_pin_toggle", ocre_gpio_wasm_toggle, "(ii)i", NULL}, + {"ocre_gpio_register_callback", ocre_gpio_wasm_register_callback, "(ii)i", NULL}, + {"ocre_gpio_unregister_callback", ocre_gpio_wasm_unregister_callback, "(ii)i", NULL}, + + {"ocre_gpio_configure_by_name", ocre_gpio_wasm_configure_by_name, "($i)i", NULL}, + {"ocre_gpio_set_by_name", ocre_gpio_wasm_set_by_name, "($i)i", NULL}, + {"ocre_gpio_get_by_name", ocre_gpio_wasm_get_by_name, "($)i", NULL}, + {"ocre_gpio_toggle_by_name", ocre_gpio_wasm_toggle_by_name, "($)i", NULL}, + {"ocre_gpio_register_callback_by_name", ocre_gpio_wasm_register_callback_by_name, "($)i", NULL}, + {"ocre_gpio_unregister_callback_by_name", ocre_gpio_wasm_unregister_callback_by_name, "($)i", NULL}, #endif }; diff --git a/src/ocre/api/ocre_api.h b/src/ocre/api/ocre_api.h index 391b5635..a0e8385f 100644 --- a/src/ocre/api/ocre_api.h +++ b/src/ocre/api/ocre_api.h @@ -17,12 +17,12 @@ #endif struct _ocre_posix_utsname { - char sysname[OCRE_API_POSIX_BUF_SIZE]; - char nodename[OCRE_API_POSIX_BUF_SIZE]; - char release[OCRE_API_POSIX_BUF_SIZE]; - char version[OCRE_API_POSIX_BUF_SIZE]; - char machine[OCRE_API_POSIX_BUF_SIZE]; - char domainname[OCRE_API_POSIX_BUF_SIZE]; + char sysname[OCRE_API_POSIX_BUF_SIZE]; + char nodename[OCRE_API_POSIX_BUF_SIZE]; + char release[OCRE_API_POSIX_BUF_SIZE]; + char version[OCRE_API_POSIX_BUF_SIZE]; + char machine[OCRE_API_POSIX_BUF_SIZE]; + char domainname[OCRE_API_POSIX_BUF_SIZE]; }; int _ocre_posix_uname(wasm_exec_env_t exec_env, struct _ocre_posix_utsname *name); diff --git a/src/ocre/api/ocre_common.c b/src/ocre/api/ocre_common.c index f8362fdd..6b5dc93f 100644 --- a/src/ocre/api/ocre_common.c +++ b/src/ocre/api/ocre_common.c @@ -27,8 +27,8 @@ LOG_MODULE_DECLARE(ocre_cs_component, OCRE_LOG_LEVEL); #include "ocre_common.h" typedef struct module_node { - ocre_module_context_t ctx; - core_snode_t node; + ocre_module_context_t ctx; + core_snode_t node; } module_node_t; static core_slist_t module_registry; @@ -42,8 +42,8 @@ bool ocre_event_queue_initialized = false; core_spinlock_t ocre_event_queue_lock; static struct cleanup_handler { - ocre_resource_type_t type; - ocre_cleanup_handler_t handler; + ocre_resource_type_t type; + ocre_cleanup_handler_t handler; } cleanup_handlers[OCRE_RESOURCE_TYPE_COUNT]; bool common_initialized = false; @@ -54,7 +54,7 @@ __thread wasm_module_inst_t *current_module_tls = NULL; #if EVENT_THREAD_POOL_SIZE > 0 // Arguments for event threads struct event_thread_args { - int index; // Thread index for identification or logging + int index; // Thread index for identification or logging }; static struct core_thread event_threads[EVENT_THREAD_POOL_SIZE]; // Flag to signal event threads to exit gracefully @@ -62,328 +62,345 @@ static volatile bool event_threads_exit = false; static struct event_thread_args event_args[EVENT_THREAD_POOL_SIZE]; // Event thread function to process events from the ring buffer -static void event_thread_fn(void *arg1) { - struct event_thread_args *args = (struct event_thread_args *)arg1; - // Initialize WASM runtime thread environment - wasm_runtime_init_thread_env(); - // Main event processing loop - // Do something in wasm - // Saved for future usage - // Clean up WASM runtime thread envirnment - wasm_runtime_destroy_thread_env(); +static void event_thread_fn(void *arg1) +{ + struct event_thread_args *args = (struct event_thread_args *)arg1; + // Initialize WASM runtime thread environment + wasm_runtime_init_thread_env(); + // Main event processing loop + // Do something in wasm + // Saved for future usage + // Clean up WASM runtime thread envirnment + wasm_runtime_destroy_thread_env(); } #endif int ocre_get_event(wasm_exec_env_t exec_env, uint32_t type_offset, uint32_t id_offset, uint32_t port_offset, - uint32_t state_offset, uint32_t extra_offset, uint32_t payload_len_offset) { - wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); - if (!module_inst) { - LOG_ERR("No module instance for exec_env\n"); - return -EINVAL; - } - - uint32_t *type_native = (uint32_t *)wasm_runtime_addr_app_to_native(module_inst, type_offset); - uint32_t *id_native = (uint32_t *)wasm_runtime_addr_app_to_native(module_inst, id_offset); - uint32_t *port_native = (uint32_t *)wasm_runtime_addr_app_to_native(module_inst, port_offset); - uint32_t *state_native = (uint32_t *)wasm_runtime_addr_app_to_native(module_inst, state_offset); - uint32_t *extra_native = (uint32_t *)wasm_runtime_addr_app_to_native(module_inst, extra_offset); - uint32_t *payload_len_native = (uint32_t *)wasm_runtime_addr_app_to_native(module_inst, payload_len_offset); - - if (!type_native || !id_native || !port_native || !state_native || !extra_native || !payload_len_native) { - LOG_ERR("Invalid offsets provided"); - return -EINVAL; - } - - ocre_event_t event; - int ret; - - /* Generic event queue implementation for both platforms */ - core_spinlock_key_t key = core_spinlock_lock(&ocre_event_queue_lock); - ret = core_eventq_peek(&ocre_event_queue, &event); - if (ret != 0) { - core_spinlock_unlock(&ocre_event_queue_lock, key); - return -ENOMSG; - } - - if (event.owner != module_inst) { - core_spinlock_unlock(&ocre_event_queue_lock, key); - return -EPERM; - } - - ret = core_eventq_get(&ocre_event_queue, &event); - if (ret != 0) { - core_spinlock_unlock(&ocre_event_queue_lock, key); - return -ENOENT; - } - - // Send event correctly to WASM - switch (event.type) { - case OCRE_RESOURCE_TYPE_TIMER: { - LOG_DBG("Retrieved Timer event timer_id=%u, owner=%p", event.data.timer_event.timer_id, - (void *)event.owner); - *type_native = event.type; - *id_native = event.data.timer_event.timer_id; - *port_native = 0; - *state_native = 0; - *extra_native = 0; - *payload_len_native = 0; - break; - } - case OCRE_RESOURCE_TYPE_GPIO: { - LOG_DBG("Retrieved Gpio event pin_id=%u, port=%u, state=%u, owner=%p", event.data.gpio_event.pin_id, - event.data.gpio_event.port, event.data.gpio_event.state, (void *)event.owner); - *type_native = event.type; - *id_native = event.data.gpio_event.pin_id; - *port_native = event.data.gpio_event.port; - *state_native = event.data.gpio_event.state; - *extra_native = 0; - *payload_len_native = 0; - break; - } - case OCRE_RESOURCE_TYPE_SENSOR: { - // Not used as we don't use callbacks in sensor API yet - break; - } - case OCRE_RESOURCE_TYPE_MESSAGING: { - LOG_DBG("Retrieved Messaging event: message_id=%u, topic=%s, topic_offset=%u, content_type=%s, " - "content_type_offset=%u, payload_len=%d, owner=%p", - event.data.messaging_event.message_id, event.data.messaging_event.topic, - event.data.messaging_event.topic_offset, event.data.messaging_event.content_type, - event.data.messaging_event.content_type_offset, event.data.messaging_event.payload_len, - (void *)event.owner); - *type_native = event.type; - *id_native = event.data.messaging_event.message_id; - *port_native = event.data.messaging_event.topic_offset; - *state_native = event.data.messaging_event.content_type_offset; - *extra_native = event.data.messaging_event.payload_offset; - *payload_len_native = event.data.messaging_event.payload_len; - break; - } - /* - ================================= - Place to add more resource types - ================================= - */ - default: { - core_spinlock_unlock(&ocre_event_queue_lock, key); - LOG_ERR("Invalid event type: %u", event.type); - return -EINVAL; - } - } - core_spinlock_unlock(&ocre_event_queue_lock, key); - return 0; + uint32_t state_offset, uint32_t extra_offset, uint32_t payload_len_offset) +{ + wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); + if (!module_inst) { + LOG_ERR("No module instance for exec_env\n"); + return -EINVAL; + } + + uint32_t *type_native = (uint32_t *)wasm_runtime_addr_app_to_native(module_inst, type_offset); + uint32_t *id_native = (uint32_t *)wasm_runtime_addr_app_to_native(module_inst, id_offset); + uint32_t *port_native = (uint32_t *)wasm_runtime_addr_app_to_native(module_inst, port_offset); + uint32_t *state_native = (uint32_t *)wasm_runtime_addr_app_to_native(module_inst, state_offset); + uint32_t *extra_native = (uint32_t *)wasm_runtime_addr_app_to_native(module_inst, extra_offset); + uint32_t *payload_len_native = (uint32_t *)wasm_runtime_addr_app_to_native(module_inst, payload_len_offset); + + if (!type_native || !id_native || !port_native || !state_native || !extra_native || !payload_len_native) { + LOG_ERR("Invalid offsets provided"); + return -EINVAL; + } + + ocre_event_t event; + int ret; + + /* Generic event queue implementation for both platforms */ + core_spinlock_key_t key = core_spinlock_lock(&ocre_event_queue_lock); + ret = core_eventq_peek(&ocre_event_queue, &event); + if (ret != 0) { + core_spinlock_unlock(&ocre_event_queue_lock, key); + return -ENOMSG; + } + + if (event.owner != module_inst) { + core_spinlock_unlock(&ocre_event_queue_lock, key); + return -EPERM; + } + + ret = core_eventq_get(&ocre_event_queue, &event); + if (ret != 0) { + core_spinlock_unlock(&ocre_event_queue_lock, key); + return -ENOENT; + } + + // Send event correctly to WASM + switch (event.type) { + case OCRE_RESOURCE_TYPE_TIMER: { + LOG_DBG("Retrieved Timer event timer_id=%u, owner=%p", event.data.timer_event.timer_id, + (void *)event.owner); + *type_native = event.type; + *id_native = event.data.timer_event.timer_id; + *port_native = 0; + *state_native = 0; + *extra_native = 0; + *payload_len_native = 0; + break; + } + case OCRE_RESOURCE_TYPE_GPIO: { + LOG_DBG("Retrieved Gpio event pin_id=%u, port=%u, state=%u, owner=%p", + event.data.gpio_event.pin_id, event.data.gpio_event.port, event.data.gpio_event.state, + (void *)event.owner); + *type_native = event.type; + *id_native = event.data.gpio_event.pin_id; + *port_native = event.data.gpio_event.port; + *state_native = event.data.gpio_event.state; + *extra_native = 0; + *payload_len_native = 0; + break; + } + case OCRE_RESOURCE_TYPE_SENSOR: { + // Not used as we don't use callbacks in sensor API yet + break; + } + case OCRE_RESOURCE_TYPE_MESSAGING: { + LOG_DBG("Retrieved Messaging event: message_id=%u, topic=%s, topic_offset=%u, content_type=%s, " + "content_type_offset=%u, payload_len=%d, owner=%p", + event.data.messaging_event.message_id, event.data.messaging_event.topic, + event.data.messaging_event.topic_offset, event.data.messaging_event.content_type, + event.data.messaging_event.content_type_offset, event.data.messaging_event.payload_len, + (void *)event.owner); + *type_native = event.type; + *id_native = event.data.messaging_event.message_id; + *port_native = event.data.messaging_event.topic_offset; + *state_native = event.data.messaging_event.content_type_offset; + *extra_native = event.data.messaging_event.payload_offset; + *payload_len_native = event.data.messaging_event.payload_len; + break; + } + /* + ================================= + Place to add more resource types + ================================= + */ + default: { + core_spinlock_unlock(&ocre_event_queue_lock, key); + LOG_ERR("Invalid event type: %u", event.type); + return -EINVAL; + } + } + core_spinlock_unlock(&ocre_event_queue_lock, key); + return 0; } -int ocre_common_init(void) { - static bool initialized = false; - if (initialized) { - LOG_INF("Common system already initialized"); - return 0; - } - - core_mutex_init(®istry_mutex); - core_slist_init(&module_registry); - - core_eventq_init(&ocre_event_queue, sizeof(ocre_event_t), SIZE_OCRE_EVENT_BUFFER); - - /* Purge any stale events from queue */ - ocre_event_t dummy; - while (core_eventq_get(&ocre_event_queue, &dummy) == 0) { - LOG_INF("Purged stale event from queue"); - } - - /* Temporary platform-specific initialization */ +int ocre_common_init(void) +{ + static bool initialized = false; + if (initialized) { + LOG_INF("Common system already initialized"); + return 0; + } + + core_mutex_init(®istry_mutex); + core_slist_init(&module_registry); + + core_eventq_init(&ocre_event_queue, sizeof(ocre_event_t), SIZE_OCRE_EVENT_BUFFER); + + /* Purge any stale events from queue */ + ocre_event_t dummy; + while (core_eventq_get(&ocre_event_queue, &dummy) == 0) { + LOG_INF("Purged stale event from queue"); + } + + /* Temporary platform-specific initialization */ #ifdef __ZEPHYR__ - /* No additional Zephyr-specific initialization needed */ + /* No additional Zephyr-specific initialization needed */ #else /* POSIX */ - pthread_mutex_init(&ocre_event_queue_lock.mutex, NULL); + pthread_mutex_init(&ocre_event_queue_lock.mutex, NULL); #endif - ocre_event_queue_initialized = true; + ocre_event_queue_initialized = true; #if EVENT_THREAD_POOL_SIZE > 0 - LOG_INF("ocre_event_queue initialized at %p, size=%d", (void *)&ocre_event_queue, sizeof(ocre_event_t)); - for (int i = 0; i < EVENT_THREAD_POOL_SIZE; i++) { - event_args[i].index = i; - char thread_name[16]; - snprintf(thread_name, sizeof(thread_name), "event_thread_%d", i); - int ret = core_thread_create(&event_threads[i], event_thread_fn, &event_args[i], thread_name, - EVENT_THREAD_STACK_SIZE, 5); - if (ret != 0) { - LOG_ERR("Failed to create thread for event %d", i); - return -1; - } - LOG_INF("Started event thread %s", thread_name); - } + LOG_INF("ocre_event_queue initialized at %p, size=%d", (void *)&ocre_event_queue, sizeof(ocre_event_t)); + for (int i = 0; i < EVENT_THREAD_POOL_SIZE; i++) { + event_args[i].index = i; + char thread_name[16]; + snprintf(thread_name, sizeof(thread_name), "event_thread_%d", i); + int ret = core_thread_create(&event_threads[i], event_thread_fn, &event_args[i], thread_name, + EVENT_THREAD_STACK_SIZE, 5); + if (ret != 0) { + LOG_ERR("Failed to create thread for event %d", i); + return -1; + } + LOG_INF("Started event thread %s", thread_name); + } #endif - initialized = true; - common_initialized = true; - - LOG_INF("OCRE common initialized successfully"); - return 0; + initialized = true; + common_initialized = true; + + LOG_INF("OCRE common initialized successfully"); + return 0; } -void ocre_common_shutdown(void) { +void ocre_common_shutdown(void) +{ #if EVENT_THREAD_POOL_SIZE > 0 - event_threads_exit = true; - for (int i = EVENT_THREAD_POOL_SIZE; i > 0; i--) { - event_args[i].index = i; - char thread_name[16]; - snprintf(thread_name, sizeof(thread_name), "event_thread_%d", i); - core_thread_destroy(&event_threads[i]); - } + event_threads_exit = true; + for (int i = EVENT_THREAD_POOL_SIZE; i > 0; i--) { + event_args[i].index = i; + char thread_name[16]; + snprintf(thread_name, sizeof(thread_name), "event_thread_%d", i); + core_thread_destroy(&event_threads[i]); + } #endif - common_initialized = false; - LOG_INF("OCRE common shutdown successfully"); + common_initialized = false; + LOG_INF("OCRE common shutdown successfully"); } -int ocre_register_cleanup_handler(ocre_resource_type_t type, ocre_cleanup_handler_t handler) { - if (type >= OCRE_RESOURCE_TYPE_COUNT) { - LOG_ERR("Invalid resource type: %d", type); - return -EINVAL; - } - cleanup_handlers[type] = (struct cleanup_handler){type, handler}; - LOG_INF("Registered cleanup handler for type %d", type); - return 0; +int ocre_register_cleanup_handler(ocre_resource_type_t type, ocre_cleanup_handler_t handler) +{ + if (type >= OCRE_RESOURCE_TYPE_COUNT) { + LOG_ERR("Invalid resource type: %d", type); + return -EINVAL; + } + cleanup_handlers[type] = (struct cleanup_handler){type, handler}; + LOG_INF("Registered cleanup handler for type %d", type); + return 0; } -int ocre_register_module(wasm_module_inst_t module_inst) { - if (!module_inst) { - LOG_ERR("Null module instance"); - return -EINVAL; - } - module_node_t *node = core_malloc(sizeof(module_node_t)); - if (!node) { - LOG_ERR("Failed to allocate module node"); - return -ENOMEM; - } - node->ctx.inst = module_inst; - node->ctx.exec_env = wasm_runtime_create_exec_env(module_inst, OCRE_WASM_STACK_SIZE); - if (!node->ctx.exec_env) { - LOG_ERR("Failed to create exec env for module %p", (void *)module_inst); - core_free(node); - return -ENOMEM; - } - node->ctx.in_use = true; - node->ctx.last_activity = core_uptime_get(); - memset(node->ctx.resource_count, 0, sizeof(node->ctx.resource_count)); - memset(node->ctx.dispatchers, 0, sizeof(node->ctx.dispatchers)); - - core_mutex_lock(®istry_mutex); - core_slist_append(&module_registry, &node->node); - core_mutex_unlock(®istry_mutex); - - LOG_INF("Module registered: %p", (void *)module_inst); - return 0; +int ocre_register_module(wasm_module_inst_t module_inst) +{ + if (!module_inst) { + LOG_ERR("Null module instance"); + return -EINVAL; + } + module_node_t *node = core_malloc(sizeof(module_node_t)); + if (!node) { + LOG_ERR("Failed to allocate module node"); + return -ENOMEM; + } + node->ctx.inst = module_inst; + node->ctx.exec_env = wasm_runtime_create_exec_env(module_inst, OCRE_WASM_STACK_SIZE); + if (!node->ctx.exec_env) { + LOG_ERR("Failed to create exec env for module %p", (void *)module_inst); + core_free(node); + return -ENOMEM; + } + node->ctx.in_use = true; + node->ctx.last_activity = core_uptime_get(); + memset(node->ctx.resource_count, 0, sizeof(node->ctx.resource_count)); + memset(node->ctx.dispatchers, 0, sizeof(node->ctx.dispatchers)); + + core_mutex_lock(®istry_mutex); + core_slist_append(&module_registry, &node->node); + core_mutex_unlock(®istry_mutex); + + LOG_INF("Module registered: %p", (void *)module_inst); + return 0; } -void ocre_unregister_module(wasm_module_inst_t module_inst) { - if (!module_inst) { - LOG_ERR("Null module instance"); - return; - } - - core_mutex_lock(®istry_mutex); - module_node_t *node, *tmp; - module_node_t *prev = NULL; - CORE_SLIST_FOR_EACH_CONTAINER_SAFE(&module_registry, node, tmp, node) { - if (node->ctx.inst == module_inst) { - ocre_cleanup_module_resources(module_inst); - if (node->ctx.exec_env) { - wasm_runtime_destroy_exec_env(node->ctx.exec_env); - } - core_slist_remove(&module_registry, prev ? &prev->node : NULL, &node->node); - core_free(node); - LOG_INF("Module unregistered: %p", (void *)module_inst); - break; - } - prev = node; - } - core_mutex_unlock(®istry_mutex); +void ocre_unregister_module(wasm_module_inst_t module_inst) +{ + if (!module_inst) { + LOG_ERR("Null module instance"); + return; + } + + core_mutex_lock(®istry_mutex); + module_node_t *node, *tmp; + module_node_t *prev = NULL; + CORE_SLIST_FOR_EACH_CONTAINER_SAFE(&module_registry, node, tmp, node) + { + if (node->ctx.inst == module_inst) { + ocre_cleanup_module_resources(module_inst); + if (node->ctx.exec_env) { + wasm_runtime_destroy_exec_env(node->ctx.exec_env); + } + core_slist_remove(&module_registry, prev ? &prev->node : NULL, &node->node); + core_free(node); + LOG_INF("Module unregistered: %p", (void *)module_inst); + break; + } + prev = node; + } + core_mutex_unlock(®istry_mutex); } -ocre_module_context_t *ocre_get_module_context(wasm_module_inst_t module_inst) { - if (!module_inst) { - LOG_ERR("Null module instance"); - return NULL; - } - core_mutex_lock(®istry_mutex); - for (core_snode_t *current = module_registry.head; current != NULL; current = current->next) { - module_node_t *node = (module_node_t *)((char *)current - offsetof(module_node_t, node)); - if (node->ctx.inst == module_inst) { - node->ctx.last_activity = core_uptime_get(); - core_mutex_unlock(®istry_mutex); - return &node->ctx; - } - } - core_mutex_unlock(®istry_mutex); - LOG_ERR("Module context not found for %p", (void *)module_inst); - return NULL; +ocre_module_context_t *ocre_get_module_context(wasm_module_inst_t module_inst) +{ + if (!module_inst) { + LOG_ERR("Null module instance"); + return NULL; + } + core_mutex_lock(®istry_mutex); + for (core_snode_t *current = module_registry.head; current != NULL; current = current->next) { + module_node_t *node = (module_node_t *)((char *)current - offsetof(module_node_t, node)); + if (node->ctx.inst == module_inst) { + node->ctx.last_activity = core_uptime_get(); + core_mutex_unlock(®istry_mutex); + return &node->ctx; + } + } + core_mutex_unlock(®istry_mutex); + LOG_ERR("Module context not found for %p", (void *)module_inst); + return NULL; } -int ocre_register_dispatcher(wasm_exec_env_t exec_env, ocre_resource_type_t type, const char *function_name) { - if (!exec_env || !function_name || type >= OCRE_RESOURCE_TYPE_COUNT) { - LOG_ERR("Invalid dispatcher params: exec_env=%p, type=%d, func=%s", (void *)exec_env, type, - function_name ? function_name : "null"); - return -EINVAL; - } - - wasm_module_inst_t module_inst = current_module_tls ? *current_module_tls : wasm_runtime_get_module_inst(exec_env); - - if (!module_inst) { - LOG_ERR("No module instance for event type %d", type); - return -EINVAL; - } - ocre_module_context_t *ctx = ocre_get_module_context(module_inst); - if (!ctx) { - LOG_ERR("Module context not found for %p", (void *)module_inst); - return -EINVAL; - } - LOG_DBG("Attempting to lookup function '%s' in module %p", function_name, (void *)module_inst); - wasm_function_inst_t func = wasm_runtime_lookup_function(module_inst, function_name); - if (!func) { - LOG_ERR("Function %s not found in module %p", function_name, (void *)module_inst); - return -EINVAL; - } - core_mutex_lock(®istry_mutex); - ctx->dispatchers[type] = func; - core_mutex_unlock(®istry_mutex); - LOG_INF("Registered dispatcher for type %d: %s", type, function_name); - return 0; +int ocre_register_dispatcher(wasm_exec_env_t exec_env, ocre_resource_type_t type, const char *function_name) +{ + if (!exec_env || !function_name || type >= OCRE_RESOURCE_TYPE_COUNT) { + LOG_ERR("Invalid dispatcher params: exec_env=%p, type=%d, func=%s", (void *)exec_env, type, + function_name ? function_name : "null"); + return -EINVAL; + } + + wasm_module_inst_t module_inst = + current_module_tls ? *current_module_tls : wasm_runtime_get_module_inst(exec_env); + + if (!module_inst) { + LOG_ERR("No module instance for event type %d", type); + return -EINVAL; + } + ocre_module_context_t *ctx = ocre_get_module_context(module_inst); + if (!ctx) { + LOG_ERR("Module context not found for %p", (void *)module_inst); + return -EINVAL; + } + LOG_DBG("Attempting to lookup function '%s' in module %p", function_name, (void *)module_inst); + wasm_function_inst_t func = wasm_runtime_lookup_function(module_inst, function_name); + if (!func) { + LOG_ERR("Function %s not found in module %p", function_name, (void *)module_inst); + return -EINVAL; + } + core_mutex_lock(®istry_mutex); + ctx->dispatchers[type] = func; + core_mutex_unlock(®istry_mutex); + LOG_INF("Registered dispatcher for type %d: %s", type, function_name); + return 0; } -uint32_t ocre_get_resource_count(wasm_module_inst_t module_inst, ocre_resource_type_t type) { - ocre_module_context_t *ctx = ocre_get_module_context(module_inst); - return ctx ? ctx->resource_count[type] : 0; +uint32_t ocre_get_resource_count(wasm_module_inst_t module_inst, ocre_resource_type_t type) +{ + ocre_module_context_t *ctx = ocre_get_module_context(module_inst); + return ctx ? ctx->resource_count[type] : 0; } -void ocre_increment_resource_count(wasm_module_inst_t module_inst, ocre_resource_type_t type) { - ocre_module_context_t *ctx = ocre_get_module_context(module_inst); - if (ctx && type < OCRE_RESOURCE_TYPE_COUNT) { - core_mutex_lock(®istry_mutex); - ctx->resource_count[type]++; - core_mutex_unlock(®istry_mutex); - LOG_INF("Incremented resource count: type=%d, count=%d", type, ctx->resource_count[type]); - } +void ocre_increment_resource_count(wasm_module_inst_t module_inst, ocre_resource_type_t type) +{ + ocre_module_context_t *ctx = ocre_get_module_context(module_inst); + if (ctx && type < OCRE_RESOURCE_TYPE_COUNT) { + core_mutex_lock(®istry_mutex); + ctx->resource_count[type]++; + core_mutex_unlock(®istry_mutex); + LOG_INF("Incremented resource count: type=%d, count=%d", type, ctx->resource_count[type]); + } } -void ocre_decrement_resource_count(wasm_module_inst_t module_inst, ocre_resource_type_t type) { - ocre_module_context_t *ctx = ocre_get_module_context(module_inst); - if (ctx && type < OCRE_RESOURCE_TYPE_COUNT && ctx->resource_count[type] > 0) { - core_mutex_lock(®istry_mutex); - ctx->resource_count[type]--; - core_mutex_unlock(®istry_mutex); - LOG_INF("Decremented resource count: type=%d, count=%d", type, ctx->resource_count[type]); - } +void ocre_decrement_resource_count(wasm_module_inst_t module_inst, ocre_resource_type_t type) +{ + ocre_module_context_t *ctx = ocre_get_module_context(module_inst); + if (ctx && type < OCRE_RESOURCE_TYPE_COUNT && ctx->resource_count[type] > 0) { + core_mutex_lock(®istry_mutex); + ctx->resource_count[type]--; + core_mutex_unlock(®istry_mutex); + LOG_INF("Decremented resource count: type=%d, count=%d", type, ctx->resource_count[type]); + } } -void ocre_cleanup_module_resources(wasm_module_inst_t module_inst) { - for (int i = 0; i < OCRE_RESOURCE_TYPE_COUNT; i++) { - if (cleanup_handlers[i].handler) { - cleanup_handlers[i].handler(module_inst); - } - } +void ocre_cleanup_module_resources(wasm_module_inst_t module_inst) +{ + for (int i = 0; i < OCRE_RESOURCE_TYPE_COUNT; i++) { + if (cleanup_handlers[i].handler) { + cleanup_handlers[i].handler(module_inst); + } + } } -wasm_module_inst_t ocre_get_current_module(void) { - return current_module_tls ? *current_module_tls : NULL; +wasm_module_inst_t ocre_get_current_module(void) +{ + return current_module_tls ? *current_module_tls : NULL; } diff --git a/src/ocre/api/ocre_common.h b/src/ocre/api/ocre_common.h index 95be03a9..97d7c5f3 100644 --- a/src/ocre/api/ocre_common.h +++ b/src/ocre/api/ocre_common.h @@ -16,40 +16,39 @@ #define OCRE_EVENT_THREAD_STACK_SIZE 2048 #define OCRE_EVENT_THREAD_PRIORITY 5 -#define OCRE_WASM_STACK_SIZE 16384 -#define EVENT_THREAD_POOL_SIZE 0 +#define OCRE_WASM_STACK_SIZE 16384 +#define EVENT_THREAD_POOL_SIZE 0 extern bool common_initialized; extern bool ocre_event_queue_initialized; extern __thread wasm_module_inst_t *current_module_tls; -extern char *ocre_event_queue_buffer_ptr; // Defined in ocre_common.c +extern char *ocre_event_queue_buffer_ptr; // Defined in ocre_common.c /* External declarations for unified event queue */ -extern core_eventq_t ocre_event_queue; // Defined in ocre_common.c -extern core_spinlock_t ocre_event_queue_lock; // Defined in ocre_common.c - +extern core_eventq_t ocre_event_queue; // Defined in ocre_common.c +extern core_spinlock_t ocre_event_queue_lock; // Defined in ocre_common.c /** * @brief Enumeration of OCRE resource types. */ typedef enum { - OCRE_RESOURCE_TYPE_TIMER, ///< Timer resource - OCRE_RESOURCE_TYPE_GPIO, ///< GPIO resource - OCRE_RESOURCE_TYPE_SENSOR, ///< Sensor resource - OCRE_RESOURCE_TYPE_MESSAGING, ///< Messaging resource - OCRE_RESOURCE_TYPE_COUNT ///< Total number of resource types + OCRE_RESOURCE_TYPE_TIMER, ///< Timer resource + OCRE_RESOURCE_TYPE_GPIO, ///< GPIO resource + OCRE_RESOURCE_TYPE_SENSOR, ///< Sensor resource + OCRE_RESOURCE_TYPE_MESSAGING, ///< Messaging resource + OCRE_RESOURCE_TYPE_COUNT ///< Total number of resource types } ocre_resource_type_t; /** * @brief Structure representing the context of an OCRE module. */ typedef struct { - wasm_module_inst_t inst; ///< WASM module instance - wasm_exec_env_t exec_env; ///< WASM execution environment - bool in_use; ///< Flag indicating if the module is in use - uint32_t last_activity; ///< Timestamp of the last activity - uint32_t resource_count[OCRE_RESOURCE_TYPE_COUNT]; ///< Count of resources per type - wasm_function_inst_t dispatchers[OCRE_RESOURCE_TYPE_COUNT]; ///< Event dispatchers per resource type + wasm_module_inst_t inst; ///< WASM module instance + wasm_exec_env_t exec_env; ///< WASM execution environment + bool in_use; ///< Flag indicating if the module is in use + uint32_t last_activity; ///< Timestamp of the last activity + uint32_t resource_count[OCRE_RESOURCE_TYPE_COUNT]; ///< Count of resources per type + wasm_function_inst_t dispatchers[OCRE_RESOURCE_TYPE_COUNT]; ///< Event dispatchers per resource type } ocre_module_context_t; /** @@ -63,38 +62,38 @@ typedef void (*ocre_cleanup_handler_t)(wasm_module_inst_t module_inst); * @brief Structure representing an OCRE event for dispatching. */ typedef struct { - union { - struct { - uint32_t timer_id; ///< Timer ID - } timer_event; ///< Timer event data - struct { - uint32_t pin_id; ///< GPIO pin ID - uint32_t port; ///< GPIO port - uint32_t state; ///< GPIO state - } gpio_event; ///< GPIO event data - struct { - uint32_t sensor_id; ///< Sensor ID - uint32_t channel; ///< Sensor channel - uint32_t value; ///< Sensor value - } sensor_event; ///< Sensor event data - struct { - uint32_t message_id; ///< Message ID - char *topic; ///< Message topic - uint32_t topic_offset; ///< Message topic offset - char *content_type; ///< Message content type - uint32_t content_type_offset; ///< Message content type offset - void *payload; ///< Message payload - uint32_t payload_offset; ///< Message payload offset - uint32_t payload_len; ///< Payload length - } messaging_event; ///< Messaging event data - /* - ============================= - Place to add more event data - ============================= - */ - } data; ///< Union of event data - wasm_module_inst_t owner; ///< Owner module instance - ocre_resource_type_t type; ///< Type of the event + union { + struct { + uint32_t timer_id; ///< Timer ID + } timer_event; ///< Timer event data + struct { + uint32_t pin_id; ///< GPIO pin ID + uint32_t port; ///< GPIO port + uint32_t state; ///< GPIO state + } gpio_event; ///< GPIO event data + struct { + uint32_t sensor_id; ///< Sensor ID + uint32_t channel; ///< Sensor channel + uint32_t value; ///< Sensor value + } sensor_event; ///< Sensor event data + struct { + uint32_t message_id; ///< Message ID + char *topic; ///< Message topic + uint32_t topic_offset; ///< Message topic offset + char *content_type; ///< Message content type + uint32_t content_type_offset; ///< Message content type offset + void *payload; ///< Message payload + uint32_t payload_offset; ///< Message payload offset + uint32_t payload_len; ///< Payload length + } messaging_event; ///< Messaging event data + /* + ============================= + Place to add more event data + ============================= + */ + } data; ///< Union of event data + wasm_module_inst_t owner; ///< Owner module instance + ocre_resource_type_t type; ///< Type of the event } ocre_event_t; /** @@ -200,7 +199,7 @@ wasm_module_inst_t ocre_get_current_module(void); * @return 0 on success, negative error code on failure. */ int ocre_get_event(wasm_exec_env_t exec_env, uint32_t type_offset, uint32_t id_offset, uint32_t port_offset, - uint32_t state_offset, uint32_t extra_offset, uint32_t payload_len_offset); + uint32_t state_offset, uint32_t extra_offset, uint32_t payload_len_offset); void ocre_common_shutdown(void); diff --git a/src/ocre/component/component.c b/src/ocre/component/component.c index daa6121b..10849e52 100644 --- a/src/ocre/component/component.c +++ b/src/ocre/component/component.c @@ -10,12 +10,14 @@ #include "ocre_core_external.h" #include "component.h" -void ocre_component_init(struct ocre_component *component) { - core_mq_init(&component->msgq, "/ocre_component_msgq", sizeof(struct ocre_message), MSG_QUEUE_DEPTH); +void ocre_component_init(struct ocre_component *component) +{ + core_mq_init(&component->msgq, "/ocre_component_msgq", sizeof(struct ocre_message), MSG_QUEUE_DEPTH); } -int ocre_component_send(struct ocre_component *component, struct ocre_message *msg) { - int ret = core_mq_send(&component->msgq, msg, sizeof(struct ocre_message)); +int ocre_component_send(struct ocre_component *component, struct ocre_message *msg) +{ + int ret = core_mq_send(&component->msgq, msg, sizeof(struct ocre_message)); - return ret; + return ret; } diff --git a/src/ocre/component/component.h b/src/ocre/component/component.h index b6d96e7a..d11f8a18 100644 --- a/src/ocre/component/component.h +++ b/src/ocre/component/component.h @@ -15,12 +15,12 @@ #define MSG_QUEUE_DEPTH 10 #define COMPONENT_SEND_SIMPLE(c, e) \ - struct ocre_message _msg = {.event = e}; \ - ocre_component_send(c, &_msg) + struct ocre_message _msg = {.event = e}; \ + ocre_component_send(c, &_msg) struct ocre_component { - struct ocre_message msg; /*!< Message struct for reading messages into */ - core_mq_t msgq; /*!< Message queue to read from */ + struct ocre_message msg; /*!< Message struct for reading messages into */ + core_mq_t msgq; /*!< Message queue to read from */ }; void ocre_component_init(struct ocre_component *component); diff --git a/src/ocre/components/container_supervisor/cs_main.c b/src/ocre/components/container_supervisor/cs_main.c index 2727572f..85ec7551 100644 --- a/src/ocre/components/container_supervisor/cs_main.c +++ b/src/ocre/components/container_supervisor/cs_main.c @@ -11,38 +11,42 @@ LOG_MODULE_REGISTER(ocre_cs_component, OCRE_LOG_LEVEL); -#define OCRE_CS_THREAD_PRIORITY 0 +#define OCRE_CS_THREAD_PRIORITY 0 static core_thread_t ocre_cs_thread; static int ocre_cs_thread_initialized = 0; -static void ocre_cs_main(void *ctx) { - wasm_runtime_init_thread_env(); - LOG_INF("Container Supervisor started."); - int ret = _ocre_cs_run(ctx); - LOG_ERR("Container Supervisor exited: %d", ret); - wasm_runtime_destroy_thread_env(); +static void ocre_cs_main(void *ctx) +{ + wasm_runtime_init_thread_env(); + LOG_INF("Container Supervisor started."); + int ret = _ocre_cs_run(ctx); + LOG_ERR("Container Supervisor exited: %d", ret); + wasm_runtime_destroy_thread_env(); } // Function to start the thread -void start_ocre_cs_thread(ocre_cs_ctx *ctx) { - if (ocre_cs_thread_initialized) { - LOG_WRN("Container Supervisor thread is already running."); - return; - } - int ret = core_thread_create(&ocre_cs_thread, ocre_cs_main, ctx, "Ocre Container Supervisor", OCRE_CS_THREAD_STACK_SIZE, OCRE_CS_THREAD_PRIORITY); - if (ret != 0) { - LOG_ERR("Failed to create Container Supervisor thread: %d", ret); - return; - } - ocre_cs_thread_initialized = 1; +void start_ocre_cs_thread(ocre_cs_ctx *ctx) +{ + if (ocre_cs_thread_initialized) { + LOG_WRN("Container Supervisor thread is already running."); + return; + } + int ret = core_thread_create(&ocre_cs_thread, ocre_cs_main, ctx, "Ocre Container Supervisor", + OCRE_CS_THREAD_STACK_SIZE, OCRE_CS_THREAD_PRIORITY); + if (ret != 0) { + LOG_ERR("Failed to create Container Supervisor thread: %d", ret); + return; + } + ocre_cs_thread_initialized = 1; } -void destroy_ocre_cs_thread(void) { - if (!ocre_cs_thread_initialized) { - LOG_ERR("Container Supervisor thread is not running.\n"); - return; - } - core_thread_destroy(&ocre_cs_thread); - ocre_cs_thread_initialized = 0; +void destroy_ocre_cs_thread(void) +{ + if (!ocre_cs_thread_initialized) { + LOG_ERR("Container Supervisor thread is not running.\n"); + return; + } + core_thread_destroy(&ocre_cs_thread); + ocre_cs_thread_initialized = 0; } diff --git a/src/ocre/components/container_supervisor/cs_sm.c b/src/ocre/components/container_supervisor/cs_sm.c index 9f2bc585..275d7bf9 100644 --- a/src/ocre/components/container_supervisor/cs_sm.c +++ b/src/ocre/components/container_supervisor/cs_sm.c @@ -20,150 +20,160 @@ struct ocre_component ocre_cs_component; state_machine_t ocre_cs_state_machine; /* State event handlers */ -static void runtime_uninitialized_entry(void *o) { +static void runtime_uninitialized_entry(void *o) +{ #if OCRE_CS_DEBUG_ON - LOG_INF("HELLO runtime_uninitialized_entry"); + LOG_INF("HELLO runtime_uninitialized_entry"); #endif - struct ocre_message event = {.event = EVENT_CS_INITIALIZE}; - ocre_component_send(&ocre_cs_component, &event); + struct ocre_message event = {.event = EVENT_CS_INITIALIZE}; + ocre_component_send(&ocre_cs_component, &event); } -static enum smf_state_result runtime_uninitialized_run(void *o) { +static enum smf_state_result runtime_uninitialized_run(void *o) +{ #if OCRE_CS_DEBUG_ON - LOG_INF("HELLO runtime_uninitialized_run"); + LOG_INF("HELLO runtime_uninitialized_run"); #endif - struct ocre_message *msg = SM_GET_EVENT(o); + struct ocre_message *msg = SM_GET_EVENT(o); - switch (msg->event) { - case EVENT_CS_INITIALIZE: + switch (msg->event) { + case EVENT_CS_INITIALIZE: #if OCRE_CS_DEBUG_ON - LOG_INF("Transitioning from state STATE_RUNTIME_UNINITIALIZED_RUN to state STATE_RUNTIME_RUNNING"); + LOG_INF("Transitioning from state STATE_RUNTIME_UNINITIALIZED_RUN to state " + "STATE_RUNTIME_RUNNING"); #endif - sm_transition(&ocre_cs_state_machine, STATE_RUNTIME_RUNNING); - break; - default: - break; - } - SM_MARK_EVENT_HANDLED(o); - return SMF_EVENT_HANDLED; + sm_transition(&ocre_cs_state_machine, STATE_RUNTIME_RUNNING); + break; + default: + break; + } + SM_MARK_EVENT_HANDLED(o); + return SMF_EVENT_HANDLED; } -static void runtime_running_entry(void *o) { +static void runtime_running_entry(void *o) +{ #if OCRE_CS_DEBUG_ON - LOG_INF("HELLO runtime_running_entry"); + LOG_INF("HELLO runtime_running_entry"); #endif } -static enum smf_state_result runtime_running_run(void *o) { +static enum smf_state_result runtime_running_run(void *o) +{ #if OCRE_CS_DEBUG_ON - LOG_INF("HELLO runtime_running_run"); + LOG_INF("HELLO runtime_running_run"); #endif - struct ocre_message *msg = SM_GET_EVENT(o); - ocre_cs_ctx *ctx = SM_GET_CUSTOM_CTX(o); - ocre_container_runtime_cb callback = NULL; - switch (msg->event) { - case EVENT_CREATE_CONTAINER: { - LOG_INF("EVENT_CREATE_CONTAINER"); - - if (msg->containerId < 0 || msg->containerId >= CONFIG_MAX_CONTAINERS) { - LOG_ERR("Invalid container ID: %d", msg->containerId); - break; - } - - if (CS_create_container(&ctx->containers[msg->containerId]) == CONTAINER_STATUS_CREATED) { - LOG_INF("Created container in slot:%d", msg->containerId); - } else { - LOG_ERR("Failed to create container in slot:%d", msg->containerId); - } - break; - } - case EVENT_RUN_CONTAINER: { - LOG_INF("EVENT_RUN_CONTAINER"); - - if (msg->containerId < 0 || msg->containerId >= CONFIG_MAX_CONTAINERS) { - LOG_ERR("Invalid container ID: %d", msg->containerId); - break; - } - - if (CS_run_container(&ctx->containers[msg->containerId]) == CONTAINER_STATUS_RUNNING) { - LOG_INF("Started container in slot:%d", msg->containerId); - } else { - LOG_ERR("Failed to run container in slot:%d", msg->containerId); - } - break; - } - case EVENT_STOP_CONTAINER: { - LOG_INF("EVENT_STOP_CONTAINER"); - - if (msg->containerId < 0 || msg->containerId >= CONFIG_MAX_CONTAINERS) { - LOG_ERR("Invalid container ID: %d", msg->containerId); - break; - } - - if (CS_stop_container(&ctx->containers[msg->containerId], callback) == CONTAINER_STATUS_STOPPED) { - LOG_INF("Stopped container in slot:%d", msg->containerId); - } else { - LOG_ERR("Failed to stop container in slot:%d", msg->containerId); - } - break; - } - case EVENT_DESTROY_CONTAINER: { - LOG_INF("EVENT_DESTROY_CONTAINER"); - - if (msg->containerId < 0 || msg->containerId >= CONFIG_MAX_CONTAINERS) { - LOG_ERR("Invalid container ID: %d", msg->containerId); - break; - } - - if (CS_destroy_container(&ctx->containers[msg->containerId], callback) == CONTAINER_STATUS_DESTROYED) { - LOG_INF("Destroyed container in slot:%d", msg->containerId); - } else { - LOG_ERR("Failed to destroy container in slot:%d", msg->containerId); - } - break; - } - case EVENT_RESTART_CONTAINER: { - LOG_INF("EVENT_RESTART_CONTAINER"); - if (msg->containerId < 0 || msg->containerId >= CONFIG_MAX_CONTAINERS) { - LOG_ERR("Invalid container ID: %d", msg->containerId); - break; - } - - if (CS_restart_container(&ctx->containers[msg->containerId], callback) == CONTAINER_STATUS_RUNNING) { - LOG_INF("Container in slot:%d restarted successfully", msg->containerId); - } else { - LOG_ERR("Failed to restart container in slot:%d", msg->containerId); - } - break; - } - case EVENT_CS_DESTROY: - LOG_INF("EVENT_CS_DESTROY"); - sm_transition(&ocre_cs_state_machine, STATE_RUNTIME_UNINITIALIZED); - break; - default: - break; - } - - SM_MARK_EVENT_HANDLED(o); - return SMF_EVENT_HANDLED; + struct ocre_message *msg = SM_GET_EVENT(o); + ocre_cs_ctx *ctx = SM_GET_CUSTOM_CTX(o); + ocre_container_runtime_cb callback = NULL; + switch (msg->event) { + case EVENT_CREATE_CONTAINER: { + LOG_INF("EVENT_CREATE_CONTAINER"); + + if (msg->containerId < 0 || msg->containerId >= CONFIG_MAX_CONTAINERS) { + LOG_ERR("Invalid container ID: %d", msg->containerId); + break; + } + + if (CS_create_container(&ctx->containers[msg->containerId]) == CONTAINER_STATUS_CREATED) { + LOG_INF("Created container in slot:%d", msg->containerId); + } else { + LOG_ERR("Failed to create container in slot:%d", msg->containerId); + } + break; + } + case EVENT_RUN_CONTAINER: { + LOG_INF("EVENT_RUN_CONTAINER"); + + if (msg->containerId < 0 || msg->containerId >= CONFIG_MAX_CONTAINERS) { + LOG_ERR("Invalid container ID: %d", msg->containerId); + break; + } + + if (CS_run_container(&ctx->containers[msg->containerId]) == CONTAINER_STATUS_RUNNING) { + LOG_INF("Started container in slot:%d", msg->containerId); + } else { + LOG_ERR("Failed to run container in slot:%d", msg->containerId); + } + break; + } + case EVENT_STOP_CONTAINER: { + LOG_INF("EVENT_STOP_CONTAINER"); + + if (msg->containerId < 0 || msg->containerId >= CONFIG_MAX_CONTAINERS) { + LOG_ERR("Invalid container ID: %d", msg->containerId); + break; + } + + if (CS_stop_container(&ctx->containers[msg->containerId], callback) == + CONTAINER_STATUS_STOPPED) { + LOG_INF("Stopped container in slot:%d", msg->containerId); + } else { + LOG_ERR("Failed to stop container in slot:%d", msg->containerId); + } + break; + } + case EVENT_DESTROY_CONTAINER: { + LOG_INF("EVENT_DESTROY_CONTAINER"); + + if (msg->containerId < 0 || msg->containerId >= CONFIG_MAX_CONTAINERS) { + LOG_ERR("Invalid container ID: %d", msg->containerId); + break; + } + + if (CS_destroy_container(&ctx->containers[msg->containerId], callback) == + CONTAINER_STATUS_DESTROYED) { + LOG_INF("Destroyed container in slot:%d", msg->containerId); + } else { + LOG_ERR("Failed to destroy container in slot:%d", msg->containerId); + } + break; + } + case EVENT_RESTART_CONTAINER: { + LOG_INF("EVENT_RESTART_CONTAINER"); + if (msg->containerId < 0 || msg->containerId >= CONFIG_MAX_CONTAINERS) { + LOG_ERR("Invalid container ID: %d", msg->containerId); + break; + } + + if (CS_restart_container(&ctx->containers[msg->containerId], callback) == + CONTAINER_STATUS_RUNNING) { + LOG_INF("Container in slot:%d restarted successfully", msg->containerId); + } else { + LOG_ERR("Failed to restart container in slot:%d", msg->containerId); + } + break; + } + case EVENT_CS_DESTROY: + LOG_INF("EVENT_CS_DESTROY"); + sm_transition(&ocre_cs_state_machine, STATE_RUNTIME_UNINITIALIZED); + break; + default: + break; + } + + SM_MARK_EVENT_HANDLED(o); + return SMF_EVENT_HANDLED; } -static enum smf_state_result runtime_error_run(void *o) { +static enum smf_state_result runtime_error_run(void *o) +{ #if OCRE_CS_DEBUG_ON - LOG_INF("HELLO runtime_error_run"); + LOG_INF("HELLO runtime_error_run"); #endif - return SMF_EVENT_HANDLED; + return SMF_EVENT_HANDLED; } static const struct smf_state hsm[] = { - [STATE_RUNTIME_UNINITIALIZED] = - SMF_CREATE_STATE(runtime_uninitialized_entry, runtime_uninitialized_run, NULL, NULL, NULL), - [STATE_RUNTIME_RUNNING] = SMF_CREATE_STATE(runtime_running_entry, runtime_running_run, NULL, NULL, NULL), - [STATE_RUNTIME_ERROR] = SMF_CREATE_STATE(NULL, runtime_error_run, NULL, NULL, NULL)}; + [STATE_RUNTIME_UNINITIALIZED] = + SMF_CREATE_STATE(runtime_uninitialized_entry, runtime_uninitialized_run, NULL, NULL, NULL), + [STATE_RUNTIME_RUNNING] = SMF_CREATE_STATE(runtime_running_entry, runtime_running_run, NULL, NULL, NULL), + [STATE_RUNTIME_ERROR] = SMF_CREATE_STATE(NULL, runtime_error_run, NULL, NULL, NULL)}; // Entry point for running the state machine -int _ocre_cs_run(ocre_cs_ctx *ctx) { - ocre_component_init(&ocre_cs_component); - sm_init(&ocre_cs_state_machine, &ocre_cs_component.msgq, &ocre_cs_component.msg, ctx, hsm); - return sm_run(&ocre_cs_state_machine, STATE_RUNTIME_UNINITIALIZED); +int _ocre_cs_run(ocre_cs_ctx *ctx) +{ + ocre_component_init(&ocre_cs_component); + sm_init(&ocre_cs_state_machine, &ocre_cs_component.msgq, &ocre_cs_component.msg, ctx, hsm); + return sm_run(&ocre_cs_state_machine, STATE_RUNTIME_UNINITIALIZED); } diff --git a/src/ocre/components/container_supervisor/cs_sm.h b/src/ocre/components/container_supervisor/cs_sm.h index 4ba02bc3..3a323949 100644 --- a/src/ocre/components/container_supervisor/cs_sm.h +++ b/src/ocre/components/container_supervisor/cs_sm.h @@ -18,28 +18,28 @@ extern struct ocre_component ocre_cs_component; extern state_machine_t ocre_cs_state_machine; // TODO This needs to get encapsulated into the - // sm. it's only here so components can operate - // timers. timers need to be encapsulated. + // sm. it's only here so components can operate + // timers. timers need to be encapsulated. enum CONTAINER_RUNTIME_STATE { - STATE_RUNTIME_UNINITIALIZED, - STATE_RUNTIME_RUNNING, - STATE_RUNTIME_ERROR + STATE_RUNTIME_UNINITIALIZED, + STATE_RUNTIME_RUNNING, + STATE_RUNTIME_ERROR }; enum OCRE_CS_EVENT { - // CS Events - EVENT_CS_INITIALIZE, - EVENT_CS_DESTROY, - EVENT_CS_ERROR, - - // Container related events - EVENT_CREATE_CONTAINER, - EVENT_RUN_CONTAINER, - EVENT_STOP_CONTAINER, - EVENT_DESTROY_CONTAINER, - EVENT_RESTART_CONTAINER, - EVENT_ERROR + // CS Events + EVENT_CS_INITIALIZE, + EVENT_CS_DESTROY, + EVENT_CS_ERROR, + + // Container related events + EVENT_CREATE_CONTAINER, + EVENT_RUN_CONTAINER, + EVENT_STOP_CONTAINER, + EVENT_DESTROY_CONTAINER, + EVENT_RESTART_CONTAINER, + EVENT_ERROR }; void start_ocre_cs_thread(ocre_cs_ctx *ctx); diff --git a/src/ocre/components/container_supervisor/cs_sm_impl.c b/src/ocre/components/container_supervisor/cs_sm_impl.c index c86a4fdc..c462c975 100644 --- a/src/ocre/components/container_supervisor/cs_sm_impl.c +++ b/src/ocre/components/container_supervisor/cs_sm_impl.c @@ -17,11 +17,10 @@ #include "ocre_messaging/ocre_messaging.h" #endif #if defined(CONFIG_OCRE_TIMER) || defined(CONFIG_OCRE_GPIO) || defined(CONFIG_OCRE_SENSORS) || \ - defined(CONFIG_OCRE_CONTAINER_MESSAGING) + defined(CONFIG_OCRE_CONTAINER_MESSAGING) #include "api/ocre_common.h" #endif - #ifdef CONFIG_OCRE_SHELL #include "ocre/shell/ocre_shell.h" #endif @@ -34,16 +33,12 @@ LOG_MODULE_DECLARE(ocre_cs_component, OCRE_LOG_LEVEL); #include "cs_sm.h" #include "cs_sm_impl.h" -// External RAM support for WAMR heap on boards that have it +#include "ocre_psram.h" + +// WAMR heap buffer - uses PSRAM when available #if defined(CONFIG_MEMC) - #if defined(CONFIG_BOARD_ARDUINO_PORTENTA_H7) - __attribute__((section("SDRAM1"), aligned(32))) - #elif defined(CONFIG_BOARD_B_U585I_IOT02A) - __attribute__((section(".stm32_psram"), aligned(32))) - #elif defined(CONFIG_BOARD_MIMXRT1064_EVK) - __attribute__((section("SDRAM"), aligned(32))) - #endif // defined () -#endif // defined(CONFIG_MEMC) +PSRAM_SECTION_ATTR +#endif static char wamr_heap_buf[CONFIG_OCRE_WAMR_HEAP_BUFFER_SIZE] = {0}; // Thread pool for container execution @@ -55,495 +50,592 @@ static core_mutex_t container_mutex; // Arguments for container threads struct container_thread_args { - ocre_container_t *container; + ocre_container_t *container; }; #ifdef CONFIG_OCRE_MEMORY_CHECK_ENABLED -static size_t ocre_get_available_memory(void) { +static size_t ocre_get_available_memory(void) +{ #ifdef CONFIG_HEAP_MEM_POOL_SIZE - struct k_heap_stats stats; - k_heap_sys_get_stats(&stats); - return stats.free_bytes; + struct k_heap_stats stats; + k_heap_sys_get_stats(&stats); + return stats.free_bytes; #else - extern char *z_malloc_mem_pool_area_start; - extern char *z_malloc_mem_pool_area_end; - extern struct sys_mem_pool_base z_malloc_mem_pool; + extern char *z_malloc_mem_pool_area_start; + extern char *z_malloc_mem_pool_area_end; + extern struct sys_mem_pool_base z_malloc_mem_pool; - size_t total_size = z_malloc_mem_pool_area_end - z_malloc_mem_pool_area_start; - size_t used_size = sys_mem_pool_get_used_size(&z_malloc_mem_pool); - return total_size - used_size; + size_t total_size = z_malloc_mem_pool_area_end - z_malloc_mem_pool_area_start; + size_t used_size = sys_mem_pool_get_used_size(&z_malloc_mem_pool); + return total_size - used_size; #endif } #endif -static bool validate_container_memory(ocre_container_t *container) { +#ifdef CONFIG_OCRE_SHARED_HEAP +// Shared heap for memory-mapped access +wasm_shared_heap_t _shared_heap = NULL; +#ifdef CONFIG_OCRE_SHARED_HEAP_BUF_VIRTUAL +uint8 preallocated_buf[CONFIG_OCRE_SHARED_HEAP_BUF_SIZE]; +#endif +#endif + +static bool validate_container_memory(ocre_container_t *container) +{ #ifdef CONFIG_OCRE_MEMORY_CHECK_ENABLED - size_t requested_heap = container->ocre_container_data.heap_size; - size_t requested_stack = container->ocre_container_data.stack_size; - - if (requested_heap == 0 || requested_heap > CONFIG_OCRE_CONTAINER_DEFAULT_HEAP_SIZE) { - LOG_ERR("Invalid heap size requested: %zu bytes", requested_heap); - return false; - } - - if (requested_stack == 0 || requested_stack > CONFIG_OCRE_CONTAINER_DEFAULT_STACK_SIZE) { - LOG_ERR("Invalid stack size requested: %zu bytes", requested_stack); - return false; - } - - size_t available_memory = ocre_get_available_memory(); - size_t required_memory = requested_heap + requested_stack + sizeof(WASMExecEnv); - - if (available_memory < required_memory) { - LOG_ERR("Insufficient memory for container %d: required %zu bytes, available %zu bytes", - container->container_ID, required_memory, available_memory); - return false; - } - LOG_INF("Memory check passed: %zu bytes required, %zu bytes available", required_memory, available_memory); - - container->ocre_runtime_arguments.stack_size = requested_stack; - container->ocre_runtime_arguments.heap_size = requested_heap; + size_t requested_heap = container->ocre_container_data.heap_size; + size_t requested_stack = container->ocre_container_data.stack_size; + + if (requested_heap == 0 || requested_heap > CONFIG_OCRE_CONTAINER_DEFAULT_HEAP_SIZE) { + LOG_ERR("Invalid heap size requested: %zu bytes", requested_heap); + return false; + } + + if (requested_stack == 0 || requested_stack > CONFIG_OCRE_CONTAINER_DEFAULT_STACK_SIZE) { + LOG_ERR("Invalid stack size requested: %zu bytes", requested_stack); + return false; + } + + size_t available_memory = ocre_get_available_memory(); + size_t required_memory = requested_heap + requested_stack + sizeof(WASMExecEnv); + + if (available_memory < required_memory) { + LOG_ERR("Insufficient memory for container %d: required %zu bytes, available %zu bytes", + container->container_ID, required_memory, available_memory); + return false; + } + LOG_INF("Memory check passed: %zu bytes required, %zu bytes available", required_memory, available_memory); + + container->ocre_runtime_arguments.stack_size = requested_stack; + container->ocre_runtime_arguments.heap_size = requested_heap; #else - container->ocre_runtime_arguments.stack_size = CONFIG_OCRE_CONTAINER_DEFAULT_STACK_SIZE; - container->ocre_runtime_arguments.heap_size = CONFIG_OCRE_CONTAINER_DEFAULT_HEAP_SIZE; + container->ocre_runtime_arguments.stack_size = CONFIG_OCRE_CONTAINER_DEFAULT_STACK_SIZE; + container->ocre_runtime_arguments.heap_size = CONFIG_OCRE_CONTAINER_DEFAULT_HEAP_SIZE; #endif - return true; + return true; } // Container thread entry function -static void container_thread_entry(void *args) { - struct container_thread_args *container_args = args; - ocre_container_t *container = container_args->container; - wasm_module_inst_t module_inst = container->ocre_runtime_arguments.module_inst; +static void container_thread_entry(void *args) +{ + struct container_thread_args *container_args = args; + ocre_container_t *container = container_args->container; + wasm_module_inst_t module_inst = container->ocre_runtime_arguments.module_inst; - // Initialize WASM runtime thread environment - wasm_runtime_init_thread_env(); + // Initialize WASM runtime thread environment + wasm_runtime_init_thread_env(); - LOG_INF("Container thread %d started", container->container_ID); + LOG_INF("Container thread %d started", container->container_ID); #if defined(CONFIG_OCRE_TIMER) || defined(CONFIG_OCRE_GPIO) || defined(CONFIG_OCRE_SENSORS) || \ - defined(CONFIG_OCRE_CONTAINER_MESSAGING) - // Set TLS for the container's WASM module - current_module_tls = &module_inst; -#endif - // Run the WASM main function - bool success = wasm_application_execute_main(module_inst, 0, NULL); - // Update container status - if (container->container_runtime_status != CONTAINER_STATUS_STOPPED) - container->container_runtime_status = success ? CONTAINER_STATUS_STOPPED : CONTAINER_STATUS_ERROR; - // Cleanup sequence - core_mutex_lock(&container->lock); - { - // Cleanup subsystems + defined(CONFIG_OCRE_CONTAINER_MESSAGING) + // Set TLS for the container's WASM module + current_module_tls = &module_inst; +#endif + + // Run the WASM main function with exception handling + bool success = false; + const char *exception = NULL; + + // Clear any previous exceptions + wasm_runtime_clear_exception(module_inst); + + // Execute main function + success = wasm_application_execute_main(module_inst, 0, NULL); + + // Check for exceptions + exception = wasm_runtime_get_exception(module_inst); + if (exception) { + LOG_ERR("Container %d exception: %s", container->container_ID, exception); + success = false; + } + // Update container status + if (container->container_runtime_status != CONTAINER_STATUS_STOPPED) + container->container_runtime_status = success ? CONTAINER_STATUS_STOPPED : CONTAINER_STATUS_ERROR; + // Cleanup sequence + core_mutex_lock(&container->lock); + { + // Cleanup subsystems #ifdef CONFIG_OCRE_TIMER - ocre_timer_cleanup_container(module_inst); + ocre_timer_cleanup_container(module_inst); #endif #ifdef CONFIG_OCRE_GPIO - ocre_gpio_cleanup_container(module_inst); + ocre_gpio_cleanup_container(module_inst); #endif #ifdef CONFIG_OCRE_CONTAINER_MESSAGING - ocre_messaging_cleanup_container(module_inst); + ocre_messaging_cleanup_container(module_inst); #endif - // Clear thread tracking - container_thread_active[container->container_ID] = false; + // Clear thread tracking + container_thread_active[container->container_ID] = false; #if defined(CONFIG_OCRE_TIMER) || defined(CONFIG_OCRE_GPIO) || defined(CONFIG_OCRE_SENSORS) || \ - defined(CONFIG_OCRE_CONTAINER_MESSAGING) - // Clear TLS - current_module_tls = NULL; + defined(CONFIG_OCRE_CONTAINER_MESSAGING) + // Clear TLS + current_module_tls = NULL; #endif - - } - core_mutex_unlock(&container->lock); - - LOG_INF("Container thread %d exited cleanly", container->container_ID); - - // Clean up WASM runtime thread environment - wasm_runtime_destroy_thread_env(); - core_free(args); // Free the dynamically allocated args + } + core_mutex_unlock(&container->lock); + + if (success) { + LOG_INF("Container %d completed successfully", container->container_ID); + } else { + LOG_ERR("Container %d failed: %s", container->container_ID, exception ? exception : "unknown error"); + } + + // Clean up WASM runtime thread environment + wasm_runtime_destroy_thread_env(); + core_free(args); // Free the dynamically allocated args } -static int get_available_thread(void) { - for (int i = 0; i < CONTAINER_THREAD_POOL_SIZE; i++) { - if (!container_thread_active[i]) { - return i; - } - } - return -1; +static int get_available_thread(void) +{ + for (int i = 0; i < CONTAINER_THREAD_POOL_SIZE; i++) { + if (!container_thread_active[i]) { + return i; + } + } + return -1; } static int load_binary_to_buffer_fs(ocre_runtime_arguments_t *container_arguments, - ocre_container_data_t *container_data) { - int ret = 0; - size_t file_size = 0; - void *file_handle = NULL; - char filepath[FILE_PATH_MAX]; - - ret = core_construct_filepath(filepath, sizeof(filepath), container_data->sha256); - if (ret < 0) { - LOG_ERR("Failed to construct filepath for %s: %d", container_data->sha256, ret); - return ret; - } - ret = core_filestat(filepath, &file_size); - if (ret < 0) { - LOG_ERR("Failed to get file status for %s: %d", filepath, ret); - return ret; - } - - container_arguments->size = file_size; - container_arguments->buffer = malloc(file_size); - if (!container_arguments->buffer) { - LOG_ERR("Failed to allocate memory for container binary."); - return -ENOMEM; - } - - LOG_INF("File path: %s, size: %lu", filepath, (long unsigned int)file_size); - - ret = core_fileopen(filepath, &file_handle); - if (ret < 0) { - LOG_ERR("Failed to open file %s: %d", filepath, ret); - free(container_arguments->buffer); - return ret; - } - - ret = core_fileread(file_handle, container_arguments->buffer, file_size); - if (ret < 0) { - LOG_ERR("Failed to read file %s: %d", filepath, ret); - core_fileclose(file_handle); - free(container_arguments->buffer); - return ret; - } - - ret = core_fileclose(file_handle); - if (ret < 0) { - LOG_ERR("Failed to close file %s: %d", filepath, ret); - free(container_arguments->buffer); - return ret; - } - return 0; + ocre_container_data_t *container_data) +{ + int ret = 0; + size_t file_size = 0; + void *file_handle = NULL; + char filepath[FILE_PATH_MAX]; + + ret = core_construct_filepath(filepath, sizeof(filepath), container_data->sha256); + if (ret < 0) { + LOG_ERR("Failed to construct filepath for %s: %d", container_data->sha256, ret); + return ret; + } + ret = core_filestat(filepath, &file_size); + if (ret < 0) { + LOG_ERR("Failed to get file status for %s: %d", filepath, ret); + return ret; + } + + container_arguments->size = file_size; + container_arguments->buffer = storage_heap_alloc(file_size); + if (!container_arguments->buffer) { + LOG_ERR("Failed to allocate memory for container binary from PSRAM."); + return -ENOMEM; + } + + LOG_INF("File path: %s, size: %lu", filepath, (long unsigned int)file_size); + + ret = core_fileopen(filepath, &file_handle); + if (ret < 0) { + LOG_ERR("Failed to open file %s: %d", filepath, ret); + storage_heap_free(container_arguments->buffer); + return ret; + } + + ret = core_fileread(file_handle, container_arguments->buffer, file_size); + if (ret < 0) { + LOG_ERR("Failed to read file %s: %d", filepath, ret); + core_fileclose(file_handle); + storage_heap_free(container_arguments->buffer); + return ret; + } + + ret = core_fileclose(file_handle); + if (ret < 0) { + LOG_ERR("Failed to close file %s: %d", filepath, ret); + storage_heap_free(container_arguments->buffer); + return ret; + } + return 0; } -int CS_ctx_init(ocre_cs_ctx *ctx) { - for (int i = 0; i < CONFIG_MAX_CONTAINERS; i++) { - core_mutex_init(&ctx->containers[i].lock); - ctx->containers[i].container_runtime_status = CONTAINER_STATUS_UNKNOWN; - ctx->containers[i].ocre_container_data.heap_size = CONFIG_OCRE_CONTAINER_DEFAULT_HEAP_SIZE; - ctx->containers[i].ocre_container_data.stack_size = CONFIG_OCRE_CONTAINER_DEFAULT_STACK_SIZE; - memset(ctx->containers[i].ocre_container_data.name, 0, sizeof(ctx->containers[i].ocre_container_data.name)); - memset(ctx->containers[i].ocre_container_data.sha256, 0, sizeof(ctx->containers[i].ocre_container_data.sha256)); - ctx->containers[i].ocre_container_data.timers = 0; - ctx->containers[i].container_ID = i; - } +int CS_ctx_init(ocre_cs_ctx *ctx) +{ + for (int i = 0; i < CONFIG_MAX_CONTAINERS; i++) { + core_mutex_init(&ctx->containers[i].lock); + ctx->containers[i].container_runtime_status = CONTAINER_STATUS_UNKNOWN; + ctx->containers[i].ocre_container_data.heap_size = CONFIG_OCRE_CONTAINER_DEFAULT_HEAP_SIZE; + ctx->containers[i].ocre_container_data.stack_size = CONFIG_OCRE_CONTAINER_DEFAULT_STACK_SIZE; + memset(ctx->containers[i].ocre_container_data.name, 0, + sizeof(ctx->containers[i].ocre_container_data.name)); + memset(ctx->containers[i].ocre_container_data.sha256, 0, + sizeof(ctx->containers[i].ocre_container_data.sha256)); + ctx->containers[i].ocre_container_data.timers = 0; + ctx->containers[i].container_ID = i; + } #ifdef CONFIG_OCRE_SHELL - register_ocre_shell(ctx); + register_ocre_shell(ctx); #endif - core_mutex_init(&container_mutex); - return 0; + core_mutex_init(&container_mutex); + return 0; } -ocre_container_runtime_status_t CS_runtime_init(ocre_cs_ctx *ctx, ocre_container_init_arguments_t *args) { - RuntimeInitArgs init_args; - memset(&init_args, 0, sizeof(RuntimeInitArgs)); - init_args.mem_alloc_type = Alloc_With_Pool; - init_args.mem_alloc_option.pool.heap_buf = wamr_heap_buf; - init_args.mem_alloc_option.pool.heap_size = sizeof(wamr_heap_buf); - init_args.native_module_name = "env"; - init_args.n_native_symbols = ocre_api_table_size; - init_args.native_symbols = ocre_api_table; - - if (!wasm_runtime_full_init(&init_args)) { - LOG_ERR("Failed to initialize the WASM runtime"); - return RUNTIME_STATUS_ERROR; - } - - bh_log_set_verbose_level(BH_LOG_LEVEL_WARNING); - - if (!wasm_runtime_register_natives("env", ocre_api_table, ocre_api_table_size)) { - LOG_ERR("Failed to register the API's"); - return RUNTIME_STATUS_ERROR; - } +ocre_container_runtime_status_t CS_runtime_init(ocre_cs_ctx *ctx, ocre_container_init_arguments_t *args) +{ + RuntimeInitArgs init_args; + memset(&init_args, 0, sizeof(RuntimeInitArgs)); + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = wamr_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(wamr_heap_buf); + init_args.native_module_name = "env"; + init_args.n_native_symbols = ocre_api_table_size; + init_args.native_symbols = ocre_api_table; + + if (!wasm_runtime_full_init(&init_args)) { + LOG_ERR("Failed to initialize the WASM runtime"); + return RUNTIME_STATUS_ERROR; + } + + bh_log_set_verbose_level(BH_LOG_LEVEL_WARNING); + + if (!wasm_runtime_register_natives("env", ocre_api_table, ocre_api_table_size)) { + LOG_ERR("Failed to register the API's"); + return RUNTIME_STATUS_ERROR; + } #ifdef CONFIG_OCRE_TIMER - ocre_timer_init(); + ocre_timer_init(); #endif #ifdef CONFIG_OCRE_CONTAINER_MESSAGING - ocre_messaging_init(); + ocre_messaging_init(); +#endif +#ifdef CONFIG_OCRE_SHARED_HEAP + SharedHeapInitArgs heap_init_args; + memset(&heap_init_args, 0, sizeof(heap_init_args)); + +#ifdef CONFIG_OCRE_SHARED_HEAP_BUF_PHYSICAL + // Physical mode - map hardware register address + heap_init_args.pre_allocated_addr = (void *)CONFIG_OCRE_SHARED_HEAP_BUF_ADDRESS; + LOG_INF("Creating physical memory mapping at 0x%08X (hardware registers)", CONFIG_OCRE_SHARED_HEAP_BUF_ADDRESS); +#elif CONFIG_OCRE_SHARED_HEAP_BUF_VIRTUAL + // Virtual mode - allocate from RAM + heap_init_args.pre_allocated_addr = preallocated_buf; + LOG_INF("Creating virtual shared heap in RAM, size=%d bytes", CONFIG_OCRE_SHARED_HEAP_BUF_SIZE); +#endif + heap_init_args.size = CONFIG_OCRE_SHARED_HEAP_BUF_SIZE; + _shared_heap = wasm_runtime_create_shared_heap(&heap_init_args); + + if (!_shared_heap) { + LOG_ERR("Create preallocated shared heap failed"); + return RUNTIME_STATUS_ERROR; + } #endif - return RUNTIME_STATUS_INITIALIZED; + + storage_heap_init(); + return RUNTIME_STATUS_INITIALIZED; } -ocre_container_runtime_status_t CS_runtime_destroy(void) { - // Signal event threads to exit gracefully +ocre_container_runtime_status_t CS_runtime_destroy(void) +{ + // Signal event threads to exit gracefully #if defined(CONFIG_OCRE_TIMER) || defined(CONFIG_OCRE_GPIO) || defined(CONFIG_OCRE_SENSORS) || \ - defined(CONFIG_OCRE_CONTAINER_MESSAGING) - ocre_common_shutdown(); -#endif - - // Abort any active container threads - for (int i = 0; i < CONTAINER_THREAD_POOL_SIZE; i++) { - if (container_thread_active[i]) { - core_thread_destroy(&container_threads[i]); - container_thread_active[i] = false; - } - } - return RUNTIME_STATUS_DESTROYED; + defined(CONFIG_OCRE_CONTAINER_MESSAGING) + ocre_common_shutdown(); +#endif + + // Abort any active container threads + for (int i = 0; i < CONTAINER_THREAD_POOL_SIZE; i++) { + if (container_thread_active[i]) { + core_thread_destroy(&container_threads[i]); + container_thread_active[i] = false; + } + } + return RUNTIME_STATUS_DESTROYED; } -ocre_container_status_t CS_create_container(ocre_container_t *container) { - uint32_t curr_container_ID = container->container_ID; - ocre_container_data_t *curr_container_data = &container->ocre_container_data; - ocre_runtime_arguments_t *curr_container_arguments = &container->ocre_runtime_arguments; - - if (container->container_runtime_status == CONTAINER_STATUS_STOPPED) { - LOG_WRN("Container %d is in STOPPED state, destroying it before reuse", curr_container_ID); - CS_destroy_container(container, NULL); - } - - if (container->container_runtime_status != CONTAINER_STATUS_UNKNOWN && - container->container_runtime_status != CONTAINER_STATUS_DESTROYED) { - LOG_ERR("Cannot create container again container with ID: %d, already exists", curr_container_ID); - return CONTAINER_STATUS_ERROR; - } - - if (!validate_container_memory(container)) { - LOG_ERR("Memory check not passed"); - return CONTAINER_STATUS_ERROR; - } - - LOG_INF("Allocating memory for container %d", curr_container_ID); - int ret = load_binary_to_buffer_fs(curr_container_arguments, curr_container_data); - if (ret < 0) { - LOG_ERR("Failed to load binary to buffer: %d", ret); - return CONTAINER_STATUS_ERROR; - } - LOG_INF("Loaded binary to buffer for container %d", curr_container_ID); - - curr_container_arguments->module = - wasm_runtime_load(curr_container_arguments->buffer, curr_container_arguments->size, - curr_container_arguments->error_buf, sizeof(curr_container_arguments->error_buf)); - if (!curr_container_arguments->module) { - LOG_ERR("Failed to load WASM module: %s", curr_container_arguments->error_buf); - free(curr_container_arguments->buffer); - return CONTAINER_STATUS_ERROR; - } - - container->container_runtime_status = CONTAINER_STATUS_CREATED; - LOG_WRN("Created container:%d", curr_container_ID); - return container->container_runtime_status; +ocre_container_status_t CS_create_container(ocre_container_t *container) +{ + uint32_t curr_container_ID = container->container_ID; + ocre_container_data_t *curr_container_data = &container->ocre_container_data; + ocre_runtime_arguments_t *curr_container_arguments = &container->ocre_runtime_arguments; + + if (container->container_runtime_status == CONTAINER_STATUS_STOPPED) { + LOG_WRN("Container %d is in STOPPED state, destroying it before reuse", curr_container_ID); + CS_destroy_container(container, NULL); + } + + if (container->container_runtime_status != CONTAINER_STATUS_UNKNOWN && + container->container_runtime_status != CONTAINER_STATUS_DESTROYED) { + LOG_ERR("Cannot create container again container with ID: %d, already exists", curr_container_ID); + return CONTAINER_STATUS_ERROR; + } + + if (!validate_container_memory(container)) { + LOG_ERR("Memory check not passed"); + return CONTAINER_STATUS_ERROR; + } + + LOG_INF("Allocating memory for container %d", curr_container_ID); + int ret = load_binary_to_buffer_fs(curr_container_arguments, curr_container_data); + if (ret < 0) { + LOG_ERR("Failed to load binary to buffer: %d", ret); + return CONTAINER_STATUS_ERROR; + } + LOG_INF("Loaded binary to buffer for container %d", curr_container_ID); + + curr_container_arguments->module = + wasm_runtime_load(curr_container_arguments->buffer, curr_container_arguments->size, + curr_container_arguments->error_buf, sizeof(curr_container_arguments->error_buf)); + if (!curr_container_arguments->module) { + LOG_ERR("Failed to load WASM module: %s", curr_container_arguments->error_buf); + storage_heap_free(curr_container_arguments->buffer); + return CONTAINER_STATUS_ERROR; + } + + container->container_runtime_status = CONTAINER_STATUS_CREATED; + LOG_WRN("Created container:%d", curr_container_ID); + return container->container_runtime_status; } -ocre_container_status_t CS_run_container(ocre_container_t *container) { - uint32_t curr_container_ID = container->container_ID; - ocre_runtime_arguments_t *curr_container_arguments = &container->ocre_runtime_arguments; - - if (container->container_runtime_status == CONTAINER_STATUS_RUNNING) { - LOG_WRN("Container status is already in RUNNING state"); - return CONTAINER_STATUS_RUNNING; - } - - if (container->container_runtime_status != CONTAINER_STATUS_CREATED && - container->container_runtime_status != CONTAINER_STATUS_STOPPED) { - LOG_ERR("Container (ID: %d), is not in a valid state to run", curr_container_ID); - container->container_runtime_status = CONTAINER_STATUS_ERROR; - return CONTAINER_STATUS_ERROR; - } - - #ifdef CONFIG_OCRE_NETWORKING - #define ADDRESS_POOL_SIZE 1 - const char *addr_pool[ADDRESS_POOL_SIZE] = { - "0.0.0.0/0", - }; - wasm_runtime_set_wasi_addr_pool(curr_container_arguments->module, addr_pool, ADDRESS_POOL_SIZE); - #endif - - #ifdef CONFIG_OCRE_CONTAINER_FILESYSTEM - // Simple for now: map CONTAINER_FS_PATH to / - // TODO: eventually every container should probably have its own root folder, - // however wasm_runtime_set_wasi_args expects constant values. - #define DIR_LIST_SIZE 1 - static const char *dir_map_list[DIR_LIST_SIZE] = { - "/::" CONTAINER_FS_PATH - }; - wasm_runtime_set_wasi_args(curr_container_arguments->module, - NULL, 0, - dir_map_list, DIR_LIST_SIZE, - NULL, 0, NULL, 0); - #endif - - if (curr_container_arguments->module_inst) { - LOG_INF("WASM runtime already instantiated for container:%d", curr_container_ID); - } else { - LOG_INF("Instantiating WASM runtime for container:%d", curr_container_ID); - curr_container_arguments->module_inst = - wasm_runtime_instantiate(curr_container_arguments->module, curr_container_arguments->stack_size, - curr_container_arguments->heap_size, curr_container_arguments->error_buf, - sizeof(curr_container_arguments->error_buf)); - if (!curr_container_arguments->module_inst) { - LOG_ERR("Failed to instantiate WASM module: %s, for containerID= %d", curr_container_arguments->error_buf, - curr_container_ID); - wasm_runtime_unload(curr_container_arguments->module); - free(curr_container_arguments->buffer); - return CONTAINER_STATUS_ERROR; - } +ocre_container_status_t CS_run_container(ocre_container_t *container) +{ + uint32_t curr_container_ID = container->container_ID; + ocre_runtime_arguments_t *curr_container_arguments = &container->ocre_runtime_arguments; + + if (container->container_runtime_status == CONTAINER_STATUS_RUNNING) { + LOG_WRN("Container status is already in RUNNING state"); + return CONTAINER_STATUS_RUNNING; + } + + if (container->container_runtime_status != CONTAINER_STATUS_CREATED && + container->container_runtime_status != CONTAINER_STATUS_STOPPED) { + LOG_ERR("Container (ID: %d), is not in a valid state to run", curr_container_ID); + container->container_runtime_status = CONTAINER_STATUS_ERROR; + return CONTAINER_STATUS_ERROR; + } + +#ifdef CONFIG_OCRE_NETWORKING +#define ADDRESS_POOL_SIZE 1 + const char *addr_pool[ADDRESS_POOL_SIZE] = { + "0.0.0.0/0", + }; + wasm_runtime_set_wasi_addr_pool(curr_container_arguments->module, addr_pool, ADDRESS_POOL_SIZE); + /** + * Configure which domain names a WebAssembly module is allowed to resolve via DNS lookups + * ns_lookup_pool: An array of domain name patterns (e.g., "example.com", "*.example.com", or "*" for any + * domain) + */ + + const char *ns_lookup_pool[] = {"*"}; + wasm_runtime_set_wasi_ns_lookup_pool(curr_container_arguments->module, ns_lookup_pool, + sizeof(ns_lookup_pool) / sizeof(ns_lookup_pool[0])); +#endif + +#ifdef CONFIG_OCRE_CONTAINER_FILESYSTEM +// Simple for now: map CONTAINER_FS_PATH to / +// TODO: eventually every container should probably have its own root folder, +// however wasm_runtime_set_wasi_args expects constant values. +#define DIR_LIST_SIZE 1 + static const char *dir_map_list[DIR_LIST_SIZE] = {"/::" CONTAINER_FS_PATH}; + wasm_runtime_set_wasi_args(curr_container_arguments->module, NULL, 0, dir_map_list, DIR_LIST_SIZE, NULL, 0, + NULL, 0); +#endif + + if (curr_container_arguments->module_inst) { + LOG_INF("WASM runtime already instantiated for container:%d", curr_container_ID); + } else { + LOG_INF("Instantiating WASM runtime for container:%d", curr_container_ID); + curr_container_arguments->module_inst = wasm_runtime_instantiate( + curr_container_arguments->module, curr_container_arguments->stack_size, + curr_container_arguments->heap_size, curr_container_arguments->error_buf, + sizeof(curr_container_arguments->error_buf)); + if (!curr_container_arguments->module_inst) { + LOG_ERR("Failed to instantiate WASM module: %s, for containerID= %d", + curr_container_arguments->error_buf, curr_container_ID); + wasm_runtime_unload(curr_container_arguments->module); + storage_heap_free(curr_container_arguments->buffer); + return CONTAINER_STATUS_ERROR; + } #if defined(CONFIG_OCRE_TIMER) || defined(CONFIG_OCRE_GPIO) || defined(CONFIG_OCRE_SENSORS) || \ - defined(CONFIG_OCRE_CONTAINER_MESSAGING) - ocre_register_module(curr_container_arguments->module_inst); -#endif - } - - core_mutex_lock(&container_mutex); - int thread_idx = get_available_thread(); - if (thread_idx == -1) { - LOG_ERR("No available threads for container %d", curr_container_ID); - container->container_runtime_status = CONTAINER_STATUS_ERROR; - core_mutex_unlock(&container_mutex); - return CONTAINER_STATUS_ERROR; - } - - // Allocate thread arguments dynamically - struct container_thread_args *args = core_malloc(sizeof(struct container_thread_args)); - if (!args) { - LOG_ERR("Failed to allocate thread args for container %d", curr_container_ID); - container->container_runtime_status = CONTAINER_STATUS_ERROR; - core_mutex_unlock(&container_mutex); - return CONTAINER_STATUS_ERROR; - } - args->container = container; - - // Create and start a new thread for the container - char thread_name[16]; - snprintf(thread_name, sizeof(thread_name), "container_%d", curr_container_ID); - container_threads[thread_idx].user_options = curr_container_ID; - int ret = core_thread_create(&container_threads[thread_idx], container_thread_entry, args, thread_name, - CONTAINER_THREAD_STACK_SIZE, 5); - - if (ret != 0) { - LOG_ERR("Failed to create thread for container %d", curr_container_ID); - container->container_runtime_status = CONTAINER_STATUS_ERROR; - - core_free(args); // Free the dynamically allocated args - - core_mutex_unlock(&container_mutex); - return CONTAINER_STATUS_ERROR; - } - - container_thread_active[thread_idx] = true; - core_mutex_unlock(&container_mutex); - - container->container_runtime_status = CONTAINER_STATUS_RUNNING; - LOG_WRN("Running container:%d in dedicated thread", curr_container_ID); - return CONTAINER_STATUS_RUNNING; + defined(CONFIG_OCRE_CONTAINER_MESSAGING) + ocre_register_module(curr_container_arguments->module_inst); +#endif +#ifdef CONFIG_OCRE_SHARED_HEAP + LOG_INF("Attaching shared heap to container %d", curr_container_ID); + /* attach module instance to the shared heap */ + if (!wasm_runtime_attach_shared_heap(curr_container_arguments->module_inst, _shared_heap)) { + LOG_ERR("Attach shared heap failed."); + return CONTAINER_STATUS_ERROR; + } + +#ifdef CONFIG_OCRE_SHARED_HEAP_BUF_PHYSICAL + // For physical mode, get the base address from the shared heap itself + // The WASM address space already knows about the physical mapping + uint32 shared_heap_base_addr = wasm_runtime_addr_native_to_app( + curr_container_arguments->module_inst, (void *)CONFIG_OCRE_SHARED_HEAP_BUF_ADDRESS); + LOG_INF("Physical shared heap base address in app: 0x%x", shared_heap_base_addr); +#elif CONFIG_OCRE_SHARED_HEAP_BUF_VIRTUAL + // For virtual mode, convert the allocated buffer address + uint32 shared_heap_base_addr = + wasm_runtime_addr_native_to_app(curr_container_arguments->module_inst, preallocated_buf); + LOG_INF("Virtual shared heap base address in app: 0x%x", shared_heap_base_addr); +#endif + + if (shared_heap_base_addr == 0) { + LOG_ERR("Failed to get shared heap WASM address!"); + return CONTAINER_STATUS_ERROR; + } +#endif + } + core_mutex_lock(&container_mutex); + int thread_idx = get_available_thread(); + if (thread_idx == -1) { + LOG_ERR("No available threads for container %d", curr_container_ID); + container->container_runtime_status = CONTAINER_STATUS_ERROR; + core_mutex_unlock(&container_mutex); + return CONTAINER_STATUS_ERROR; + } + + // Allocate thread arguments dynamically + struct container_thread_args *args = core_malloc(sizeof(struct container_thread_args)); + if (!args) { + LOG_ERR("Failed to allocate thread args for container %d", curr_container_ID); + container->container_runtime_status = CONTAINER_STATUS_ERROR; + core_mutex_unlock(&container_mutex); + return CONTAINER_STATUS_ERROR; + } + args->container = container; + + // Create and start a new thread for the container + char thread_name[16]; + snprintf(thread_name, sizeof(thread_name), "container_%d", curr_container_ID); + container_threads[thread_idx].user_options = curr_container_ID; + int ret = core_thread_create(&container_threads[thread_idx], container_thread_entry, args, thread_name, + CONTAINER_THREAD_STACK_SIZE, 5); + + if (ret != 0) { + LOG_ERR("Failed to create thread for container %d", curr_container_ID); + container->container_runtime_status = CONTAINER_STATUS_ERROR; + + core_free(args); // Free the dynamically allocated args + + core_mutex_unlock(&container_mutex); + return CONTAINER_STATUS_ERROR; + } + + container_thread_active[thread_idx] = true; + core_mutex_unlock(&container_mutex); + + container->container_runtime_status = CONTAINER_STATUS_RUNNING; + LOG_WRN("Running container:%d in dedicated thread", curr_container_ID); + return CONTAINER_STATUS_RUNNING; } -ocre_container_status_t CS_get_container_status(ocre_cs_ctx *ctx, int container_id) { - if (container_id < 0 || container_id >= CONFIG_MAX_CONTAINERS) { - LOG_ERR("Invalid container ID: %d", container_id); - return CONTAINER_STATUS_ERROR; - } +ocre_container_status_t CS_get_container_status(ocre_cs_ctx *ctx, int container_id) +{ + if (container_id < 0 || container_id >= CONFIG_MAX_CONTAINERS) { + LOG_ERR("Invalid container ID: %d", container_id); + return CONTAINER_STATUS_ERROR; + } - return ctx->containers[container_id].container_runtime_status; + return ctx->containers[container_id].container_runtime_status; } -ocre_container_status_t CS_stop_container(ocre_container_t *container, ocre_container_runtime_cb callback) { - uint32_t curr_container_ID = container->container_ID; - ocre_runtime_arguments_t *curr_container_arguments = &container->ocre_runtime_arguments; - if (container->container_runtime_status == CONTAINER_STATUS_STOPPED) { - LOG_WRN("Container status is already in STOP state"); - return CONTAINER_STATUS_STOPPED; - } - core_mutex_lock(&container->lock); - { - LOG_INF("Stopping container %d from state %d", curr_container_ID, container->container_runtime_status); - - for (int i = 0; i < CONTAINER_THREAD_POOL_SIZE; i++) { - if (container_thread_active[i] && container_threads[i].user_options == curr_container_ID) { +ocre_container_status_t CS_stop_container(ocre_container_t *container, ocre_container_runtime_cb callback) +{ + uint32_t curr_container_ID = container->container_ID; + ocre_runtime_arguments_t *curr_container_arguments = &container->ocre_runtime_arguments; + if (container->container_runtime_status == CONTAINER_STATUS_STOPPED) { + LOG_WRN("Container status is already in STOP state"); + return CONTAINER_STATUS_STOPPED; + } + core_mutex_lock(&container->lock); + { + LOG_INF("Stopping container %d from state %d", curr_container_ID, container->container_runtime_status); + + for (int i = 0; i < CONTAINER_THREAD_POOL_SIZE; i++) { + if (container_thread_active[i] && container_threads[i].user_options == curr_container_ID) { #if defined(CONFIG_OCRE_CONTAINER_WAMR_TERMINATION) -/** - * wasm_runtime_terminate uses POSIX signals to terminate the thread from the outside; calling core_thread_destroy - * would try to destroy again the thread, and pthread_join() will never return, while freeing the stack would cause - * segfault. This separation is needed to distinguish platform supported by wamr with this features, - * from those which aren't. Since this function exists on those platforms, but stubbed, config parameter is used. - */ - wasm_runtime_terminate(curr_container_arguments->module_inst); + /** + * wasm_runtime_terminate uses POSIX signals to terminate the thread from the outside; + * calling core_thread_destroy would try to destroy again the thread, and pthread_join() + * will never return, while freeing the stack would cause segfault. This separation is + * needed to distinguish platform supported by wamr with this features, from those which + * aren't. Since this function exists on those platforms, but stubbed, config parameter + * is used. + */ + wasm_runtime_terminate(curr_container_arguments->module_inst); #else - core_thread_destroy(&container_threads[i]); + core_thread_destroy(&container_threads[i]); #endif - container_thread_active[i] = false; - } - } + container_thread_active[i] = false; + } + } #ifdef CONFIG_OCRE_TIMER - ocre_timer_cleanup_container(curr_container_arguments->module_inst); + ocre_timer_cleanup_container(curr_container_arguments->module_inst); #endif #ifdef CONFIG_OCRE_GPIO - ocre_gpio_cleanup_container(curr_container_arguments->module_inst); + ocre_gpio_cleanup_container(curr_container_arguments->module_inst); #endif #ifdef CONFIG_OCRE_CONTAINER_MESSAGING - ocre_messaging_cleanup_container(curr_container_arguments->module_inst); + ocre_messaging_cleanup_container(curr_container_arguments->module_inst); #endif #if defined(CONFIG_OCRE_TIMER) || defined(CONFIG_OCRE_GPIO) || defined(CONFIG_OCRE_SENSORS) || \ - defined(CONFIG_OCRE_CONTAINER_MESSAGING) - ocre_unregister_module(curr_container_arguments->module_inst); + defined(CONFIG_OCRE_CONTAINER_MESSAGING) + ocre_unregister_module(curr_container_arguments->module_inst); #endif - if (curr_container_arguments->module_inst) { - wasm_runtime_deinstantiate(curr_container_arguments->module_inst); - curr_container_arguments->module_inst = NULL; - } + if (curr_container_arguments->module_inst) { + wasm_runtime_deinstantiate(curr_container_arguments->module_inst); + curr_container_arguments->module_inst = NULL; + } - container->container_runtime_status = CONTAINER_STATUS_STOPPED; - } - core_mutex_unlock(&container->lock); + container->container_runtime_status = CONTAINER_STATUS_STOPPED; + } + core_mutex_unlock(&container->lock); - if (callback) { - callback(); - } - return CONTAINER_STATUS_STOPPED; + if (callback) { + callback(); + } + return CONTAINER_STATUS_STOPPED; } -ocre_container_status_t CS_destroy_container(ocre_container_t *container, ocre_container_runtime_cb callback) { - if (container->container_runtime_status != CONTAINER_STATUS_STOPPED) { - CS_stop_container(container, NULL); - } - - core_mutex_lock(&container->lock); - { - LOG_INF("Destroying container %d", container->container_ID); - if (container->ocre_runtime_arguments.module) { - wasm_runtime_unload(container->ocre_runtime_arguments.module); - container->ocre_runtime_arguments.module = NULL; - } - - if (container->ocre_runtime_arguments.buffer) { - free(container->ocre_runtime_arguments.buffer); - container->ocre_runtime_arguments.buffer = NULL; - } - - memset(&container->ocre_container_data, 0, sizeof(ocre_container_data_t)); - container->container_runtime_status = CONTAINER_STATUS_DESTROYED; - } - core_mutex_unlock(&container->lock); - - if (callback) { - callback(); - } - return CONTAINER_STATUS_DESTROYED; +ocre_container_status_t CS_destroy_container(ocre_container_t *container, ocre_container_runtime_cb callback) +{ + if (container->container_runtime_status != CONTAINER_STATUS_STOPPED) { + CS_stop_container(container, NULL); + } + + core_mutex_lock(&container->lock); + { + LOG_INF("Destroying container %d", container->container_ID); + if (container->ocre_runtime_arguments.module) { + wasm_runtime_unload(container->ocre_runtime_arguments.module); + container->ocre_runtime_arguments.module = NULL; + } + + if (container->ocre_runtime_arguments.buffer) { + storage_heap_free(container->ocre_runtime_arguments.buffer); + container->ocre_runtime_arguments.buffer = NULL; + } + + memset(&container->ocre_container_data, 0, sizeof(ocre_container_data_t)); + container->container_runtime_status = CONTAINER_STATUS_DESTROYED; + } + core_mutex_unlock(&container->lock); + + if (callback) { + callback(); + } + return CONTAINER_STATUS_DESTROYED; } -ocre_container_status_t CS_restart_container(ocre_container_t *container, ocre_container_runtime_cb callback) { - ocre_container_status_t status = CS_stop_container(container, NULL); - if (status != CONTAINER_STATUS_STOPPED) { - LOG_ERR("Failed to stop container: %d", container->container_ID); - return CONTAINER_STATUS_ERROR; - } - - status = CS_run_container(container); - if (status != CONTAINER_STATUS_RUNNING) { - LOG_ERR("Failed to start container: %d", container->container_ID); - return CONTAINER_STATUS_ERROR; - } - if (callback) { - callback(); - } - - return CONTAINER_STATUS_RUNNING; +ocre_container_status_t CS_restart_container(ocre_container_t *container, ocre_container_runtime_cb callback) +{ + ocre_container_status_t status = CS_stop_container(container, NULL); + if (status != CONTAINER_STATUS_STOPPED) { + LOG_ERR("Failed to stop container: %d", container->container_ID); + return CONTAINER_STATUS_ERROR; + } + + status = CS_run_container(container); + if (status != CONTAINER_STATUS_RUNNING) { + LOG_ERR("Failed to start container: %d", container->container_ID); + return CONTAINER_STATUS_ERROR; + } + if (callback) { + callback(); + } + + return CONTAINER_STATUS_RUNNING; } diff --git a/src/ocre/components/container_supervisor/message_types.h b/src/ocre/components/container_supervisor/message_types.h index 8a7f1e75..9c29425c 100644 --- a/src/ocre/components/container_supervisor/message_types.h +++ b/src/ocre/components/container_supervisor/message_types.h @@ -11,23 +11,23 @@ #include "ocre_core_external.h" struct install { - char name[OCRE_MODULE_NAME_LEN]; // download_count = 0; - - start_ocre_cs_thread(ctx); - core_sleep_ms(1000); - return RUNTIME_STATUS_INITIALIZED; +ocre_container_runtime_status_t ocre_container_runtime_init(ocre_cs_ctx *ctx, ocre_container_init_arguments_t *args) +{ + // Zeroing the context + if (CS_runtime_init(ctx, args) != RUNTIME_STATUS_INITIALIZED) { + LOG_ERR("Failed to initialize container runtime"); + return RUNTIME_STATUS_ERROR; + } + + CS_ctx_init(ctx); + ctx->download_count = 0; + + start_ocre_cs_thread(ctx); + core_sleep_ms(1000); + return RUNTIME_STATUS_INITIALIZED; } -ocre_container_status_t ocre_container_runtime_destroy(void) { - wasm_runtime_destroy(); - destroy_ocre_cs_thread(); - return RUNTIME_STATUS_DESTROYED; +ocre_container_status_t ocre_container_runtime_destroy(void) +{ + wasm_runtime_destroy(); + destroy_ocre_cs_thread(); + return RUNTIME_STATUS_DESTROYED; } ocre_container_status_t ocre_container_runtime_create_container(ocre_cs_ctx *ctx, ocre_container_data_t *container_data, - int *container_id, ocre_container_runtime_cb callback) { - int i; - uint8_t validity_flag = false; - // Find available slot for new container - for (i = 0; i < CONFIG_MAX_CONTAINERS; i++) { - if ((ctx->containers[i].container_runtime_status == CONTAINER_STATUS_UNKNOWN) || - (ctx->containers[i].container_runtime_status == CONTAINER_STATUS_DESTROYED)) { - *container_id = i; - ctx->containers[i].container_ID = i; - validity_flag = true; - break; - } - } - - if (validity_flag == false) { - LOG_ERR("No available slots, unable to create container"); - return CONTAINER_STATUS_ERROR; - } - LOG_INF("Request to create new container in slot: %d", *container_id); - - struct ocre_message event = {.event = EVENT_CREATE_CONTAINER}; - ocre_container_data_t Data; - event.containerId = *container_id; - Data = *container_data; - ctx->containers[*container_id].ocre_container_data = Data; - ctx->containers[*container_id].ocre_runtime_arguments.module_inst = NULL; - ctx->download_count++; - - ocre_component_send(&ocre_cs_component, &event); - return CONTAINER_STATUS_CREATED; + int *container_id, ocre_container_runtime_cb callback) +{ + int i; + uint8_t validity_flag = false; + // Find available slot for new container + for (i = 0; i < CONFIG_MAX_CONTAINERS; i++) { + if ((ctx->containers[i].container_runtime_status == CONTAINER_STATUS_UNKNOWN) || + (ctx->containers[i].container_runtime_status == CONTAINER_STATUS_DESTROYED)) { + *container_id = i; + ctx->containers[i].container_ID = i; + validity_flag = true; + break; + } + } + + if (validity_flag == false) { + LOG_ERR("No available slots, unable to create container"); + return CONTAINER_STATUS_ERROR; + } + LOG_INF("Request to create new container in slot: %d", *container_id); + + struct ocre_message event = {.event = EVENT_CREATE_CONTAINER}; + ocre_container_data_t Data; + event.containerId = *container_id; + Data = *container_data; + ctx->containers[*container_id].ocre_container_data = Data; + ctx->containers[*container_id].ocre_runtime_arguments.module_inst = NULL; + ctx->download_count++; + + ocre_component_send(&ocre_cs_component, &event); + return CONTAINER_STATUS_CREATED; } -ocre_container_status_t ocre_container_runtime_run_container(int container_id, ocre_container_runtime_cb callback) { - if (container_id < 0 || container_id >= CONFIG_MAX_CONTAINERS) { - LOG_ERR("Invalid container ID: %d", container_id); - return CONTAINER_STATUS_ERROR; - } - - LOG_INF("Request to run container in slot:%d", container_id); - struct ocre_message event = {.event = EVENT_RUN_CONTAINER}; - event.containerId = container_id; - ocre_component_send(&ocre_cs_component, &event); - return CONTAINER_STATUS_RUNNING; +ocre_container_status_t ocre_container_runtime_run_container(int container_id, ocre_container_runtime_cb callback) +{ + if (container_id < 0 || container_id >= CONFIG_MAX_CONTAINERS) { + LOG_ERR("Invalid container ID: %d", container_id); + return CONTAINER_STATUS_ERROR; + } + + LOG_INF("Request to run container in slot:%d", container_id); + struct ocre_message event = {.event = EVENT_RUN_CONTAINER}; + event.containerId = container_id; + ocre_component_send(&ocre_cs_component, &event); + return CONTAINER_STATUS_RUNNING; } -ocre_container_status_t ocre_container_runtime_get_container_status(ocre_cs_ctx *ctx, int container_id) { - if (container_id < 0 || container_id >= CONFIG_MAX_CONTAINERS) { - LOG_ERR("Invalid container ID: %d", container_id); - return CONTAINER_STATUS_ERROR; - } +ocre_container_status_t ocre_container_runtime_get_container_status(ocre_cs_ctx *ctx, int container_id) +{ + if (container_id < 0 || container_id >= CONFIG_MAX_CONTAINERS) { + LOG_ERR("Invalid container ID: %d", container_id); + return CONTAINER_STATUS_ERROR; + } - return ctx->containers[container_id].container_runtime_status; + return ctx->containers[container_id].container_runtime_status; } -ocre_container_status_t ocre_container_runtime_stop_container(int container_id, ocre_container_runtime_cb callback) { - if (container_id < 0 || container_id >= CONFIG_MAX_CONTAINERS) { - LOG_ERR("Invalid container ID: %d", container_id); - return CONTAINER_STATUS_ERROR; - } - LOG_INF("Request to stop container in slot: %d", container_id); - struct ocre_message event = {.event = EVENT_STOP_CONTAINER}; - event.containerId = container_id; - ocre_component_send(&ocre_cs_component, &event); - return CONTAINER_STATUS_STOPPED; +ocre_container_status_t ocre_container_runtime_stop_container(int container_id, ocre_container_runtime_cb callback) +{ + if (container_id < 0 || container_id >= CONFIG_MAX_CONTAINERS) { + LOG_ERR("Invalid container ID: %d", container_id); + return CONTAINER_STATUS_ERROR; + } + LOG_INF("Request to stop container in slot: %d", container_id); + struct ocre_message event = {.event = EVENT_STOP_CONTAINER}; + event.containerId = container_id; + ocre_component_send(&ocre_cs_component, &event); + return CONTAINER_STATUS_STOPPED; } ocre_container_status_t ocre_container_runtime_destroy_container(ocre_cs_ctx *ctx, int container_id, - ocre_container_runtime_cb callback) { - if (container_id < 0 || container_id >= CONFIG_MAX_CONTAINERS) { - LOG_ERR("Invalid container ID: %d", container_id); - return CONTAINER_STATUS_ERROR; - } - LOG_INF("Request to destroy container in slot: %d", container_id); - struct ocre_message event = {.event = EVENT_DESTROY_CONTAINER}; - event.containerId = container_id; - ocre_component_send(&ocre_cs_component, &event); - return CONTAINER_STATUS_DESTROYED; + ocre_container_runtime_cb callback) +{ + if (container_id < 0 || container_id >= CONFIG_MAX_CONTAINERS) { + LOG_ERR("Invalid container ID: %d", container_id); + return CONTAINER_STATUS_ERROR; + } + LOG_INF("Request to destroy container in slot: %d", container_id); + struct ocre_message event = {.event = EVENT_DESTROY_CONTAINER}; + event.containerId = container_id; + ocre_component_send(&ocre_cs_component, &event); + return CONTAINER_STATUS_DESTROYED; } ocre_container_status_t ocre_container_runtime_restart_container(ocre_cs_ctx *ctx, int container_id, - ocre_container_runtime_cb callback) { - if (container_id < 0 || container_id >= CONFIG_MAX_CONTAINERS) { - LOG_ERR("Invalid container ID: %d", container_id); - return CONTAINER_STATUS_ERROR; - } - LOG_INF("Request to restart container in slot: %d", container_id); - struct ocre_message event = {.event = EVENT_RESTART_CONTAINER}; - event.containerId = container_id; - ocre_component_send(&ocre_cs_component, &event); - return ctx->containers[container_id].container_runtime_status; + ocre_container_runtime_cb callback) +{ + if (container_id < 0 || container_id >= CONFIG_MAX_CONTAINERS) { + LOG_ERR("Invalid container ID: %d", container_id); + return CONTAINER_STATUS_ERROR; + } + LOG_INF("Request to restart container in slot: %d", container_id); + struct ocre_message event = {.event = EVENT_RESTART_CONTAINER}; + event.containerId = container_id; + ocre_component_send(&ocre_cs_component, &event); + return ctx->containers[container_id].container_runtime_status; } diff --git a/src/ocre/ocre_container_runtime/ocre_container_runtime.h b/src/ocre/ocre_container_runtime/ocre_container_runtime.h index 2d1b46cd..e3dda8ff 100644 --- a/src/ocre/ocre_container_runtime/ocre_container_runtime.h +++ b/src/ocre/ocre_container_runtime/ocre_container_runtime.h @@ -13,23 +13,22 @@ #include "ocre_core_external.h" #include "wasm_export.h" -#define OCRE_CR_DEBUG_ON 0 // Debug flag for container runtime (0: OFF, 1: ON) -#define FILE_PATH_MAX 256 // Maximum file path length +#define OCRE_CR_DEBUG_ON 0 // Debug flag for container runtime (0: OFF, 1: ON) +#define FILE_PATH_MAX 256 // Maximum file path length #define OCRE_CR_INIT_TIMEOUT 500 // Timeout to wait for the container registry to initialize - /** * @brief Structure containing the runtime arguments for a container runtime. */ typedef struct ocre_runtime_arguments_t { - uint32_t size; ///< Size of the buffer. - char *buffer; ///< Pointer to the buffer containing the WASM module. - char error_buf[128]; ///< Buffer to store error messages. - wasm_module_t module; ///< Handle to the loaded WASM module. - wasm_module_inst_t module_inst; ///< Handle to the instantiated WASM module. - wasm_function_inst_t func; ///< Handle to the function to be executed within the WASM module. - uint32_t stack_size; ///< Stack size for the WASM module. - uint32_t heap_size; ///< Heap size for the WASM module. + uint32_t size; ///< Size of the buffer. + char *buffer; ///< Pointer to the buffer containing the WASM module. + char error_buf[128]; ///< Buffer to store error messages. + wasm_module_t module; ///< Handle to the loaded WASM module. + wasm_module_inst_t module_inst; ///< Handle to the instantiated WASM module. + wasm_function_inst_t func; ///< Handle to the function to be executed within the WASM module. + uint32_t stack_size; ///< Stack size for the WASM module. + uint32_t heap_size; ///< Heap size for the WASM module. } ocre_runtime_arguments_t; /** @@ -37,62 +36,62 @@ typedef struct ocre_runtime_arguments_t { * NOT USED YET */ typedef enum { - OCRE_CONTAINER_PERM_READ_ONLY, ///< Container has read-only permissions. - OCRE_CONTAINER_PERM_READ_WRITE, ///< Container has read and write permissions. - OCRE_CONTAINER_PERM_EXECUTE ///< Container has execute permissions. + OCRE_CONTAINER_PERM_READ_ONLY, ///< Container has read-only permissions. + OCRE_CONTAINER_PERM_READ_WRITE, ///< Container has read and write permissions. + OCRE_CONTAINER_PERM_EXECUTE ///< Container has execute permissions. } ocre_container_permissions_t; /** * @brief Enum representing the possible status of the container runtime */ typedef enum { - RUNTIME_STATUS_UNKNOWN, ///< Status is unknown. - RUNTIME_STATUS_INITIALIZED, ///< Runtime has been initialized. - RUNTIME_STATUS_DESTROYED, ///< Runtime has been destroyed - RUNTIME_STATUS_ERROR ///< An error occurred with the container. + RUNTIME_STATUS_UNKNOWN, ///< Status is unknown. + RUNTIME_STATUS_INITIALIZED, ///< Runtime has been initialized. + RUNTIME_STATUS_DESTROYED, ///< Runtime has been destroyed + RUNTIME_STATUS_ERROR ///< An error occurred with the container. } ocre_container_runtime_status_t; /** * @brief Enum representing the possible status of a container. */ typedef enum { - CONTAINER_STATUS_UNKNOWN, ///< Status is unknown. - CONTAINER_STATUS_CREATED, ///< Container has been created. - CONTAINER_STATUS_RUNNING, ///< Container is currently running. - CONTAINER_STATUS_STOPPED, ///< Container has been stopped. - CONTAINER_STATUS_DESTROYED, ///< Container has been destroyed. - CONTAINER_STATUS_UNRESPONSIVE, ///< Container is unresponsive. -> For Healthcheck - CONTAINER_STATUS_ERROR, ///< An error occurred with the container. + CONTAINER_STATUS_UNKNOWN, ///< Status is unknown. + CONTAINER_STATUS_CREATED, ///< Container has been created. + CONTAINER_STATUS_RUNNING, ///< Container is currently running. + CONTAINER_STATUS_STOPPED, ///< Container has been stopped. + CONTAINER_STATUS_DESTROYED, ///< Container has been destroyed. + CONTAINER_STATUS_UNRESPONSIVE, ///< Container is unresponsive. -> For Healthcheck + CONTAINER_STATUS_ERROR, ///< An error occurred with the container. } ocre_container_status_t; typedef struct ocre_container_runtime_init_arguments_t { - uint32_t default_stack_size; ///< Stack size for the WASM module. - uint32_t default_heap_size; ///< Heap size for the WASM module. - int maximum_containers; ///< Maximum number of containers allowed. - NativeSymbol *ocre_api_functions; + uint32_t default_stack_size; ///< Stack size for the WASM module. + uint32_t default_heap_size; ///< Heap size for the WASM module. + int maximum_containers; ///< Maximum number of containers allowed. + NativeSymbol *ocre_api_functions; } ocre_container_init_arguments_t; /** * @brief Structure representing the data associated with a container. */ typedef struct ocre_container_data_t { - char name[OCRE_MODULE_NAME_LEN]; // pin >= CONFIG_OCRE_GPIO_PINS_PER_PORT || - config->port_idx >= CONFIG_OCRE_GPIO_MAX_PORTS || !port_ready[config->port_idx]) { - LOG_ERR("Invalid GPIO config: port=%d, pin=%d, port_ready=%d", config ? config->port_idx : -1, - config ? config->pin : -1, config ? port_ready[config->port_idx] : false); - return -EINVAL; - } - int port_idx = config->port_idx; - gpio_pin_t pin = config->pin; - gpio_flags_t flags = (config->direction == OCRE_GPIO_DIR_INPUT) ? GPIO_INPUT : GPIO_OUTPUT; - if (config->direction == OCRE_GPIO_DIR_INPUT) { - flags |= GPIO_PULL_UP; - } - int ret = gpio_pin_configure(gpio_ports[port_idx], pin, flags); - if (ret != 0) { - LOG_ERR("Failed to configure GPIO pin %d on port %d: %d", pin, port_idx, ret); - return ret; - } - wasm_module_inst_t module_inst = ocre_get_current_module(); - if (!module_inst) { - LOG_ERR("No current module instance for GPIO configuration"); - return -EINVAL; - } - int global_pin = port_idx * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; - if (global_pin >= CONFIG_OCRE_GPIO_MAX_PINS) { - LOG_ERR("Global pin %d exceeds max %d", global_pin, CONFIG_OCRE_GPIO_MAX_PINS); - return -EINVAL; - } - gpio_pins[global_pin] = (gpio_pin_ocre){.in_use = 1, - .direction = (config->direction == OCRE_GPIO_DIR_OUTPUT), - .pin_number = pin, - .port_idx = port_idx, - .cb = NULL, - .owner = module_inst}; - ocre_increment_resource_count(module_inst, OCRE_RESOURCE_TYPE_GPIO); - LOG_INF("Configured GPIO pin %d on port %d (global %d) for module %p", pin, port_idx, global_pin, - (void *)module_inst); - return 0; +int ocre_gpio_configure(const ocre_gpio_config_t *config) +{ + if (!gpio_system_initialized || !config || config->pin >= CONFIG_OCRE_GPIO_PINS_PER_PORT || + config->port_idx >= CONFIG_OCRE_GPIO_MAX_PORTS || !port_ready[config->port_idx]) { + LOG_ERR("Invalid GPIO config: port=%d, pin=%d, port_ready=%d", config ? config->port_idx : -1, + config ? config->pin : -1, config ? port_ready[config->port_idx] : false); + return -EINVAL; + } + int port_idx = config->port_idx; + gpio_pin_t pin = config->pin; + gpio_flags_t flags = (config->direction == OCRE_GPIO_DIR_INPUT) ? GPIO_INPUT : GPIO_OUTPUT; + if (config->direction == OCRE_GPIO_DIR_INPUT) { + flags |= GPIO_PULL_UP; + } + int ret = gpio_pin_configure(gpio_ports[port_idx], pin, flags); + if (ret != 0) { + LOG_ERR("Failed to configure GPIO pin %d on port %d: %d", pin, port_idx, ret); + return ret; + } + wasm_module_inst_t module_inst = ocre_get_current_module(); + if (!module_inst) { + LOG_ERR("No current module instance for GPIO configuration"); + return -EINVAL; + } + int global_pin = port_idx * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; + if (global_pin >= CONFIG_OCRE_GPIO_MAX_PINS) { + LOG_ERR("Global pin %d exceeds max %d", global_pin, CONFIG_OCRE_GPIO_MAX_PINS); + return -EINVAL; + } + gpio_pins[global_pin] = (gpio_pin_ocre){.in_use = 1, + .direction = (config->direction == OCRE_GPIO_DIR_OUTPUT), + .pin_number = pin, + .port_idx = port_idx, + .cb = NULL, + .owner = module_inst}; + ocre_increment_resource_count(module_inst, OCRE_RESOURCE_TYPE_GPIO); + LOG_INF("Configured GPIO pin %d on port %d (global %d) for module %p", pin, port_idx, global_pin, + (void *)module_inst); + return 0; } -int ocre_gpio_pin_set(int pin, ocre_gpio_pin_state_t state) { - if (pin >= CONFIG_OCRE_GPIO_MAX_PINS || !gpio_pins[pin].in_use || gpio_pins[pin].direction != 1 || - !port_ready[gpio_pins[pin].port_idx]) { - LOG_ERR("Invalid GPIO pin %d or not configured as output or port not ready", pin); - return -EINVAL; - } - int ret = gpio_pin_set(gpio_ports[gpio_pins[pin].port_idx], gpio_pins[pin].pin_number, state); - if (ret != 0) { - LOG_ERR("Failed to set GPIO pin %d: %d", pin, ret); - } - return ret; +int ocre_gpio_pin_set(int pin, ocre_gpio_pin_state_t state) +{ + if (pin >= CONFIG_OCRE_GPIO_MAX_PINS || !gpio_pins[pin].in_use || gpio_pins[pin].direction != 1 || + !port_ready[gpio_pins[pin].port_idx]) { + LOG_ERR("Invalid GPIO pin %d or not configured as output or port not ready", pin); + return -EINVAL; + } + int ret = gpio_pin_set(gpio_ports[gpio_pins[pin].port_idx], gpio_pins[pin].pin_number, state); + if (ret != 0) { + LOG_ERR("Failed to set GPIO pin %d: %d", pin, ret); + } + return ret; } -ocre_gpio_pin_state_t ocre_gpio_pin_get(int pin) { - if (pin >= CONFIG_OCRE_GPIO_MAX_PINS || !gpio_pins[pin].in_use || !port_ready[gpio_pins[pin].port_idx]) { - LOG_ERR("Invalid or unconfigured GPIO pin %d or port not ready", pin); - return -EINVAL; - } - int value = gpio_pin_get(gpio_ports[gpio_pins[pin].port_idx], gpio_pins[pin].pin_number); - return (value >= 0) ? (value ? OCRE_GPIO_PIN_SET : OCRE_GPIO_PIN_RESET) : value; +ocre_gpio_pin_state_t ocre_gpio_pin_get(int pin) +{ + if (pin >= CONFIG_OCRE_GPIO_MAX_PINS || !gpio_pins[pin].in_use || !port_ready[gpio_pins[pin].port_idx]) { + LOG_ERR("Invalid or unconfigured GPIO pin %d or port not ready", pin); + return -EINVAL; + } + int value = gpio_pin_get(gpio_ports[gpio_pins[pin].port_idx], gpio_pins[pin].pin_number); + return (value >= 0) ? (value ? OCRE_GPIO_PIN_SET : OCRE_GPIO_PIN_RESET) : value; } -int ocre_gpio_pin_toggle(int pin) { - if (pin >= CONFIG_OCRE_GPIO_MAX_PINS || !gpio_pins[pin].in_use || gpio_pins[pin].direction != 1 || - !port_ready[gpio_pins[pin].port_idx]) { - LOG_ERR("Invalid GPIO pin %d or not configured as output or port not ready", pin); - return -EINVAL; - } - int ret = gpio_pin_toggle(gpio_ports[gpio_pins[pin].port_idx], gpio_pins[pin].pin_number); - if (ret != 0) { - LOG_ERR("Failed to toggle GPIO pin %d: %d", pin, ret); - } - return ret; +int ocre_gpio_pin_toggle(int pin) +{ + if (pin >= CONFIG_OCRE_GPIO_MAX_PINS || !gpio_pins[pin].in_use || gpio_pins[pin].direction != 1 || + !port_ready[gpio_pins[pin].port_idx]) { + LOG_ERR("Invalid GPIO pin %d or not configured as output or port not ready", pin); + return -EINVAL; + } + int ret = gpio_pin_toggle(gpio_ports[gpio_pins[pin].port_idx], gpio_pins[pin].pin_number); + if (ret != 0) { + LOG_ERR("Failed to toggle GPIO pin %d: %d", pin, ret); + } + return ret; } -int ocre_gpio_register_callback(int pin) { - if (pin >= CONFIG_OCRE_GPIO_MAX_PINS || !gpio_pins[pin].in_use || gpio_pins[pin].direction != 0 || - !port_ready[gpio_pins[pin].port_idx]) { - LOG_ERR("Invalid GPIO pin %d or not configured as input or port not ready", pin); - return -EINVAL; - } - gpio_pin_ocre *gpio = &gpio_pins[pin]; - if (!gpio->cb) { - gpio->cb = k_calloc(1, sizeof(struct gpio_callback)); - if (!gpio->cb) { - LOG_ERR("Failed to allocate memory for GPIO callback"); - return -ENOMEM; - } - } - int ret = gpio_pin_interrupt_configure(gpio_ports[gpio->port_idx], gpio->pin_number, GPIO_INT_EDGE_BOTH); - if (ret) { - LOG_ERR("Failed to configure interrupt for GPIO pin %d: %d", pin, ret); - k_free(gpio->cb); - gpio->cb = NULL; - return ret; - } - gpio_init_callback(gpio->cb, gpio_callback_handler, BIT(gpio->pin_number)); - ret = gpio_add_callback(gpio_ports[gpio->port_idx], gpio->cb); - if (ret) { - LOG_ERR("Failed to add callback for GPIO pin %d: %d", pin, ret); - k_free(gpio->cb); - gpio->cb = NULL; - return ret; - } - LOG_INF("Registered callback for GPIO pin %d (port %d, pin %d)", pin, gpio->port_idx, gpio->pin_number); - return 0; +int ocre_gpio_register_callback(int pin) +{ + if (pin >= CONFIG_OCRE_GPIO_MAX_PINS || !gpio_pins[pin].in_use || gpio_pins[pin].direction != 0 || + !port_ready[gpio_pins[pin].port_idx]) { + LOG_ERR("Invalid GPIO pin %d or not configured as input or port not ready", pin); + return -EINVAL; + } + gpio_pin_ocre *gpio = &gpio_pins[pin]; + if (!gpio->cb) { + gpio->cb = k_calloc(1, sizeof(struct gpio_callback)); + if (!gpio->cb) { + LOG_ERR("Failed to allocate memory for GPIO callback"); + return -ENOMEM; + } + } + int ret = gpio_pin_interrupt_configure(gpio_ports[gpio->port_idx], gpio->pin_number, GPIO_INT_EDGE_BOTH); + if (ret) { + LOG_ERR("Failed to configure interrupt for GPIO pin %d: %d", pin, ret); + k_free(gpio->cb); + gpio->cb = NULL; + return ret; + } + gpio_init_callback(gpio->cb, gpio_callback_handler, BIT(gpio->pin_number)); + ret = gpio_add_callback(gpio_ports[gpio->port_idx], gpio->cb); + if (ret) { + LOG_ERR("Failed to add callback for GPIO pin %d: %d", pin, ret); + k_free(gpio->cb); + gpio->cb = NULL; + return ret; + } + LOG_INF("Registered callback for GPIO pin %d (port %d, pin %d)", pin, gpio->port_idx, gpio->pin_number); + return 0; } -int ocre_gpio_unregister_callback(int pin) { - if (pin >= CONFIG_OCRE_GPIO_MAX_PINS || !gpio_pins[pin].in_use || !gpio_pins[pin].cb || - !port_ready[gpio_pins[pin].port_idx]) { - LOG_ERR("Invalid GPIO pin %d or no callback registered or port not ready", pin); - return -EINVAL; - } - gpio_pin_ocre *gpio = &gpio_pins[pin]; - int ret = gpio_pin_interrupt_configure(gpio_ports[gpio->port_idx], gpio->pin_number, GPIO_INT_DISABLE); - if (ret) { - LOG_ERR("Failed to disable interrupt for GPIO pin %d: %d", pin, ret); - return ret; - } - ret = gpio_remove_callback(gpio_ports[gpio->port_idx], gpio->cb); - if (ret) { - LOG_ERR("Failed to remove callback for GPIO pin %d: %d", pin, ret); - } - k_free(gpio->cb); - gpio->cb = NULL; - LOG_INF("Unregistered callback for GPIO pin %d", pin); - return ret; +int ocre_gpio_unregister_callback(int pin) +{ + if (pin >= CONFIG_OCRE_GPIO_MAX_PINS || !gpio_pins[pin].in_use || !gpio_pins[pin].cb || + !port_ready[gpio_pins[pin].port_idx]) { + LOG_ERR("Invalid GPIO pin %d or no callback registered or port not ready", pin); + return -EINVAL; + } + gpio_pin_ocre *gpio = &gpio_pins[pin]; + int ret = gpio_pin_interrupt_configure(gpio_ports[gpio->port_idx], gpio->pin_number, GPIO_INT_DISABLE); + if (ret) { + LOG_ERR("Failed to disable interrupt for GPIO pin %d: %d", pin, ret); + return ret; + } + ret = gpio_remove_callback(gpio_ports[gpio->port_idx], gpio->cb); + if (ret) { + LOG_ERR("Failed to remove callback for GPIO pin %d: %d", pin, ret); + } + k_free(gpio->cb); + gpio->cb = NULL; + LOG_INF("Unregistered callback for GPIO pin %d", pin); + return ret; } -void ocre_gpio_cleanup_container(wasm_module_inst_t module_inst) { - if (!gpio_system_initialized || !module_inst) { - LOG_ERR("GPIO system not initialized or invalid module %p", (void *)module_inst); - return; - } - for (int i = 0; i < CONFIG_OCRE_GPIO_MAX_PINS; i++) { - if (gpio_pins[i].in_use && gpio_pins[i].owner == module_inst) { - if (gpio_pins[i].direction == 0) { - ocre_gpio_unregister_callback(i); - } - gpio_pins[i].in_use = 0; - gpio_pins[i].owner = NULL; - ocre_decrement_resource_count(module_inst, OCRE_RESOURCE_TYPE_GPIO); - LOG_DBG("Cleaned up GPIO pin %d", i); - } - } - LOG_DBG("Cleaned up GPIO resources for module %p", (void *)module_inst); +void ocre_gpio_cleanup_container(wasm_module_inst_t module_inst) +{ + if (!gpio_system_initialized || !module_inst) { + LOG_DBG("GPIO system not initialized or invalid module %p", (void *)module_inst); + return; + } + for (int i = 0; i < CONFIG_OCRE_GPIO_MAX_PINS; i++) { + if (gpio_pins[i].in_use && gpio_pins[i].owner == module_inst) { + if (gpio_pins[i].direction == 0) { + ocre_gpio_unregister_callback(i); + } + gpio_pins[i].in_use = 0; + gpio_pins[i].owner = NULL; + ocre_decrement_resource_count(module_inst, OCRE_RESOURCE_TYPE_GPIO); + LOG_DBG("Cleaned up GPIO pin %d", i); + } + } + LOG_DBG("Cleaned up GPIO resources for module %p", (void *)module_inst); } -void ocre_gpio_set_dispatcher(wasm_exec_env_t exec_env) { - wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); - if (module_inst) { - // Dispatcher set in wasm container application - LOG_INF("Set dispatcher for module %p", (void *)module_inst); - } +void ocre_gpio_set_dispatcher(wasm_exec_env_t exec_env) +{ + wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); + if (module_inst) { + // Dispatcher set in wasm container application + LOG_INF("Set dispatcher for module %p", (void *)module_inst); + } } -int ocre_gpio_wasm_init(wasm_exec_env_t exec_env) { - return ocre_gpio_init(); +int ocre_gpio_wasm_init(wasm_exec_env_t exec_env) +{ + return ocre_gpio_init(); } -int ocre_gpio_wasm_configure(wasm_exec_env_t exec_env, int port, int pin, int direction) { - wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); - if (!module_inst) { - LOG_ERR("No module instance for GPIO configuration"); - return -EINVAL; - } - if (port >= CONFIG_OCRE_GPIO_MAX_PORTS || pin >= CONFIG_OCRE_GPIO_PINS_PER_PORT || !port_ready[port]) { - LOG_ERR("Invalid port=%d, pin=%d, or port not ready", port, pin); - return -EINVAL; - } - int global_pin = port * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; - LOG_INF("Configuring GPIO: port=%d, pin=%d, global_pin=%d, direction=%d", port, pin, global_pin, direction); - if (global_pin >= CONFIG_OCRE_GPIO_MAX_PINS) { - LOG_ERR("Global pin %d exceeds max %d", global_pin, CONFIG_OCRE_GPIO_MAX_PINS); - return -EINVAL; - } - ocre_gpio_config_t config = {.pin = pin, .port_idx = port, .direction = direction}; - return ocre_gpio_configure(&config); +int ocre_gpio_wasm_configure(wasm_exec_env_t exec_env, int port, int pin, int direction) +{ + wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); + if (!module_inst) { + LOG_ERR("No module instance for GPIO configuration"); + return -EINVAL; + } + if (port >= CONFIG_OCRE_GPIO_MAX_PORTS || pin >= CONFIG_OCRE_GPIO_PINS_PER_PORT || !port_ready[port]) { + LOG_ERR("Invalid port=%d, pin=%d, or port not ready", port, pin); + return -EINVAL; + } + int global_pin = port * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; + LOG_INF("Configuring GPIO: port=%d, pin=%d, global_pin=%d, direction=%d", port, pin, global_pin, direction); + if (global_pin >= CONFIG_OCRE_GPIO_MAX_PINS) { + LOG_ERR("Global pin %d exceeds max %d", global_pin, CONFIG_OCRE_GPIO_MAX_PINS); + return -EINVAL; + } + ocre_gpio_config_t config = {.pin = pin, .port_idx = port, .direction = direction}; + return ocre_gpio_configure(&config); } -int ocre_gpio_wasm_set(wasm_exec_env_t exec_env, int port, int pin, int state) { - int global_pin = port * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; - LOG_INF("Setting GPIO: port=%d, pin=%d, global_pin=%d, state=%d", port, pin, global_pin, state); - if (!port_ready[port]) { - LOG_ERR("Port %d not ready", port); - return -EINVAL; - } - return ocre_gpio_pin_set(global_pin, state ? OCRE_GPIO_PIN_SET : OCRE_GPIO_PIN_RESET); +int ocre_gpio_wasm_set(wasm_exec_env_t exec_env, int port, int pin, int state) +{ + int global_pin = port * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; + LOG_INF("Setting GPIO: port=%d, pin=%d, global_pin=%d, state=%d", port, pin, global_pin, state); + if (!port_ready[port]) { + LOG_ERR("Port %d not ready", port); + return -EINVAL; + } + return ocre_gpio_pin_set(global_pin, state ? OCRE_GPIO_PIN_SET : OCRE_GPIO_PIN_RESET); } -int ocre_gpio_wasm_get(wasm_exec_env_t exec_env, int port, int pin) { - int global_pin = port * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; - LOG_INF("Getting GPIO: port=%d, pin=%d, global_pin=%d", port, pin, global_pin); - if (!port_ready[port]) { - LOG_ERR("Port %d not ready", port); - return -EINVAL; - } - return ocre_gpio_pin_get(global_pin); +int ocre_gpio_wasm_get(wasm_exec_env_t exec_env, int port, int pin) +{ + int global_pin = port * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; + LOG_INF("Getting GPIO: port=%d, pin=%d, global_pin=%d", port, pin, global_pin); + if (!port_ready[port]) { + LOG_ERR("Port %d not ready", port); + return -EINVAL; + } + return ocre_gpio_pin_get(global_pin); } -int ocre_gpio_wasm_toggle(wasm_exec_env_t exec_env, int port, int pin) { - int global_pin = port * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; - LOG_INF("Toggling GPIO: port=%d, pin=%d, global_pin=%d", port, pin, global_pin); - if (!port_ready[port]) { - LOG_ERR("Port %d not ready", port); - return -EINVAL; - } - return ocre_gpio_pin_toggle(global_pin); +int ocre_gpio_wasm_toggle(wasm_exec_env_t exec_env, int port, int pin) +{ + int global_pin = port * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; + LOG_INF("Toggling GPIO: port=%d, pin=%d, global_pin=%d", port, pin, global_pin); + if (!port_ready[port]) { + LOG_ERR("Port %d not ready", port); + return -EINVAL; + } + return ocre_gpio_pin_toggle(global_pin); } -int ocre_gpio_wasm_register_callback(wasm_exec_env_t exec_env, int port, int pin) { - int global_pin = port * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; - LOG_INF("Registering callback: port=%d, pin=%d, global_pin=%d", port, pin, global_pin); - if (global_pin >= CONFIG_OCRE_GPIO_MAX_PINS || !port_ready[port]) { - LOG_ERR("Global pin %d exceeds max %d or port %d not ready", global_pin, CONFIG_OCRE_GPIO_MAX_PINS, port); - return -EINVAL; - } - return ocre_gpio_register_callback(global_pin); +int ocre_gpio_wasm_register_callback(wasm_exec_env_t exec_env, int port, int pin) +{ + int global_pin = port * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; + LOG_INF("Registering callback: port=%d, pin=%d, global_pin=%d", port, pin, global_pin); + if (global_pin >= CONFIG_OCRE_GPIO_MAX_PINS || !port_ready[port]) { + LOG_ERR("Global pin %d exceeds max %d or port %d not ready", global_pin, CONFIG_OCRE_GPIO_MAX_PINS, + port); + return -EINVAL; + } + return ocre_gpio_register_callback(global_pin); } -int ocre_gpio_wasm_unregister_callback(wasm_exec_env_t exec_env, int port, int pin) { - int global_pin = port * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; - LOG_INF("Unregistering callback: port=%d, pin=%d, global_pin=%d", port, pin, global_pin); - if (!port_ready[port]) { - LOG_ERR("Port %d not ready", port); - return -EINVAL; - } - return ocre_gpio_unregister_callback(global_pin); +int ocre_gpio_wasm_unregister_callback(wasm_exec_env_t exec_env, int port, int pin) +{ + int global_pin = port * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; + LOG_INF("Unregistering callback: port=%d, pin=%d, global_pin=%d", port, pin, global_pin); + if (!port_ready[port]) { + LOG_ERR("Port %d not ready", port); + return -EINVAL; + } + return ocre_gpio_unregister_callback(global_pin); } -static void gpio_callback_handler(const struct device *port, struct gpio_callback *cb, gpio_port_pins_t pins) { - if (!port || !cb) { - LOG_ERR("Null port or callback in GPIO handler"); - return; - } - for (int i = 0; i < CONFIG_OCRE_GPIO_MAX_PINS; i++) { - if (gpio_pins[i].in_use && gpio_pins[i].cb == cb && (pins & BIT(gpio_pins[i].pin_number))) { - int state = gpio_pin_get(port, gpio_pins[i].pin_number); - if (state >= 0) { - - ocre_event_t event; - event.type = OCRE_RESOURCE_TYPE_GPIO; - event.data.gpio_event.pin_id = gpio_pins[i].pin_number; - event.data.gpio_event.port = gpio_pins[i].port_idx; - event.data.gpio_event.state = (uint32_t)state; - event.owner = gpio_pins[i].owner; - core_spinlock_key_t key = core_spinlock_lock(&ocre_event_queue_lock); - if (core_eventq_put(&ocre_event_queue, &event) != 0) { - LOG_ERR("Failed to queue GPIO event for pin %d", i); - } else { - LOG_INF("Queued GPIO event for pin %d (port=%d, pin=%d), state=%d", i, gpio_pins[i].port_idx, - gpio_pins[i].pin_number, state); - } - core_spinlock_unlock(&ocre_event_queue_lock, key); - } - } - } +static void gpio_callback_handler(const struct device *port, struct gpio_callback *cb, gpio_port_pins_t pins) +{ + if (!port || !cb) { + LOG_ERR("Null port or callback in GPIO handler"); + return; + } + for (int i = 0; i < CONFIG_OCRE_GPIO_MAX_PINS; i++) { + if (gpio_pins[i].in_use && gpio_pins[i].cb == cb && (pins & BIT(gpio_pins[i].pin_number))) { + int state = gpio_pin_get(port, gpio_pins[i].pin_number); + if (state >= 0) { + + ocre_event_t event; + event.type = OCRE_RESOURCE_TYPE_GPIO; + event.data.gpio_event.pin_id = gpio_pins[i].pin_number; + event.data.gpio_event.port = gpio_pins[i].port_idx; + event.data.gpio_event.state = (uint32_t)state; + event.owner = gpio_pins[i].owner; + core_spinlock_key_t key = core_spinlock_lock(&ocre_event_queue_lock); + if (core_eventq_put(&ocre_event_queue, &event) != 0) { + LOG_ERR("Failed to queue GPIO event for pin %d", i); + } else { + LOG_INF("Queued GPIO event for pin %d (port=%d, pin=%d), state=%d", i, + gpio_pins[i].port_idx, gpio_pins[i].pin_number, state); + } + core_spinlock_unlock(&ocre_event_queue_lock, key); + } + } + } } //======================================================================================================================================================================================================================================================================================================== -// By Name +// By Name //======================================================================================================================================================================================================================================================================================================== -static int find_port_index(const struct device *port) { - if (!port) { - LOG_ERR("Null port provided to find_port_index"); - return -EINVAL; - } - for (int i = 0; i < CONFIG_OCRE_GPIO_MAX_PORTS; i++) { - if (port_ready[i] && gpio_ports[i] == port) { - LOG_DBG("Found port at index %d: %p", i, port); - return i; - } - } - LOG_ERR("Port %p not found in initialized ports", port); - return -1; +static int find_port_index(const struct device *port) +{ + if (!port) { + LOG_ERR("Null port provided to find_port_index"); + return -EINVAL; + } + for (int i = 0; i < CONFIG_OCRE_GPIO_MAX_PORTS; i++) { + if (port_ready[i] && gpio_ports[i] == port) { + LOG_DBG("Found port at index %d: %p", i, port); + return i; + } + } + LOG_ERR("Port %p not found in initialized ports", port); + return -1; } -static int resolve_gpio_alias(const char *name, int *port_idx, gpio_pin_t *pin) { - if (!name || !port_idx || !pin) { - LOG_ERR("Invalid parameters: name=%p, port_idx=%p, pin=%p", name, port_idx, pin); - return -EINVAL; - } - - // Check if GPIO system is initialized - if (!gpio_system_initialized) { - LOG_ERR("GPIO system not initialized when resolving alias '%s'", name); - return -ENODEV; - } - - // First check if we already have this alias cached - for (int i = 0; i < gpio_alias_count; i++) { - if (strcmp(gpio_aliases[i].name, name) == 0) { - *port_idx = gpio_aliases[i].port_idx; - *pin = gpio_aliases[i].pin; - LOG_INF("Found cached GPIO alias '%s': port %d, pin %d", name, *port_idx, *pin); - return 0; - } - } - - // Try to resolve the alias using devicetree - const struct gpio_dt_spec *spec = NULL; - static struct gpio_dt_spec gpio_spec; - - // Check common aliases - only compile if they exist - if (strcmp(name, "led0") == 0) { +static int resolve_gpio_alias(const char *name, int *port_idx, gpio_pin_t *pin) +{ + if (!name || !port_idx || !pin) { + LOG_ERR("Invalid parameters: name=%p, port_idx=%p, pin=%p", name, port_idx, pin); + return -EINVAL; + } + + // Check if GPIO system is initialized + if (!gpio_system_initialized) { + LOG_ERR("GPIO system not initialized when resolving alias '%s'", name); + return -ENODEV; + } + + // First check if we already have this alias cached + for (int i = 0; i < gpio_alias_count; i++) { + if (strcmp(gpio_aliases[i].name, name) == 0) { + *port_idx = gpio_aliases[i].port_idx; + *pin = gpio_aliases[i].pin; + LOG_INF("Found cached GPIO alias '%s': port %d, pin %d", name, *port_idx, *pin); + return 0; + } + } + + // Try to resolve the alias using devicetree + const struct gpio_dt_spec *spec = NULL; + static struct gpio_dt_spec gpio_spec; + + // Check common aliases - only compile if they exist + if (strcmp(name, "led0") == 0) { #if DT_NODE_EXISTS(DT_ALIAS(led0)) - gpio_spec = (struct gpio_dt_spec)GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios); - spec = &gpio_spec; - LOG_DBG("Resolved DT_ALIAS(led0) to port %p, pin %d", spec ? spec->port : NULL, spec ? spec->pin : 0); + gpio_spec = (struct gpio_dt_spec)GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios); + spec = &gpio_spec; + LOG_DBG("Resolved DT_ALIAS(led0) to port %p, pin %d", spec ? spec->port : NULL, spec ? spec->pin : 0); #else - LOG_ERR("DT_ALIAS(led0) not defined in device tree"); - return -ENODEV; + LOG_ERR("DT_ALIAS(led0) not defined in device tree"); + return -ENODEV; #endif - } else if (strcmp(name, "led1") == 0) { + } else if (strcmp(name, "led1") == 0) { #if DT_NODE_EXISTS(DT_ALIAS(led1)) - gpio_spec = (struct gpio_dt_spec)GPIO_DT_SPEC_GET(DT_ALIAS(led1), gpios); - spec = &gpio_spec; - LOG_DBG("Resolved DT_ALIAS(led1) to port %p, pin %d", spec ? spec->port : NULL, spec ? spec->pin : 0); + gpio_spec = (struct gpio_dt_spec)GPIO_DT_SPEC_GET(DT_ALIAS(led1), gpios); + spec = &gpio_spec; + LOG_DBG("Resolved DT_ALIAS(led1) to port %p, pin %d", spec ? spec->port : NULL, spec ? spec->pin : 0); #else - LOG_ERR("DT_ALIAS(led1) not defined in device tree"); - return -ENODEV; + LOG_ERR("DT_ALIAS(led1) not defined in device tree"); + return -ENODEV; #endif - } else if (strcmp(name, "led2") == 0) { + } else if (strcmp(name, "led2") == 0) { #if DT_NODE_EXISTS(DT_ALIAS(led2)) - gpio_spec = (struct gpio_dt_spec)GPIO_DT_SPEC_GET(DT_ALIAS(led2), gpios); - spec = &gpio_spec; - LOG_DBG("Resolved DT_ALIAS(led2) to port %p, pin %d", spec ? spec->port : NULL, spec ? spec->pin : 0); + gpio_spec = (struct gpio_dt_spec)GPIO_DT_SPEC_GET(DT_ALIAS(led2), gpios); + spec = &gpio_spec; + LOG_DBG("Resolved DT_ALIAS(led2) to port %p, pin %d", spec ? spec->port : NULL, spec ? spec->pin : 0); #else - LOG_ERR("DT_ALIAS(led2) not defined in device tree"); - return -ENODEV; + LOG_ERR("DT_ALIAS(led2) not defined in device tree"); + return -ENODEV; #endif - } else if (strcmp(name, "sw0") == 0) { + } else if (strcmp(name, "sw0") == 0) { #if DT_NODE_EXISTS(DT_ALIAS(sw0)) - gpio_spec = (struct gpio_dt_spec)GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios); - spec = &gpio_spec; - LOG_DBG("Resolved DT_ALIAS(sw0) to port %p, pin %d", spec ? spec->port : NULL, spec ? spec->pin : 0); + gpio_spec = (struct gpio_dt_spec)GPIO_DT_SPEC_GET(DT_ALIAS(sw0), gpios); + spec = &gpio_spec; + LOG_DBG("Resolved DT_ALIAS(sw0) to port %p, pin %d", spec ? spec->port : NULL, spec ? spec->pin : 0); #else - LOG_ERR("DT_ALIAS(sw0) not defined in device tree"); - return -ENODEV; + LOG_ERR("DT_ALIAS(sw0) not defined in device tree"); + return -ENODEV; #endif - } else if (strcmp(name, "sw1") == 0) { + } else if (strcmp(name, "sw1") == 0) { #if DT_NODE_EXISTS(DT_ALIAS(sw1)) - gpio_spec = (struct gpio_dt_spec)GPIO_DT_SPEC_GET(DT_ALIAS(sw1), gpios); - spec = &gpio_spec; - LOG_DBG("Resolved DT_ALIAS(sw1) to port %p, pin %d", spec ? spec->port : NULL, spec ? spec->pin : 0); + gpio_spec = (struct gpio_dt_spec)GPIO_DT_SPEC_GET(DT_ALIAS(sw1), gpios); + spec = &gpio_spec; + LOG_DBG("Resolved DT_ALIAS(sw1) to port %p, pin %d", spec ? spec->port : NULL, spec ? spec->pin : 0); #else - LOG_ERR("DT_ALIAS(sw1) not defined in device tree"); - return -ENODEV; + LOG_ERR("DT_ALIAS(sw1) not defined in device tree"); + return -ENODEV; #endif - } else { - LOG_ERR("Unknown GPIO alias '%s'", name); - return -EINVAL; - } - - if (!spec || !spec->port) { - LOG_ERR("GPIO alias '%s' not found in device tree or invalid spec", name); - return -ENODEV; - } - - // Verify device readiness - if (!device_is_ready(spec->port)) { - LOG_ERR("Device for GPIO alias '%s' (port %p) not ready", name, spec->port); - return -ENODEV; - } - - // Find the port index - int found_port_idx = find_port_index(spec->port); - if (found_port_idx < 0) { - LOG_ERR("Port for alias '%s' (port %p) not found in initialized ports", name, spec->port); - // Debug: print all available ports - LOG_ERR("Available ports:"); - bool any_ports = false; - for (int i = 0; i < CONFIG_OCRE_GPIO_MAX_PORTS; i++) { - if (port_ready[i] && gpio_ports[i]) { - LOG_ERR(" Port %d: %p", i, gpio_ports[i]); - any_ports = true; - } - } - if (!any_ports) { - LOG_ERR(" No ports initialized"); - } - LOG_ERR("Looking for port: %p", spec->port); - return -ENODEV; - } - - *port_idx = found_port_idx; - *pin = spec->pin; - - // Cache the resolved alias - if (gpio_alias_count < CONFIG_OCRE_GPIO_MAX_PINS) { - gpio_aliases[gpio_alias_count].name = name; - gpio_aliases[gpio_alias_count].port = spec->port; - gpio_aliases[gpio_alias_count].pin = spec->pin; - gpio_aliases[gpio_alias_count].port_idx = found_port_idx; - gpio_alias_count++; - LOG_INF("Cached GPIO alias '%s': port %d, pin %d", name, found_port_idx, spec->pin); - } else { - LOG_WRN("Cannot cache alias '%s': alias table full", name); - } - - LOG_INF("Resolved GPIO alias '%s' to port %d, pin %d", name, *port_idx, *pin); - return 0; + } else { + LOG_ERR("Unknown GPIO alias '%s'", name); + return -EINVAL; + } + + if (!spec || !spec->port) { + LOG_ERR("GPIO alias '%s' not found in device tree or invalid spec", name); + return -ENODEV; + } + + // Verify device readiness + if (!device_is_ready(spec->port)) { + LOG_ERR("Device for GPIO alias '%s' (port %p) not ready", name, spec->port); + return -ENODEV; + } + + // Find the port index + int found_port_idx = find_port_index(spec->port); + if (found_port_idx < 0) { + LOG_ERR("Port for alias '%s' (port %p) not found in initialized ports", name, spec->port); + // Debug: print all available ports + LOG_ERR("Available ports:"); + bool any_ports = false; + for (int i = 0; i < CONFIG_OCRE_GPIO_MAX_PORTS; i++) { + if (port_ready[i] && gpio_ports[i]) { + LOG_ERR(" Port %d: %p", i, gpio_ports[i]); + any_ports = true; + } + } + if (!any_ports) { + LOG_ERR(" No ports initialized"); + } + LOG_ERR("Looking for port: %p", spec->port); + return -ENODEV; + } + + *port_idx = found_port_idx; + *pin = spec->pin; + + // Cache the resolved alias + if (gpio_alias_count < CONFIG_OCRE_GPIO_MAX_PINS) { + gpio_aliases[gpio_alias_count].name = name; + gpio_aliases[gpio_alias_count].port = spec->port; + gpio_aliases[gpio_alias_count].pin = spec->pin; + gpio_aliases[gpio_alias_count].port_idx = found_port_idx; + gpio_alias_count++; + LOG_INF("Cached GPIO alias '%s': port %d, pin %d", name, found_port_idx, spec->pin); + } else { + LOG_WRN("Cannot cache alias '%s': alias table full", name); + } + + LOG_INF("Resolved GPIO alias '%s' to port %d, pin %d", name, *port_idx, *pin); + return 0; } -int ocre_gpio_configure_by_name(const char *name, ocre_gpio_direction_t direction) { - if (!name) { - LOG_ERR("Invalid name parameter"); - return -EINVAL; - } - - int port_idx; - gpio_pin_t pin; - int ret = resolve_gpio_alias(name, &port_idx, &pin); - if (ret != 0) { - return ret; - } - - ocre_gpio_config_t config = { - .pin = pin, - .port_idx = port_idx, - .direction = direction - }; - - return ocre_gpio_configure(&config); -} +int ocre_gpio_configure_by_name(const char *name, ocre_gpio_direction_t direction) +{ + if (!name) { + LOG_ERR("Invalid name parameter"); + return -EINVAL; + } -int ocre_gpio_set_by_name(const char *name, ocre_gpio_pin_state_t state) { - if (!name) { - LOG_ERR("Invalid name parameter"); - return -EINVAL; - } - - int port_idx; - gpio_pin_t pin; - int ret = resolve_gpio_alias(name, &port_idx, &pin); - if (ret != 0) { - return ret; - } - - int global_pin = port_idx * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; - return ocre_gpio_pin_set(global_pin, state); -} + int port_idx; + gpio_pin_t pin; + int ret = resolve_gpio_alias(name, &port_idx, &pin); + if (ret != 0) { + return ret; + } -int ocre_gpio_toggle_by_name(const char *name) { - if (!name) { - LOG_ERR("Invalid name parameter"); - return -EINVAL; - } - - int port_idx; - gpio_pin_t pin; - int ret = resolve_gpio_alias(name, &port_idx, &pin); - if (ret != 0) { - return ret; - } - - int global_pin = port_idx * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; - return ocre_gpio_pin_toggle(global_pin); + ocre_gpio_config_t config = {.pin = pin, .port_idx = port_idx, .direction = direction}; + + return ocre_gpio_configure(&config); } -ocre_gpio_pin_state_t ocre_gpio_get_by_name(const char *name) { - if (!name) { - LOG_ERR("Invalid name parameter"); - return -EINVAL; - } - - int port_idx; - gpio_pin_t pin; - int ret = resolve_gpio_alias(name, &port_idx, &pin); - if (ret != 0) { - return ret; - } - - int global_pin = port_idx * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; - return ocre_gpio_pin_get(global_pin); +int ocre_gpio_set_by_name(const char *name, ocre_gpio_pin_state_t state) +{ + if (!name) { + LOG_ERR("Invalid name parameter"); + return -EINVAL; + } + + int port_idx; + gpio_pin_t pin; + int ret = resolve_gpio_alias(name, &port_idx, &pin); + if (ret != 0) { + return ret; + } + + int global_pin = port_idx * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; + return ocre_gpio_pin_set(global_pin, state); } -int ocre_gpio_wasm_configure_by_name(wasm_exec_env_t exec_env, const char *name, int direction) { - if (!name) { - LOG_ERR("Invalid name parameter"); - return -EINVAL; - } +int ocre_gpio_toggle_by_name(const char *name) +{ + if (!name) { + LOG_ERR("Invalid name parameter"); + return -EINVAL; + } + + int port_idx; + gpio_pin_t pin; + int ret = resolve_gpio_alias(name, &port_idx, &pin); + if (ret != 0) { + return ret; + } + + int global_pin = port_idx * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; + return ocre_gpio_pin_toggle(global_pin); +} - wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); - if (!module_inst) { - LOG_ERR("No module instance for GPIO configuration"); - return -EINVAL; - } +ocre_gpio_pin_state_t ocre_gpio_get_by_name(const char *name) +{ + if (!name) { + LOG_ERR("Invalid name parameter"); + return -EINVAL; + } + + int port_idx; + gpio_pin_t pin; + int ret = resolve_gpio_alias(name, &port_idx, &pin); + if (ret != 0) { + return ret; + } + + int global_pin = port_idx * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; + return ocre_gpio_pin_get(global_pin); +} - LOG_INF("Configuring GPIO by name: %s, direction=%d", name, direction); - return ocre_gpio_configure_by_name(name, direction); +int ocre_gpio_wasm_configure_by_name(wasm_exec_env_t exec_env, const char *name, int direction) +{ + if (!name) { + LOG_ERR("Invalid name parameter"); + return -EINVAL; + } + + wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); + if (!module_inst) { + LOG_ERR("No module instance for GPIO configuration"); + return -EINVAL; + } + + LOG_INF("Configuring GPIO by name: %s, direction=%d", name, direction); + return ocre_gpio_configure_by_name(name, direction); } -int ocre_gpio_wasm_set_by_name(wasm_exec_env_t exec_env, const char *name, int state) { - if (!name) { - LOG_ERR("Invalid name parameter"); - return -EINVAL; - } +int ocre_gpio_wasm_set_by_name(wasm_exec_env_t exec_env, const char *name, int state) +{ + if (!name) { + LOG_ERR("Invalid name parameter"); + return -EINVAL; + } - LOG_INF("Setting GPIO by name: %s, state=%d", name, state); - return ocre_gpio_set_by_name(name, state ? OCRE_GPIO_PIN_SET : OCRE_GPIO_PIN_RESET); + LOG_INF("Setting GPIO by name: %s, state=%d", name, state); + return ocre_gpio_set_by_name(name, state ? OCRE_GPIO_PIN_SET : OCRE_GPIO_PIN_RESET); } -int ocre_gpio_wasm_get_by_name(wasm_exec_env_t exec_env, const char *name) { - if (!name) { - LOG_ERR("Invalid name parameter"); - return -EINVAL; - } +int ocre_gpio_wasm_get_by_name(wasm_exec_env_t exec_env, const char *name) +{ + if (!name) { + LOG_ERR("Invalid name parameter"); + return -EINVAL; + } - LOG_INF("Getting GPIO by name: %s", name); - return ocre_gpio_get_by_name(name); + LOG_INF("Getting GPIO by name: %s", name); + return ocre_gpio_get_by_name(name); } -int ocre_gpio_wasm_toggle_by_name(wasm_exec_env_t exec_env, const char *name) { - if (!name) { - LOG_ERR("Invalid name parameter"); - return -EINVAL; - } +int ocre_gpio_wasm_toggle_by_name(wasm_exec_env_t exec_env, const char *name) +{ + if (!name) { + LOG_ERR("Invalid name parameter"); + return -EINVAL; + } - LOG_INF("Toggling GPIO by name: %s", name); - return ocre_gpio_toggle_by_name(name); + LOG_INF("Toggling GPIO by name: %s", name); + return ocre_gpio_toggle_by_name(name); } -int ocre_gpio_wasm_register_callback_by_name(wasm_exec_env_t exec_env, const char *name) { - if (!name) { - LOG_ERR("Invalid name parameter"); - return -EINVAL; - } - - int port_idx; - gpio_pin_t pin; - int ret = resolve_gpio_alias(name, &port_idx, &pin); - if (ret != 0) { - return ret; - } - - int global_pin = port_idx * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; - LOG_INF("Registering callback by name: %s, global_pin=%d", name, global_pin); - - if (global_pin >= CONFIG_OCRE_GPIO_MAX_PINS) { - LOG_ERR("Global pin %d exceeds max %d", global_pin, CONFIG_OCRE_GPIO_MAX_PINS); - return -EINVAL; - } - - return ocre_gpio_register_callback(global_pin); +int ocre_gpio_wasm_register_callback_by_name(wasm_exec_env_t exec_env, const char *name) +{ + if (!name) { + LOG_ERR("Invalid name parameter"); + return -EINVAL; + } + + int port_idx; + gpio_pin_t pin; + int ret = resolve_gpio_alias(name, &port_idx, &pin); + if (ret != 0) { + return ret; + } + + int global_pin = port_idx * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; + LOG_INF("Registering callback by name: %s, global_pin=%d", name, global_pin); + + if (global_pin >= CONFIG_OCRE_GPIO_MAX_PINS) { + LOG_ERR("Global pin %d exceeds max %d", global_pin, CONFIG_OCRE_GPIO_MAX_PINS); + return -EINVAL; + } + + return ocre_gpio_register_callback(global_pin); } -int ocre_gpio_wasm_unregister_callback_by_name(wasm_exec_env_t exec_env, const char *name) { - if (!name) { - LOG_ERR("Invalid name parameter"); - return -EINVAL; - } - - int port_idx; - gpio_pin_t pin; - int ret = resolve_gpio_alias(name, &port_idx, &pin); - if (ret != 0) { - return ret; - } - - int global_pin = port_idx * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; - LOG_INF("Unregistering callback by name: %s, global_pin=%d", name, global_pin); - - return ocre_gpio_unregister_callback(global_pin); +int ocre_gpio_wasm_unregister_callback_by_name(wasm_exec_env_t exec_env, const char *name) +{ + if (!name) { + LOG_ERR("Invalid name parameter"); + return -EINVAL; + } + + int port_idx; + gpio_pin_t pin; + int ret = resolve_gpio_alias(name, &port_idx, &pin); + if (ret != 0) { + return ret; + } + + int global_pin = port_idx * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; + LOG_INF("Unregistering callback by name: %s, global_pin=%d", name, global_pin); + + return ocre_gpio_unregister_callback(global_pin); } diff --git a/src/ocre/ocre_gpio/ocre_gpio.h b/src/ocre/ocre_gpio/ocre_gpio.h index 80e48bc0..74258537 100644 --- a/src/ocre/ocre_gpio/ocre_gpio.h +++ b/src/ocre/ocre_gpio/ocre_gpio.h @@ -29,25 +29,25 @@ * GPIO pin state */ typedef enum { - OCRE_GPIO_PIN_RESET = 0, - OCRE_GPIO_PIN_SET = 1 + OCRE_GPIO_PIN_RESET = 0, + OCRE_GPIO_PIN_SET = 1 } ocre_gpio_pin_state_t; /** * GPIO pin direction */ typedef enum { - OCRE_GPIO_DIR_INPUT = 0, - OCRE_GPIO_DIR_OUTPUT = 1 + OCRE_GPIO_DIR_INPUT = 0, + OCRE_GPIO_DIR_OUTPUT = 1 } ocre_gpio_direction_t; /** * GPIO configuration structure */ typedef struct { - int pin; /**< GPIO pin number (logical) */ - int port_idx; - ocre_gpio_direction_t direction; /**< Pin direction */ + int pin; /**< GPIO pin number (logical) */ + int port_idx; + ocre_gpio_direction_t direction; /**< Pin direction */ } ocre_gpio_config_t; /** @@ -128,7 +128,7 @@ void ocre_gpio_set_dispatcher(wasm_exec_env_t exec_env); /** * @brief Configure a GPIO pin by alias name - * + * * @param name GPIO alias name (e.g., "led0", "sw0") * @param direction GPIO direction (OCRE_GPIO_DIR_INPUT or OCRE_GPIO_DIR_OUTPUT) * @return int 0 on success, negative error code on failure @@ -137,7 +137,7 @@ int ocre_gpio_configure_by_name(const char *name, ocre_gpio_direction_t directio /** * @brief Set a GPIO pin state by alias name - * + * * @param name GPIO alias name (e.g., "led0", "sw0") * @param state Pin state (OCRE_GPIO_PIN_SET or OCRE_GPIO_PIN_RESET) * @return int 0 on success, negative error code on failure @@ -146,7 +146,7 @@ int ocre_gpio_set_by_name(const char *name, ocre_gpio_pin_state_t state); /** * @brief Toggle a GPIO pin by alias name - * + * * @param name GPIO alias name (e.g., "led0", "sw0") * @return int 0 on success, negative error code on failure */ @@ -154,7 +154,7 @@ int ocre_gpio_toggle_by_name(const char *name); /** * @brief Get a GPIO pin state by alias name - * + * * @param name GPIO alias name (e.g., "led0", "sw0") * @return ocre_gpio_pin_state_t Pin state or negative error code on failure */ diff --git a/src/ocre/ocre_input_file.h b/src/ocre/ocre_input_file.h index 74a39052..7b8d74ad 100644 --- a/src/ocre/ocre_input_file.h +++ b/src/ocre/ocre_input_file.h @@ -8,330 +8,222 @@ #ifndef OCRE_INPUT_FILE_H #define OCRE_INPUT_FILE_H // Sample WASM binary data -static unsigned char wasm_binary[] = { - 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x35, 0x09, 0x60, - 0x03, 0x7f, 0x7f, 0x7f, 0x01, 0x7f, 0x60, 0x03, 0x7f, 0x7e, 0x7f, 0x01, - 0x7e, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, - 0x60, 0x04, 0x7f, 0x7e, 0x7f, 0x7f, 0x01, 0x7f, 0x60, 0x04, 0x7f, 0x7f, - 0x7f, 0x7f, 0x01, 0x7f, 0x60, 0x01, 0x7f, 0x00, 0x60, 0x00, 0x00, 0x60, - 0x00, 0x01, 0x7f, 0x02, 0xb0, 0x01, 0x05, 0x16, 0x77, 0x61, 0x73, 0x69, - 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, - 0x65, 0x76, 0x69, 0x65, 0x77, 0x31, 0x08, 0x66, 0x64, 0x5f, 0x63, 0x6c, - 0x6f, 0x73, 0x65, 0x00, 0x02, 0x16, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x73, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x76, - 0x69, 0x65, 0x77, 0x31, 0x0d, 0x66, 0x64, 0x5f, 0x66, 0x64, 0x73, 0x74, - 0x61, 0x74, 0x5f, 0x67, 0x65, 0x74, 0x00, 0x03, 0x16, 0x77, 0x61, 0x73, - 0x69, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, - 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x31, 0x07, 0x66, 0x64, 0x5f, 0x73, - 0x65, 0x65, 0x6b, 0x00, 0x04, 0x16, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x73, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x76, - 0x69, 0x65, 0x77, 0x31, 0x08, 0x66, 0x64, 0x5f, 0x77, 0x72, 0x69, 0x74, - 0x65, 0x00, 0x05, 0x16, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x73, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, - 0x77, 0x31, 0x09, 0x70, 0x72, 0x6f, 0x63, 0x5f, 0x65, 0x78, 0x69, 0x74, - 0x00, 0x06, 0x03, 0x1d, 0x1c, 0x07, 0x07, 0x08, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x07, 0x08, 0x07, 0x02, 0x05, 0x03, 0x03, 0x02, 0x07, 0x02, - 0x02, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01, 0x00, 0x02, 0x04, 0x05, 0x01, - 0x70, 0x01, 0x05, 0x05, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x0d, 0x02, - 0x7f, 0x01, 0x41, 0xc0, 0x91, 0x04, 0x0b, 0x7f, 0x00, 0x41, 0x00, 0x0b, - 0x07, 0x1a, 0x03, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, - 0x06, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x06, 0x04, 0x6d, 0x61, - 0x69, 0x6e, 0x00, 0x07, 0x09, 0x0a, 0x01, 0x00, 0x41, 0x01, 0x0b, 0x04, - 0x1a, 0x18, 0x1c, 0x1e, 0x0a, 0x93, 0x1a, 0x1c, 0x02, 0x00, 0x0b, 0x51, - 0x01, 0x01, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x23, 0x81, 0x80, 0x80, 0x80, - 0x00, 0x41, 0xa0, 0x89, 0x80, 0x80, 0x00, 0x6a, 0x28, 0x02, 0x00, 0x0d, - 0x00, 0x23, 0x81, 0x80, 0x80, 0x80, 0x00, 0x41, 0xa0, 0x89, 0x80, 0x80, - 0x00, 0x6a, 0x41, 0x01, 0x36, 0x02, 0x00, 0x10, 0x85, 0x80, 0x80, 0x80, - 0x00, 0x10, 0x87, 0x80, 0x80, 0x80, 0x00, 0x21, 0x00, 0x10, 0x8e, 0x80, - 0x80, 0x80, 0x00, 0x20, 0x00, 0x0d, 0x01, 0x0f, 0x0b, 0x00, 0x0b, 0x20, - 0x00, 0x10, 0x8c, 0x80, 0x80, 0x80, 0x00, 0x00, 0x0b, 0x11, 0x00, 0x41, - 0x80, 0x88, 0x80, 0x80, 0x00, 0x10, 0x95, 0x80, 0x80, 0x80, 0x00, 0x1a, - 0x41, 0x00, 0x0b, 0x0f, 0x00, 0x20, 0x00, 0x10, 0x80, 0x80, 0x80, 0x80, - 0x00, 0x41, 0xff, 0xff, 0x03, 0x71, 0x0b, 0x11, 0x00, 0x20, 0x00, 0x20, - 0x01, 0x10, 0x81, 0x80, 0x80, 0x80, 0x00, 0x41, 0xff, 0xff, 0x03, 0x71, - 0x0b, 0x15, 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x10, - 0x82, 0x80, 0x80, 0x80, 0x00, 0x41, 0xff, 0xff, 0x03, 0x71, 0x0b, 0x15, - 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x10, 0x83, 0x80, - 0x80, 0x80, 0x00, 0x41, 0xff, 0xff, 0x03, 0x71, 0x0b, 0x0b, 0x00, 0x20, - 0x00, 0x10, 0x84, 0x80, 0x80, 0x80, 0x00, 0x00, 0x0b, 0x02, 0x00, 0x0b, - 0x0e, 0x00, 0x10, 0x8d, 0x80, 0x80, 0x80, 0x00, 0x10, 0x90, 0x80, 0x80, - 0x80, 0x00, 0x0b, 0x08, 0x00, 0x41, 0xa4, 0x89, 0x80, 0x80, 0x00, 0x0b, - 0xa3, 0x03, 0x01, 0x03, 0x7f, 0x02, 0x40, 0x10, 0x8f, 0x80, 0x80, 0x80, - 0x00, 0x28, 0x02, 0x00, 0x22, 0x00, 0x45, 0x0d, 0x00, 0x03, 0x40, 0x02, - 0x40, 0x20, 0x00, 0x28, 0x02, 0x14, 0x20, 0x00, 0x28, 0x02, 0x18, 0x46, - 0x0d, 0x00, 0x20, 0x00, 0x41, 0x00, 0x41, 0x00, 0x20, 0x00, 0x28, 0x02, - 0x20, 0x11, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, - 0x1a, 0x0b, 0x02, 0x40, 0x20, 0x00, 0x28, 0x02, 0x04, 0x22, 0x01, 0x20, - 0x00, 0x28, 0x02, 0x08, 0x22, 0x02, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x20, - 0x01, 0x20, 0x02, 0x6b, 0xac, 0x41, 0x01, 0x20, 0x00, 0x28, 0x02, 0x24, - 0x11, 0x81, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1a, - 0x0b, 0x20, 0x00, 0x28, 0x02, 0x34, 0x22, 0x00, 0x0d, 0x00, 0x0b, 0x0b, - 0x02, 0x40, 0x41, 0x00, 0x28, 0x02, 0xa8, 0x89, 0x80, 0x80, 0x00, 0x22, - 0x00, 0x45, 0x0d, 0x00, 0x02, 0x40, 0x20, 0x00, 0x28, 0x02, 0x14, 0x20, - 0x00, 0x28, 0x02, 0x18, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x00, 0x41, - 0x00, 0x20, 0x00, 0x28, 0x02, 0x20, 0x11, 0x80, 0x80, 0x80, 0x80, 0x00, - 0x80, 0x80, 0x80, 0x80, 0x00, 0x1a, 0x0b, 0x20, 0x00, 0x28, 0x02, 0x04, - 0x22, 0x01, 0x20, 0x00, 0x28, 0x02, 0x08, 0x22, 0x02, 0x46, 0x0d, 0x00, - 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x6b, 0xac, 0x41, 0x01, 0x20, 0x00, - 0x28, 0x02, 0x24, 0x11, 0x81, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, - 0x80, 0x00, 0x1a, 0x0b, 0x02, 0x40, 0x41, 0x00, 0x28, 0x02, 0x90, 0x89, - 0x80, 0x80, 0x00, 0x22, 0x00, 0x45, 0x0d, 0x00, 0x02, 0x40, 0x20, 0x00, - 0x28, 0x02, 0x14, 0x20, 0x00, 0x28, 0x02, 0x18, 0x46, 0x0d, 0x00, 0x20, - 0x00, 0x41, 0x00, 0x41, 0x00, 0x20, 0x00, 0x28, 0x02, 0x20, 0x11, 0x80, - 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1a, 0x0b, 0x20, - 0x00, 0x28, 0x02, 0x04, 0x22, 0x01, 0x20, 0x00, 0x28, 0x02, 0x08, 0x22, - 0x02, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x6b, 0xac, - 0x41, 0x01, 0x20, 0x00, 0x28, 0x02, 0x24, 0x11, 0x81, 0x80, 0x80, 0x80, - 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1a, 0x0b, 0x02, 0x40, 0x41, 0x00, - 0x28, 0x02, 0xa8, 0x89, 0x80, 0x80, 0x00, 0x22, 0x00, 0x45, 0x0d, 0x00, - 0x02, 0x40, 0x20, 0x00, 0x28, 0x02, 0x14, 0x20, 0x00, 0x28, 0x02, 0x18, - 0x46, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x00, 0x41, 0x00, 0x20, 0x00, 0x28, - 0x02, 0x20, 0x11, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, - 0x00, 0x1a, 0x0b, 0x20, 0x00, 0x28, 0x02, 0x04, 0x22, 0x01, 0x20, 0x00, - 0x28, 0x02, 0x08, 0x22, 0x02, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x01, - 0x20, 0x02, 0x6b, 0xac, 0x41, 0x01, 0x20, 0x00, 0x28, 0x02, 0x24, 0x11, - 0x81, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1a, 0x0b, - 0x0b, 0x5c, 0x01, 0x01, 0x7f, 0x20, 0x00, 0x20, 0x00, 0x28, 0x02, 0x3c, - 0x22, 0x01, 0x41, 0x7f, 0x6a, 0x20, 0x01, 0x72, 0x36, 0x02, 0x3c, 0x02, - 0x40, 0x20, 0x00, 0x28, 0x02, 0x00, 0x22, 0x01, 0x41, 0x08, 0x71, 0x45, - 0x0d, 0x00, 0x20, 0x00, 0x20, 0x01, 0x41, 0x20, 0x72, 0x36, 0x02, 0x00, - 0x41, 0x7f, 0x0f, 0x0b, 0x20, 0x00, 0x42, 0x00, 0x37, 0x02, 0x04, 0x20, - 0x00, 0x20, 0x00, 0x28, 0x02, 0x28, 0x22, 0x01, 0x36, 0x02, 0x18, 0x20, - 0x00, 0x20, 0x01, 0x36, 0x02, 0x14, 0x20, 0x00, 0x20, 0x01, 0x20, 0x00, - 0x28, 0x02, 0x2c, 0x6a, 0x36, 0x02, 0x10, 0x41, 0x00, 0x0b, 0xa8, 0x02, - 0x01, 0x05, 0x7f, 0x20, 0x02, 0x20, 0x01, 0x6c, 0x21, 0x04, 0x02, 0x40, - 0x02, 0x40, 0x20, 0x03, 0x28, 0x02, 0x10, 0x22, 0x05, 0x0d, 0x00, 0x41, - 0x00, 0x21, 0x06, 0x20, 0x03, 0x10, 0x91, 0x80, 0x80, 0x80, 0x00, 0x0d, - 0x01, 0x20, 0x03, 0x28, 0x02, 0x10, 0x21, 0x05, 0x0b, 0x02, 0x40, 0x20, - 0x05, 0x20, 0x03, 0x28, 0x02, 0x14, 0x22, 0x07, 0x6b, 0x20, 0x04, 0x4f, - 0x0d, 0x00, 0x20, 0x03, 0x20, 0x00, 0x20, 0x04, 0x20, 0x03, 0x28, 0x02, - 0x20, 0x11, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, - 0x21, 0x06, 0x0c, 0x01, 0x0b, 0x41, 0x00, 0x21, 0x08, 0x02, 0x40, 0x02, - 0x40, 0x20, 0x04, 0x0d, 0x00, 0x20, 0x04, 0x21, 0x05, 0x0c, 0x01, 0x0b, - 0x41, 0x00, 0x21, 0x05, 0x02, 0x40, 0x20, 0x03, 0x28, 0x02, 0x40, 0x41, - 0x00, 0x4e, 0x0d, 0x00, 0x20, 0x04, 0x21, 0x05, 0x0c, 0x01, 0x0b, 0x20, - 0x00, 0x20, 0x04, 0x6a, 0x21, 0x06, 0x02, 0x40, 0x03, 0x40, 0x20, 0x06, - 0x20, 0x05, 0x6a, 0x41, 0x7f, 0x6a, 0x2d, 0x00, 0x00, 0x41, 0x0a, 0x46, - 0x0d, 0x01, 0x20, 0x04, 0x20, 0x05, 0x41, 0x7f, 0x6a, 0x22, 0x05, 0x6a, - 0x0d, 0x00, 0x0b, 0x41, 0x00, 0x21, 0x08, 0x20, 0x04, 0x21, 0x05, 0x0c, - 0x01, 0x0b, 0x20, 0x03, 0x20, 0x00, 0x20, 0x04, 0x20, 0x05, 0x6a, 0x22, - 0x08, 0x20, 0x03, 0x28, 0x02, 0x20, 0x11, 0x80, 0x80, 0x80, 0x80, 0x00, - 0x80, 0x80, 0x80, 0x80, 0x00, 0x22, 0x06, 0x20, 0x08, 0x49, 0x0d, 0x01, - 0x20, 0x08, 0x20, 0x00, 0x6a, 0x21, 0x00, 0x41, 0x00, 0x20, 0x05, 0x6b, - 0x21, 0x05, 0x20, 0x03, 0x28, 0x02, 0x14, 0x21, 0x07, 0x0b, 0x20, 0x07, - 0x20, 0x00, 0x20, 0x05, 0x10, 0x9f, 0x80, 0x80, 0x80, 0x00, 0x1a, 0x20, - 0x03, 0x20, 0x03, 0x28, 0x02, 0x14, 0x20, 0x05, 0x6a, 0x36, 0x02, 0x14, - 0x20, 0x08, 0x20, 0x05, 0x6a, 0x21, 0x06, 0x0b, 0x02, 0x40, 0x20, 0x06, - 0x20, 0x04, 0x47, 0x0d, 0x00, 0x20, 0x02, 0x41, 0x00, 0x20, 0x01, 0x1b, - 0x0f, 0x0b, 0x20, 0x06, 0x20, 0x01, 0x6e, 0x0b, 0x24, 0x01, 0x01, 0x7f, - 0x20, 0x00, 0x10, 0xa0, 0x80, 0x80, 0x80, 0x00, 0x21, 0x02, 0x41, 0x7f, - 0x41, 0x00, 0x20, 0x02, 0x20, 0x00, 0x41, 0x01, 0x20, 0x02, 0x20, 0x01, - 0x10, 0x92, 0x80, 0x80, 0x80, 0x00, 0x47, 0x1b, 0x0b, 0xb3, 0x01, 0x01, - 0x03, 0x7f, 0x23, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x10, 0x6b, 0x22, - 0x02, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, 0x02, 0x20, 0x01, 0x3a, - 0x00, 0x0f, 0x02, 0x40, 0x02, 0x40, 0x20, 0x00, 0x28, 0x02, 0x10, 0x22, - 0x03, 0x0d, 0x00, 0x02, 0x40, 0x20, 0x00, 0x10, 0x91, 0x80, 0x80, 0x80, - 0x00, 0x45, 0x0d, 0x00, 0x41, 0x7f, 0x21, 0x03, 0x0c, 0x02, 0x0b, 0x20, - 0x00, 0x28, 0x02, 0x10, 0x21, 0x03, 0x0b, 0x02, 0x40, 0x20, 0x00, 0x28, - 0x02, 0x14, 0x22, 0x04, 0x20, 0x03, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x28, - 0x02, 0x40, 0x20, 0x01, 0x41, 0xff, 0x01, 0x71, 0x22, 0x03, 0x46, 0x0d, - 0x00, 0x20, 0x00, 0x20, 0x04, 0x41, 0x01, 0x6a, 0x36, 0x02, 0x14, 0x20, - 0x04, 0x20, 0x01, 0x3a, 0x00, 0x00, 0x0c, 0x01, 0x0b, 0x02, 0x40, 0x20, - 0x00, 0x20, 0x02, 0x41, 0x0f, 0x6a, 0x41, 0x01, 0x20, 0x00, 0x28, 0x02, - 0x20, 0x11, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, - 0x41, 0x01, 0x46, 0x0d, 0x00, 0x41, 0x7f, 0x21, 0x03, 0x0c, 0x01, 0x0b, - 0x20, 0x02, 0x2d, 0x00, 0x0f, 0x21, 0x03, 0x0b, 0x20, 0x02, 0x41, 0x10, - 0x6a, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, 0x03, 0x0b, 0x6c, 0x00, - 0x02, 0x40, 0x20, 0x00, 0x41, 0xa0, 0x88, 0x80, 0x80, 0x00, 0x10, 0x93, - 0x80, 0x80, 0x80, 0x00, 0x41, 0x00, 0x4e, 0x0d, 0x00, 0x41, 0x7f, 0x0f, - 0x0b, 0x02, 0x40, 0x41, 0x00, 0x28, 0x02, 0xe0, 0x88, 0x80, 0x80, 0x00, - 0x41, 0x0a, 0x46, 0x0d, 0x00, 0x41, 0x00, 0x28, 0x02, 0xb4, 0x88, 0x80, - 0x80, 0x00, 0x22, 0x00, 0x41, 0x00, 0x28, 0x02, 0xb0, 0x88, 0x80, 0x80, - 0x00, 0x46, 0x0d, 0x00, 0x41, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x36, - 0x02, 0xb4, 0x88, 0x80, 0x80, 0x00, 0x20, 0x00, 0x41, 0x0a, 0x3a, 0x00, - 0x00, 0x41, 0x00, 0x0f, 0x0b, 0x41, 0xa0, 0x88, 0x80, 0x80, 0x00, 0x41, - 0x0a, 0x10, 0x94, 0x80, 0x80, 0x80, 0x00, 0x41, 0x1f, 0x75, 0x0b, 0x02, - 0x00, 0x0b, 0x27, 0x00, 0x10, 0x96, 0x80, 0x80, 0x80, 0x00, 0x02, 0x40, - 0x20, 0x00, 0x10, 0x88, 0x80, 0x80, 0x80, 0x00, 0x22, 0x00, 0x0d, 0x00, - 0x41, 0x00, 0x0f, 0x0b, 0x41, 0x00, 0x20, 0x00, 0x36, 0x02, 0xac, 0x89, - 0x80, 0x80, 0x00, 0x41, 0x7f, 0x0b, 0x0d, 0x00, 0x20, 0x00, 0x28, 0x02, - 0x38, 0x10, 0x97, 0x80, 0x80, 0x80, 0x00, 0x0b, 0x71, 0x01, 0x02, 0x7f, - 0x23, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x10, 0x6b, 0x22, 0x03, 0x24, - 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x7f, 0x21, 0x04, 0x02, 0x40, 0x02, - 0x40, 0x20, 0x02, 0x41, 0x7f, 0x4a, 0x0d, 0x00, 0x41, 0x00, 0x41, 0x1c, - 0x36, 0x02, 0xac, 0x89, 0x80, 0x80, 0x00, 0x0c, 0x01, 0x0b, 0x02, 0x40, - 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x41, 0x0c, 0x6a, 0x10, - 0x8b, 0x80, 0x80, 0x80, 0x00, 0x22, 0x02, 0x45, 0x0d, 0x00, 0x41, 0x00, - 0x20, 0x02, 0x36, 0x02, 0xac, 0x89, 0x80, 0x80, 0x00, 0x41, 0x7f, 0x21, - 0x04, 0x0c, 0x01, 0x0b, 0x20, 0x03, 0x28, 0x02, 0x0c, 0x21, 0x04, 0x0b, - 0x20, 0x03, 0x41, 0x10, 0x6a, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, - 0x04, 0x0b, 0xbb, 0x02, 0x01, 0x07, 0x7f, 0x23, 0x80, 0x80, 0x80, 0x80, - 0x00, 0x41, 0x10, 0x6b, 0x22, 0x03, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, - 0x20, 0x03, 0x20, 0x02, 0x36, 0x02, 0x0c, 0x20, 0x03, 0x20, 0x01, 0x36, - 0x02, 0x08, 0x20, 0x03, 0x20, 0x00, 0x28, 0x02, 0x18, 0x22, 0x01, 0x36, - 0x02, 0x00, 0x20, 0x03, 0x20, 0x00, 0x28, 0x02, 0x14, 0x20, 0x01, 0x6b, - 0x22, 0x04, 0x36, 0x02, 0x04, 0x41, 0x02, 0x21, 0x05, 0x02, 0x40, 0x02, - 0x40, 0x20, 0x00, 0x28, 0x02, 0x38, 0x20, 0x03, 0x41, 0x02, 0x10, 0x99, - 0x80, 0x80, 0x80, 0x00, 0x22, 0x01, 0x20, 0x04, 0x20, 0x02, 0x6a, 0x22, - 0x06, 0x46, 0x0d, 0x00, 0x20, 0x03, 0x21, 0x04, 0x03, 0x40, 0x02, 0x40, - 0x20, 0x01, 0x41, 0x7f, 0x4a, 0x0d, 0x00, 0x41, 0x00, 0x21, 0x01, 0x20, - 0x00, 0x41, 0x00, 0x36, 0x02, 0x18, 0x20, 0x00, 0x42, 0x00, 0x37, 0x03, - 0x10, 0x20, 0x00, 0x20, 0x00, 0x28, 0x02, 0x00, 0x41, 0x20, 0x72, 0x36, - 0x02, 0x00, 0x20, 0x05, 0x41, 0x02, 0x46, 0x0d, 0x03, 0x20, 0x02, 0x20, - 0x04, 0x28, 0x02, 0x04, 0x6b, 0x21, 0x01, 0x0c, 0x03, 0x0b, 0x20, 0x04, - 0x20, 0x01, 0x20, 0x04, 0x28, 0x02, 0x04, 0x22, 0x07, 0x4b, 0x22, 0x08, - 0x41, 0x03, 0x74, 0x6a, 0x22, 0x09, 0x20, 0x09, 0x28, 0x02, 0x00, 0x20, - 0x01, 0x20, 0x07, 0x41, 0x00, 0x20, 0x08, 0x1b, 0x6b, 0x22, 0x07, 0x6a, - 0x36, 0x02, 0x00, 0x20, 0x04, 0x41, 0x0c, 0x41, 0x04, 0x20, 0x08, 0x1b, - 0x6a, 0x22, 0x04, 0x20, 0x04, 0x28, 0x02, 0x00, 0x20, 0x07, 0x6b, 0x36, - 0x02, 0x00, 0x20, 0x09, 0x21, 0x04, 0x20, 0x06, 0x20, 0x01, 0x6b, 0x22, - 0x06, 0x20, 0x00, 0x28, 0x02, 0x38, 0x20, 0x09, 0x20, 0x05, 0x20, 0x08, - 0x6b, 0x22, 0x05, 0x10, 0x99, 0x80, 0x80, 0x80, 0x00, 0x22, 0x01, 0x47, - 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x00, 0x20, 0x00, 0x28, 0x02, 0x28, 0x22, - 0x01, 0x36, 0x02, 0x18, 0x20, 0x00, 0x20, 0x01, 0x36, 0x02, 0x14, 0x20, - 0x00, 0x20, 0x01, 0x20, 0x00, 0x28, 0x02, 0x2c, 0x6a, 0x36, 0x02, 0x10, - 0x20, 0x02, 0x21, 0x01, 0x0b, 0x20, 0x03, 0x41, 0x10, 0x6a, 0x24, 0x80, - 0x80, 0x80, 0x80, 0x00, 0x20, 0x01, 0x0b, 0x66, 0x01, 0x02, 0x7f, 0x23, - 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x20, 0x6b, 0x22, 0x01, 0x24, 0x80, - 0x80, 0x80, 0x80, 0x00, 0x02, 0x40, 0x02, 0x40, 0x20, 0x00, 0x20, 0x01, - 0x41, 0x08, 0x6a, 0x10, 0x89, 0x80, 0x80, 0x80, 0x00, 0x22, 0x00, 0x0d, - 0x00, 0x41, 0x3b, 0x21, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x08, 0x41, 0x02, - 0x47, 0x0d, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x10, 0x41, 0x24, 0x71, 0x0d, - 0x00, 0x41, 0x01, 0x21, 0x02, 0x0c, 0x01, 0x0b, 0x41, 0x00, 0x21, 0x02, - 0x41, 0x00, 0x20, 0x00, 0x36, 0x02, 0xac, 0x89, 0x80, 0x80, 0x00, 0x0b, - 0x20, 0x01, 0x41, 0x20, 0x6a, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, - 0x02, 0x0b, 0x3b, 0x00, 0x20, 0x00, 0x41, 0x81, 0x80, 0x80, 0x80, 0x00, - 0x36, 0x02, 0x20, 0x02, 0x40, 0x20, 0x00, 0x2d, 0x00, 0x00, 0x41, 0xc0, - 0x00, 0x71, 0x0d, 0x00, 0x20, 0x00, 0x28, 0x02, 0x38, 0x10, 0x9b, 0x80, - 0x80, 0x80, 0x00, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x7f, 0x36, 0x02, 0x40, - 0x0b, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x10, 0x9a, 0x80, 0x80, 0x80, - 0x00, 0x0b, 0x64, 0x01, 0x01, 0x7f, 0x23, 0x80, 0x80, 0x80, 0x80, 0x00, - 0x41, 0x10, 0x6b, 0x22, 0x03, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x02, - 0x40, 0x02, 0x40, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x41, 0xff, 0x01, - 0x71, 0x20, 0x03, 0x41, 0x08, 0x6a, 0x10, 0x8a, 0x80, 0x80, 0x80, 0x00, - 0x22, 0x02, 0x45, 0x0d, 0x00, 0x41, 0x00, 0x41, 0xc6, 0x00, 0x20, 0x02, - 0x20, 0x02, 0x41, 0xcc, 0x00, 0x46, 0x1b, 0x36, 0x02, 0xac, 0x89, 0x80, - 0x80, 0x00, 0x42, 0x7f, 0x21, 0x01, 0x0c, 0x01, 0x0b, 0x20, 0x03, 0x29, - 0x03, 0x08, 0x21, 0x01, 0x0b, 0x20, 0x03, 0x41, 0x10, 0x6a, 0x24, 0x80, - 0x80, 0x80, 0x80, 0x00, 0x20, 0x01, 0x0b, 0x11, 0x00, 0x20, 0x00, 0x28, - 0x02, 0x38, 0x20, 0x01, 0x20, 0x02, 0x10, 0x9d, 0x80, 0x80, 0x80, 0x00, - 0x0b, 0xee, 0x07, 0x01, 0x04, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, - 0x20, 0x02, 0x41, 0x20, 0x4b, 0x0d, 0x00, 0x20, 0x01, 0x41, 0x03, 0x71, - 0x45, 0x0d, 0x01, 0x20, 0x02, 0x45, 0x0d, 0x01, 0x20, 0x00, 0x20, 0x01, - 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x02, 0x41, 0x7f, 0x6a, 0x21, - 0x03, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x21, 0x04, 0x20, 0x01, 0x41, 0x01, - 0x6a, 0x22, 0x05, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x02, 0x20, 0x03, 0x45, - 0x0d, 0x02, 0x20, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x01, 0x3a, 0x00, 0x01, - 0x20, 0x02, 0x41, 0x7e, 0x6a, 0x21, 0x03, 0x20, 0x00, 0x41, 0x02, 0x6a, - 0x21, 0x04, 0x20, 0x01, 0x41, 0x02, 0x6a, 0x22, 0x05, 0x41, 0x03, 0x71, - 0x45, 0x0d, 0x02, 0x20, 0x03, 0x45, 0x0d, 0x02, 0x20, 0x00, 0x20, 0x01, - 0x2d, 0x00, 0x02, 0x3a, 0x00, 0x02, 0x20, 0x02, 0x41, 0x7d, 0x6a, 0x21, - 0x03, 0x20, 0x00, 0x41, 0x03, 0x6a, 0x21, 0x04, 0x20, 0x01, 0x41, 0x03, - 0x6a, 0x22, 0x05, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x02, 0x20, 0x03, 0x45, - 0x0d, 0x02, 0x20, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x03, 0x3a, 0x00, 0x03, - 0x20, 0x02, 0x41, 0x7c, 0x6a, 0x21, 0x03, 0x20, 0x00, 0x41, 0x04, 0x6a, - 0x21, 0x04, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x05, 0x0c, 0x02, 0x0b, - 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0xfc, 0x0a, 0x00, 0x00, 0x20, 0x00, - 0x0f, 0x0b, 0x20, 0x02, 0x21, 0x03, 0x20, 0x00, 0x21, 0x04, 0x20, 0x01, - 0x21, 0x05, 0x0b, 0x02, 0x40, 0x02, 0x40, 0x20, 0x04, 0x41, 0x03, 0x71, - 0x22, 0x02, 0x0d, 0x00, 0x02, 0x40, 0x02, 0x40, 0x20, 0x03, 0x41, 0x10, - 0x4f, 0x0d, 0x00, 0x20, 0x03, 0x21, 0x02, 0x0c, 0x01, 0x0b, 0x02, 0x40, - 0x20, 0x03, 0x41, 0x70, 0x6a, 0x22, 0x02, 0x41, 0x10, 0x71, 0x0d, 0x00, - 0x20, 0x04, 0x20, 0x05, 0x29, 0x02, 0x00, 0x37, 0x02, 0x00, 0x20, 0x04, - 0x20, 0x05, 0x29, 0x02, 0x08, 0x37, 0x02, 0x08, 0x20, 0x04, 0x41, 0x10, - 0x6a, 0x21, 0x04, 0x20, 0x05, 0x41, 0x10, 0x6a, 0x21, 0x05, 0x20, 0x02, - 0x21, 0x03, 0x0b, 0x20, 0x02, 0x41, 0x10, 0x49, 0x0d, 0x00, 0x20, 0x03, - 0x21, 0x02, 0x03, 0x40, 0x20, 0x04, 0x20, 0x05, 0x29, 0x02, 0x00, 0x37, - 0x02, 0x00, 0x20, 0x04, 0x20, 0x05, 0x29, 0x02, 0x08, 0x37, 0x02, 0x08, - 0x20, 0x04, 0x20, 0x05, 0x29, 0x02, 0x10, 0x37, 0x02, 0x10, 0x20, 0x04, - 0x20, 0x05, 0x29, 0x02, 0x18, 0x37, 0x02, 0x18, 0x20, 0x04, 0x41, 0x20, - 0x6a, 0x21, 0x04, 0x20, 0x05, 0x41, 0x20, 0x6a, 0x21, 0x05, 0x20, 0x02, - 0x41, 0x60, 0x6a, 0x22, 0x02, 0x41, 0x0f, 0x4b, 0x0d, 0x00, 0x0b, 0x0b, - 0x02, 0x40, 0x20, 0x02, 0x41, 0x08, 0x49, 0x0d, 0x00, 0x20, 0x04, 0x20, - 0x05, 0x29, 0x02, 0x00, 0x37, 0x02, 0x00, 0x20, 0x05, 0x41, 0x08, 0x6a, - 0x21, 0x05, 0x20, 0x04, 0x41, 0x08, 0x6a, 0x21, 0x04, 0x0b, 0x02, 0x40, - 0x20, 0x02, 0x41, 0x04, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x04, 0x20, 0x05, - 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x05, 0x41, 0x04, 0x6a, 0x21, - 0x05, 0x20, 0x04, 0x41, 0x04, 0x6a, 0x21, 0x04, 0x0b, 0x02, 0x40, 0x20, - 0x02, 0x41, 0x02, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x04, 0x20, 0x05, 0x2f, - 0x00, 0x00, 0x3b, 0x00, 0x00, 0x20, 0x04, 0x41, 0x02, 0x6a, 0x21, 0x04, - 0x20, 0x05, 0x41, 0x02, 0x6a, 0x21, 0x05, 0x0b, 0x20, 0x02, 0x41, 0x01, - 0x71, 0x45, 0x0d, 0x01, 0x20, 0x04, 0x20, 0x05, 0x2d, 0x00, 0x00, 0x3a, - 0x00, 0x00, 0x20, 0x00, 0x0f, 0x0b, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, - 0x02, 0x40, 0x02, 0x40, 0x20, 0x03, 0x41, 0x20, 0x49, 0x0d, 0x00, 0x20, - 0x04, 0x20, 0x05, 0x28, 0x02, 0x00, 0x22, 0x03, 0x3a, 0x00, 0x00, 0x02, - 0x40, 0x02, 0x40, 0x20, 0x02, 0x41, 0x7f, 0x6a, 0x0e, 0x03, 0x03, 0x00, - 0x01, 0x03, 0x0b, 0x20, 0x04, 0x20, 0x03, 0x41, 0x08, 0x76, 0x3a, 0x00, - 0x01, 0x20, 0x04, 0x20, 0x05, 0x41, 0x06, 0x6a, 0x29, 0x01, 0x00, 0x37, - 0x02, 0x06, 0x20, 0x04, 0x20, 0x05, 0x28, 0x02, 0x04, 0x41, 0x10, 0x74, - 0x20, 0x03, 0x41, 0x10, 0x76, 0x72, 0x36, 0x02, 0x02, 0x20, 0x04, 0x41, - 0x12, 0x6a, 0x21, 0x02, 0x20, 0x05, 0x41, 0x12, 0x6a, 0x21, 0x01, 0x41, - 0x0e, 0x21, 0x06, 0x20, 0x05, 0x41, 0x0e, 0x6a, 0x28, 0x01, 0x00, 0x21, - 0x05, 0x41, 0x0e, 0x21, 0x03, 0x0c, 0x03, 0x0b, 0x20, 0x04, 0x20, 0x05, - 0x41, 0x05, 0x6a, 0x29, 0x00, 0x00, 0x37, 0x02, 0x05, 0x20, 0x04, 0x20, - 0x05, 0x28, 0x02, 0x04, 0x41, 0x18, 0x74, 0x20, 0x03, 0x41, 0x08, 0x76, - 0x72, 0x36, 0x02, 0x01, 0x20, 0x04, 0x41, 0x11, 0x6a, 0x21, 0x02, 0x20, - 0x05, 0x41, 0x11, 0x6a, 0x21, 0x01, 0x41, 0x0d, 0x21, 0x06, 0x20, 0x05, - 0x41, 0x0d, 0x6a, 0x28, 0x00, 0x00, 0x21, 0x05, 0x41, 0x0f, 0x21, 0x03, - 0x0c, 0x02, 0x0b, 0x02, 0x40, 0x02, 0x40, 0x20, 0x03, 0x41, 0x10, 0x4f, - 0x0d, 0x00, 0x20, 0x04, 0x21, 0x02, 0x20, 0x05, 0x21, 0x01, 0x0c, 0x01, - 0x0b, 0x20, 0x04, 0x20, 0x05, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, - 0x04, 0x20, 0x05, 0x28, 0x00, 0x01, 0x36, 0x00, 0x01, 0x20, 0x04, 0x20, - 0x05, 0x29, 0x00, 0x05, 0x37, 0x00, 0x05, 0x20, 0x04, 0x20, 0x05, 0x2f, - 0x00, 0x0d, 0x3b, 0x00, 0x0d, 0x20, 0x04, 0x20, 0x05, 0x2d, 0x00, 0x0f, - 0x3a, 0x00, 0x0f, 0x20, 0x04, 0x41, 0x10, 0x6a, 0x21, 0x02, 0x20, 0x05, - 0x41, 0x10, 0x6a, 0x21, 0x01, 0x0b, 0x20, 0x03, 0x41, 0x08, 0x71, 0x0d, - 0x02, 0x0c, 0x03, 0x0b, 0x20, 0x04, 0x20, 0x03, 0x41, 0x10, 0x76, 0x3a, - 0x00, 0x02, 0x20, 0x04, 0x20, 0x03, 0x41, 0x08, 0x76, 0x3a, 0x00, 0x01, - 0x20, 0x04, 0x20, 0x05, 0x41, 0x07, 0x6a, 0x29, 0x00, 0x00, 0x37, 0x02, - 0x07, 0x20, 0x04, 0x20, 0x05, 0x28, 0x02, 0x04, 0x41, 0x08, 0x74, 0x20, - 0x03, 0x41, 0x18, 0x76, 0x72, 0x36, 0x02, 0x03, 0x20, 0x04, 0x41, 0x13, - 0x6a, 0x21, 0x02, 0x20, 0x05, 0x41, 0x13, 0x6a, 0x21, 0x01, 0x41, 0x0f, - 0x21, 0x06, 0x20, 0x05, 0x41, 0x0f, 0x6a, 0x28, 0x00, 0x00, 0x21, 0x05, - 0x41, 0x0d, 0x21, 0x03, 0x0b, 0x20, 0x04, 0x20, 0x06, 0x6a, 0x20, 0x05, - 0x36, 0x02, 0x00, 0x0b, 0x20, 0x02, 0x20, 0x01, 0x29, 0x00, 0x00, 0x37, - 0x00, 0x00, 0x20, 0x02, 0x41, 0x08, 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, - 0x08, 0x6a, 0x21, 0x01, 0x0b, 0x02, 0x40, 0x20, 0x03, 0x41, 0x04, 0x71, - 0x45, 0x0d, 0x00, 0x20, 0x02, 0x20, 0x01, 0x28, 0x00, 0x00, 0x36, 0x00, - 0x00, 0x20, 0x02, 0x41, 0x04, 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, 0x04, - 0x6a, 0x21, 0x01, 0x0b, 0x02, 0x40, 0x20, 0x03, 0x41, 0x02, 0x71, 0x45, - 0x0d, 0x00, 0x20, 0x02, 0x20, 0x01, 0x2f, 0x00, 0x00, 0x3b, 0x00, 0x00, - 0x20, 0x02, 0x41, 0x02, 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, 0x02, 0x6a, - 0x21, 0x01, 0x0b, 0x20, 0x03, 0x41, 0x01, 0x71, 0x45, 0x0d, 0x00, 0x20, - 0x02, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x0b, 0x20, 0x00, - 0x0b, 0xcf, 0x01, 0x01, 0x03, 0x7f, 0x20, 0x00, 0x21, 0x01, 0x02, 0x40, - 0x02, 0x40, 0x20, 0x00, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, 0x02, 0x40, - 0x20, 0x00, 0x2d, 0x00, 0x00, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x00, 0x6b, - 0x0f, 0x0b, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x22, 0x01, 0x41, 0x03, 0x71, - 0x45, 0x0d, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x45, 0x0d, 0x01, 0x20, - 0x00, 0x41, 0x02, 0x6a, 0x22, 0x01, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, - 0x20, 0x01, 0x2d, 0x00, 0x00, 0x45, 0x0d, 0x01, 0x20, 0x00, 0x41, 0x03, - 0x6a, 0x22, 0x01, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x01, 0x2d, - 0x00, 0x00, 0x45, 0x0d, 0x01, 0x20, 0x00, 0x41, 0x04, 0x6a, 0x22, 0x01, - 0x41, 0x03, 0x71, 0x0d, 0x01, 0x0b, 0x20, 0x01, 0x41, 0x7c, 0x6a, 0x21, - 0x02, 0x20, 0x01, 0x41, 0x7b, 0x6a, 0x21, 0x01, 0x03, 0x40, 0x20, 0x01, - 0x41, 0x04, 0x6a, 0x21, 0x01, 0x41, 0x80, 0x82, 0x84, 0x08, 0x20, 0x02, - 0x41, 0x04, 0x6a, 0x22, 0x02, 0x28, 0x02, 0x00, 0x22, 0x03, 0x6b, 0x20, - 0x03, 0x72, 0x41, 0x80, 0x81, 0x82, 0x84, 0x78, 0x71, 0x41, 0x80, 0x81, - 0x82, 0x84, 0x78, 0x46, 0x0d, 0x00, 0x0b, 0x03, 0x40, 0x20, 0x01, 0x41, - 0x01, 0x6a, 0x21, 0x01, 0x20, 0x02, 0x2d, 0x00, 0x00, 0x21, 0x03, 0x20, - 0x02, 0x41, 0x01, 0x6a, 0x21, 0x02, 0x20, 0x03, 0x0d, 0x00, 0x0b, 0x0b, - 0x20, 0x01, 0x20, 0x00, 0x6b, 0x0b, 0x0b, 0x9d, 0x01, 0x02, 0x00, 0x41, - 0x80, 0x08, 0x0b, 0x1c, 0x0a, 0x0a, 0x09, 0x48, 0x65, 0x6c, 0x6c, 0x6f, - 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, - 0x4f, 0x63, 0x72, 0x65, 0x21, 0x0a, 0x0a, 0x00, 0x00, 0x41, 0xa0, 0x08, - 0x0b, 0x74, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, - 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xb8, 0x04, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00 - }; +static const unsigned char wasm_binary[] = { + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x35, 0x09, 0x60, 0x03, 0x7f, 0x7f, 0x7f, 0x01, 0x7f, + 0x60, 0x03, 0x7f, 0x7e, 0x7f, 0x01, 0x7e, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, + 0x60, 0x04, 0x7f, 0x7e, 0x7f, 0x7f, 0x01, 0x7f, 0x60, 0x04, 0x7f, 0x7f, 0x7f, 0x7f, 0x01, 0x7f, 0x60, 0x01, + 0x7f, 0x00, 0x60, 0x00, 0x00, 0x60, 0x00, 0x01, 0x7f, 0x02, 0xb0, 0x01, 0x05, 0x16, 0x77, 0x61, 0x73, 0x69, + 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x31, + 0x08, 0x66, 0x64, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x00, 0x02, 0x16, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x73, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x31, 0x0d, 0x66, + 0x64, 0x5f, 0x66, 0x64, 0x73, 0x74, 0x61, 0x74, 0x5f, 0x67, 0x65, 0x74, 0x00, 0x03, 0x16, 0x77, 0x61, 0x73, + 0x69, 0x5f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, + 0x31, 0x07, 0x66, 0x64, 0x5f, 0x73, 0x65, 0x65, 0x6b, 0x00, 0x04, 0x16, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x73, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x31, 0x08, 0x66, + 0x64, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x00, 0x05, 0x16, 0x77, 0x61, 0x73, 0x69, 0x5f, 0x73, 0x6e, 0x61, + 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x31, 0x09, 0x70, 0x72, 0x6f, + 0x63, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x00, 0x06, 0x03, 0x1d, 0x1c, 0x07, 0x07, 0x08, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x07, 0x08, 0x07, 0x02, 0x05, 0x03, 0x03, 0x02, 0x07, 0x02, 0x02, 0x00, 0x00, 0x02, 0x00, 0x01, + 0x01, 0x00, 0x02, 0x04, 0x05, 0x01, 0x70, 0x01, 0x05, 0x05, 0x05, 0x03, 0x01, 0x00, 0x02, 0x06, 0x0d, 0x02, + 0x7f, 0x01, 0x41, 0xc0, 0x91, 0x04, 0x0b, 0x7f, 0x00, 0x41, 0x00, 0x0b, 0x07, 0x1a, 0x03, 0x06, 0x6d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x06, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x06, 0x04, 0x6d, 0x61, + 0x69, 0x6e, 0x00, 0x07, 0x09, 0x0a, 0x01, 0x00, 0x41, 0x01, 0x0b, 0x04, 0x1a, 0x18, 0x1c, 0x1e, 0x0a, 0x93, + 0x1a, 0x1c, 0x02, 0x00, 0x0b, 0x51, 0x01, 0x01, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x23, 0x81, 0x80, 0x80, 0x80, + 0x00, 0x41, 0xa0, 0x89, 0x80, 0x80, 0x00, 0x6a, 0x28, 0x02, 0x00, 0x0d, 0x00, 0x23, 0x81, 0x80, 0x80, 0x80, + 0x00, 0x41, 0xa0, 0x89, 0x80, 0x80, 0x00, 0x6a, 0x41, 0x01, 0x36, 0x02, 0x00, 0x10, 0x85, 0x80, 0x80, 0x80, + 0x00, 0x10, 0x87, 0x80, 0x80, 0x80, 0x00, 0x21, 0x00, 0x10, 0x8e, 0x80, 0x80, 0x80, 0x00, 0x20, 0x00, 0x0d, + 0x01, 0x0f, 0x0b, 0x00, 0x0b, 0x20, 0x00, 0x10, 0x8c, 0x80, 0x80, 0x80, 0x00, 0x00, 0x0b, 0x11, 0x00, 0x41, + 0x80, 0x88, 0x80, 0x80, 0x00, 0x10, 0x95, 0x80, 0x80, 0x80, 0x00, 0x1a, 0x41, 0x00, 0x0b, 0x0f, 0x00, 0x20, + 0x00, 0x10, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0xff, 0xff, 0x03, 0x71, 0x0b, 0x11, 0x00, 0x20, 0x00, 0x20, + 0x01, 0x10, 0x81, 0x80, 0x80, 0x80, 0x00, 0x41, 0xff, 0xff, 0x03, 0x71, 0x0b, 0x15, 0x00, 0x20, 0x00, 0x20, + 0x01, 0x20, 0x02, 0x20, 0x03, 0x10, 0x82, 0x80, 0x80, 0x80, 0x00, 0x41, 0xff, 0xff, 0x03, 0x71, 0x0b, 0x15, + 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x10, 0x83, 0x80, 0x80, 0x80, 0x00, 0x41, 0xff, 0xff, + 0x03, 0x71, 0x0b, 0x0b, 0x00, 0x20, 0x00, 0x10, 0x84, 0x80, 0x80, 0x80, 0x00, 0x00, 0x0b, 0x02, 0x00, 0x0b, + 0x0e, 0x00, 0x10, 0x8d, 0x80, 0x80, 0x80, 0x00, 0x10, 0x90, 0x80, 0x80, 0x80, 0x00, 0x0b, 0x08, 0x00, 0x41, + 0xa4, 0x89, 0x80, 0x80, 0x00, 0x0b, 0xa3, 0x03, 0x01, 0x03, 0x7f, 0x02, 0x40, 0x10, 0x8f, 0x80, 0x80, 0x80, + 0x00, 0x28, 0x02, 0x00, 0x22, 0x00, 0x45, 0x0d, 0x00, 0x03, 0x40, 0x02, 0x40, 0x20, 0x00, 0x28, 0x02, 0x14, + 0x20, 0x00, 0x28, 0x02, 0x18, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x00, 0x41, 0x00, 0x20, 0x00, 0x28, 0x02, + 0x20, 0x11, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1a, 0x0b, 0x02, 0x40, 0x20, 0x00, + 0x28, 0x02, 0x04, 0x22, 0x01, 0x20, 0x00, 0x28, 0x02, 0x08, 0x22, 0x02, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x20, + 0x01, 0x20, 0x02, 0x6b, 0xac, 0x41, 0x01, 0x20, 0x00, 0x28, 0x02, 0x24, 0x11, 0x81, 0x80, 0x80, 0x80, 0x00, + 0x80, 0x80, 0x80, 0x80, 0x00, 0x1a, 0x0b, 0x20, 0x00, 0x28, 0x02, 0x34, 0x22, 0x00, 0x0d, 0x00, 0x0b, 0x0b, + 0x02, 0x40, 0x41, 0x00, 0x28, 0x02, 0xa8, 0x89, 0x80, 0x80, 0x00, 0x22, 0x00, 0x45, 0x0d, 0x00, 0x02, 0x40, + 0x20, 0x00, 0x28, 0x02, 0x14, 0x20, 0x00, 0x28, 0x02, 0x18, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x00, 0x41, + 0x00, 0x20, 0x00, 0x28, 0x02, 0x20, 0x11, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1a, + 0x0b, 0x20, 0x00, 0x28, 0x02, 0x04, 0x22, 0x01, 0x20, 0x00, 0x28, 0x02, 0x08, 0x22, 0x02, 0x46, 0x0d, 0x00, + 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x6b, 0xac, 0x41, 0x01, 0x20, 0x00, 0x28, 0x02, 0x24, 0x11, 0x81, 0x80, + 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1a, 0x0b, 0x02, 0x40, 0x41, 0x00, 0x28, 0x02, 0x90, 0x89, + 0x80, 0x80, 0x00, 0x22, 0x00, 0x45, 0x0d, 0x00, 0x02, 0x40, 0x20, 0x00, 0x28, 0x02, 0x14, 0x20, 0x00, 0x28, + 0x02, 0x18, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x00, 0x41, 0x00, 0x20, 0x00, 0x28, 0x02, 0x20, 0x11, 0x80, + 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1a, 0x0b, 0x20, 0x00, 0x28, 0x02, 0x04, 0x22, 0x01, + 0x20, 0x00, 0x28, 0x02, 0x08, 0x22, 0x02, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x6b, 0xac, + 0x41, 0x01, 0x20, 0x00, 0x28, 0x02, 0x24, 0x11, 0x81, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, + 0x1a, 0x0b, 0x02, 0x40, 0x41, 0x00, 0x28, 0x02, 0xa8, 0x89, 0x80, 0x80, 0x00, 0x22, 0x00, 0x45, 0x0d, 0x00, + 0x02, 0x40, 0x20, 0x00, 0x28, 0x02, 0x14, 0x20, 0x00, 0x28, 0x02, 0x18, 0x46, 0x0d, 0x00, 0x20, 0x00, 0x41, + 0x00, 0x41, 0x00, 0x20, 0x00, 0x28, 0x02, 0x20, 0x11, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, + 0x00, 0x1a, 0x0b, 0x20, 0x00, 0x28, 0x02, 0x04, 0x22, 0x01, 0x20, 0x00, 0x28, 0x02, 0x08, 0x22, 0x02, 0x46, + 0x0d, 0x00, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x6b, 0xac, 0x41, 0x01, 0x20, 0x00, 0x28, 0x02, 0x24, 0x11, + 0x81, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x1a, 0x0b, 0x0b, 0x5c, 0x01, 0x01, 0x7f, 0x20, + 0x00, 0x20, 0x00, 0x28, 0x02, 0x3c, 0x22, 0x01, 0x41, 0x7f, 0x6a, 0x20, 0x01, 0x72, 0x36, 0x02, 0x3c, 0x02, + 0x40, 0x20, 0x00, 0x28, 0x02, 0x00, 0x22, 0x01, 0x41, 0x08, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x00, 0x20, 0x01, + 0x41, 0x20, 0x72, 0x36, 0x02, 0x00, 0x41, 0x7f, 0x0f, 0x0b, 0x20, 0x00, 0x42, 0x00, 0x37, 0x02, 0x04, 0x20, + 0x00, 0x20, 0x00, 0x28, 0x02, 0x28, 0x22, 0x01, 0x36, 0x02, 0x18, 0x20, 0x00, 0x20, 0x01, 0x36, 0x02, 0x14, + 0x20, 0x00, 0x20, 0x01, 0x20, 0x00, 0x28, 0x02, 0x2c, 0x6a, 0x36, 0x02, 0x10, 0x41, 0x00, 0x0b, 0xa8, 0x02, + 0x01, 0x05, 0x7f, 0x20, 0x02, 0x20, 0x01, 0x6c, 0x21, 0x04, 0x02, 0x40, 0x02, 0x40, 0x20, 0x03, 0x28, 0x02, + 0x10, 0x22, 0x05, 0x0d, 0x00, 0x41, 0x00, 0x21, 0x06, 0x20, 0x03, 0x10, 0x91, 0x80, 0x80, 0x80, 0x00, 0x0d, + 0x01, 0x20, 0x03, 0x28, 0x02, 0x10, 0x21, 0x05, 0x0b, 0x02, 0x40, 0x20, 0x05, 0x20, 0x03, 0x28, 0x02, 0x14, + 0x22, 0x07, 0x6b, 0x20, 0x04, 0x4f, 0x0d, 0x00, 0x20, 0x03, 0x20, 0x00, 0x20, 0x04, 0x20, 0x03, 0x28, 0x02, + 0x20, 0x11, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x21, 0x06, 0x0c, 0x01, 0x0b, 0x41, + 0x00, 0x21, 0x08, 0x02, 0x40, 0x02, 0x40, 0x20, 0x04, 0x0d, 0x00, 0x20, 0x04, 0x21, 0x05, 0x0c, 0x01, 0x0b, + 0x41, 0x00, 0x21, 0x05, 0x02, 0x40, 0x20, 0x03, 0x28, 0x02, 0x40, 0x41, 0x00, 0x4e, 0x0d, 0x00, 0x20, 0x04, + 0x21, 0x05, 0x0c, 0x01, 0x0b, 0x20, 0x00, 0x20, 0x04, 0x6a, 0x21, 0x06, 0x02, 0x40, 0x03, 0x40, 0x20, 0x06, + 0x20, 0x05, 0x6a, 0x41, 0x7f, 0x6a, 0x2d, 0x00, 0x00, 0x41, 0x0a, 0x46, 0x0d, 0x01, 0x20, 0x04, 0x20, 0x05, + 0x41, 0x7f, 0x6a, 0x22, 0x05, 0x6a, 0x0d, 0x00, 0x0b, 0x41, 0x00, 0x21, 0x08, 0x20, 0x04, 0x21, 0x05, 0x0c, + 0x01, 0x0b, 0x20, 0x03, 0x20, 0x00, 0x20, 0x04, 0x20, 0x05, 0x6a, 0x22, 0x08, 0x20, 0x03, 0x28, 0x02, 0x20, + 0x11, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x22, 0x06, 0x20, 0x08, 0x49, 0x0d, 0x01, + 0x20, 0x08, 0x20, 0x00, 0x6a, 0x21, 0x00, 0x41, 0x00, 0x20, 0x05, 0x6b, 0x21, 0x05, 0x20, 0x03, 0x28, 0x02, + 0x14, 0x21, 0x07, 0x0b, 0x20, 0x07, 0x20, 0x00, 0x20, 0x05, 0x10, 0x9f, 0x80, 0x80, 0x80, 0x00, 0x1a, 0x20, + 0x03, 0x20, 0x03, 0x28, 0x02, 0x14, 0x20, 0x05, 0x6a, 0x36, 0x02, 0x14, 0x20, 0x08, 0x20, 0x05, 0x6a, 0x21, + 0x06, 0x0b, 0x02, 0x40, 0x20, 0x06, 0x20, 0x04, 0x47, 0x0d, 0x00, 0x20, 0x02, 0x41, 0x00, 0x20, 0x01, 0x1b, + 0x0f, 0x0b, 0x20, 0x06, 0x20, 0x01, 0x6e, 0x0b, 0x24, 0x01, 0x01, 0x7f, 0x20, 0x00, 0x10, 0xa0, 0x80, 0x80, + 0x80, 0x00, 0x21, 0x02, 0x41, 0x7f, 0x41, 0x00, 0x20, 0x02, 0x20, 0x00, 0x41, 0x01, 0x20, 0x02, 0x20, 0x01, + 0x10, 0x92, 0x80, 0x80, 0x80, 0x00, 0x47, 0x1b, 0x0b, 0xb3, 0x01, 0x01, 0x03, 0x7f, 0x23, 0x80, 0x80, 0x80, + 0x80, 0x00, 0x41, 0x10, 0x6b, 0x22, 0x02, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, 0x02, 0x20, 0x01, 0x3a, + 0x00, 0x0f, 0x02, 0x40, 0x02, 0x40, 0x20, 0x00, 0x28, 0x02, 0x10, 0x22, 0x03, 0x0d, 0x00, 0x02, 0x40, 0x20, + 0x00, 0x10, 0x91, 0x80, 0x80, 0x80, 0x00, 0x45, 0x0d, 0x00, 0x41, 0x7f, 0x21, 0x03, 0x0c, 0x02, 0x0b, 0x20, + 0x00, 0x28, 0x02, 0x10, 0x21, 0x03, 0x0b, 0x02, 0x40, 0x20, 0x00, 0x28, 0x02, 0x14, 0x22, 0x04, 0x20, 0x03, + 0x46, 0x0d, 0x00, 0x20, 0x00, 0x28, 0x02, 0x40, 0x20, 0x01, 0x41, 0xff, 0x01, 0x71, 0x22, 0x03, 0x46, 0x0d, + 0x00, 0x20, 0x00, 0x20, 0x04, 0x41, 0x01, 0x6a, 0x36, 0x02, 0x14, 0x20, 0x04, 0x20, 0x01, 0x3a, 0x00, 0x00, + 0x0c, 0x01, 0x0b, 0x02, 0x40, 0x20, 0x00, 0x20, 0x02, 0x41, 0x0f, 0x6a, 0x41, 0x01, 0x20, 0x00, 0x28, 0x02, + 0x20, 0x11, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x01, 0x46, 0x0d, 0x00, 0x41, + 0x7f, 0x21, 0x03, 0x0c, 0x01, 0x0b, 0x20, 0x02, 0x2d, 0x00, 0x0f, 0x21, 0x03, 0x0b, 0x20, 0x02, 0x41, 0x10, + 0x6a, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, 0x03, 0x0b, 0x6c, 0x00, 0x02, 0x40, 0x20, 0x00, 0x41, 0xa0, + 0x88, 0x80, 0x80, 0x00, 0x10, 0x93, 0x80, 0x80, 0x80, 0x00, 0x41, 0x00, 0x4e, 0x0d, 0x00, 0x41, 0x7f, 0x0f, + 0x0b, 0x02, 0x40, 0x41, 0x00, 0x28, 0x02, 0xe0, 0x88, 0x80, 0x80, 0x00, 0x41, 0x0a, 0x46, 0x0d, 0x00, 0x41, + 0x00, 0x28, 0x02, 0xb4, 0x88, 0x80, 0x80, 0x00, 0x22, 0x00, 0x41, 0x00, 0x28, 0x02, 0xb0, 0x88, 0x80, 0x80, + 0x00, 0x46, 0x0d, 0x00, 0x41, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x36, 0x02, 0xb4, 0x88, 0x80, 0x80, 0x00, + 0x20, 0x00, 0x41, 0x0a, 0x3a, 0x00, 0x00, 0x41, 0x00, 0x0f, 0x0b, 0x41, 0xa0, 0x88, 0x80, 0x80, 0x00, 0x41, + 0x0a, 0x10, 0x94, 0x80, 0x80, 0x80, 0x00, 0x41, 0x1f, 0x75, 0x0b, 0x02, 0x00, 0x0b, 0x27, 0x00, 0x10, 0x96, + 0x80, 0x80, 0x80, 0x00, 0x02, 0x40, 0x20, 0x00, 0x10, 0x88, 0x80, 0x80, 0x80, 0x00, 0x22, 0x00, 0x0d, 0x00, + 0x41, 0x00, 0x0f, 0x0b, 0x41, 0x00, 0x20, 0x00, 0x36, 0x02, 0xac, 0x89, 0x80, 0x80, 0x00, 0x41, 0x7f, 0x0b, + 0x0d, 0x00, 0x20, 0x00, 0x28, 0x02, 0x38, 0x10, 0x97, 0x80, 0x80, 0x80, 0x00, 0x0b, 0x71, 0x01, 0x02, 0x7f, + 0x23, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x10, 0x6b, 0x22, 0x03, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, + 0x7f, 0x21, 0x04, 0x02, 0x40, 0x02, 0x40, 0x20, 0x02, 0x41, 0x7f, 0x4a, 0x0d, 0x00, 0x41, 0x00, 0x41, 0x1c, + 0x36, 0x02, 0xac, 0x89, 0x80, 0x80, 0x00, 0x0c, 0x01, 0x0b, 0x02, 0x40, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, + 0x20, 0x03, 0x41, 0x0c, 0x6a, 0x10, 0x8b, 0x80, 0x80, 0x80, 0x00, 0x22, 0x02, 0x45, 0x0d, 0x00, 0x41, 0x00, + 0x20, 0x02, 0x36, 0x02, 0xac, 0x89, 0x80, 0x80, 0x00, 0x41, 0x7f, 0x21, 0x04, 0x0c, 0x01, 0x0b, 0x20, 0x03, + 0x28, 0x02, 0x0c, 0x21, 0x04, 0x0b, 0x20, 0x03, 0x41, 0x10, 0x6a, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, + 0x04, 0x0b, 0xbb, 0x02, 0x01, 0x07, 0x7f, 0x23, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x10, 0x6b, 0x22, 0x03, + 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, 0x03, 0x20, 0x02, 0x36, 0x02, 0x0c, 0x20, 0x03, 0x20, 0x01, 0x36, + 0x02, 0x08, 0x20, 0x03, 0x20, 0x00, 0x28, 0x02, 0x18, 0x22, 0x01, 0x36, 0x02, 0x00, 0x20, 0x03, 0x20, 0x00, + 0x28, 0x02, 0x14, 0x20, 0x01, 0x6b, 0x22, 0x04, 0x36, 0x02, 0x04, 0x41, 0x02, 0x21, 0x05, 0x02, 0x40, 0x02, + 0x40, 0x20, 0x00, 0x28, 0x02, 0x38, 0x20, 0x03, 0x41, 0x02, 0x10, 0x99, 0x80, 0x80, 0x80, 0x00, 0x22, 0x01, + 0x20, 0x04, 0x20, 0x02, 0x6a, 0x22, 0x06, 0x46, 0x0d, 0x00, 0x20, 0x03, 0x21, 0x04, 0x03, 0x40, 0x02, 0x40, + 0x20, 0x01, 0x41, 0x7f, 0x4a, 0x0d, 0x00, 0x41, 0x00, 0x21, 0x01, 0x20, 0x00, 0x41, 0x00, 0x36, 0x02, 0x18, + 0x20, 0x00, 0x42, 0x00, 0x37, 0x03, 0x10, 0x20, 0x00, 0x20, 0x00, 0x28, 0x02, 0x00, 0x41, 0x20, 0x72, 0x36, + 0x02, 0x00, 0x20, 0x05, 0x41, 0x02, 0x46, 0x0d, 0x03, 0x20, 0x02, 0x20, 0x04, 0x28, 0x02, 0x04, 0x6b, 0x21, + 0x01, 0x0c, 0x03, 0x0b, 0x20, 0x04, 0x20, 0x01, 0x20, 0x04, 0x28, 0x02, 0x04, 0x22, 0x07, 0x4b, 0x22, 0x08, + 0x41, 0x03, 0x74, 0x6a, 0x22, 0x09, 0x20, 0x09, 0x28, 0x02, 0x00, 0x20, 0x01, 0x20, 0x07, 0x41, 0x00, 0x20, + 0x08, 0x1b, 0x6b, 0x22, 0x07, 0x6a, 0x36, 0x02, 0x00, 0x20, 0x04, 0x41, 0x0c, 0x41, 0x04, 0x20, 0x08, 0x1b, + 0x6a, 0x22, 0x04, 0x20, 0x04, 0x28, 0x02, 0x00, 0x20, 0x07, 0x6b, 0x36, 0x02, 0x00, 0x20, 0x09, 0x21, 0x04, + 0x20, 0x06, 0x20, 0x01, 0x6b, 0x22, 0x06, 0x20, 0x00, 0x28, 0x02, 0x38, 0x20, 0x09, 0x20, 0x05, 0x20, 0x08, + 0x6b, 0x22, 0x05, 0x10, 0x99, 0x80, 0x80, 0x80, 0x00, 0x22, 0x01, 0x47, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x00, + 0x20, 0x00, 0x28, 0x02, 0x28, 0x22, 0x01, 0x36, 0x02, 0x18, 0x20, 0x00, 0x20, 0x01, 0x36, 0x02, 0x14, 0x20, + 0x00, 0x20, 0x01, 0x20, 0x00, 0x28, 0x02, 0x2c, 0x6a, 0x36, 0x02, 0x10, 0x20, 0x02, 0x21, 0x01, 0x0b, 0x20, + 0x03, 0x41, 0x10, 0x6a, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, 0x01, 0x0b, 0x66, 0x01, 0x02, 0x7f, 0x23, + 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x20, 0x6b, 0x22, 0x01, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x02, 0x40, + 0x02, 0x40, 0x20, 0x00, 0x20, 0x01, 0x41, 0x08, 0x6a, 0x10, 0x89, 0x80, 0x80, 0x80, 0x00, 0x22, 0x00, 0x0d, + 0x00, 0x41, 0x3b, 0x21, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x08, 0x41, 0x02, 0x47, 0x0d, 0x00, 0x20, 0x01, 0x2d, + 0x00, 0x10, 0x41, 0x24, 0x71, 0x0d, 0x00, 0x41, 0x01, 0x21, 0x02, 0x0c, 0x01, 0x0b, 0x41, 0x00, 0x21, 0x02, + 0x41, 0x00, 0x20, 0x00, 0x36, 0x02, 0xac, 0x89, 0x80, 0x80, 0x00, 0x0b, 0x20, 0x01, 0x41, 0x20, 0x6a, 0x24, + 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, 0x02, 0x0b, 0x3b, 0x00, 0x20, 0x00, 0x41, 0x81, 0x80, 0x80, 0x80, 0x00, + 0x36, 0x02, 0x20, 0x02, 0x40, 0x20, 0x00, 0x2d, 0x00, 0x00, 0x41, 0xc0, 0x00, 0x71, 0x0d, 0x00, 0x20, 0x00, + 0x28, 0x02, 0x38, 0x10, 0x9b, 0x80, 0x80, 0x80, 0x00, 0x0d, 0x00, 0x20, 0x00, 0x41, 0x7f, 0x36, 0x02, 0x40, + 0x0b, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x10, 0x9a, 0x80, 0x80, 0x80, 0x00, 0x0b, 0x64, 0x01, 0x01, 0x7f, + 0x23, 0x80, 0x80, 0x80, 0x80, 0x00, 0x41, 0x10, 0x6b, 0x22, 0x03, 0x24, 0x80, 0x80, 0x80, 0x80, 0x00, 0x02, + 0x40, 0x02, 0x40, 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0x41, 0xff, 0x01, 0x71, 0x20, 0x03, 0x41, 0x08, 0x6a, + 0x10, 0x8a, 0x80, 0x80, 0x80, 0x00, 0x22, 0x02, 0x45, 0x0d, 0x00, 0x41, 0x00, 0x41, 0xc6, 0x00, 0x20, 0x02, + 0x20, 0x02, 0x41, 0xcc, 0x00, 0x46, 0x1b, 0x36, 0x02, 0xac, 0x89, 0x80, 0x80, 0x00, 0x42, 0x7f, 0x21, 0x01, + 0x0c, 0x01, 0x0b, 0x20, 0x03, 0x29, 0x03, 0x08, 0x21, 0x01, 0x0b, 0x20, 0x03, 0x41, 0x10, 0x6a, 0x24, 0x80, + 0x80, 0x80, 0x80, 0x00, 0x20, 0x01, 0x0b, 0x11, 0x00, 0x20, 0x00, 0x28, 0x02, 0x38, 0x20, 0x01, 0x20, 0x02, + 0x10, 0x9d, 0x80, 0x80, 0x80, 0x00, 0x0b, 0xee, 0x07, 0x01, 0x04, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, + 0x20, 0x02, 0x41, 0x20, 0x4b, 0x0d, 0x00, 0x20, 0x01, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x01, 0x20, 0x02, 0x45, + 0x0d, 0x01, 0x20, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x02, 0x41, 0x7f, 0x6a, 0x21, + 0x03, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x21, 0x04, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x22, 0x05, 0x41, 0x03, 0x71, + 0x45, 0x0d, 0x02, 0x20, 0x03, 0x45, 0x0d, 0x02, 0x20, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x01, 0x3a, 0x00, 0x01, + 0x20, 0x02, 0x41, 0x7e, 0x6a, 0x21, 0x03, 0x20, 0x00, 0x41, 0x02, 0x6a, 0x21, 0x04, 0x20, 0x01, 0x41, 0x02, + 0x6a, 0x22, 0x05, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x02, 0x20, 0x03, 0x45, 0x0d, 0x02, 0x20, 0x00, 0x20, 0x01, + 0x2d, 0x00, 0x02, 0x3a, 0x00, 0x02, 0x20, 0x02, 0x41, 0x7d, 0x6a, 0x21, 0x03, 0x20, 0x00, 0x41, 0x03, 0x6a, + 0x21, 0x04, 0x20, 0x01, 0x41, 0x03, 0x6a, 0x22, 0x05, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x02, 0x20, 0x03, 0x45, + 0x0d, 0x02, 0x20, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x03, 0x3a, 0x00, 0x03, 0x20, 0x02, 0x41, 0x7c, 0x6a, 0x21, + 0x03, 0x20, 0x00, 0x41, 0x04, 0x6a, 0x21, 0x04, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x05, 0x0c, 0x02, 0x0b, + 0x20, 0x00, 0x20, 0x01, 0x20, 0x02, 0xfc, 0x0a, 0x00, 0x00, 0x20, 0x00, 0x0f, 0x0b, 0x20, 0x02, 0x21, 0x03, + 0x20, 0x00, 0x21, 0x04, 0x20, 0x01, 0x21, 0x05, 0x0b, 0x02, 0x40, 0x02, 0x40, 0x20, 0x04, 0x41, 0x03, 0x71, + 0x22, 0x02, 0x0d, 0x00, 0x02, 0x40, 0x02, 0x40, 0x20, 0x03, 0x41, 0x10, 0x4f, 0x0d, 0x00, 0x20, 0x03, 0x21, + 0x02, 0x0c, 0x01, 0x0b, 0x02, 0x40, 0x20, 0x03, 0x41, 0x70, 0x6a, 0x22, 0x02, 0x41, 0x10, 0x71, 0x0d, 0x00, + 0x20, 0x04, 0x20, 0x05, 0x29, 0x02, 0x00, 0x37, 0x02, 0x00, 0x20, 0x04, 0x20, 0x05, 0x29, 0x02, 0x08, 0x37, + 0x02, 0x08, 0x20, 0x04, 0x41, 0x10, 0x6a, 0x21, 0x04, 0x20, 0x05, 0x41, 0x10, 0x6a, 0x21, 0x05, 0x20, 0x02, + 0x21, 0x03, 0x0b, 0x20, 0x02, 0x41, 0x10, 0x49, 0x0d, 0x00, 0x20, 0x03, 0x21, 0x02, 0x03, 0x40, 0x20, 0x04, + 0x20, 0x05, 0x29, 0x02, 0x00, 0x37, 0x02, 0x00, 0x20, 0x04, 0x20, 0x05, 0x29, 0x02, 0x08, 0x37, 0x02, 0x08, + 0x20, 0x04, 0x20, 0x05, 0x29, 0x02, 0x10, 0x37, 0x02, 0x10, 0x20, 0x04, 0x20, 0x05, 0x29, 0x02, 0x18, 0x37, + 0x02, 0x18, 0x20, 0x04, 0x41, 0x20, 0x6a, 0x21, 0x04, 0x20, 0x05, 0x41, 0x20, 0x6a, 0x21, 0x05, 0x20, 0x02, + 0x41, 0x60, 0x6a, 0x22, 0x02, 0x41, 0x0f, 0x4b, 0x0d, 0x00, 0x0b, 0x0b, 0x02, 0x40, 0x20, 0x02, 0x41, 0x08, + 0x49, 0x0d, 0x00, 0x20, 0x04, 0x20, 0x05, 0x29, 0x02, 0x00, 0x37, 0x02, 0x00, 0x20, 0x05, 0x41, 0x08, 0x6a, + 0x21, 0x05, 0x20, 0x04, 0x41, 0x08, 0x6a, 0x21, 0x04, 0x0b, 0x02, 0x40, 0x20, 0x02, 0x41, 0x04, 0x71, 0x45, + 0x0d, 0x00, 0x20, 0x04, 0x20, 0x05, 0x28, 0x02, 0x00, 0x36, 0x02, 0x00, 0x20, 0x05, 0x41, 0x04, 0x6a, 0x21, + 0x05, 0x20, 0x04, 0x41, 0x04, 0x6a, 0x21, 0x04, 0x0b, 0x02, 0x40, 0x20, 0x02, 0x41, 0x02, 0x71, 0x45, 0x0d, + 0x00, 0x20, 0x04, 0x20, 0x05, 0x2f, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x20, 0x04, 0x41, 0x02, 0x6a, 0x21, 0x04, + 0x20, 0x05, 0x41, 0x02, 0x6a, 0x21, 0x05, 0x0b, 0x20, 0x02, 0x41, 0x01, 0x71, 0x45, 0x0d, 0x01, 0x20, 0x04, + 0x20, 0x05, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, 0x00, 0x0f, 0x0b, 0x02, 0x40, 0x02, 0x40, 0x02, 0x40, + 0x02, 0x40, 0x02, 0x40, 0x20, 0x03, 0x41, 0x20, 0x49, 0x0d, 0x00, 0x20, 0x04, 0x20, 0x05, 0x28, 0x02, 0x00, + 0x22, 0x03, 0x3a, 0x00, 0x00, 0x02, 0x40, 0x02, 0x40, 0x20, 0x02, 0x41, 0x7f, 0x6a, 0x0e, 0x03, 0x03, 0x00, + 0x01, 0x03, 0x0b, 0x20, 0x04, 0x20, 0x03, 0x41, 0x08, 0x76, 0x3a, 0x00, 0x01, 0x20, 0x04, 0x20, 0x05, 0x41, + 0x06, 0x6a, 0x29, 0x01, 0x00, 0x37, 0x02, 0x06, 0x20, 0x04, 0x20, 0x05, 0x28, 0x02, 0x04, 0x41, 0x10, 0x74, + 0x20, 0x03, 0x41, 0x10, 0x76, 0x72, 0x36, 0x02, 0x02, 0x20, 0x04, 0x41, 0x12, 0x6a, 0x21, 0x02, 0x20, 0x05, + 0x41, 0x12, 0x6a, 0x21, 0x01, 0x41, 0x0e, 0x21, 0x06, 0x20, 0x05, 0x41, 0x0e, 0x6a, 0x28, 0x01, 0x00, 0x21, + 0x05, 0x41, 0x0e, 0x21, 0x03, 0x0c, 0x03, 0x0b, 0x20, 0x04, 0x20, 0x05, 0x41, 0x05, 0x6a, 0x29, 0x00, 0x00, + 0x37, 0x02, 0x05, 0x20, 0x04, 0x20, 0x05, 0x28, 0x02, 0x04, 0x41, 0x18, 0x74, 0x20, 0x03, 0x41, 0x08, 0x76, + 0x72, 0x36, 0x02, 0x01, 0x20, 0x04, 0x41, 0x11, 0x6a, 0x21, 0x02, 0x20, 0x05, 0x41, 0x11, 0x6a, 0x21, 0x01, + 0x41, 0x0d, 0x21, 0x06, 0x20, 0x05, 0x41, 0x0d, 0x6a, 0x28, 0x00, 0x00, 0x21, 0x05, 0x41, 0x0f, 0x21, 0x03, + 0x0c, 0x02, 0x0b, 0x02, 0x40, 0x02, 0x40, 0x20, 0x03, 0x41, 0x10, 0x4f, 0x0d, 0x00, 0x20, 0x04, 0x21, 0x02, + 0x20, 0x05, 0x21, 0x01, 0x0c, 0x01, 0x0b, 0x20, 0x04, 0x20, 0x05, 0x2d, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x20, + 0x04, 0x20, 0x05, 0x28, 0x00, 0x01, 0x36, 0x00, 0x01, 0x20, 0x04, 0x20, 0x05, 0x29, 0x00, 0x05, 0x37, 0x00, + 0x05, 0x20, 0x04, 0x20, 0x05, 0x2f, 0x00, 0x0d, 0x3b, 0x00, 0x0d, 0x20, 0x04, 0x20, 0x05, 0x2d, 0x00, 0x0f, + 0x3a, 0x00, 0x0f, 0x20, 0x04, 0x41, 0x10, 0x6a, 0x21, 0x02, 0x20, 0x05, 0x41, 0x10, 0x6a, 0x21, 0x01, 0x0b, + 0x20, 0x03, 0x41, 0x08, 0x71, 0x0d, 0x02, 0x0c, 0x03, 0x0b, 0x20, 0x04, 0x20, 0x03, 0x41, 0x10, 0x76, 0x3a, + 0x00, 0x02, 0x20, 0x04, 0x20, 0x03, 0x41, 0x08, 0x76, 0x3a, 0x00, 0x01, 0x20, 0x04, 0x20, 0x05, 0x41, 0x07, + 0x6a, 0x29, 0x00, 0x00, 0x37, 0x02, 0x07, 0x20, 0x04, 0x20, 0x05, 0x28, 0x02, 0x04, 0x41, 0x08, 0x74, 0x20, + 0x03, 0x41, 0x18, 0x76, 0x72, 0x36, 0x02, 0x03, 0x20, 0x04, 0x41, 0x13, 0x6a, 0x21, 0x02, 0x20, 0x05, 0x41, + 0x13, 0x6a, 0x21, 0x01, 0x41, 0x0f, 0x21, 0x06, 0x20, 0x05, 0x41, 0x0f, 0x6a, 0x28, 0x00, 0x00, 0x21, 0x05, + 0x41, 0x0d, 0x21, 0x03, 0x0b, 0x20, 0x04, 0x20, 0x06, 0x6a, 0x20, 0x05, 0x36, 0x02, 0x00, 0x0b, 0x20, 0x02, + 0x20, 0x01, 0x29, 0x00, 0x00, 0x37, 0x00, 0x00, 0x20, 0x02, 0x41, 0x08, 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, + 0x08, 0x6a, 0x21, 0x01, 0x0b, 0x02, 0x40, 0x20, 0x03, 0x41, 0x04, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x02, 0x20, + 0x01, 0x28, 0x00, 0x00, 0x36, 0x00, 0x00, 0x20, 0x02, 0x41, 0x04, 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, 0x04, + 0x6a, 0x21, 0x01, 0x0b, 0x02, 0x40, 0x20, 0x03, 0x41, 0x02, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x02, 0x20, 0x01, + 0x2f, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x20, 0x02, 0x41, 0x02, 0x6a, 0x21, 0x02, 0x20, 0x01, 0x41, 0x02, 0x6a, + 0x21, 0x01, 0x0b, 0x20, 0x03, 0x41, 0x01, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x02, 0x20, 0x01, 0x2d, 0x00, 0x00, + 0x3a, 0x00, 0x00, 0x0b, 0x20, 0x00, 0x0b, 0xcf, 0x01, 0x01, 0x03, 0x7f, 0x20, 0x00, 0x21, 0x01, 0x02, 0x40, + 0x02, 0x40, 0x20, 0x00, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, 0x02, 0x40, 0x20, 0x00, 0x2d, 0x00, 0x00, 0x0d, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x6b, 0x0f, 0x0b, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x22, 0x01, 0x41, 0x03, 0x71, + 0x45, 0x0d, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x45, 0x0d, 0x01, 0x20, 0x00, 0x41, 0x02, 0x6a, 0x22, 0x01, + 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x45, 0x0d, 0x01, 0x20, 0x00, 0x41, 0x03, + 0x6a, 0x22, 0x01, 0x41, 0x03, 0x71, 0x45, 0x0d, 0x00, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x45, 0x0d, 0x01, 0x20, + 0x00, 0x41, 0x04, 0x6a, 0x22, 0x01, 0x41, 0x03, 0x71, 0x0d, 0x01, 0x0b, 0x20, 0x01, 0x41, 0x7c, 0x6a, 0x21, + 0x02, 0x20, 0x01, 0x41, 0x7b, 0x6a, 0x21, 0x01, 0x03, 0x40, 0x20, 0x01, 0x41, 0x04, 0x6a, 0x21, 0x01, 0x41, + 0x80, 0x82, 0x84, 0x08, 0x20, 0x02, 0x41, 0x04, 0x6a, 0x22, 0x02, 0x28, 0x02, 0x00, 0x22, 0x03, 0x6b, 0x20, + 0x03, 0x72, 0x41, 0x80, 0x81, 0x82, 0x84, 0x78, 0x71, 0x41, 0x80, 0x81, 0x82, 0x84, 0x78, 0x46, 0x0d, 0x00, + 0x0b, 0x03, 0x40, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x20, 0x02, 0x2d, 0x00, 0x00, 0x21, 0x03, 0x20, + 0x02, 0x41, 0x01, 0x6a, 0x21, 0x02, 0x20, 0x03, 0x0d, 0x00, 0x0b, 0x0b, 0x20, 0x01, 0x20, 0x00, 0x6b, 0x0b, + 0x0b, 0x9d, 0x01, 0x02, 0x00, 0x41, 0x80, 0x08, 0x0b, 0x1c, 0x0a, 0x0a, 0x09, 0x48, 0x65, 0x6c, 0x6c, 0x6f, + 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x4f, 0x63, 0x72, 0x65, 0x21, 0x0a, + 0x0a, 0x00, 0x00, 0x41, 0xa0, 0x08, 0x0b, 0x74, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xb8, 0x04, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00}; -static unsigned int wasm_binary_len = 3850; +static const unsigned int wasm_binary_len = 3850; #endif // OCRE_INPUT_FILE_H diff --git a/src/ocre/ocre_messaging/ocre_messaging.c b/src/ocre/ocre_messaging/ocre_messaging.c index 29cfe5c2..4d68a71f 100644 --- a/src/ocre/ocre_messaging/ocre_messaging.c +++ b/src/ocre/ocre_messaging/ocre_messaging.c @@ -20,255 +20,263 @@ LOG_MODULE_DECLARE(ocre_cs_component, OCRE_LOG_LEVEL); /* Messaging subscription structure */ typedef struct { - char topic[OCRE_MAX_TOPIC_LEN]; - wasm_module_inst_t module_inst; - bool is_active; + char topic[OCRE_MAX_TOPIC_LEN]; + wasm_module_inst_t module_inst; + bool is_active; } ocre_messaging_subscription_t; typedef struct { - ocre_messaging_subscription_t subscriptions[CONFIG_MESSAGING_MAX_SUBSCRIPTIONS]; - uint16_t subscription_count; - core_mutex_t mutex; + ocre_messaging_subscription_t subscriptions[CONFIG_MESSAGING_MAX_SUBSCRIPTIONS]; + uint16_t subscription_count; + core_mutex_t mutex; } ocre_messaging_system_t; static ocre_messaging_system_t messaging_system = {0}; static bool messaging_system_initialized = false; /* Initialize messaging system */ -int ocre_messaging_init(void) { - if (messaging_system_initialized) { - LOG_INF("Messaging system already initialized"); - return 0; - } - - if (!common_initialized && ocre_common_init() != 0) { - LOG_ERR("Failed to initialize common subsystem"); - return -EAGAIN; - } - - memset(&messaging_system, 0, sizeof(ocre_messaging_system_t)); - - core_mutex_init(&messaging_system.mutex); - - ocre_register_cleanup_handler(OCRE_RESOURCE_TYPE_MESSAGING, ocre_messaging_cleanup_container); - messaging_system_initialized = true; - LOG_INF("Messaging system initialized"); - return 0; +int ocre_messaging_init(void) +{ + if (messaging_system_initialized) { + LOG_INF("Messaging system already initialized"); + return 0; + } + + if (!common_initialized && ocre_common_init() != 0) { + LOG_ERR("Failed to initialize common subsystem"); + return -EAGAIN; + } + + memset(&messaging_system, 0, sizeof(ocre_messaging_system_t)); + + core_mutex_init(&messaging_system.mutex); + + ocre_register_cleanup_handler(OCRE_RESOURCE_TYPE_MESSAGING, ocre_messaging_cleanup_container); + messaging_system_initialized = true; + LOG_INF("Messaging system initialized"); + return 0; } /* Cleanup messaging resources for a module */ -void ocre_messaging_cleanup_container(wasm_module_inst_t module_inst) { - if (!messaging_system_initialized || !module_inst) { - return; - } - - core_mutex_lock(&messaging_system.mutex); - - for (int i = 0; i < CONFIG_MESSAGING_MAX_SUBSCRIPTIONS; i++) { - if (messaging_system.subscriptions[i].is_active && - messaging_system.subscriptions[i].module_inst == module_inst) { - messaging_system.subscriptions[i].is_active = false; - messaging_system.subscriptions[i].module_inst = NULL; - messaging_system.subscriptions[i].topic[0] = '\0'; - messaging_system.subscription_count--; - ocre_decrement_resource_count(module_inst, OCRE_RESOURCE_TYPE_MESSAGING); - LOG_DBG("Cleaned up subscription %d for module %p", i, (void *)module_inst); - } - } - - core_mutex_unlock(&messaging_system.mutex); - - LOG_DBG("Cleaned up messaging resources for module %p", (void *)module_inst); +void ocre_messaging_cleanup_container(wasm_module_inst_t module_inst) +{ + if (!messaging_system_initialized || !module_inst) { + return; + } + + core_mutex_lock(&messaging_system.mutex); + + for (int i = 0; i < CONFIG_MESSAGING_MAX_SUBSCRIPTIONS; i++) { + if (messaging_system.subscriptions[i].is_active && + messaging_system.subscriptions[i].module_inst == module_inst) { + messaging_system.subscriptions[i].is_active = false; + messaging_system.subscriptions[i].module_inst = NULL; + messaging_system.subscriptions[i].topic[0] = '\0'; + messaging_system.subscription_count--; + ocre_decrement_resource_count(module_inst, OCRE_RESOURCE_TYPE_MESSAGING); + LOG_DBG("Cleaned up subscription %d for module %p", i, (void *)module_inst); + } + } + + core_mutex_unlock(&messaging_system.mutex); + + LOG_DBG("Cleaned up messaging resources for module %p", (void *)module_inst); } /* Subscribe to a topic */ -int ocre_messaging_subscribe(wasm_exec_env_t exec_env, void *topic) { - if (!messaging_system_initialized) { - if (ocre_messaging_init() != 0) { - LOG_ERR("Failed to initialize messaging system"); - return -EINVAL; - } - } - - if (!topic || ((char *)topic)[0] == '\0') { - LOG_ERR("Topic is NULL or empty"); - return -EINVAL; - } - - wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); - if (!module_inst) { - LOG_ERR("No module instance for exec_env"); - return -EINVAL; - } - - ocre_module_context_t *ctx = ocre_get_module_context(module_inst); - if (!ctx) { - LOG_ERR("Module context not found for module instance %p", (void *)module_inst); - return -EINVAL; - } - - core_mutex_lock(&messaging_system.mutex); - - // Check if already subscribed - for (int i = 0; i < CONFIG_MESSAGING_MAX_SUBSCRIPTIONS; i++) { - if (messaging_system.subscriptions[i].is_active && - messaging_system.subscriptions[i].module_inst == module_inst && - strcmp(messaging_system.subscriptions[i].topic, (char *)topic) == 0) { - LOG_INF("Already subscribed to topic: %s", (char *)topic); - core_mutex_unlock(&messaging_system.mutex); - return 0; - } - } - - // Find a free slot - for (int i = 0; i < CONFIG_MESSAGING_MAX_SUBSCRIPTIONS; i++) { - if (!messaging_system.subscriptions[i].is_active) { - strncpy(messaging_system.subscriptions[i].topic, (char *)topic, OCRE_MAX_TOPIC_LEN - 1); - messaging_system.subscriptions[i].topic[OCRE_MAX_TOPIC_LEN - 1] = '\0'; - messaging_system.subscriptions[i].module_inst = module_inst; - messaging_system.subscriptions[i].is_active = true; - messaging_system.subscription_count++; - ocre_increment_resource_count(module_inst, OCRE_RESOURCE_TYPE_MESSAGING); - LOG_INF("Subscribed to topic: %s, module: %p", (char *)topic, (void *)module_inst); - core_mutex_unlock(&messaging_system.mutex); - return 0; - } - } - - core_mutex_unlock(&messaging_system.mutex); - - LOG_ERR("No free subscription slots available"); - return -ENOMEM; +int ocre_messaging_subscribe(wasm_exec_env_t exec_env, void *topic) +{ + if (!messaging_system_initialized) { + if (ocre_messaging_init() != 0) { + LOG_ERR("Failed to initialize messaging system"); + return -EINVAL; + } + } + + if (!topic || ((char *)topic)[0] == '\0') { + LOG_ERR("Topic is NULL or empty"); + return -EINVAL; + } + + wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); + if (!module_inst) { + LOG_ERR("No module instance for exec_env"); + return -EINVAL; + } + + ocre_module_context_t *ctx = ocre_get_module_context(module_inst); + if (!ctx) { + LOG_ERR("Module context not found for module instance %p", (void *)module_inst); + return -EINVAL; + } + + core_mutex_lock(&messaging_system.mutex); + + // Check if already subscribed + for (int i = 0; i < CONFIG_MESSAGING_MAX_SUBSCRIPTIONS; i++) { + if (messaging_system.subscriptions[i].is_active && + messaging_system.subscriptions[i].module_inst == module_inst && + strcmp(messaging_system.subscriptions[i].topic, (char *)topic) == 0) { + LOG_INF("Already subscribed to topic: %s", (char *)topic); + core_mutex_unlock(&messaging_system.mutex); + return 0; + } + } + + // Find a free slot + for (int i = 0; i < CONFIG_MESSAGING_MAX_SUBSCRIPTIONS; i++) { + if (!messaging_system.subscriptions[i].is_active) { + strncpy(messaging_system.subscriptions[i].topic, (char *)topic, OCRE_MAX_TOPIC_LEN - 1); + messaging_system.subscriptions[i].topic[OCRE_MAX_TOPIC_LEN - 1] = '\0'; + messaging_system.subscriptions[i].module_inst = module_inst; + messaging_system.subscriptions[i].is_active = true; + messaging_system.subscription_count++; + ocre_increment_resource_count(module_inst, OCRE_RESOURCE_TYPE_MESSAGING); + LOG_INF("Subscribed to topic: %s, module: %p", (char *)topic, (void *)module_inst); + core_mutex_unlock(&messaging_system.mutex); + return 0; + } + } + + core_mutex_unlock(&messaging_system.mutex); + + LOG_ERR("No free subscription slots available"); + return -ENOMEM; } /* Publish a message */ -int ocre_messaging_publish(wasm_exec_env_t exec_env, void *topic, void *content_type, void *payload, int payload_len) { - if (!messaging_system_initialized) { - if (ocre_messaging_init() != 0) { - LOG_ERR("Failed to initialize messaging system"); - return -EINVAL; - } - } - - if (!topic || ((char *)topic)[0] == '\0') { - LOG_ERR("Topic is NULL or empty"); - return -EINVAL; - } - if (!content_type || ((char *)content_type)[0] == '\0') { - LOG_ERR("Content type is NULL or empty"); - return -EINVAL; - } - if (!payload || payload_len <= 0) { - LOG_ERR("Payload is NULL or payload_len is invalid"); - return -EINVAL; - } - - wasm_module_inst_t publisher_module = wasm_runtime_get_module_inst(exec_env); - if (!publisher_module) { - LOG_ERR("No module instance for exec_env"); - return -EINVAL; - } - - static uint32_t message_id = 0; - bool message_sent = false; - - core_mutex_lock(&messaging_system.mutex); - - // Find matching subscriptions - for (int i = 0; i < CONFIG_MESSAGING_MAX_SUBSCRIPTIONS; i++) { - if (!messaging_system.subscriptions[i].is_active) { - continue; - } - - // Check if the published topic matches the subscription (prefix match) - const char *subscribed_topic = messaging_system.subscriptions[i].topic; - size_t subscribed_len = strlen(subscribed_topic); - - if (strncmp(subscribed_topic, (char *)topic, subscribed_len) != 0) { - continue; // No prefix match - } - - wasm_module_inst_t target_module = messaging_system.subscriptions[i].module_inst; - if (!target_module) { - LOG_ERR("Invalid module instance for subscription %d", i); - continue; - } - - // Allocate WASM memory for the target module - uint32_t topic_offset = (uint32_t)wasm_runtime_module_dup_data(target_module, (char *)topic, strlen((char *)topic) + 1); - if (topic_offset == 0) { - LOG_ERR("Failed to allocate WASM memory for topic"); - continue; - } - - uint32_t content_offset = (uint32_t)wasm_runtime_module_dup_data(target_module, (char *)content_type, strlen((char *)content_type) + 1); - if (content_offset == 0) { - LOG_ERR("Failed to allocate WASM memory for content_type"); - wasm_runtime_module_free(target_module, topic_offset); - continue; - } - - uint32_t payload_offset = (uint32_t)wasm_runtime_module_dup_data(target_module, payload, payload_len); - if (payload_offset == 0) { - LOG_ERR("Failed to allocate WASM memory for payload"); - wasm_runtime_module_free(target_module, topic_offset); - wasm_runtime_module_free(target_module, content_offset); - continue; - } - - // Create and queue the messaging event - ocre_event_t event; - event.type = OCRE_RESOURCE_TYPE_MESSAGING; - event.data.messaging_event.message_id = message_id; - event.data.messaging_event.topic = topic; - event.data.messaging_event.topic_offset = topic_offset; - event.data.messaging_event.content_type = content_type; - event.data.messaging_event.content_type_offset = content_offset; - event.data.messaging_event.payload = payload; - event.data.messaging_event.payload_offset = payload_offset; - event.data.messaging_event.payload_len = (uint32_t)payload_len; - event.owner = target_module; - - LOG_DBG("Creating messaging event: ID=%d, topic=%s, content_type=%s, payload_len=%d for module %p", - message_id, (char *)topic, (char *)content_type, payload_len, (void *)target_module); - - core_spinlock_key_t key = core_spinlock_lock(&ocre_event_queue_lock); - if (core_eventq_put(&ocre_event_queue, &event) != 0) { - LOG_ERR("Failed to queue messaging event for message ID %d", message_id); - wasm_runtime_module_free(target_module, topic_offset); - wasm_runtime_module_free(target_module, content_offset); - wasm_runtime_module_free(target_module, payload_offset); - } else { - message_sent = true; - LOG_DBG("Queued messaging event for message ID %d", message_id); - } - core_spinlock_unlock(&ocre_event_queue_lock, key); - } - - core_mutex_unlock(&messaging_system.mutex); - - if (message_sent) { - LOG_DBG("Published message: ID=%d, topic=%s, content_type=%s, payload_len=%d", - message_id, (char *)topic, (char *)content_type, payload_len); - message_id++; - return 0; - } else { - LOG_WRN("No matching subscriptions found for topic %s", (char *)topic); - return -ENOENT; - } +int ocre_messaging_publish(wasm_exec_env_t exec_env, void *topic, void *content_type, void *payload, int payload_len) +{ + if (!messaging_system_initialized) { + if (ocre_messaging_init() != 0) { + LOG_ERR("Failed to initialize messaging system"); + return -EINVAL; + } + } + + if (!topic || ((char *)topic)[0] == '\0') { + LOG_ERR("Topic is NULL or empty"); + return -EINVAL; + } + if (!content_type || ((char *)content_type)[0] == '\0') { + LOG_ERR("Content type is NULL or empty"); + return -EINVAL; + } + if (!payload || payload_len <= 0) { + LOG_ERR("Payload is NULL or payload_len is invalid"); + return -EINVAL; + } + + wasm_module_inst_t publisher_module = wasm_runtime_get_module_inst(exec_env); + if (!publisher_module) { + LOG_ERR("No module instance for exec_env"); + return -EINVAL; + } + + static uint32_t message_id = 0; + bool message_sent = false; + + core_mutex_lock(&messaging_system.mutex); + + // Find matching subscriptions + for (int i = 0; i < CONFIG_MESSAGING_MAX_SUBSCRIPTIONS; i++) { + if (!messaging_system.subscriptions[i].is_active) { + continue; + } + + // Check if the published topic matches the subscription (prefix match) + const char *subscribed_topic = messaging_system.subscriptions[i].topic; + size_t subscribed_len = strlen(subscribed_topic); + + if (strncmp(subscribed_topic, (char *)topic, subscribed_len) != 0) { + continue; // No prefix match + } + + wasm_module_inst_t target_module = messaging_system.subscriptions[i].module_inst; + if (!target_module) { + LOG_ERR("Invalid module instance for subscription %d", i); + continue; + } + + // Allocate WASM memory for the target module + uint32_t topic_offset = + (uint32_t)wasm_runtime_module_dup_data(target_module, (char *)topic, strlen((char *)topic) + 1); + if (topic_offset == 0) { + LOG_ERR("Failed to allocate WASM memory for topic"); + continue; + } + + uint32_t content_offset = (uint32_t)wasm_runtime_module_dup_data(target_module, (char *)content_type, + strlen((char *)content_type) + 1); + if (content_offset == 0) { + LOG_ERR("Failed to allocate WASM memory for content_type"); + wasm_runtime_module_free(target_module, topic_offset); + continue; + } + + uint32_t payload_offset = (uint32_t)wasm_runtime_module_dup_data(target_module, payload, payload_len); + if (payload_offset == 0) { + LOG_ERR("Failed to allocate WASM memory for payload"); + wasm_runtime_module_free(target_module, topic_offset); + wasm_runtime_module_free(target_module, content_offset); + continue; + } + + // Create and queue the messaging event + ocre_event_t event; + event.type = OCRE_RESOURCE_TYPE_MESSAGING; + event.data.messaging_event.message_id = message_id; + event.data.messaging_event.topic = topic; + event.data.messaging_event.topic_offset = topic_offset; + event.data.messaging_event.content_type = content_type; + event.data.messaging_event.content_type_offset = content_offset; + event.data.messaging_event.payload = payload; + event.data.messaging_event.payload_offset = payload_offset; + event.data.messaging_event.payload_len = (uint32_t)payload_len; + event.owner = target_module; + + LOG_DBG("Creating messaging event: ID=%d, topic=%s, content_type=%s, payload_len=%d for module %p", + message_id, (char *)topic, (char *)content_type, payload_len, (void *)target_module); + + core_spinlock_key_t key = core_spinlock_lock(&ocre_event_queue_lock); + if (core_eventq_put(&ocre_event_queue, &event) != 0) { + LOG_ERR("Failed to queue messaging event for message ID %d", message_id); + wasm_runtime_module_free(target_module, topic_offset); + wasm_runtime_module_free(target_module, content_offset); + wasm_runtime_module_free(target_module, payload_offset); + } else { + message_sent = true; + LOG_DBG("Queued messaging event for message ID %d", message_id); + } + core_spinlock_unlock(&ocre_event_queue_lock, key); + } + + core_mutex_unlock(&messaging_system.mutex); + + if (message_sent) { + LOG_DBG("Published message: ID=%d, topic=%s, content_type=%s, payload_len=%d", message_id, + (char *)topic, (char *)content_type, payload_len); + message_id++; + return 0; + } else { + LOG_WRN("No matching subscriptions found for topic %s", (char *)topic); + return -ENOENT; + } } /* Free module event data */ -int ocre_messaging_free_module_event_data(wasm_exec_env_t exec_env, uint32_t topic_offset, uint32_t content_offset, uint32_t payload_offset) { - wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); - if (!module_inst) { - LOG_ERR("Cannot find module_inst for free event data"); - return -EINVAL; - } - - wasm_runtime_module_free(module_inst, topic_offset); - wasm_runtime_module_free(module_inst, content_offset); - wasm_runtime_module_free(module_inst, payload_offset); - - return 0; +int ocre_messaging_free_module_event_data(wasm_exec_env_t exec_env, uint32_t topic_offset, uint32_t content_offset, + uint32_t payload_offset) +{ + wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); + if (!module_inst) { + LOG_ERR("Cannot find module_inst for free event data"); + return -EINVAL; + } + + wasm_runtime_module_free(module_inst, topic_offset); + wasm_runtime_module_free(module_inst, content_offset); + wasm_runtime_module_free(module_inst, payload_offset); + + return 0; } diff --git a/src/ocre/ocre_messaging/ocre_messaging.h b/src/ocre/ocre_messaging/ocre_messaging.h index d46eb56e..9d74d1a2 100644 --- a/src/ocre/ocre_messaging/ocre_messaging.h +++ b/src/ocre/ocre_messaging/ocre_messaging.h @@ -18,11 +18,11 @@ * @brief Structure representing an OCRE message. */ typedef struct { - uint32_t mid; ///< Message ID - void *topic; ///< Topic of the message (pointer to string) - void *content_type; ///< Content type (e.g., MIME type, pointer to string) - void *payload; ///< Message payload - uint32_t payload_len; ///< Length of the payload + uint32_t mid; ///< Message ID + void *topic; ///< Topic of the message (pointer to string) + void *content_type; ///< Content type (e.g., MIME type, pointer to string) + void *payload; ///< Message payload + uint32_t payload_len; ///< Length of the payload } ocre_msg_t; /** @@ -73,6 +73,6 @@ void ocre_messaging_cleanup_container(wasm_module_inst_t module_inst); * @return OCRE_SUCCESS on success, negative error code on failure. */ int ocre_messaging_free_module_event_data(wasm_exec_env_t exec_env, uint32_t topic_offset, uint32_t content_offset, - uint32_t payload_offset); + uint32_t payload_offset); #endif /* OCRE_MESSAGING_H */ diff --git a/src/ocre/ocre_sensors/ocre_sensors.c b/src/ocre/ocre_sensors/ocre_sensors.c index e2d36dd8..3e1af8c1 100644 --- a/src/ocre/ocre_sensors/ocre_sensors.c +++ b/src/ocre/ocre_sensors/ocre_sensors.c @@ -13,14 +13,14 @@ LOG_MODULE_DECLARE(ocre_sensors, OCRE_LOG_LEVEL); #include "ocre_sensors.h" -#define DEVICE_NODE DT_PATH(devices) +#define DEVICE_NODE DT_PATH(devices) #define HAS_DEVICE_NODES DT_NODE_EXISTS(DEVICE_NODE) && DT_PROP_LEN(DEVICE_NODE, device_list) > 1 /* Define sensor discovery names from device tree if available */ #if (CONFIG_OCRE_SENSORS) && (HAS_DEVICE_NODES) #define EXTRACT_LABELS(node_id, prop, idx) DT_PROP_BY_PHANDLE_IDX_OR(node_id, prop, idx, label, "undefined") static const char *sensor_discovery_names[] = { - DT_FOREACH_PROP_ELEM_SEP(DEVICE_NODE, device_list, EXTRACT_LABELS, (, ))}; + DT_FOREACH_PROP_ELEM_SEP(DEVICE_NODE, device_list, EXTRACT_LABELS, (, ))}; static int sensor_names_count = sizeof(sensor_discovery_names) / sizeof(sensor_discovery_names[0]); #else static const char *sensor_discovery_names[] = {}; @@ -28,266 +28,282 @@ static int sensor_names_count = 0; #endif typedef struct { - const struct device *device; - ocre_sensor_t info; - bool in_use; + const struct device *device; + ocre_sensor_t info; + bool in_use; } ocre_sensor_internal_t; static ocre_sensor_internal_t sensors[CONFIG_MAX_SENSORS] = {0}; static int sensor_count = 0; -static int set_opened_channels(const struct device *dev, enum sensor_channel *channels) { - if (!channels) { - LOG_ERR("Channels array is NULL"); - return -EINVAL; - } - - if (!device_is_ready(dev)) { - LOG_ERR("Device is not ready"); - return -ENODEV; - } - - if (sensor_sample_fetch(dev) < 0) { - LOG_WRN("Failed to fetch sensor data - sensor might not be initialized"); - } - - int count = 0; - struct sensor_value value = {}; - - for (int channel = 0; channel < SENSOR_CHAN_ALL && count < CONFIG_MAX_CHANNELS_PER_SENSOR; channel++) { - if (channel != SENSOR_CHAN_ACCEL_XYZ && channel != SENSOR_CHAN_GYRO_XYZ && channel != SENSOR_CHAN_MAGN_XYZ && - channel != SENSOR_CHAN_POS_DXYZ) { - if (sensor_channel_get(dev, channel, &value) == 0) { - channels[count] = channel; - count++; - } - } - } - return count; +static int set_opened_channels(const struct device *dev, enum sensor_channel *channels) +{ + if (!channels) { + LOG_ERR("Channels array is NULL"); + return -EINVAL; + } + + if (!device_is_ready(dev)) { + LOG_ERR("Device is not ready"); + return -ENODEV; + } + + if (sensor_sample_fetch(dev) < 0) { + LOG_WRN("Failed to fetch sensor data - sensor might not be initialized"); + } + + int count = 0; + struct sensor_value value = {}; + + for (int channel = 0; channel < SENSOR_CHAN_ALL && count < CONFIG_MAX_CHANNELS_PER_SENSOR; channel++) { + if (channel != SENSOR_CHAN_ACCEL_XYZ && channel != SENSOR_CHAN_GYRO_XYZ && + channel != SENSOR_CHAN_MAGN_XYZ && channel != SENSOR_CHAN_POS_DXYZ) { + if (sensor_channel_get(dev, channel, &value) == 0) { + channels[count] = channel; + count++; + } + } + } + return count; } -int ocre_sensors_init(wasm_exec_env_t exec_env) { - memset(sensors, 0, sizeof(sensors)); - sensor_count = 0; - return 0; +int ocre_sensors_init(wasm_exec_env_t exec_env) +{ + memset(sensors, 0, sizeof(sensors)); + sensor_count = 0; + return 0; } -int ocre_sensors_open(wasm_exec_env_t exec_env, ocre_sensor_handle_t handle) { - if (handle < 0 || handle >= sensor_count || !sensors[handle].in_use) { - LOG_ERR("Invalid sensor handle: %d", handle); - return -EINVAL; - } +int ocre_sensors_open(wasm_exec_env_t exec_env, ocre_sensor_handle_t handle) +{ + if (handle < 0 || handle >= sensor_count || !sensors[handle].in_use) { + LOG_ERR("Invalid sensor handle: %d", handle); + return -EINVAL; + } - if (!device_is_ready(sensors[handle].device)) { - LOG_ERR("Device %s is not ready", sensors[handle].info.sensor_name); - return -ENODEV; - } + if (!device_is_ready(sensors[handle].device)) { + LOG_ERR("Device %s is not ready", sensors[handle].info.sensor_name); + return -ENODEV; + } - return 0; + return 0; } -int ocre_sensors_discover(wasm_exec_env_t exec_env) { - memset(sensors, 0, sizeof(sensors)); - sensor_count = 0; - - const struct device *dev = NULL; - size_t device_count = z_device_get_all_static(&dev); - - if (!dev) { - LOG_ERR("Device list is NULL. Possible memory corruption!"); - return -EINVAL; - } - if (device_count == 0) { - LOG_ERR("No static devices found"); - return -ENODEV; - } - - LOG_INF("Total static devices found: %zu", device_count); - - for (size_t i = 0; i < device_count && sensor_count < CONFIG_MAX_SENSORS; i++) { - if (!dev[i].name) { - LOG_ERR("Device %zu has NULL name, skipping!", i); - continue; - } - - LOG_INF("Checking device: %s", dev[i].name); - - bool sensor_found = false; - for (int j = 0; j < sensor_names_count; j++) { - if (strcmp(dev[i].name, sensor_discovery_names[j]) == 0) { - sensor_found = true; - break; - } - } - if (!sensor_found) { - LOG_WRN("Skipping device, not in sensor list: %s", dev[i].name); - continue; - } - - const struct sensor_driver_api *api = (const struct sensor_driver_api *)dev[i].api; - if (!api || !api->channel_get) { - LOG_WRN("Device %s does not support sensor API or channel_get, skipping", dev[i].name); - continue; - } - - if (sensor_count >= CONFIG_MAX_SENSORS) { - LOG_WRN("Max sensor limit reached, skipping device: %s", dev[i].name); - continue; - } - - ocre_sensor_internal_t *sensor = &sensors[sensor_count]; - sensor->device = &dev[i]; - sensor->in_use = true; - sensor->info.handle = sensor_count; - - strncpy(sensor->info.sensor_name, dev[i].name, CONFIG_MAX_SENSOR_NAME_LENGTH - 1); - sensor->info.sensor_name[CONFIG_MAX_SENSOR_NAME_LENGTH - 1] = '\0'; - - sensor->info.num_channels = set_opened_channels(&dev[i], sensor->info.channels); - if (sensor->info.num_channels <= 0) { - LOG_WRN("Device %s does not have opened channels, skipping", dev[i].name); - continue; - } - - LOG_INF("Device has %d channels", sensor->info.num_channels); - sensor_count++; - } - - LOG_INF("Discovered %d sensors", sensor_count); - return sensor_count; +int ocre_sensors_discover(wasm_exec_env_t exec_env) +{ + memset(sensors, 0, sizeof(sensors)); + sensor_count = 0; + + const struct device *dev = NULL; + size_t device_count = z_device_get_all_static(&dev); + + if (!dev) { + LOG_ERR("Device list is NULL. Possible memory corruption!"); + return -EINVAL; + } + if (device_count == 0) { + LOG_ERR("No static devices found"); + return -ENODEV; + } + + LOG_INF("Total static devices found: %zu", device_count); + + for (size_t i = 0; i < device_count && sensor_count < CONFIG_MAX_SENSORS; i++) { + if (!dev[i].name) { + LOG_ERR("Device %zu has NULL name, skipping!", i); + continue; + } + + LOG_INF("Checking device: %s", dev[i].name); + + bool sensor_found = false; + for (int j = 0; j < sensor_names_count; j++) { + if (strcmp(dev[i].name, sensor_discovery_names[j]) == 0) { + sensor_found = true; + break; + } + } + if (!sensor_found) { + LOG_WRN("Skipping device, not in sensor list: %s", dev[i].name); + continue; + } + + const struct sensor_driver_api *api = (const struct sensor_driver_api *)dev[i].api; + if (!api || !api->channel_get) { + LOG_WRN("Device %s does not support sensor API or channel_get, skipping", dev[i].name); + continue; + } + + if (sensor_count >= CONFIG_MAX_SENSORS) { + LOG_WRN("Max sensor limit reached, skipping device: %s", dev[i].name); + continue; + } + + ocre_sensor_internal_t *sensor = &sensors[sensor_count]; + sensor->device = &dev[i]; + sensor->in_use = true; + sensor->info.handle = sensor_count; + + strncpy(sensor->info.sensor_name, dev[i].name, CONFIG_MAX_SENSOR_NAME_LENGTH - 1); + sensor->info.sensor_name[CONFIG_MAX_SENSOR_NAME_LENGTH - 1] = '\0'; + + sensor->info.num_channels = set_opened_channels(&dev[i], sensor->info.channels); + if (sensor->info.num_channels <= 0) { + LOG_WRN("Device %s does not have opened channels, skipping", dev[i].name); + continue; + } + + LOG_INF("Device has %d channels", sensor->info.num_channels); + sensor_count++; + } + + LOG_INF("Discovered %d sensors", sensor_count); + return sensor_count; } -int ocre_sensors_get_handle(wasm_exec_env_t exec_env, int sensor_id) { - if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use) { - return -EINVAL; - } - return sensors[sensor_id].info.handle; +int ocre_sensors_get_handle(wasm_exec_env_t exec_env, int sensor_id) +{ + if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use) { + return -EINVAL; + } + return sensors[sensor_id].info.handle; } -int ocre_sensors_get_name(wasm_exec_env_t exec_env, int sensor_id, char *buffer, int buffer_size) { - if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use || !buffer) { - return -EINVAL; - } +int ocre_sensors_get_name(wasm_exec_env_t exec_env, int sensor_id, char *buffer, int buffer_size) +{ + if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use || !buffer) { + return -EINVAL; + } - int name_len = strlen(sensors[sensor_id].info.sensor_name); - if (name_len >= buffer_size) { - return -ENOSPC; - } + int name_len = strlen(sensors[sensor_id].info.sensor_name); + if (name_len >= buffer_size) { + return -ENOSPC; + } - strncpy(buffer, sensors[sensor_id].info.sensor_name, buffer_size - 1); - buffer[buffer_size - 1] = '\0'; - return name_len; + strncpy(buffer, sensors[sensor_id].info.sensor_name, buffer_size - 1); + buffer[buffer_size - 1] = '\0'; + return name_len; } -int ocre_sensors_get_channel_count(wasm_exec_env_t exec_env, int sensor_id) { - if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use) { - return -EINVAL; - } - return sensors[sensor_id].info.num_channels; +int ocre_sensors_get_channel_count(wasm_exec_env_t exec_env, int sensor_id) +{ + if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use) { + return -EINVAL; + } + return sensors[sensor_id].info.num_channels; } -int ocre_sensors_get_channel_type(wasm_exec_env_t exec_env, int sensor_id, int channel_index) { - if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use || channel_index < 0 || - channel_index >= sensors[sensor_id].info.num_channels) { - return -EINVAL; - } - return sensors[sensor_id].info.channels[channel_index]; +int ocre_sensors_get_channel_type(wasm_exec_env_t exec_env, int sensor_id, int channel_index) +{ + if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use || channel_index < 0 || + channel_index >= sensors[sensor_id].info.num_channels) { + return -EINVAL; + } + return sensors[sensor_id].info.channels[channel_index]; } -double ocre_sensors_read(wasm_exec_env_t exec_env, int sensor_id, int channel_type) { - if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use) { - return -EINVAL; - } +double ocre_sensors_read(wasm_exec_env_t exec_env, int sensor_id, int channel_type) +{ + if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use) { + return -EINVAL; + } - const struct device *dev = sensors[sensor_id].device; - struct sensor_value value = {}; + const struct device *dev = sensors[sensor_id].device; + struct sensor_value value = {}; - if (sensor_sample_fetch(dev) < 0) { - LOG_ERR("Failed to fetch sensor data"); - return -EIO; - } + if (sensor_sample_fetch(dev) < 0) { + LOG_ERR("Failed to fetch sensor data"); + return -EIO; + } - if (sensor_channel_get(dev, channel_type, &value) < 0) { - LOG_ERR("Failed to get scalar channel data"); - return -EIO; - } + if (sensor_channel_get(dev, channel_type, &value) < 0) { + LOG_ERR("Failed to get scalar channel data"); + return -EIO; + } - return sensor_value_to_double(&value); + return sensor_value_to_double(&value); } -static int find_sensor_by_name(const char *name) { - if (!name) { - return -EINVAL; - } +static int find_sensor_by_name(const char *name) +{ + if (!name) { + return -EINVAL; + } - for (int i = 0; i < sensor_count; i++) { - if (sensors[i].in_use && strcmp(sensors[i].info.sensor_name, name) == 0) { - return i; - } - } + for (int i = 0; i < sensor_count; i++) { + if (sensors[i].in_use && strcmp(sensors[i].info.sensor_name, name) == 0) { + return i; + } + } - return -ENOENT; + return -ENOENT; } -int ocre_sensors_open_by_name(wasm_exec_env_t exec_env, const char *sensor_name) { - int sensor_id = find_sensor_by_name(sensor_name); - if (sensor_id < 0) { - LOG_ERR("Sensor not found: %s", sensor_name); - return -ENOENT; - } +int ocre_sensors_open_by_name(wasm_exec_env_t exec_env, const char *sensor_name) +{ + int sensor_id = find_sensor_by_name(sensor_name); + if (sensor_id < 0) { + LOG_ERR("Sensor not found: %s", sensor_name); + return -ENOENT; + } - return ocre_sensors_open(exec_env, sensor_id); + return ocre_sensors_open(exec_env, sensor_id); } -int ocre_sensors_get_handle_by_name(wasm_exec_env_t exec_env, const char *sensor_name) { - int sensor_id = find_sensor_by_name(sensor_name); - if (sensor_id < 0) { - return -ENOENT; - } +int ocre_sensors_get_handle_by_name(wasm_exec_env_t exec_env, const char *sensor_name) +{ + int sensor_id = find_sensor_by_name(sensor_name); + if (sensor_id < 0) { + return -ENOENT; + } - return sensors[sensor_id].info.handle; + return sensors[sensor_id].info.handle; } -int ocre_sensors_get_channel_count_by_name(wasm_exec_env_t exec_env, const char *sensor_name) { - int sensor_id = find_sensor_by_name(sensor_name); - if (sensor_id < 0) { - return -ENOENT; - } +int ocre_sensors_get_channel_count_by_name(wasm_exec_env_t exec_env, const char *sensor_name) +{ + int sensor_id = find_sensor_by_name(sensor_name); + if (sensor_id < 0) { + return -ENOENT; + } - return sensors[sensor_id].info.num_channels; + return sensors[sensor_id].info.num_channels; } -int ocre_sensors_get_channel_type_by_name(wasm_exec_env_t exec_env, const char *sensor_name, int channel_index) { - int sensor_id = find_sensor_by_name(sensor_name); - if (sensor_id < 0) { - return -ENOENT; - } +int ocre_sensors_get_channel_type_by_name(wasm_exec_env_t exec_env, const char *sensor_name, int channel_index) +{ + int sensor_id = find_sensor_by_name(sensor_name); + if (sensor_id < 0) { + return -ENOENT; + } - return ocre_sensors_get_channel_type(exec_env, sensor_id, channel_index); + return ocre_sensors_get_channel_type(exec_env, sensor_id, channel_index); } -double ocre_sensors_read_by_name(wasm_exec_env_t exec_env, const char *sensor_name, int channel_type) { - int sensor_id = find_sensor_by_name(sensor_name); - if (sensor_id < 0) { - LOG_ERR("Sensor not found: %s", sensor_name); - return -ENOENT; - } +double ocre_sensors_read_by_name(wasm_exec_env_t exec_env, const char *sensor_name, int channel_type) +{ + int sensor_id = find_sensor_by_name(sensor_name); + if (sensor_id < 0) { + LOG_ERR("Sensor not found: %s", sensor_name); + return -ENOENT; + } - return ocre_sensors_read(exec_env, sensor_id, channel_type); + return ocre_sensors_read(exec_env, sensor_id, channel_type); } -int ocre_sensors_get_list(wasm_exec_env_t exec_env, char **name_list, int max_names) { - if (!name_list || max_names <= 0) { - return -EINVAL; - } - - int count = 0; - for (int i = 0; i < sensor_count && count < max_names; i++) { - if (sensors[i].in_use) { - name_list[count] = (char *)sensors[i].info.sensor_name; - count++; - } - } - - return count; +int ocre_sensors_get_list(wasm_exec_env_t exec_env, char **name_list, int max_names) +{ + if (!name_list || max_names <= 0) { + return -EINVAL; + } + + int count = 0; + for (int i = 0; i < sensor_count && count < max_names; i++) { + if (sensors[i].in_use) { + name_list[count] = (char *)sensors[i].info.sensor_name; + count++; + } + } + + return count; } diff --git a/src/ocre/ocre_sensors/ocre_sensors.h b/src/ocre/ocre_sensors/ocre_sensors.h index badad07b..31059638 100644 --- a/src/ocre/ocre_sensors/ocre_sensors.h +++ b/src/ocre/ocre_sensors/ocre_sensors.h @@ -19,25 +19,25 @@ typedef int32_t ocre_sensor_handle_t; * @brief Enum representing different sensor channels */ typedef enum { - SENSOR_CHANNEL_ACCELERATION, - SENSOR_CHANNEL_GYRO, - SENSOR_CHANNEL_MAGNETIC_FIELD, - SENSOR_CHANNEL_LIGHT, - SENSOR_CHANNEL_PRESSURE, - SENSOR_CHANNEL_PROXIMITY, - SENSOR_CHANNEL_HUMIDITY, - SENSOR_CHANNEL_TEMPERATURE, - // Add more channels as needed + SENSOR_CHANNEL_ACCELERATION, + SENSOR_CHANNEL_GYRO, + SENSOR_CHANNEL_MAGNETIC_FIELD, + SENSOR_CHANNEL_LIGHT, + SENSOR_CHANNEL_PRESSURE, + SENSOR_CHANNEL_PROXIMITY, + SENSOR_CHANNEL_HUMIDITY, + SENSOR_CHANNEL_TEMPERATURE, + // Add more channels as needed } sensor_channel_t; /** * @brief Structure representing a sensor instance */ typedef struct ocre_sensor_t { - ocre_sensor_handle_t handle; - char sensor_name[CONFIG_MAX_SENSOR_NAME_LENGTH]; - int num_channels; - enum sensor_channel channels[CONFIG_MAX_CHANNELS_PER_SENSOR]; + ocre_sensor_handle_t handle; + char sensor_name[CONFIG_MAX_SENSOR_NAME_LENGTH]; + int num_channels; + enum sensor_channel channels[CONFIG_MAX_CHANNELS_PER_SENSOR]; } ocre_sensor_t; /** * @brief Initialize the sensor system diff --git a/src/ocre/ocre_sensors/rng_sensor.c b/src/ocre/ocre_sensors/rng_sensor.c index c172b59e..22acc6df 100644 --- a/src/ocre/ocre_sensors/rng_sensor.c +++ b/src/ocre/ocre_sensors/rng_sensor.c @@ -14,53 +14,56 @@ /* Define the sensor channels */ static enum sensor_channel rng_sensor_channels[] __attribute__((unused)) = { - SENSOR_CHAN_CUSTOM + 1, /* Define a custom channel */ + SENSOR_CHAN_CUSTOM + 1, /* Define a custom channel */ }; /* Define the sensor data structure */ struct rng_sensor_data { - struct sensor_value value; + struct sensor_value value; }; /* Define the sensor driver API functions */ /* Function to get sensor data */ -static int rng_sensor_sample_fetch(const struct device *dev, enum sensor_channel chan) { - struct rng_sensor_data *data = dev->data; +static int rng_sensor_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + struct rng_sensor_data *data = dev->data; - /* Generate a random 32-bit number */ - uint32_t random_number = sys_rand16_get(); + /* Generate a random 32-bit number */ + uint32_t random_number = sys_rand16_get(); - /* Store the random number in sensor_value */ - data->value.val1 = random_number; /* Integer part */ - data->value.val2 = 0; /* Fractional part */ + /* Store the random number in sensor_value */ + data->value.val1 = random_number; /* Integer part */ + data->value.val2 = 0; /* Fractional part */ - return 0; + return 0; } /* Function to retrieve sensor data */ -static int rng_sensor_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { - struct rng_sensor_data *data = dev->data; +static int rng_sensor_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) +{ + struct rng_sensor_data *data = dev->data; - if (chan != SENSOR_CHAN_CUSTOM + 1) { - return -ENOTSUP; - } + if (chan != SENSOR_CHAN_CUSTOM + 1) { + return -ENOTSUP; + } - *val = data->value; + *val = data->value; - return 0; + return 0; } /* Define the sensor driver API */ static const struct sensor_driver_api rng_sensor_api = { - .sample_fetch = rng_sensor_sample_fetch, - .channel_get = rng_sensor_channel_get, + .sample_fetch = rng_sensor_sample_fetch, + .channel_get = rng_sensor_channel_get, }; /* Initialization function */ -int rng_sensor_init(const struct device *dev) { - /* Initialization code if needed */ - return 0; +int rng_sensor_init(const struct device *dev) +{ + /* Initialization code if needed */ + return 0; } // /* Define the sensor device */ @@ -68,5 +71,5 @@ int rng_sensor_init(const struct device *dev) { static struct rng_sensor_data rng_sensor_data; DEVICE_DT_DEFINE(DT_DRV_INST(0), rng_sensor_init, NULL, &rng_sensor_data, NULL, POST_KERNEL, - CONFIG_SENSOR_INIT_PRIORITY, &rng_sensor_api); + CONFIG_SENSOR_INIT_PRIORITY, &rng_sensor_api); #endif diff --git a/src/ocre/ocre_timers/ocre_timer.c b/src/ocre/ocre_timers/ocre_timer.c index 02a67d91..c1ce7b57 100644 --- a/src/ocre/ocre_timers/ocre_timer.c +++ b/src/ocre/ocre_timers/ocre_timer.c @@ -19,14 +19,14 @@ LOG_MODULE_DECLARE(ocre_cs_component, OCRE_LOG_LEVEL); /* Unified timer structure using core_timer API */ typedef struct { - uint32_t in_use: 1; - uint32_t id: 8; // Up to 256 timers - uint32_t interval: 16; // Up to 65s intervals - uint32_t periodic: 1; - uint32_t running: 1; // Track if timer is currently running - uint32_t start_time; // Start time for remaining time calculations - core_timer_t timer; // Unified core timer - wasm_module_inst_t owner; + uint32_t in_use : 1; + uint32_t id : 8; // Up to 256 timers + uint32_t interval : 16; // Up to 65s intervals + uint32_t periodic : 1; + uint32_t running : 1; // Track if timer is currently running + uint32_t start_time; // Start time for remaining time calculations + core_timer_t timer; // Unified core timer + wasm_module_inst_t owner; } ocre_timer_internal; #ifndef CONFIG_MAX_TIMERS @@ -39,217 +39,225 @@ static bool timer_system_initialized = false; static void unified_timer_callback(void *user_data); -void ocre_timer_init(void) { - if (timer_system_initialized) { - LOG_INF("Timer system already initialized"); - return; - } +void ocre_timer_init(void) +{ + if (timer_system_initialized) { + LOG_INF("Timer system already initialized"); + return; + } - if (!common_initialized && ocre_common_init() != 0) { - LOG_ERR("Failed to initialize common subsystem"); - return; - } + if (!common_initialized && ocre_common_init() != 0) { + LOG_ERR("Failed to initialize common subsystem"); + return; + } - ocre_register_cleanup_handler(OCRE_RESOURCE_TYPE_TIMER, ocre_timer_cleanup_container); - timer_system_initialized = true; - LOG_INF("Timer system initialized"); + ocre_register_cleanup_handler(OCRE_RESOURCE_TYPE_TIMER, ocre_timer_cleanup_container); + timer_system_initialized = true; + LOG_INF("Timer system initialized"); } -int ocre_timer_create(wasm_exec_env_t exec_env, int id) { - wasm_module_inst_t module = wasm_runtime_get_module_inst(exec_env); - if (!module || id <= 0 || id > CONFIG_MAX_TIMERS) { - LOG_ERR("Invalid module %p or timer ID %d (max: %d)", (void *)module, id, CONFIG_MAX_TIMERS); - return -EINVAL; - } - - ocre_timer_internal *timer = &timers[id - 1]; - if (timer->in_use) { - LOG_ERR("Timer ID %d already in use", id); - return -EBUSY; - } - - timer->id = id; - timer->owner = module; - timer->in_use = 1; - - // Initialize unified core timer - if (core_timer_init(&timer->timer, unified_timer_callback, timer) != 0) { - LOG_ERR("Failed to initialize core timer %d", id); - timer->in_use = 0; - return -EINVAL; - } - - ocre_increment_resource_count(module, OCRE_RESOURCE_TYPE_TIMER); - LOG_INF("Created timer %d for module %p", id, (void *)module); - return 0; +int ocre_timer_create(wasm_exec_env_t exec_env, int id) +{ + wasm_module_inst_t module = wasm_runtime_get_module_inst(exec_env); + if (!module || id <= 0 || id > CONFIG_MAX_TIMERS) { + LOG_ERR("Invalid module %p or timer ID %d (max: %d)", (void *)module, id, CONFIG_MAX_TIMERS); + return -EINVAL; + } + + ocre_timer_internal *timer = &timers[id - 1]; + if (timer->in_use) { + LOG_ERR("Timer ID %d already in use", id); + return -EBUSY; + } + + timer->id = id; + timer->owner = module; + timer->in_use = 1; + + // Initialize unified core timer + if (core_timer_init(&timer->timer, unified_timer_callback, timer) != 0) { + LOG_ERR("Failed to initialize core timer %d", id); + timer->in_use = 0; + return -EINVAL; + } + + ocre_increment_resource_count(module, OCRE_RESOURCE_TYPE_TIMER); + LOG_INF("Created timer %d for module %p", id, (void *)module); + return 0; } -int ocre_timer_delete(wasm_exec_env_t exec_env, ocre_timer_t id) { - wasm_module_inst_t module = wasm_runtime_get_module_inst(exec_env); - if (!module || id <= 0 || id > CONFIG_MAX_TIMERS) { - LOG_ERR("Invalid module %p or timer ID %d", (void *)module, id); - return -EINVAL; - } - - ocre_timer_internal *timer = &timers[id - 1]; - if (!timer->in_use || timer->owner != module) { - LOG_ERR("Timer ID %d not in use or not owned by module %p", id, (void *)module); - return -EINVAL; - } - - // Stop unified core timer - core_timer_stop(&timer->timer); - - timer->in_use = 0; - timer->running = 0; - timer->owner = NULL; - ocre_decrement_resource_count(module, OCRE_RESOURCE_TYPE_TIMER); - LOG_INF("Deleted timer %d", id); - return 0; +int ocre_timer_delete(wasm_exec_env_t exec_env, ocre_timer_t id) +{ + wasm_module_inst_t module = wasm_runtime_get_module_inst(exec_env); + if (!module || id <= 0 || id > CONFIG_MAX_TIMERS) { + LOG_ERR("Invalid module %p or timer ID %d", (void *)module, id); + return -EINVAL; + } + + ocre_timer_internal *timer = &timers[id - 1]; + if (!timer->in_use || timer->owner != module) { + LOG_ERR("Timer ID %d not in use or not owned by module %p", id, (void *)module); + return -EINVAL; + } + + // Stop unified core timer + core_timer_stop(&timer->timer); + + timer->in_use = 0; + timer->running = 0; + timer->owner = NULL; + ocre_decrement_resource_count(module, OCRE_RESOURCE_TYPE_TIMER); + LOG_INF("Deleted timer %d", id); + return 0; } -int ocre_timer_start(wasm_exec_env_t exec_env, ocre_timer_t id, int interval, int is_periodic) { - wasm_module_inst_t module = wasm_runtime_get_module_inst(exec_env); - if (!module || id <= 0 || id > CONFIG_MAX_TIMERS) { - LOG_ERR("Invalid module %p or timer ID %d", (void *)module, id); - return -EINVAL; - } - - ocre_timer_internal *timer = &timers[id - 1]; - if (!timer->in_use || timer->owner != module) { - LOG_ERR("Timer ID %d not in use or not owned by module %p", id, (void *)module); - return -EINVAL; - } - - if (interval <= 0 || interval > 65535) { - LOG_ERR("Invalid interval %dms (must be 1-65535ms)", interval); - return -EINVAL; - } - - timer->interval = interval; - timer->periodic = is_periodic; - timer->start_time = core_uptime_get(); - timer->running = 1; - - // Start unified core timer - int period_ms = is_periodic ? interval : 0; - if (core_timer_start(&timer->timer, interval, period_ms) != 0) { - LOG_ERR("Failed to start core timer %d", id); - timer->running = 0; - return -EINVAL; - } - - LOG_INF("Started timer %d with interval %dms, periodic=%d", id, interval, is_periodic); - return 0; +int ocre_timer_start(wasm_exec_env_t exec_env, ocre_timer_t id, int interval, int is_periodic) +{ + wasm_module_inst_t module = wasm_runtime_get_module_inst(exec_env); + if (!module || id <= 0 || id > CONFIG_MAX_TIMERS) { + LOG_ERR("Invalid module %p or timer ID %d", (void *)module, id); + return -EINVAL; + } + + ocre_timer_internal *timer = &timers[id - 1]; + if (!timer->in_use || timer->owner != module) { + LOG_ERR("Timer ID %d not in use or not owned by module %p", id, (void *)module); + return -EINVAL; + } + + if (interval <= 0 || interval > 65535) { + LOG_ERR("Invalid interval %dms (must be 1-65535ms)", interval); + return -EINVAL; + } + + timer->interval = interval; + timer->periodic = is_periodic; + timer->start_time = core_uptime_get(); + timer->running = 1; + + // Start unified core timer + int period_ms = is_periodic ? interval : 0; + if (core_timer_start(&timer->timer, interval, period_ms) != 0) { + LOG_ERR("Failed to start core timer %d", id); + timer->running = 0; + return -EINVAL; + } + + LOG_INF("Started timer %d with interval %dms, periodic=%d", id, interval, is_periodic); + return 0; } -int ocre_timer_stop(wasm_exec_env_t exec_env, ocre_timer_t id) { - wasm_module_inst_t module = wasm_runtime_get_module_inst(exec_env); - if (!module || id <= 0 || id > CONFIG_MAX_TIMERS) { - LOG_ERR("Invalid module %p or timer ID %d", (void *)module, id); - return -EINVAL; - } - - ocre_timer_internal *timer = &timers[id - 1]; - if (!timer->in_use || timer->owner != module) { - LOG_ERR("Timer ID %d not in use or not owned by module %p", id, (void *)module); - return -EINVAL; - } - - // Stop unified core timer - core_timer_stop(&timer->timer); - timer->running = 0; - - LOG_INF("Stopped timer %d", id); - return 0; +int ocre_timer_stop(wasm_exec_env_t exec_env, ocre_timer_t id) +{ + wasm_module_inst_t module = wasm_runtime_get_module_inst(exec_env); + if (!module || id <= 0 || id > CONFIG_MAX_TIMERS) { + LOG_ERR("Invalid module %p or timer ID %d", (void *)module, id); + return -EINVAL; + } + + ocre_timer_internal *timer = &timers[id - 1]; + if (!timer->in_use || timer->owner != module) { + LOG_ERR("Timer ID %d not in use or not owned by module %p", id, (void *)module); + return -EINVAL; + } + + // Stop unified core timer + core_timer_stop(&timer->timer); + timer->running = 0; + + LOG_INF("Stopped timer %d", id); + return 0; } -int ocre_timer_get_remaining(wasm_exec_env_t exec_env, ocre_timer_t id) { - wasm_module_inst_t module = wasm_runtime_get_module_inst(exec_env); - if (!module || id <= 0 || id > CONFIG_MAX_TIMERS) { - LOG_ERR("Invalid module %p or timer ID %d", (void *)module, id); - return -EINVAL; - } - - ocre_timer_internal *timer = &timers[id - 1]; - if (!timer->in_use || timer->owner != module) { - LOG_ERR("Timer ID %d not in use or not owned by module %p", id, (void *)module); - return -EINVAL; - } - - int remaining; - if (!timer->running) { - remaining = 0; - } else { - uint32_t current_time = core_uptime_get(); - uint32_t elapsed = current_time - timer->start_time; - if (elapsed >= timer->interval) { - remaining = 0; // Timer should have expired - } else { - remaining = timer->interval - elapsed; - } - } - - LOG_INF("Timer %d remaining time: %dms", id, remaining); - return remaining; +int ocre_timer_get_remaining(wasm_exec_env_t exec_env, ocre_timer_t id) +{ + wasm_module_inst_t module = wasm_runtime_get_module_inst(exec_env); + if (!module || id <= 0 || id > CONFIG_MAX_TIMERS) { + LOG_ERR("Invalid module %p or timer ID %d", (void *)module, id); + return -EINVAL; + } + + ocre_timer_internal *timer = &timers[id - 1]; + if (!timer->in_use || timer->owner != module) { + LOG_ERR("Timer ID %d not in use or not owned by module %p", id, (void *)module); + return -EINVAL; + } + + int remaining; + if (!timer->running) { + remaining = 0; + } else { + uint32_t current_time = core_uptime_get(); + uint32_t elapsed = current_time - timer->start_time; + if (elapsed >= timer->interval) { + remaining = 0; // Timer should have expired + } else { + remaining = timer->interval - elapsed; + } + } + + LOG_INF("Timer %d remaining time: %dms", id, remaining); + return remaining; } -void ocre_timer_cleanup_container(wasm_module_inst_t module_inst) { - if (!module_inst) { - LOG_ERR("Invalid module instance for cleanup"); - return; - } - - for (int i = 0; i < CONFIG_MAX_TIMERS; i++) { - if (timers[i].in_use && timers[i].owner == module_inst) { - // Stop unified core timer - core_timer_stop(&timers[i].timer); - timers[i].in_use = 0; - timers[i].running = 0; - timers[i].owner = NULL; - ocre_decrement_resource_count(module_inst, OCRE_RESOURCE_TYPE_TIMER); - LOG_DBG("Cleaned up timer %d for module %p", i + 1, (void *)module_inst); - } - } - LOG_DBG("Cleaned up timer resources for module %p", (void *)module_inst); +void ocre_timer_cleanup_container(wasm_module_inst_t module_inst) +{ + if (!module_inst) { + LOG_ERR("Invalid module instance for cleanup"); + return; + } + + for (int i = 0; i < CONFIG_MAX_TIMERS; i++) { + if (timers[i].in_use && timers[i].owner == module_inst) { + // Stop unified core timer + core_timer_stop(&timers[i].timer); + timers[i].in_use = 0; + timers[i].running = 0; + timers[i].owner = NULL; + ocre_decrement_resource_count(module_inst, OCRE_RESOURCE_TYPE_TIMER); + LOG_DBG("Cleaned up timer %d for module %p", i + 1, (void *)module_inst); + } + } + LOG_DBG("Cleaned up timer resources for module %p", (void *)module_inst); } /* Unified timer callback using core_timer API */ -static void unified_timer_callback(void *user_data) { - if (!timer_system_initialized || !common_initialized || !ocre_event_queue_initialized) { - LOG_ERR("Timer, common, or event queue not initialized, skipping callback"); - return; - } - - ocre_timer_internal *timer = (ocre_timer_internal *)user_data; - if (!timer || !timer->in_use || !timer->owner) { - LOG_ERR("Invalid timer in callback: %p", (void *)timer); - return; - } - - LOG_DBG("Timer callback for timer %d", timer->id); - - // For non-periodic timers, mark as not running - if (!timer->periodic) { - timer->running = 0; - } else { - // For periodic timers, update start time for next cycle - timer->start_time = core_uptime_get(); - } - - // Create and queue timer event - ocre_event_t event; - event.type = OCRE_RESOURCE_TYPE_TIMER; - event.data.timer_event.timer_id = timer->id; - event.owner = timer->owner; - - LOG_DBG("Creating timer event: type=%d, id=%d, for owner %p", event.type, timer->id, (void *)timer->owner); - - core_spinlock_key_t key = core_spinlock_lock(&ocre_event_queue_lock); - if (core_eventq_put(&ocre_event_queue, &event) != 0) { - LOG_ERR("Failed to queue timer event for timer %d", timer->id); - } else { - LOG_DBG("Queued timer event for timer %d", timer->id); - } - core_spinlock_unlock(&ocre_event_queue_lock, key); +static void unified_timer_callback(void *user_data) +{ + if (!timer_system_initialized || !common_initialized || !ocre_event_queue_initialized) { + LOG_ERR("Timer, common, or event queue not initialized, skipping callback"); + return; + } + + ocre_timer_internal *timer = (ocre_timer_internal *)user_data; + if (!timer || !timer->in_use || !timer->owner) { + LOG_ERR("Invalid timer in callback: %p", (void *)timer); + return; + } + + LOG_DBG("Timer callback for timer %d", timer->id); + + // For non-periodic timers, mark as not running + if (!timer->periodic) { + timer->running = 0; + } else { + // For periodic timers, update start time for next cycle + timer->start_time = core_uptime_get(); + } + + // Create and queue timer event + ocre_event_t event; + event.type = OCRE_RESOURCE_TYPE_TIMER; + event.data.timer_event.timer_id = timer->id; + event.owner = timer->owner; + + LOG_DBG("Creating timer event: type=%d, id=%d, for owner %p", event.type, timer->id, (void *)timer->owner); + + core_spinlock_key_t key = core_spinlock_lock(&ocre_event_queue_lock); + if (core_eventq_put(&ocre_event_queue, &event) != 0) { + LOG_ERR("Failed to queue timer event for timer %d", timer->id); + } else { + LOG_DBG("Queued timer event for timer %d", timer->id); + } + core_spinlock_unlock(&ocre_event_queue_lock, key); } diff --git a/src/ocre/shell/ocre_shell.c b/src/ocre/shell/ocre_shell.c index 801b2193..a60e0c0a 100644 --- a/src/ocre/shell/ocre_shell.c +++ b/src/ocre/shell/ocre_shell.c @@ -1,152 +1,157 @@ -/** - * @copyright Copyright © contributors to Project Ocre, - * which has been established as Project Ocre a Series of LF Projects, LLC - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include "ocre_shell.h" - -static ocre_cs_ctx *ctx_internal; - -int cmd_ocre_run(const struct shell *shell, size_t argc, char **argv) { - if (!ctx_internal) { - shell_error(shell, "Internal context not initialized."); - return -1; - } - - if (argc != 2) { - shell_error(shell, "Usage: ocre run "); - return -EINVAL; - } - - char *endptr; - int container_id = (int)strtol(argv[1], &endptr, 10); - - if (endptr == argv[1]) { - shell_error(shell, "No digits were found in argument .\n"); - return -EINVAL; - } else if (*endptr != '\0') { - shell_error(shell, "Invalid character: %c\n", *endptr); - return -EINVAL; - } - - int ret = -1; - for (int i = 0; i < CONFIG_MAX_CONTAINERS; i++) { - if (container_id == ctx_internal->containers[i].container_ID) { - ret = ocre_container_runtime_run_container(container_id, NULL); - break; - } - } - - if (ret == CONTAINER_STATUS_RUNNING) { - shell_info(shell, "Container started. Name: %s, ID: %d", - ctx_internal->containers[container_id].ocre_container_data.name, container_id); - return 0; - } else { - shell_error(shell, "Failed to run container: %d", container_id); - return -EIO; - } -} - -int cmd_ocre_stop(const struct shell *shell, size_t argc, char **argv) { - if (!ctx_internal) { - shell_error(shell, "Internal context not initialized."); - return -1; - } - - if (argc != 2) { - shell_error(shell, "Usage: ocre stop "); - return -EINVAL; - } - - const char *name = argv[1]; - shell_info(shell, "OCRE Shell Request to stop container with name: %s", name); - - int ret = -1; - int container_id = -1; - for (int i = 0; i < CONFIG_MAX_CONTAINERS; i++) { - if (strcmp(ctx_internal->containers[i].ocre_container_data.name, name) == 0) { - container_id = ctx_internal->containers[i].container_ID; - ret = ocre_container_runtime_stop_container(container_id, NULL); - } - } - - if (ret == CONTAINER_STATUS_STOPPED) { - shell_info(shell, "Container stopped. Name: %s, ID: %d", name, container_id); - } else if (ret == -1) { - shell_error(shell, "Failed to found container: %s", name); - } else { - shell_error(shell, "Failed to stop container: %s", name); - } - - return ret; -} - -int cmd_ocre_restart(const struct shell *shell, size_t argc, char **argv) { - if (!ctx_internal) { - shell_error(shell, "Internal context not initialized."); - return -1; - } - - if (argc != 2) { - shell_error(shell, "Usage: ocre restart "); - return -EINVAL; - } - - const char *name = argv[1]; - shell_info(shell, "OCRE Shell Request to restart container with name: %s", name); - - int ret = -1; - int container_id = -1; - for (int i = 0; i < CONFIG_MAX_CONTAINERS; i++) { - if (strcmp(ctx_internal->containers[i].ocre_container_data.name, name) == 0) { - container_id = ctx_internal->containers[i].container_ID; - ret = ocre_container_runtime_restart_container(ctx_internal, container_id, NULL); - } - } - - if (ret == CONTAINER_STATUS_RUNNING) { - shell_info(shell, "Container restarted. Name: %s, ID: %d", name, container_id); - } else if (ret == -1) { - shell_error(shell, "Failed to found container: %s", name); - } else { - shell_error(shell, "Failed to restart container: %s, status: %d", name, ret); - } - - return ret; -} - -int cmd_ocre_ls(const struct shell *shell, size_t argc, char **argv) { - ARG_UNUSED(argc); - ARG_UNUSED(argv); - - if (!ctx_internal) { - shell_error(shell, "Internal context not initialized."); - return -1; - } - - for (int i = 0; i < CONFIG_MAX_CONTAINERS; i++) { - shell_info(shell, "Container ID: %d, name: %s, status: %d", ctx_internal->containers[i].container_ID, - ctx_internal->containers[i].ocre_container_data.name, - ctx_internal->containers[i].container_runtime_status); - } - - return 0; -} - -void register_ocre_shell(ocre_cs_ctx *ctx) { - ctx_internal = ctx; - - SHELL_STATIC_SUBCMD_SET_CREATE( - ocre_subcmds, SHELL_CMD(run, NULL, "Start a new container: ocre run ", cmd_ocre_run), - SHELL_CMD(stop, NULL, "Stop a container: ocre stop ", cmd_ocre_stop), - SHELL_CMD(restart, NULL, "Restart a container: ocre restart ", cmd_ocre_restart), - SHELL_CMD(ls, NULL, "List running containers and their status", cmd_ocre_ls), SHELL_SUBCMD_SET_END); - -#if defined(CONFIG_OCRE_SHELL) - SHELL_CMD_REGISTER(ocre, &ocre_subcmds, "OCRE agent commands", NULL); -#endif -} +/** + * @copyright Copyright © contributors to Project Ocre, + * which has been established as Project Ocre a Series of LF Projects, LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "ocre_shell.h" + +static ocre_cs_ctx *ctx_internal; + +int cmd_ocre_run(const struct shell *shell, size_t argc, char **argv) +{ + if (!ctx_internal) { + shell_error(shell, "Internal context not initialized."); + return -1; + } + + if (argc != 2) { + shell_error(shell, "Usage: ocre run "); + return -EINVAL; + } + + char *endptr; + int container_id = (int)strtol(argv[1], &endptr, 10); + + if (endptr == argv[1]) { + shell_error(shell, "No digits were found in argument .\n"); + return -EINVAL; + } else if (*endptr != '\0') { + shell_error(shell, "Invalid character: %c\n", *endptr); + return -EINVAL; + } + + int ret = -1; + for (int i = 0; i < CONFIG_MAX_CONTAINERS; i++) { + if (container_id == ctx_internal->containers[i].container_ID) { + ret = ocre_container_runtime_run_container(container_id, NULL); + break; + } + } + + if (ret == CONTAINER_STATUS_RUNNING) { + shell_info(shell, "Container started. Name: %s, ID: %d", + ctx_internal->containers[container_id].ocre_container_data.name, container_id); + return 0; + } else { + shell_error(shell, "Failed to run container: %d", container_id); + return -EIO; + } +} + +int cmd_ocre_stop(const struct shell *shell, size_t argc, char **argv) +{ + if (!ctx_internal) { + shell_error(shell, "Internal context not initialized."); + return -1; + } + + if (argc != 2) { + shell_error(shell, "Usage: ocre stop "); + return -EINVAL; + } + + const char *name = argv[1]; + shell_info(shell, "OCRE Shell Request to stop container with name: %s", name); + + int ret = -1; + int container_id = -1; + for (int i = 0; i < CONFIG_MAX_CONTAINERS; i++) { + if (strcmp(ctx_internal->containers[i].ocre_container_data.name, name) == 0) { + container_id = ctx_internal->containers[i].container_ID; + ret = ocre_container_runtime_stop_container(container_id, NULL); + } + } + + if (ret == CONTAINER_STATUS_STOPPED) { + shell_info(shell, "Container stopped. Name: %s, ID: %d", name, container_id); + } else if (ret == -1) { + shell_error(shell, "Failed to found container: %s", name); + } else { + shell_error(shell, "Failed to stop container: %s", name); + } + + return ret; +} + +int cmd_ocre_restart(const struct shell *shell, size_t argc, char **argv) +{ + if (!ctx_internal) { + shell_error(shell, "Internal context not initialized."); + return -1; + } + + if (argc != 2) { + shell_error(shell, "Usage: ocre restart "); + return -EINVAL; + } + + const char *name = argv[1]; + shell_info(shell, "OCRE Shell Request to restart container with name: %s", name); + + int ret = -1; + int container_id = -1; + for (int i = 0; i < CONFIG_MAX_CONTAINERS; i++) { + if (strcmp(ctx_internal->containers[i].ocre_container_data.name, name) == 0) { + container_id = ctx_internal->containers[i].container_ID; + ret = ocre_container_runtime_restart_container(ctx_internal, container_id, NULL); + } + } + + if (ret == CONTAINER_STATUS_RUNNING) { + shell_info(shell, "Container restarted. Name: %s, ID: %d", name, container_id); + } else if (ret == -1) { + shell_error(shell, "Failed to found container: %s", name); + } else { + shell_error(shell, "Failed to restart container: %s, status: %d", name, ret); + } + + return ret; +} + +int cmd_ocre_ls(const struct shell *shell, size_t argc, char **argv) +{ + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + if (!ctx_internal) { + shell_error(shell, "Internal context not initialized."); + return -1; + } + + for (int i = 0; i < CONFIG_MAX_CONTAINERS; i++) { + shell_info(shell, "Container ID: %d, name: %s, status: %d", ctx_internal->containers[i].container_ID, + ctx_internal->containers[i].ocre_container_data.name, + ctx_internal->containers[i].container_runtime_status); + } + + return 0; +} + +void register_ocre_shell(ocre_cs_ctx *ctx) +{ + ctx_internal = ctx; + + SHELL_STATIC_SUBCMD_SET_CREATE( + ocre_subcmds, SHELL_CMD(run, NULL, "Start a new container: ocre run ", cmd_ocre_run), + SHELL_CMD(stop, NULL, "Stop a container: ocre stop ", cmd_ocre_stop), + SHELL_CMD(restart, NULL, "Restart a container: ocre restart ", cmd_ocre_restart), + SHELL_CMD(ls, NULL, "List running containers and their status", cmd_ocre_ls), SHELL_SUBCMD_SET_END); + +#if defined(CONFIG_OCRE_SHELL) + SHELL_CMD_REGISTER(ocre, &ocre_subcmds, "OCRE agent commands", NULL); +#endif +} diff --git a/src/ocre/shell/ocre_shell.h b/src/ocre/shell/ocre_shell.h index 3bb0bb81..56238c85 100644 --- a/src/ocre/shell/ocre_shell.h +++ b/src/ocre/shell/ocre_shell.h @@ -1,22 +1,22 @@ -/** - * @copyright Copyright © contributors to Project Ocre, - * which has been established as Project Ocre a Series of LF Projects, LLC - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef OCRE_SHELL_H -#define OCRE_SHELL_H - -#include -#include "../src/ocre/ocre_container_runtime/ocre_container_runtime.h" - -// Function declarations for `config` subcommand handlers -int cmd_ocre_run(const struct shell *shell, size_t argc, char **argv); -int cmd_ocre_stop(const struct shell *shell, size_t argc, char **argv); -int cmd_ocre_ps(const struct shell *shell, size_t argc, char **argv); - -// Command registration function -void register_ocre_shell(ocre_cs_ctx *ctx); - -#endif /* OCRE_SHELL_H */ +/** + * @copyright Copyright © contributors to Project Ocre, + * which has been established as Project Ocre a Series of LF Projects, LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef OCRE_SHELL_H +#define OCRE_SHELL_H + +#include +#include "../src/ocre/ocre_container_runtime/ocre_container_runtime.h" + +// Function declarations for `config` subcommand handlers +int cmd_ocre_run(const struct shell *shell, size_t argc, char **argv); +int cmd_ocre_stop(const struct shell *shell, size_t argc, char **argv); +int cmd_ocre_ps(const struct shell *shell, size_t argc, char **argv); + +// Command registration function +void register_ocre_shell(ocre_cs_ctx *ctx); + +#endif /* OCRE_SHELL_H */ diff --git a/src/ocre/sm/sm.c b/src/ocre/sm/sm.c index 4c0068a2..cd72e30f 100644 --- a/src/ocre/sm/sm.c +++ b/src/ocre/sm/sm.c @@ -16,79 +16,85 @@ #include "sm.h" LOG_MODULE_REGISTER(state_machine, OCRE_LOG_LEVEL); -void sm_init(state_machine_t *sm, core_mq_t *msgq, void *msg, void *custom_ctx, const struct smf_state *hsm) { - sm->hsm = hsm; - sm->msgq = msgq; - sm->ctx.event.msg = msg; - sm->ctx.custom_ctx = custom_ctx; +void sm_init(state_machine_t *sm, core_mq_t *msgq, void *msg, void *custom_ctx, const struct smf_state *hsm) +{ + sm->hsm = hsm; + sm->msgq = msgq; + sm->ctx.event.msg = msg; + sm->ctx.custom_ctx = custom_ctx; } -int sm_run(state_machine_t *sm, int initial_state) { - int ret; +int sm_run(state_machine_t *sm, int initial_state) +{ + int ret; - smf_set_initial(SMF_CTX(&sm->ctx), &sm->hsm[initial_state]); + smf_set_initial(SMF_CTX(&sm->ctx), &sm->hsm[initial_state]); - while (true) { - // Wait for a message from the queue - core_mq_recv(sm->msgq, sm->ctx.event.msg); - sm->ctx.event.handled = false; + while (true) { + // Wait for a message from the queue + core_mq_recv(sm->msgq, sm->ctx.event.msg); + sm->ctx.event.handled = false; - ret = smf_run_state(SMF_CTX(&sm->ctx)); + ret = smf_run_state(SMF_CTX(&sm->ctx)); - if (ret) { - LOG_ERR("State machine error: %d", ret); - break; - } + if (ret) { + LOG_ERR("State machine error: %d", ret); + break; + } - if (!sm->ctx.event.handled) { - struct ocre_message const *msg = SM_GET_EVENT(&sm->ctx); - LOG_ERR("Unhandled event: msg type or data = %d", msg->event); - } + if (!sm->ctx.event.handled) { + struct ocre_message const *msg = SM_GET_EVENT(&sm->ctx); + LOG_ERR("Unhandled event: msg type or data = %d", msg->event); + } - // Yield the current thread to allow the queue events to be processed - core_yield(); - } + // Yield the current thread to allow the queue events to be processed + core_yield(); + } - return ret; + return ret; } -int sm_transition(state_machine_t *sm, int target_state) { - if (!sm->hsm) { - LOG_ERR("State machine has not been initialized"); - return -EINVAL; - } +int sm_transition(state_machine_t *sm, int target_state) +{ + if (!sm->hsm) { + LOG_ERR("State machine has not been initialized"); + return -EINVAL; + } - smf_set_state(SMF_CTX(&sm->ctx), &sm->hsm[target_state]); + smf_set_state(SMF_CTX(&sm->ctx), &sm->hsm[target_state]); - return 0; + return 0; } -int sm_init_event_timer(state_machine_t *sm, int timer_id, void *timer_cb) { - if (timer_id < 0 || timer_id >= MAX_TIMERS) { - LOG_ERR("Invalid timer id: %d", timer_id); - return -EINVAL; - } - - core_timer_init(&sm->timers[timer_id], timer_cb, NULL); - return 0; +int sm_init_event_timer(state_machine_t *sm, int timer_id, void *timer_cb) +{ + if (timer_id < 0 || timer_id >= MAX_TIMERS) { + LOG_ERR("Invalid timer id: %d", timer_id); + return -EINVAL; + } + + core_timer_init(&sm->timers[timer_id], timer_cb, NULL); + return 0; } -int sm_set_event_timer(state_machine_t *sm, int timer_id, int duration, int period) { - if (timer_id < 0 || timer_id >= MAX_TIMERS) { - LOG_ERR("Invalid timer id: %d", timer_id); - return -EINVAL; - } +int sm_set_event_timer(state_machine_t *sm, int timer_id, int duration, int period) +{ + if (timer_id < 0 || timer_id >= MAX_TIMERS) { + LOG_ERR("Invalid timer id: %d", timer_id); + return -EINVAL; + } - core_timer_start(&sm->timers[timer_id], duration, period); - return 0; + core_timer_start(&sm->timers[timer_id], duration, period); + return 0; } -int sm_clear_event_timer(state_machine_t *sm, int timer_id) { - if (timer_id < 0 || timer_id >= MAX_TIMERS) { - LOG_ERR("Invalid timer id: %d", timer_id); - return -EINVAL; - } +int sm_clear_event_timer(state_machine_t *sm, int timer_id) +{ + if (timer_id < 0 || timer_id >= MAX_TIMERS) { + LOG_ERR("Invalid timer id: %d", timer_id); + return -EINVAL; + } - core_timer_stop(&sm->timers[timer_id]); - return 0; + core_timer_stop(&sm->timers[timer_id]); + return 0; } diff --git a/src/ocre/sm/sm.h b/src/ocre/sm/sm.h index f2fd9803..ec0fbb6b 100644 --- a/src/ocre/sm/sm.h +++ b/src/ocre/sm/sm.h @@ -13,28 +13,28 @@ #define MAX_TIMERS 3 #define SM_RETURN_IF_EVENT_HANDLED(o) \ - if (((struct sm_ctx *)o)->event.handled) \ - return SMF_EVENT_HANDLED + if (((struct sm_ctx *)o)->event.handled) \ + return SMF_EVENT_HANDLED #define SM_MARK_EVENT_HANDLED(o) ((struct sm_ctx *)o)->event.handled = true -#define SM_GET_EVENT(o) ((struct sm_ctx *)o)->event.msg -#define SM_GET_CUSTOM_CTX(o) ((struct sm_ctx *)o)->custom_ctx +#define SM_GET_EVENT(o) ((struct sm_ctx *)o)->event.msg +#define SM_GET_CUSTOM_CTX(o) ((struct sm_ctx *)o)->custom_ctx #define EVENT_LOG_MSG(fmt, event) LOG_DBG(fmt, event) struct sm_ctx { - struct smf_ctx ctx; - struct { - bool handled; - void *msg; - } event; - void *custom_ctx; + struct smf_ctx ctx; + struct { + bool handled; + void *msg; + } event; + void *custom_ctx; }; typedef struct state_machine { - core_mq_t *msgq; - core_timer_t timers[MAX_TIMERS]; - struct sm_ctx ctx; /*!< State machine context */ - const struct smf_state *hsm; /*!< State machine states */ + core_mq_t *msgq; + core_timer_t timers[MAX_TIMERS]; + struct sm_ctx ctx; /*!< State machine context */ + const struct smf_state *hsm; /*!< State machine states */ } state_machine_t; int sm_transition(state_machine_t *sm, int target_state); diff --git a/src/ocre/utils/c-smf/smf/smf.c b/src/ocre/utils/c-smf/smf/smf.c index dde5bbce..74bc1ba6 100644 --- a/src/ocre/utils/c-smf/smf/smf.c +++ b/src/ocre/utils/c-smf/smf/smf.c @@ -16,10 +16,10 @@ * member of the smf_ctx structure. */ struct internal_ctx { - bool new_state: 1; - bool terminate: 1; - bool is_exit: 1; - bool handled: 1; + bool new_state : 1; + bool terminate : 1; + bool is_exit : 1; + bool handled : 1; }; #ifdef CONFIG_SMF_ANCESTOR_SUPPORT @@ -34,8 +34,7 @@ static bool share_parent(const struct smf_state *test_state, const struct smf_st return false; } -static const struct smf_state *get_child_of(const struct smf_state *states, - const struct smf_state *parent) +static const struct smf_state *get_child_of(const struct smf_state *states, const struct smf_state *parent) { const struct smf_state *tmp = states; @@ -64,11 +63,9 @@ static const struct smf_state *get_last_of(const struct smf_state *states) * @param dest transition destination * @return LCA state, or NULL if states have no LCA. */ -static const struct smf_state *get_lca_of(const struct smf_state *source, - const struct smf_state *dest) +static const struct smf_state *get_lca_of(const struct smf_state *source, const struct smf_state *dest) { - for (const struct smf_state *ancestor = source->parent; ancestor != NULL; - ancestor = ancestor->parent) { + for (const struct smf_state *ancestor = source->parent; ancestor != NULL; ancestor = ancestor->parent) { if (ancestor == dest) { return ancestor->parent; } else if (share_parent(dest, ancestor)) { @@ -87,8 +84,7 @@ static const struct smf_state *get_lca_of(const struct smf_state *source, * @param topmost State we are entering from. Its entry action is not executed * @return true if the state machine should terminate, else false */ -static bool smf_execute_all_entry_actions(struct smf_ctx *const ctx, - const struct smf_state *new_state, +static bool smf_execute_all_entry_actions(struct smf_ctx *const ctx, const struct smf_state *new_state, const struct smf_state *topmost) { struct internal_ctx *const internal = (void *)&ctx->internal; @@ -99,8 +95,7 @@ static bool smf_execute_all_entry_actions(struct smf_ctx *const ctx, } for (const struct smf_state *to_execute = get_child_of(new_state, topmost); - to_execute != NULL && to_execute != new_state; - to_execute = get_child_of(new_state, to_execute)) { + to_execute != NULL && to_execute != new_state; to_execute = get_child_of(new_state, to_execute)) { /* Keep track of the executing entry action in case it calls * smf_set_state() */ @@ -192,8 +187,8 @@ static bool smf_execute_all_exit_actions(struct smf_ctx *const ctx, const struct { struct internal_ctx *const internal = (void *)&ctx->internal; - for (const struct smf_state *to_execute = ctx->current; - to_execute != NULL && to_execute != topmost; to_execute = to_execute->parent) { + for (const struct smf_state *to_execute = ctx->current; to_execute != NULL && to_execute != topmost; + to_execute = to_execute->parent) { if (to_execute->exit) { to_execute->exit(ctx); diff --git a/src/ocre/utils/c-smf/test/test.c b/src/ocre/utils/c-smf/test/test.c index ebf7ea64..25440810 100644 --- a/src/ocre/utils/c-smf/test/test.c +++ b/src/ocre/utils/c-smf/test/test.c @@ -2,72 +2,79 @@ #include "../smf/smf.h" // Define state entry, exit, and run actions -void state1_entry(void *ctx) { - (void)ctx; /* -Wunused-parameter */ - printf("Entering State 1\n"); +void state1_entry(void *ctx) +{ + (void)ctx; /* -Wunused-parameter */ + printf("Entering State 1\n"); } -void state1_exit(void *ctx) { - (void)ctx; /* -Wunused-parameter */ - printf("Exiting State 1\n"); +void state1_exit(void *ctx) +{ + (void)ctx; /* -Wunused-parameter */ + printf("Exiting State 1\n"); } -void state1_run(void *ctx) { - (void)ctx; /* -Wunused-parameter */ - printf("Running State 1\n"); +void state1_run(void *ctx) +{ + (void)ctx; /* -Wunused-parameter */ + printf("Running State 1\n"); } -void state2_entry(void *ctx) { - (void)ctx; /* -Wunused-parameter */ - printf("Entering State 2\n"); +void state2_entry(void *ctx) +{ + (void)ctx; /* -Wunused-parameter */ + printf("Entering State 2\n"); } -void state2_exit(void *ctx) { - (void)ctx; /* -Wunused-parameter */ - printf("Exiting State 2\n"); +void state2_exit(void *ctx) +{ + (void)ctx; /* -Wunused-parameter */ + printf("Exiting State 2\n"); } -void state2_run(void *ctx) { - (void)ctx; /* -Wunused-parameter */ - printf("Running State 2\n"); +void state2_run(void *ctx) +{ + (void)ctx; /* -Wunused-parameter */ + printf("Running State 2\n"); } // Define states struct smf_state state1 = { - .entry = state1_entry, - .run = state1_run, - .exit = state1_exit, + .entry = state1_entry, + .run = state1_run, + .exit = state1_exit, #ifdef CONFIG_SMF_ANCESTOR_SUPPORT - .parent = NULL, + .parent = NULL, #endif /* CONFIG_SMF_ANCESTOR_SUPPORT */ }; struct smf_state state2 = { - .entry = state2_entry, - .run = state2_run, - .exit = state2_exit, + .entry = state2_entry, + .run = state2_run, + .exit = state2_exit, #ifdef CONFIG_SMF_ANCESTOR_SUPPORT - .parent = NULL, + .parent = NULL, #endif /* CONFIG_SMF_ANCESTOR_SUPPORT */ }; -int main() { - struct smf_ctx ctx; +int main() +{ + struct smf_ctx ctx; - // Initialize the state machine with the initial state - smf_set_initial(&ctx, &state1); + // Initialize the state machine with the initial state + smf_set_initial(&ctx, &state1); - // Run the initial state - printf("Starting State Machine\n"); - smf_run_state(&ctx); + // Run the initial state + printf("Starting State Machine\n"); + smf_run_state(&ctx); - // Transition to a new state - printf("Transitioning to State 2\n"); - smf_set_state(&ctx, &state2); + // Transition to a new state + printf("Transitioning to State 2\n"); + smf_set_state(&ctx, &state2); - // Run the new state - smf_run_state(&ctx); + // Run the new state + smf_run_state(&ctx); - printf("State Machine Test Complete\n"); - return 0; + printf("State Machine Test Complete\n"); + return 0; } \ No newline at end of file diff --git a/src/ocre/utils/strlcat.c b/src/ocre/utils/strlcat.c index f3597793..57c3c37b 100644 --- a/src/ocre/utils/strlcat.c +++ b/src/ocre/utils/strlcat.c @@ -26,32 +26,29 @@ * Returns strlen(src) + MIN(dsize, strlen(initial dst)). * If retval >= dsize, truncation occurred. */ -size_t -strlcat (char *dst, - const char *src, - size_t dsize) +size_t strlcat(char *dst, const char *src, size_t dsize) { - const char *odst = dst; - const char *osrc = src; - size_t n = dsize; - size_t dlen; + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; - /* Find the end of dst and adjust bytes left but don't go past end. */ - while (n-- != 0 && *dst != '\0') - dst++; - dlen = dst - odst; - n = dsize - dlen; + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') + dst++; + dlen = dst - odst; + n = dsize - dlen; - if (n-- == 0) - return(dlen + strlen(src)); - while (*src != '\0') { - if (n != 0) { - *dst++ = *src; - n--; - } - src++; - } - *dst = '\0'; + if (n-- == 0) + return (dlen + strlen(src)); + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; - return(dlen + (src - osrc)); /* count does not include NUL */ + return (dlen + (src - osrc)); /* count does not include NUL */ } diff --git a/src/samples-mini/posix/main.c b/src/samples-mini/posix/main.c index 67c781d2..a28d7483 100644 --- a/src/samples-mini/posix/main.c +++ b/src/samples-mini/posix/main.c @@ -27,57 +27,59 @@ void create_sample_container(); -int main(int argc, char *argv[]) { - ocre_cs_ctx ctx; - ocre_container_init_arguments_t args; - char *container_filename = "hello"; - - ocre_app_storage_init(); - - // Step 1: Initialize the Ocre runtime - ocre_container_runtime_status_t ret = ocre_container_runtime_init(&ctx, &args); - - if (ret == RUNTIME_STATUS_INITIALIZED) { - printf("\n\nOcre runtime started\n"); - - if (argc > 1) { - set_argc(argc); - container_filename = argv[1]; // Use the filename as the container name/sha256 - } - else { - create_sample_container(container_filename); - } - - // Step 2: Create the container, this allocates and loads the container binary - ocre_container_data_t ocre_container_data[CONFIG_MAX_CONTAINERS]; - int container_ID[CONFIG_MAX_CONTAINERS]; - ocre_container_runtime_cb callback[CONFIG_MAX_CONTAINERS]; - - int i = 0; - do { - ocre_container_data[i].heap_size = 0; - snprintf(ocre_container_data[i].name, sizeof(ocre_container_data[i].name), "Container%d", i); - snprintf(ocre_container_data[i].sha256, sizeof(ocre_container_data[i].sha256), "%s", container_filename); - ocre_container_data[i].timers = 0; - ocre_container_data[i].watchdog_interval = 0; - ocre_container_runtime_create_container(&ctx, &ocre_container_data[i], &container_ID[i], callback[i]); - - // Step 3: Execute the container - ocre_container_runtime_run_container(container_ID[i], callback[i]); - core_sleep_ms(1000); - - i++; - container_filename = argv[i+1]; - } while (i < argc - 1); - - // Loop forever, without this the application will exit and stop all execution - while (true) { - core_sleep_ms(1000); - } - - } else { - printf("\n\nOcre runtime failed to start.\n"); - } +int main(int argc, char *argv[]) +{ + ocre_cs_ctx ctx; + ocre_container_init_arguments_t args; + char *container_filename = "hello"; + + ocre_app_storage_init(); + + // Step 1: Initialize the Ocre runtime + ocre_container_runtime_status_t ret = ocre_container_runtime_init(&ctx, &args); + + if (ret == RUNTIME_STATUS_INITIALIZED) { + printf("\n\nOcre runtime started\n"); + + if (argc > 1) { + set_argc(argc); + container_filename = argv[1]; // Use the filename as the container name/sha256 + } else { + create_sample_container(container_filename); + } + + // Step 2: Create the container, this allocates and loads the container binary + ocre_container_data_t ocre_container_data[CONFIG_MAX_CONTAINERS]; + int container_ID[CONFIG_MAX_CONTAINERS]; + ocre_container_runtime_cb callback[CONFIG_MAX_CONTAINERS]; + + int i = 0; + do { + ocre_container_data[i].heap_size = 0; + snprintf(ocre_container_data[i].name, sizeof(ocre_container_data[i].name), "Container%d", i); + snprintf(ocre_container_data[i].sha256, sizeof(ocre_container_data[i].sha256), "%s", + container_filename); + ocre_container_data[i].timers = 0; + ocre_container_data[i].watchdog_interval = 0; + ocre_container_runtime_create_container(&ctx, &ocre_container_data[i], &container_ID[i], + callback[i]); + + // Step 3: Execute the container + ocre_container_runtime_run_container(container_ID[i], callback[i]); + core_sleep_ms(1000); + + i++; + container_filename = argv[i + 1]; + } while (i < argc - 1); + + // Loop forever, without this the application will exit and stop all execution + while (true) { + core_sleep_ms(1000); + } + + } else { + printf("\n\nOcre runtime failed to start.\n"); + } } /** @@ -87,28 +89,29 @@ int main(int argc, char *argv[]) { * @param file_name a string containing the name of the file to create */ -void create_sample_container(char *file_name) { - static char file_path[64]; - snprintf(file_path, sizeof(file_path), "./%s/%s.bin", APP_RESOURCE_PATH, file_name); - - // Create directories if they don't exist - mkdir("./ocre", 0755); - mkdir("./ocre/images", 0755); - - // Open the file for writing - int fd = open(file_path, O_CREAT | O_RDWR, 0644); - if (fd == -1) { - perror("Error opening file"); - return; - } - // Write the binary data to the file - ssize_t bytes_written = write(fd, wasm_binary, wasm_binary_len); - if (bytes_written == -1) { - perror("Error writing to file"); - } else { - printf("Wrote %zd bytes to %s\n", bytes_written, file_path); - } - - // Close the file - close(fd); +void create_sample_container(char *file_name) +{ + static char file_path[64]; + snprintf(file_path, sizeof(file_path), "./%s/%s.bin", APP_RESOURCE_PATH, file_name); + + // Create directories if they don't exist + mkdir("./ocre", 0755); + mkdir("./ocre/images", 0755); + + // Open the file for writing + int fd = open(file_path, O_CREAT | O_RDWR, 0644); + if (fd == -1) { + perror("Error opening file"); + return; + } + // Write the binary data to the file + ssize_t bytes_written = write(fd, wasm_binary, wasm_binary_len); + if (bytes_written == -1) { + perror("Error writing to file"); + } else { + printf("Wrote %zd bytes to %s\n", bytes_written, file_path); + } + + // Close the file + close(fd); } diff --git a/src/samples-mini/zephyr/main.c b/src/samples-mini/zephyr/main.c index 024cf0a4..0927ae7a 100644 --- a/src/samples-mini/zephyr/main.c +++ b/src/samples-mini/zephyr/main.c @@ -23,50 +23,55 @@ void create_sample_container(); int ocre_network_init(); -int main(int argc, char *argv[]) { - ocre_cs_ctx ctx; - ocre_container_init_arguments_t args; - char *container_filename = "hello"; +int main(int argc, char *argv[]) +{ + ocre_cs_ctx ctx; + ocre_container_init_arguments_t args; +#ifdef OCRE_INPUT_FILE_NAME + const char *container_filename = OCRE_INPUT_FILE_NAME; +#else + const char *container_filename = "hello-from-ocre"; +#endif #ifdef CONFIG_OCRE_NETWORKING - int net_status = ocre_network_init(); - if (net_status < 0) { - printf("Unable to connect to network\n"); - } else { - printf("Network is UP\n"); - } + int net_status = ocre_network_init(); + if (net_status < 0) { + printf("Unable to connect to network\n"); + } else { + printf("Network is UP\n"); + } #endif - ocre_app_storage_init(); + ocre_app_storage_init(); - // Step 1: Initialize the Ocre runtime - ocre_container_runtime_status_t ret = ocre_container_runtime_init(&ctx, &args); + // Step 1: Initialize the Ocre runtime + ocre_container_runtime_status_t ret = ocre_container_runtime_init(&ctx, &args); - if (ret == RUNTIME_STATUS_INITIALIZED) { - printf("\n\nOcre runtime started\n"); + if (ret == RUNTIME_STATUS_INITIALIZED) { + printf("\n\nOcre runtime started\n"); - create_sample_container(container_filename); + create_sample_container(container_filename); - // Step 2: Create the container, this allocates and loads the container binary - ocre_container_data_t ocre_container_data; - int container_ID; + // Step 2: Create the container, this allocates and loads the container binary + ocre_container_data_t ocre_container_data; + int container_ID; - ocre_container_data.heap_size = 0; - snprintf(ocre_container_data.name, sizeof(ocre_container_data.name), "Hello World"); - snprintf(ocre_container_data.sha256, sizeof(ocre_container_data.sha256), "%s", container_filename); - ocre_container_data.timers = 0; - ocre_container_runtime_create_container(&ctx, &ocre_container_data, &container_ID, NULL); + ocre_container_data.heap_size = 0; + snprintf(ocre_container_data.name, sizeof(ocre_container_data.name), "%s", container_filename); + snprintf(ocre_container_data.sha256, sizeof(ocre_container_data.sha256), "%s", container_filename); + ocre_container_data.timers = 0; + ocre_container_runtime_create_container(&ctx, &ocre_container_data, &container_ID, NULL); - // Step 3: Execute the container - ocre_container_runtime_run_container(container_ID, NULL); - // Loop forever, without this the application will exit and stop all execution - while (true) { - core_sleep_ms(1000); - } + // Step 3: Execute the container + ocre_container_runtime_run_container(container_ID, NULL); + // Loop forever, without this the application will exit and stop all execution + while (true) { + core_sleep_ms(1000); + } - } else { - printf("\n\nOcre runtime failed to start.\n"); - } + } else { + printf("\n\nOcre runtime failed to start.\n"); + } } /** @@ -76,35 +81,37 @@ int main(int argc, char *argv[]) { * @param file_name a string containing the name of the file to create */ -void create_sample_container(char *file_name) { - static char file_path[64]; - struct fs_file_t f; - snprintf((char *)&file_path, 64, "/lfs/ocre/images/%s.bin", file_name); - int res; +void create_sample_container(char *file_name) +{ + static char file_path[64]; + struct fs_file_t f; + snprintf((char *)&file_path, 64, "/lfs/ocre/images/%s.bin", file_name); + int res; - fs_file_t_init(&f); - res = fs_open(&f, file_path, FS_O_CREATE | FS_O_RDWR); + fs_file_t_init(&f); + res = fs_open(&f, file_path, FS_O_CREATE | FS_O_TRUNC | FS_O_RDWR); - fs_write(&f, &wasm_binary, wasm_binary_len); - fs_close(&f); + fs_write(&f, &wasm_binary, wasm_binary_len); + fs_close(&f); } -int ocre_network_init() { +int ocre_network_init() +{ - struct net_if *iface = net_if_get_default(); - net_dhcpv4_start(iface); + struct net_if *iface = net_if_get_default(); + net_dhcpv4_start(iface); - printf("Waiting for network to be ready...\n"); + printf("Waiting for network to be ready...\n"); - int sleep_cnt = 0; - while (!net_if_is_up(iface) && (sleep_cnt < 10)) { - k_sleep(K_MSEC(200)); - sleep_cnt++; - } + int sleep_cnt = 0; + while (!net_if_is_up(iface) && (sleep_cnt < 10)) { + k_sleep(K_MSEC(200)); + sleep_cnt++; + } - if (!net_if_is_up(iface)) { - return -ENOTCONN; - } + if (!net_if_is_up(iface)) { + return -ENOTCONN; + } - return 0; + return 0; } diff --git a/src/shared/platform/ocre_core_external.h b/src/shared/platform/ocre_core_external.h index 69375219..1b852125 100644 --- a/src/shared/platform/ocre_core_external.h +++ b/src/shared/platform/ocre_core_external.h @@ -45,7 +45,8 @@ typedef struct core_thread core_thread_t; * @param priority Thread priority. * @return 0 on success, negative value on error. */ -int core_thread_create(core_thread_t *thread, core_thread_func_t func, void *arg, const char *name, size_t stack_size, int priority); +int core_thread_create(core_thread_t *thread, core_thread_func_t func, void *arg, const char *name, size_t stack_size, + int priority); /** * @brief Destroy a thread and release its resources. diff --git a/src/shared/platform/ocre_psram.h b/src/shared/platform/ocre_psram.h new file mode 100644 index 00000000..6f37e98d --- /dev/null +++ b/src/shared/platform/ocre_psram.h @@ -0,0 +1,31 @@ +#ifndef OCRE_PSRAM +#define OCRE_PSRAM + +// PSRAM configuration - centralized for different platforms +#if defined(CONFIG_MEMC) +// Board-specific PSRAM section attributes +#if defined(CONFIG_BOARD_ARDUINO_PORTENTA_H7) +#define PSRAM_SECTION_ATTR __attribute__((section("SDRAM1"), aligned(32))) +#elif defined(CONFIG_BOARD_B_U585I_IOT02A) +#define PSRAM_SECTION_ATTR __attribute__((section(".stm32_psram"), aligned(32))) +#elif defined(CONFIG_BOARD_MIMXRT1064_EVK) +#define PSRAM_SECTION_ATTR __attribute__((section("SDRAM"), aligned(32))) +#else +#define PSRAM_SECTION_ATTR __attribute__((aligned(32))) +#endif + +PSRAM_SECTION_ATTR +static char storage_heap_buf[CONFIG_OCRE_STORAGE_HEAP_BUFFER_SIZE] = {0}; + +static struct k_heap storage_heap; +#define storage_heap_init() k_heap_init(&storage_heap, storage_heap_buf, CONFIG_OCRE_STORAGE_HEAP_BUFFER_SIZE) +#define storage_heap_alloc(size) k_heap_alloc(&storage_heap, (size), K_SECONDS(1)) +#define storage_heap_free(buffer) k_heap_free(&storage_heap, (void *)buffer) +#else +// No PSRAM - use system malloc +#define storage_heap_init() /* No initialization needed */ +#define storage_heap_alloc(size) malloc(size) +#define storage_heap_free(buffer) free(buffer) +#endif + +#endif /* OCRE_PSRAM*/ diff --git a/src/shared/platform/posix/core_eventq.c b/src/shared/platform/posix/core_eventq.c index 1146a371..80119368 100644 --- a/src/shared/platform/posix/core_eventq.c +++ b/src/shared/platform/posix/core_eventq.c @@ -9,66 +9,69 @@ #include #include -int core_eventq_init(core_eventq_t *eventq, size_t item_size, size_t max_items) { - eventq->buffer = core_malloc(item_size * max_items); - if (!eventq->buffer) { - return -ENOMEM; - } - eventq->item_size = item_size; - eventq->max_items = max_items; - eventq->count = 0; - eventq->head = 0; - eventq->tail = 0; - pthread_mutex_init(&eventq->mutex, NULL); - pthread_cond_init(&eventq->cond, NULL); - return 0; +int core_eventq_init(core_eventq_t *eventq, size_t item_size, size_t max_items) +{ + eventq->buffer = core_malloc(item_size * max_items); + if (!eventq->buffer) { + return -ENOMEM; + } + eventq->item_size = item_size; + eventq->max_items = max_items; + eventq->count = 0; + eventq->head = 0; + eventq->tail = 0; + pthread_mutex_init(&eventq->mutex, NULL); + pthread_cond_init(&eventq->cond, NULL); + return 0; } -int core_eventq_peek(core_eventq_t *eventq, void *event) { - pthread_mutex_lock(&eventq->mutex); - if (eventq->count == 0) { - pthread_mutex_unlock(&eventq->mutex); - return -ENOMSG; - } - memcpy(event, (char *)eventq->buffer + (eventq->head * eventq->item_size), eventq->item_size); - pthread_mutex_unlock(&eventq->mutex); - return 0; +int core_eventq_peek(core_eventq_t *eventq, void *event) +{ + pthread_mutex_lock(&eventq->mutex); + if (eventq->count == 0) { + pthread_mutex_unlock(&eventq->mutex); + return -ENOMSG; + } + memcpy(event, (char *)eventq->buffer + (eventq->head * eventq->item_size), eventq->item_size); + pthread_mutex_unlock(&eventq->mutex); + return 0; } -int core_eventq_get(core_eventq_t *eventq, void *event) { - pthread_mutex_lock(&eventq->mutex); - if (eventq->count == 0) { - pthread_mutex_unlock(&eventq->mutex); - return -ENOENT; - } - memcpy(event, (char *)eventq->buffer + (eventq->head * eventq->item_size), eventq->item_size); - eventq->head = (eventq->head + 1) % eventq->max_items; - eventq->count--; - pthread_mutex_unlock(&eventq->mutex); - return 0; +int core_eventq_get(core_eventq_t *eventq, void *event) +{ + pthread_mutex_lock(&eventq->mutex); + if (eventq->count == 0) { + pthread_mutex_unlock(&eventq->mutex); + return -ENOENT; + } + memcpy(event, (char *)eventq->buffer + (eventq->head * eventq->item_size), eventq->item_size); + eventq->head = (eventq->head + 1) % eventq->max_items; + eventq->count--; + pthread_mutex_unlock(&eventq->mutex); + return 0; } -int core_eventq_put(core_eventq_t *eventq, const void *event) { - pthread_mutex_lock(&eventq->mutex); - if (eventq->count >= eventq->max_items) { - pthread_mutex_unlock(&eventq->mutex); - return -ENOMEM; - } - memcpy((char *)eventq->buffer + (eventq->tail * eventq->item_size), event, eventq->item_size); - eventq->tail = (eventq->tail + 1) % eventq->max_items; - eventq->count++; - pthread_cond_signal(&eventq->cond); - pthread_mutex_unlock(&eventq->mutex); - return 0; +int core_eventq_put(core_eventq_t *eventq, const void *event) +{ + pthread_mutex_lock(&eventq->mutex); + if (eventq->count >= eventq->max_items) { + pthread_mutex_unlock(&eventq->mutex); + return -ENOMEM; + } + memcpy((char *)eventq->buffer + (eventq->tail * eventq->item_size), event, eventq->item_size); + eventq->tail = (eventq->tail + 1) % eventq->max_items; + eventq->count++; + pthread_cond_signal(&eventq->cond); + pthread_mutex_unlock(&eventq->mutex); + return 0; } -void core_eventq_destroy(core_eventq_t *eventq) { - pthread_mutex_destroy(&eventq->mutex); - pthread_cond_destroy(&eventq->cond); - if (eventq->buffer) { - core_free(eventq->buffer); - eventq->buffer = NULL; - } +void core_eventq_destroy(core_eventq_t *eventq) +{ + pthread_mutex_destroy(&eventq->mutex); + pthread_cond_destroy(&eventq->cond); + if (eventq->buffer) { + core_free(eventq->buffer); + eventq->buffer = NULL; + } } - - diff --git a/src/shared/platform/posix/core_fs.c b/src/shared/platform/posix/core_fs.c index 76c2fddd..8881dd2c 100644 --- a/src/shared/platform/posix/core_fs.c +++ b/src/shared/platform/posix/core_fs.c @@ -26,11 +26,11 @@ or as a program parameter. Encapsulation is used to avoid global variables. */ static int stored_argc = 0; -void set_argc(int argc) { - stored_argc = argc; +void set_argc(int argc) +{ + stored_argc = argc; } - /** * @brief Retrieves the stored argc value. * @@ -39,122 +39,130 @@ void set_argc(int argc) { * * @return The stored argc value. */ -static int get_argc() { - return stored_argc; +static int get_argc() +{ + return stored_argc; } - -int core_construct_filepath(char *path, size_t len, char *name) { - char cwd[PATH_MAX]; - if (getcwd(cwd, sizeof(cwd)) != NULL) { - // Shall be in /build folder - LOG_DBG("Current working dir: %s", cwd); - } - if (get_argc() > 1) { - strcpy(path, name); - return 0; - } else { - return snprintf(path, len, "%s/%s/%s.bin", cwd, APP_RESOURCE_PATH, name); - } +int core_construct_filepath(char *path, size_t len, char *name) +{ + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) != NULL) { + // Shall be in /build folder + LOG_DBG("Current working dir: %s", cwd); + } + if (get_argc() > 1) { + strcpy(path, name); + return 0; + } else { + return snprintf(path, len, "%s/%s/%s.bin", cwd, APP_RESOURCE_PATH, name); + } } - -int core_filestat(const char *path, size_t *size) { - struct stat st; - if (stat(path, &st) == 0) { - if (size) { - *size = st.st_size; - } - return 0; // success - } else { - return errno; // return the specific error code - } - +int core_filestat(const char *path, size_t *size) +{ + struct stat st; + if (stat(path, &st) == 0) { + if (size) { + *size = st.st_size; + } + return 0; // success + } else { + return errno; // return the specific error code + } } -int core_fileopen(const char *path, void **handle) { - int *fd = core_malloc(sizeof(int)); - if (!fd) return -ENOMEM; - *fd = open(path, O_RDONLY); - if (*fd < 0) { - core_free(fd); - return -errno; - } - *handle = fd; - return 0; +int core_fileopen(const char *path, void **handle) +{ + int *fd = core_malloc(sizeof(int)); + if (!fd) + return -ENOMEM; + *fd = open(path, O_RDONLY); + if (*fd < 0) { + core_free(fd); + return -errno; + } + *handle = fd; + return 0; } -int core_fileread(void *handle, void *buffer, size_t size) { - int fd = *(int *)handle; - ssize_t bytes_read = read(fd, buffer, size); - if (bytes_read < 0) return -errno; - if ((size_t)bytes_read != size) return -EIO; - return 0; +int core_fileread(void *handle, void *buffer, size_t size) +{ + int fd = *(int *)handle; + ssize_t bytes_read = read(fd, buffer, size); + if (bytes_read < 0) + return -errno; + if ((size_t)bytes_read != size) + return -EIO; + return 0; } -int core_fileclose(void *handle) { - int fd = *(int *)handle; - int ret = close(fd); - core_free(handle); - return ret; +int core_fileclose(void *handle) +{ + int fd = *(int *)handle; + int ret = close(fd); + core_free(handle); + return ret; } -static int lsdir(const char *path) { - DIR *dirp; - struct dirent *entry; +static int lsdir(const char *path) +{ + DIR *dirp; + struct dirent *entry; - dirp = opendir(path); - if (!dirp) { - LOG_ERR("Error opening dir %s [%d]", path, errno); - return -errno; - } + dirp = opendir(path); + if (!dirp) { + LOG_ERR("Error opening dir %s [%d]", path, errno); + return -errno; + } - while ((entry = readdir(dirp)) != NULL) { - LOG_DBG("Found: %s", entry->d_name); - } + while ((entry = readdir(dirp)) != NULL) { + LOG_DBG("Found: %s", entry->d_name); + } - if (closedir(dirp) < 0) { - LOG_ERR("Error closing dir [%d]", errno); - return -errno; - } + if (closedir(dirp) < 0) { + LOG_ERR("Error closing dir [%d]", errno); + return -errno; + } - return 0; + return 0; } -void ocre_app_storage_init() { - struct stat st; - - if (stat(OCRE_BASE_PATH, &st) == -1) { - if (mkdir(OCRE_BASE_PATH, 0755) < 0) { - LOG_ERR("Failed to create directory %s [%d]", OCRE_BASE_PATH, errno); - } - } - - if (stat(APP_RESOURCE_PATH, &st) == -1) { - if (mkdir(APP_RESOURCE_PATH, 0755) < 0) { - LOG_ERR("Failed to create directory %s [%d]", APP_RESOURCE_PATH, errno); - } - } - - if (stat(PACKAGE_BASE_PATH, &st) == -1) { - if (mkdir(PACKAGE_BASE_PATH, 0755) < 0) { - LOG_ERR("Failed to create directory %s [%d]", PACKAGE_BASE_PATH, errno); - } - } - - if (stat(CONFIG_PATH, &st) == -1) { - if (mkdir(CONFIG_PATH, 0755) < 0) { - LOG_ERR("Failed to create directory %s [%d]", CONFIG_PATH, errno); - } - } +void ocre_app_storage_init() +{ + struct stat st; + + if (stat(OCRE_BASE_PATH, &st) == -1) { + if (mkdir(OCRE_BASE_PATH, 0755) < 0) { + LOG_ERR("Failed to create directory %s [%d]", OCRE_BASE_PATH, errno); + } + } + + if (stat(APP_RESOURCE_PATH, &st) == -1) { + if (mkdir(APP_RESOURCE_PATH, 0755) < 0) { + LOG_ERR("Failed to create directory %s [%d]", APP_RESOURCE_PATH, errno); + } + } + + if (stat(PACKAGE_BASE_PATH, &st) == -1) { + if (mkdir(PACKAGE_BASE_PATH, 0755) < 0) { + LOG_ERR("Failed to create directory %s [%d]", PACKAGE_BASE_PATH, errno); + } + } + + if (stat(CONFIG_PATH, &st) == -1) { + if (mkdir(CONFIG_PATH, 0755) < 0) { + LOG_ERR("Failed to create directory %s [%d]", CONFIG_PATH, errno); + } + } #ifdef CONFIG_OCRE_CONTAINER_FILESYSTEM - if (stat(CONTAINER_FS_PATH, &st) == -1) { - if (mkdir(CONTAINER_FS_PATH, 0755) < 0) { - LOG_ERR("Failed to create directory %s [%d]", CONTAINER_FS_PATH, errno); - } - } + if (stat(CONTAINER_FS_PATH, &st) == -1) { + if (mkdir(CONTAINER_FS_PATH, 0755) < 0) { + LOG_ERR("Failed to create directory %s [%d]", CONTAINER_FS_PATH, errno); + } + } #endif - lsdir(OCRE_BASE_PATH); + lsdir(OCRE_BASE_PATH); } diff --git a/src/shared/platform/posix/core_internal.h b/src/shared/platform/posix/core_internal.h index 0278daef..62f69e62 100644 --- a/src/shared/platform/posix/core_internal.h +++ b/src/shared/platform/posix/core_internal.h @@ -20,23 +20,23 @@ #include // Config macros -#define CONFIG_OCRE_CONTAINER_MESSAGING /*!< Enable container messaging support */ -#define CONFIG_OCRE_NETWORKING /*!< Enable networking support */ +#define CONFIG_OCRE_CONTAINER_MESSAGING /*!< Enable container messaging support */ +#define CONFIG_OCRE_NETWORKING /*!< Enable networking support */ #define CONFIG_OCRE_CONTAINER_FILESYSTEM #define CONFIG_OCRE_CONTAINER_WAMR_TERMINATION #define CONFIG_OCRE_TIMER // Base paths for the application -#define OCRE_BASE_PATH "./ocre_data" /*!< Base directory for Ocre resources */ +#define OCRE_BASE_PATH "./ocre_data" /*!< Base directory for Ocre resources */ -#define APP_RESOURCE_PATH OCRE_BASE_PATH "/images" /*!< Path to container images */ -#define PACKAGE_BASE_PATH OCRE_BASE_PATH "/manifests" /*!< Path to package manifests */ -#define CONFIG_PATH OCRE_BASE_PATH "/config" /*!< Path to configuration files */ +#define APP_RESOURCE_PATH OCRE_BASE_PATH "/images" /*!< Path to container images */ +#define PACKAGE_BASE_PATH OCRE_BASE_PATH "/manifests" /*!< Path to package manifests */ +#define CONFIG_PATH OCRE_BASE_PATH "/config" /*!< Path to configuration files */ /** * @brief Path for container filesystem root */ -#define CONTAINER_FS_PATH OCRE_BASE_PATH "/cfs" +#define CONTAINER_FS_PATH OCRE_BASE_PATH "/cfs" /** * @brief Ignore Zephyr's log module registration on POSIX. @@ -44,14 +44,13 @@ #define LOG_MODULE_REGISTER(name, level) #define LOG_MODULE_DECLARE(name, level) - /* * @brief Log level priority definitions (highest to lowest) */ -#define APP_LOG_LEVEL_ERR 1 -#define APP_LOG_LEVEL_WRN 2 -#define APP_LOG_LEVEL_INF 3 -#define APP_LOG_LEVEL_DBG 4 +#define APP_LOG_LEVEL_ERR 1 +#define APP_LOG_LEVEL_WRN 2 +#define APP_LOG_LEVEL_INF 3 +#define APP_LOG_LEVEL_DBG 4 /* * @brief Determine the current log level based on CONFIG defines @@ -59,51 +58,59 @@ * If none specified, default to INFO level */ #if defined(CONFIG_LOG_LVL_ERR) - #define APP_CURRENT_LOG_LEVEL APP_LOG_LEVEL_ERR +#define APP_CURRENT_LOG_LEVEL APP_LOG_LEVEL_ERR #elif defined(CONFIG_LOG_LVL_WRN) - #define APP_CURRENT_LOG_LEVEL APP_LOG_LEVEL_WRN +#define APP_CURRENT_LOG_LEVEL APP_LOG_LEVEL_WRN #elif defined(CONFIG_LOG_LVL_INF) - #define APP_CURRENT_LOG_LEVEL APP_LOG_LEVEL_INF +#define APP_CURRENT_LOG_LEVEL APP_LOG_LEVEL_INF #elif defined(CONFIG_LOG_LVL_DBG) - #define APP_CURRENT_LOG_LEVEL APP_LOG_LEVEL_DBG +#define APP_CURRENT_LOG_LEVEL APP_LOG_LEVEL_DBG #else - #define APP_CURRENT_LOG_LEVEL APP_LOG_LEVEL_INF /* Default to INFO level */ +#define APP_CURRENT_LOG_LEVEL APP_LOG_LEVEL_INF /* Default to INFO level */ #endif /** * @brief Log an error message (always shown if ERR level or higher). */ #if APP_CURRENT_LOG_LEVEL >= APP_LOG_LEVEL_ERR - #define LOG_ERR(fmt, ...) printf("[ERROR] " fmt "\n", ##__VA_ARGS__) +#define LOG_ERR(fmt, ...) printf("[ERROR] " fmt "\n", ##__VA_ARGS__) #else - #define LOG_ERR(fmt, ...) do { } while(0) +#define LOG_ERR(fmt, ...) \ + do { \ + } while (0) #endif /** * @brief Log a warning message (shown if WRN level or higher). */ #if APP_CURRENT_LOG_LEVEL >= APP_LOG_LEVEL_WRN - #define LOG_WRN(fmt, ...) printf("[WARNING] " fmt "\n", ##__VA_ARGS__) +#define LOG_WRN(fmt, ...) printf("[WARNING] " fmt "\n", ##__VA_ARGS__) #else - #define LOG_WRN(fmt, ...) do { } while(0) +#define LOG_WRN(fmt, ...) \ + do { \ + } while (0) #endif /** * @brief Log an informational message (shown if INF level or higher). */ #if APP_CURRENT_LOG_LEVEL >= APP_LOG_LEVEL_INF - #define LOG_INF(fmt, ...) printf("[INFO] " fmt "\n", ##__VA_ARGS__) +#define LOG_INF(fmt, ...) printf("[INFO] " fmt "\n", ##__VA_ARGS__) #else - #define LOG_INF(fmt, ...) do { } while(0) +#define LOG_INF(fmt, ...) \ + do { \ + } while (0) #endif /** * @brief Log a debug message (shown only if DBG level). */ #if APP_CURRENT_LOG_LEVEL >= APP_LOG_LEVEL_DBG - #define LOG_DBG(fmt, ...) printf("[DEBUG] " fmt "\n", ##__VA_ARGS__) +#define LOG_DBG(fmt, ...) printf("[DEBUG] " fmt "\n", ##__VA_ARGS__) #else - #define LOG_DBG(fmt, ...) do { } while(0) +#define LOG_DBG(fmt, ...) \ + do { \ + } while (0) #endif // Constants @@ -138,23 +145,23 @@ void set_argc(int argc); * @brief Application version string. */ #ifndef APP_VERSION_STRING -#define APP_VERSION_STRING "0.0.0-dev" +#define APP_VERSION_STRING "0.0.0-dev" #endif /* APP_VERSION_STRING */ /** * @brief Default heap buffer size for WAMR (in bytes). */ -#define CONFIG_OCRE_WAMR_HEAP_BUFFER_SIZE 512000 +#define CONFIG_OCRE_WAMR_HEAP_BUFFER_SIZE 512000 /** * @brief Default heap size for a container (in bytes). */ -#define CONFIG_OCRE_CONTAINER_DEFAULT_HEAP_SIZE 4096 +#define CONFIG_OCRE_CONTAINER_DEFAULT_HEAP_SIZE 4096 /** * @brief Default stack size for a container (in bytes). */ -#define CONFIG_OCRE_CONTAINER_DEFAULT_STACK_SIZE 4096 * 16 +#define CONFIG_OCRE_CONTAINER_DEFAULT_STACK_SIZE 4096 * 16 /** * @brief Default stack size for container threads (in bytes). @@ -165,17 +172,17 @@ void set_argc(int argc); * @brief Structure representing a thread in the Ocre runtime. */ struct core_thread { - pthread_t tid; /*!< POSIX thread identifier */ - void *stack; /*!< Pointer to thread stack memory */ - size_t stack_size; /*!< Size of the thread stack */ - uint32_t user_options; /*!< User-defined options for the thread */ + pthread_t tid; /*!< POSIX thread identifier */ + void *stack; /*!< Pointer to thread stack memory */ + size_t stack_size; /*!< Size of the thread stack */ + uint32_t user_options; /*!< User-defined options for the thread */ }; /** * @brief Structure representing a mutex in the Ocre runtime. */ struct core_mutex { - pthread_mutex_t native_mutex; /*!< POSIX mutex */ + pthread_mutex_t native_mutex; /*!< POSIX mutex */ }; #define MQ_DEFAULT_PRIO 0 /*!< Default message queue priority */ @@ -184,7 +191,7 @@ struct core_mutex { * @brief Structure representing a message queue in the Ocre runtime. */ struct core_mq { - mqd_t msgq; /*!< POSIX message queue descriptor */ + mqd_t msgq; /*!< POSIX message queue descriptor */ }; /** @@ -198,39 +205,37 @@ typedef void (*core_timer_callback_t)(void *user_data); * @brief Structure representing a timer in the Ocre runtime. */ struct core_timer { - timer_t timerid; /*!< POSIX timer identifier */ - core_timer_callback_t cb; /*!< Timer callback function */ - void *user_data; /*!< User data for the callback */ + timer_t timerid; /*!< POSIX timer identifier */ + core_timer_callback_t cb; /*!< Timer callback function */ + void *user_data; /*!< User data for the callback */ }; /* Generic singly-linked list iteration macros */ -#define CONTAINER_OF(ptr, type, member) \ - ((type *)((char *)(ptr) - offsetof(type, member))) +#define CONTAINER_OF(ptr, type, member) ((type *)((char *)(ptr)-offsetof(type, member))) -#define CORE_SLIST_FOR_EACH_CONTAINER_SAFE(list, var, tmp, member) \ - for (var = (list)->head ? CONTAINER_OF((list)->head, __typeof__(*var), member) : NULL, \ - tmp = var ? (var->member.next ? CONTAINER_OF(var->member.next, __typeof__(*var), member) : NULL) : NULL; \ - var; \ - var = tmp, tmp = tmp ? (tmp->member.next ? CONTAINER_OF(tmp->member.next, __typeof__(*var), member) : NULL) : NULL) +#define CORE_SLIST_FOR_EACH_CONTAINER_SAFE(list, var, tmp, member) \ + for (var = (list)->head ? CONTAINER_OF((list)->head, __typeof__(*var), member) : NULL, \ + tmp = var ? (var->member.next ? CONTAINER_OF(var->member.next, __typeof__(*var), member) : NULL) : NULL; \ + var; var = tmp, \ + tmp = tmp ? (tmp->member.next ? CONTAINER_OF(tmp->member.next, __typeof__(*var), member) : NULL) : NULL) -#define CORE_SLIST_FOR_EACH_CONTAINER(list, var, member) \ - for (var = (list)->head ? CONTAINER_OF((list)->head, __typeof__(*var), member) : NULL; \ - var; \ - var = var->member.next ? CONTAINER_OF(var->member.next, __typeof__(*var), member) : NULL) +#define CORE_SLIST_FOR_EACH_CONTAINER(list, var, member) \ + for (var = (list)->head ? CONTAINER_OF((list)->head, __typeof__(*var), member) : NULL; var; \ + var = var->member.next ? CONTAINER_OF(var->member.next, __typeof__(*var), member) : NULL) /** * @brief Structure representing a node in a singly-linked list. */ typedef struct core_snode { - struct core_snode *next; /*!< Pointer to the next node in the list */ + struct core_snode *next; /*!< Pointer to the next node in the list */ } core_snode_t; /** * @brief Structure representing a singly-linked list for POSIX platform. */ typedef struct { - core_snode_t *head; /*!< Pointer to the first node in the list */ - core_snode_t *tail; /*!< Pointer to the last node in the list */ + core_snode_t *head; /*!< Pointer to the first node in the list */ + core_snode_t *tail; /*!< Pointer to the last node in the list */ } core_slist_t; /** @@ -261,7 +266,7 @@ void core_slist_remove(core_slist_t *list, core_snode_t *prev, core_snode_t *nod * @brief Spinlock type for POSIX platform (simulated using mutex). */ typedef struct { - pthread_mutex_t mutex; /*!< POSIX mutex for spinlock simulation */ + pthread_mutex_t mutex; /*!< POSIX mutex for spinlock simulation */ } core_spinlock_t; /** @@ -271,19 +276,19 @@ typedef int core_spinlock_key_t; /** * @brief Generic event queue structure for POSIX platform. - * + * * A thread-safe circular buffer implementation that can store * any type of data items with configurable size and capacity. */ typedef struct { - void *buffer; /*!< Dynamically allocated buffer for queue items */ - size_t item_size; /*!< Size of each individual item in bytes */ - size_t max_items; /*!< Maximum number of items the queue can hold */ - size_t count; /*!< Current number of items in the queue */ - size_t head; /*!< Index of the next item to be read */ - size_t tail; /*!< Index where the next item will be written */ - pthread_mutex_t mutex; /*!< Mutex for thread-safe access */ - pthread_cond_t cond; /*!< Condition variable for signaling */ + void *buffer; /*!< Dynamically allocated buffer for queue items */ + size_t item_size; /*!< Size of each individual item in bytes */ + size_t max_items; /*!< Maximum number of items the queue can hold */ + size_t count; /*!< Current number of items in the queue */ + size_t head; /*!< Index of the next item to be read */ + size_t tail; /*!< Index where the next item will be written */ + pthread_mutex_t mutex; /*!< Mutex for thread-safe access */ + pthread_cond_t cond; /*!< Condition variable for signaling */ } core_eventq_t; #endif /* OCRE_CORE_INTERNAL_H */ diff --git a/src/shared/platform/posix/core_memory.c b/src/shared/platform/posix/core_memory.c index 0e13a8c0..33203b06 100644 --- a/src/shared/platform/posix/core_memory.c +++ b/src/shared/platform/posix/core_memory.c @@ -9,10 +9,12 @@ #include -void *core_malloc(size_t size) { - return malloc(size); +void *core_malloc(size_t size) +{ + return malloc(size); } -void core_free(void *ptr) { - free(ptr); +void core_free(void *ptr) +{ + free(ptr); } diff --git a/src/shared/platform/posix/core_misc.c b/src/shared/platform/posix/core_misc.c index 069c1735..922ee62c 100644 --- a/src/shared/platform/posix/core_misc.c +++ b/src/shared/platform/posix/core_misc.c @@ -8,49 +8,52 @@ #include "ocre_core_external.h" #include -#include +#include #include #include void core_sleep_ms(int milliseconds) { - struct timespec ts; - int res; - - if (milliseconds < 0) - { - errno = EINVAL; - fprintf(stderr, "core_sleep_ms: Invalid milliseconds value (%d)\n", milliseconds); - return; - } - - ts.tv_sec = milliseconds / 1000; - ts.tv_nsec = (milliseconds % 1000) * 1000000; - - do { - res = nanosleep(&ts, &ts); - if (res && errno != EINTR) { - fprintf(stderr, "core_sleep_ms: nanosleep failed (errno=%d)\n", errno); - } - } while (res && errno == EINTR); + struct timespec ts; + int res; + + if (milliseconds < 0) { + errno = EINVAL; + fprintf(stderr, "core_sleep_ms: Invalid milliseconds value (%d)\n", milliseconds); + return; + } + + ts.tv_sec = milliseconds / 1000; + ts.tv_nsec = (milliseconds % 1000) * 1000000; + + do { + res = nanosleep(&ts, &ts); + if (res && errno != EINTR) { + fprintf(stderr, "core_sleep_ms: nanosleep failed (errno=%d)\n", errno); + } + } while (res && errno == EINTR); } -void core_yield(void) { - sched_yield(); +void core_yield(void) +{ + sched_yield(); } -uint32_t core_uptime_get(void) { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint32_t)(ts.tv_sec * 1000 + ts.tv_nsec / 1000000); +uint32_t core_uptime_get(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint32_t)(ts.tv_sec * 1000 + ts.tv_nsec / 1000000); } -core_spinlock_key_t core_spinlock_lock(core_spinlock_t *lock) { - pthread_mutex_lock(&lock->mutex); - return 0; +core_spinlock_key_t core_spinlock_lock(core_spinlock_t *lock) +{ + pthread_mutex_lock(&lock->mutex); + return 0; } -void core_spinlock_unlock(core_spinlock_t *lock, core_spinlock_key_t key) { - (void)key; - pthread_mutex_unlock(&lock->mutex); +void core_spinlock_unlock(core_spinlock_t *lock, core_spinlock_key_t key) +{ + (void)key; + pthread_mutex_unlock(&lock->mutex); } diff --git a/src/shared/platform/posix/core_mq.c b/src/shared/platform/posix/core_mq.c index e9afa8c8..85a7d77a 100644 --- a/src/shared/platform/posix/core_mq.c +++ b/src/shared/platform/posix/core_mq.c @@ -12,54 +12,53 @@ int core_mq_init(core_mq_t *mq, const char *name, size_t msg_size, uint32_t max_msgs) { - struct mq_attr attr; + struct mq_attr attr; - // Configure the message queue attributes - attr.mq_flags = 0; // Blocking mode - attr.mq_maxmsg = max_msgs; // Maximum number of messages in the queue - attr.mq_msgsize = msg_size; // Size of each message - attr.mq_curmsgs = 0; // Number of messages currently in the queue + // Configure the message queue attributes + attr.mq_flags = 0; // Blocking mode + attr.mq_maxmsg = max_msgs; // Maximum number of messages in the queue + attr.mq_msgsize = msg_size; // Size of each message + attr.mq_curmsgs = 0; // Number of messages currently in the queue - // Try to unlink the message queue, but ignore error if it doesn't exist - if (mq_unlink(name) == -1 && errno != ENOENT) - { - perror("Main: mq_unlink"); - return -errno; - } + // Try to unlink the message queue, but ignore error if it doesn't exist + if (mq_unlink(name) == -1 && errno != ENOENT) { + perror("Main: mq_unlink"); + return -errno; + } - // Create the message queue - mq->msgq = mq_open(name, O_CREAT | O_RDWR, 0644, &attr); - if (mq->msgq == (mqd_t)-1) { - perror("Failed to create message queue"); - return -errno; - } - return 0; + // Create the message queue + mq->msgq = mq_open(name, O_CREAT | O_RDWR, 0644, &attr); + if (mq->msgq == (mqd_t)-1) { + perror("Failed to create message queue"); + return -errno; + } + return 0; } int core_mq_send(core_mq_t *mq, const void *data, size_t msg_len) { - int ret = mq_send(mq->msgq, (const char *)data, msg_len, MQ_DEFAULT_PRIO); + int ret = mq_send(mq->msgq, (const char *)data, msg_len, MQ_DEFAULT_PRIO); - if (ret == -1) { - perror("Failed to send message"); - } - return ret; + if (ret == -1) { + perror("Failed to send message"); + } + return ret; } int core_mq_recv(core_mq_t *mq, void *data) { - struct mq_attr attr; - unsigned int priority; + struct mq_attr attr; + unsigned int priority; - // Get message queue attributes - if (mq_getattr(mq->msgq, &attr) == -1) { - perror("Failed to get message queue attributes"); - return -errno; - } - ssize_t bytes_received = mq_receive(mq->msgq, (char *)data, attr.mq_msgsize, &priority); - if (bytes_received == -1) { - perror("Failed to receive message"); - return -errno; - } - return bytes_received; + // Get message queue attributes + if (mq_getattr(mq->msgq, &attr) == -1) { + perror("Failed to get message queue attributes"); + return -errno; + } + ssize_t bytes_received = mq_receive(mq->msgq, (char *)data, attr.mq_msgsize, &priority); + if (bytes_received == -1) { + perror("Failed to receive message"); + return -errno; + } + return bytes_received; } diff --git a/src/shared/platform/posix/core_mutex.c b/src/shared/platform/posix/core_mutex.c index a13753da..36d20f99 100644 --- a/src/shared/platform/posix/core_mutex.c +++ b/src/shared/platform/posix/core_mutex.c @@ -9,19 +9,24 @@ #include #include -int core_mutex_init(core_mutex_t *mutex) { - if (!mutex) return -1; - return pthread_mutex_init(&mutex->native_mutex, NULL); +int core_mutex_init(core_mutex_t *mutex) +{ + if (!mutex) + return -1; + return pthread_mutex_init(&mutex->native_mutex, NULL); } -int core_mutex_destroy(core_mutex_t *mutex) { - return pthread_mutex_destroy(&mutex->native_mutex); +int core_mutex_destroy(core_mutex_t *mutex) +{ + return pthread_mutex_destroy(&mutex->native_mutex); } -int core_mutex_lock(core_mutex_t *mutex) { - return pthread_mutex_lock(&mutex->native_mutex); +int core_mutex_lock(core_mutex_t *mutex) +{ + return pthread_mutex_lock(&mutex->native_mutex); } -int core_mutex_unlock(core_mutex_t *mutex) { - return pthread_mutex_unlock(&mutex->native_mutex); +int core_mutex_unlock(core_mutex_t *mutex) +{ + return pthread_mutex_unlock(&mutex->native_mutex); } diff --git a/src/shared/platform/posix/core_slist.c b/src/shared/platform/posix/core_slist.c index 1def4404..81311908 100644 --- a/src/shared/platform/posix/core_slist.c +++ b/src/shared/platform/posix/core_slist.c @@ -7,28 +7,31 @@ #include "ocre_core_external.h" -void core_slist_init(core_slist_t *list) { - list->head = NULL; - list->tail = NULL; +void core_slist_init(core_slist_t *list) +{ + list->head = NULL; + list->tail = NULL; } -void core_slist_append(core_slist_t *list, core_snode_t *node) { - node->next = NULL; - if (list->tail) { - list->tail->next = node; - } else { - list->head = node; - } - list->tail = node; +void core_slist_append(core_slist_t *list, core_snode_t *node) +{ + node->next = NULL; + if (list->tail) { + list->tail->next = node; + } else { + list->head = node; + } + list->tail = node; } -void core_slist_remove(core_slist_t *list, core_snode_t *prev, core_snode_t *node) { - if (prev) { - prev->next = node->next; - } else { - list->head = node->next; - } - if (list->tail == node) { - list->tail = prev; - } +void core_slist_remove(core_slist_t *list, core_snode_t *prev, core_snode_t *node) +{ + if (prev) { + prev->next = node->next; + } else { + list->head = node->next; + } + if (list->tail == node) { + list->tail = prev; + } } diff --git a/src/shared/platform/posix/core_thread.c b/src/shared/platform/posix/core_thread.c index f6763e5b..6052beeb 100644 --- a/src/shared/platform/posix/core_thread.c +++ b/src/shared/platform/posix/core_thread.c @@ -13,65 +13,70 @@ #include #include +static void *thread_entry(void *arg) +{ + struct { + core_thread_func_t func; + void *user_arg; + char name[16]; + } *entry = arg; -static void *thread_entry(void *arg) { - struct { - core_thread_func_t func; - void *user_arg; - char name[16]; - } *entry = arg; + if (entry->name[0]) + pthread_setname_np(pthread_self(), entry->name); - if (entry->name[0]) - pthread_setname_np(pthread_self(), entry->name); - - entry->func(entry->user_arg); - free(entry); - return NULL; + entry->func(entry->user_arg); + free(entry); + return NULL; } -int core_thread_create(core_thread_t *thread, core_thread_func_t func, void *arg, const char *name, size_t stack_size, int priority) { - if (!thread || !func) return -1; - pthread_attr_t attr; - int ret; +int core_thread_create(core_thread_t *thread, core_thread_func_t func, void *arg, const char *name, size_t stack_size, + int priority) +{ + if (!thread || !func) + return -1; + pthread_attr_t attr; + int ret; - if (stack_size < PTHREAD_STACK_MIN) { - fprintf(stderr, "STACK_SIZE must be at least PTHREAD_STACK_MIN (%zu)\n", (size_t)PTHREAD_STACK_MIN); - return -1; - } + if (stack_size < PTHREAD_STACK_MIN) { + fprintf(stderr, "STACK_SIZE must be at least PTHREAD_STACK_MIN (%zu)\n", (size_t)PTHREAD_STACK_MIN); + return -1; + } - thread->stack_size = stack_size; - if (posix_memalign(&thread->stack, sysconf(_SC_PAGESIZE), stack_size) != 0) { - perror("posix_memalign"); - return -1; - } + thread->stack_size = stack_size; + if (posix_memalign(&thread->stack, sysconf(_SC_PAGESIZE), stack_size) != 0) { + perror("posix_memalign"); + return -1; + } - pthread_attr_init(&attr); - pthread_attr_setstack(&attr, thread->stack, stack_size); + pthread_attr_init(&attr); + pthread_attr_setstack(&attr, thread->stack, stack_size); - // Prepare entry struct for name passing - struct { - core_thread_func_t func; - void *user_arg; - char name[16]; - } *entry = malloc(sizeof(*entry)); - entry->func = func; - entry->user_arg = arg; - strncpy(entry->name, name ? name : "", sizeof(entry->name) - 1); - entry->name[sizeof(entry->name) - 1] = '\0'; + // Prepare entry struct for name passing + struct { + core_thread_func_t func; + void *user_arg; + char name[16]; + } *entry = malloc(sizeof(*entry)); + entry->func = func; + entry->user_arg = arg; + strncpy(entry->name, name ? name : "", sizeof(entry->name) - 1); + entry->name[sizeof(entry->name) - 1] = '\0'; - ret = pthread_create(&thread->tid, &attr, thread_entry, entry); - pthread_attr_destroy(&attr); - if (ret != 0) { - free(thread->stack); - free(entry); - return -1; - } - return 0; + ret = pthread_create(&thread->tid, &attr, thread_entry, entry); + pthread_attr_destroy(&attr); + if (ret != 0) { + free(thread->stack); + free(entry); + return -1; + } + return 0; } -void core_thread_destroy(core_thread_t *thread) { - if (!thread) return; - pthread_cancel(thread->tid); - pthread_join(thread->tid, NULL); - free(thread->stack); +void core_thread_destroy(core_thread_t *thread) +{ + if (!thread) + return; + pthread_cancel(thread->tid); + pthread_join(thread->tid, NULL); + free(thread->stack); } diff --git a/src/shared/platform/posix/core_timer.c b/src/shared/platform/posix/core_timer.c index 0692de34..33e38307 100644 --- a/src/shared/platform/posix/core_timer.c +++ b/src/shared/platform/posix/core_timer.c @@ -12,41 +12,48 @@ #include #include -static void posix_timer_cb(union sigval sv) { - core_timer_t *timer = (core_timer_t *)sv.sival_ptr; - if (timer->cb) { - timer->cb(timer->user_data); - } +static void posix_timer_cb(union sigval sv) +{ + core_timer_t *timer = (core_timer_t *)sv.sival_ptr; + if (timer->cb) { + timer->cb(timer->user_data); + } } -int core_timer_init(core_timer_t *timer, core_timer_callback_t cb, void *user_data) { - if (!timer) return -1; - struct sigevent sev = {0}; - timer->cb = cb; - timer->user_data = user_data; - sev.sigev_notify = SIGEV_THREAD; - sev.sigev_notify_function = posix_timer_cb; - sev.sigev_value.sival_ptr = timer; - return timer_create(CLOCK_REALTIME, &sev, &timer->timerid); +int core_timer_init(core_timer_t *timer, core_timer_callback_t cb, void *user_data) +{ + if (!timer) + return -1; + struct sigevent sev = {0}; + timer->cb = cb; + timer->user_data = user_data; + sev.sigev_notify = SIGEV_THREAD; + sev.sigev_notify_function = posix_timer_cb; + sev.sigev_value.sival_ptr = timer; + return timer_create(CLOCK_REALTIME, &sev, &timer->timerid); } -int core_timer_start(core_timer_t *timer, int timeout_ms, int period_ms) { - if (!timer) return -1; - struct itimerspec its; - if (timeout_ms == 0 && period_ms > 0) { - its.it_value.tv_sec = period_ms / 1000; - its.it_value.tv_nsec = (period_ms % 1000) * 1000000; - } else { - its.it_value.tv_sec = timeout_ms / 1000; - its.it_value.tv_nsec = (timeout_ms % 1000) * 1000000; - } - its.it_interval.tv_sec = period_ms / 1000; - its.it_interval.tv_nsec = (period_ms % 1000) * 1000000; - return timer_settime(timer->timerid, 0, &its, NULL); +int core_timer_start(core_timer_t *timer, int timeout_ms, int period_ms) +{ + if (!timer) + return -1; + struct itimerspec its; + if (timeout_ms == 0 && period_ms > 0) { + its.it_value.tv_sec = period_ms / 1000; + its.it_value.tv_nsec = (period_ms % 1000) * 1000000; + } else { + its.it_value.tv_sec = timeout_ms / 1000; + its.it_value.tv_nsec = (timeout_ms % 1000) * 1000000; + } + its.it_interval.tv_sec = period_ms / 1000; + its.it_interval.tv_nsec = (period_ms % 1000) * 1000000; + return timer_settime(timer->timerid, 0, &its, NULL); } -int core_timer_stop(core_timer_t *timer) { - if (!timer) return -1; - struct itimerspec its = {0}; - return timer_settime(timer->timerid, 0, &its, NULL); +int core_timer_stop(core_timer_t *timer) +{ + if (!timer) + return -1; + struct itimerspec its = {0}; + return timer_settime(timer->timerid, 0, &its, NULL); } diff --git a/src/shared/platform/posix/ocre_internal.cmake b/src/shared/platform/posix/ocre_internal.cmake index 03ec062b..f37a8480 100644 --- a/src/shared/platform/posix/ocre_internal.cmake +++ b/src/shared/platform/posix/ocre_internal.cmake @@ -36,13 +36,14 @@ endif () set (WAMR_BUILD_PLATFORM "linux") set (WAMR_BUILD_INTERP 1) set (WAMR_BUILD_FAST_INTERP 0) -set (WAMR_BUILD_AOT 0) +set (WAMR_BUILD_AOT 1) set (WAMR_BUILD_JIT 0) set (WAMR_BUILD_LIBC_BUILTIN 0) set (WAMR_BUILD_LIBC_WASI 1) set (WAMR_BUILD_LIB_PTHREAD 1) set (WAMR_BUILD_REF_TYPES 1) set (WASM_ENABLE_LOG 1) +set (WAMR_BUILD_SHARED_HEAP 1) if (NOT DEFINED WAMR_BUILD_GLOBAL_HEAP_POOL) set (WAMR_BUILD_GLOBAL_HEAP_POOL 1) diff --git a/src/shared/platform/zephyr/core_eventq.c b/src/shared/platform/zephyr/core_eventq.c index 7ec83f7a..fd0a30e0 100644 --- a/src/shared/platform/zephyr/core_eventq.c +++ b/src/shared/platform/zephyr/core_eventq.c @@ -9,56 +9,59 @@ #include #include -int core_eventq_init(core_eventq_t *eventq, size_t item_size, size_t max_items) { - eventq->buffer = core_malloc(item_size * max_items); - if (!eventq->buffer) { - return -ENOMEM; - } - eventq->item_size = item_size; - eventq->max_items = max_items; - - k_msgq_init(&eventq->msgq, (char *)eventq->buffer, item_size, max_items); - return 0; -} +int core_eventq_init(core_eventq_t *eventq, size_t item_size, size_t max_items) +{ + eventq->buffer = core_malloc(item_size * max_items); + if (!eventq->buffer) { + return -ENOMEM; + } + eventq->item_size = item_size; + eventq->max_items = max_items; -int core_eventq_peek(core_eventq_t *eventq, void *event) { - int ret = k_msgq_peek(&eventq->msgq, event); - if (ret == 0) { - return 0; - } else if (ret == -ENOMSG) { - return -ENOMSG; - } else { - return ret; - } + k_msgq_init(&eventq->msgq, (char *)eventq->buffer, item_size, max_items); + return 0; } -int core_eventq_get(core_eventq_t *eventq, void *event) { - int ret = k_msgq_get(&eventq->msgq, event, K_NO_WAIT); - if (ret == 0) { - return 0; - } else if (ret == -ENOMSG) { - return -ENOENT; - } else { - return ret; - } +int core_eventq_peek(core_eventq_t *eventq, void *event) +{ + int ret = k_msgq_peek(&eventq->msgq, event); + if (ret == 0) { + return 0; + } else if (ret == -ENOMSG) { + return -ENOMSG; + } else { + return ret; + } } -int core_eventq_put(core_eventq_t *eventq, const void *event) { - int ret = k_msgq_put(&eventq->msgq, event, K_NO_WAIT); - if (ret == 0) { - return 0; - } else if (ret == -ENOMSG) { - return -ENOMEM; - } else { - return ret; - } +int core_eventq_get(core_eventq_t *eventq, void *event) +{ + int ret = k_msgq_get(&eventq->msgq, event, K_NO_WAIT); + if (ret == 0) { + return 0; + } else if (ret == -ENOMSG) { + return -ENOENT; + } else { + return ret; + } } -void core_eventq_destroy(core_eventq_t *eventq) { - if (eventq->buffer) { - core_free(eventq->buffer); - eventq->buffer = NULL; - } +int core_eventq_put(core_eventq_t *eventq, const void *event) +{ + int ret = k_msgq_put(&eventq->msgq, event, K_NO_WAIT); + if (ret == 0) { + return 0; + } else if (ret == -ENOMSG) { + return -ENOMEM; + } else { + return ret; + } } - +void core_eventq_destroy(core_eventq_t *eventq) +{ + if (eventq->buffer) { + core_free(eventq->buffer); + eventq->buffer = NULL; + } +} diff --git a/src/shared/platform/zephyr/core_fs.c b/src/shared/platform/zephyr/core_fs.c index ef08a6de..8e480ccf 100644 --- a/src/shared/platform/zephyr/core_fs.c +++ b/src/shared/platform/zephyr/core_fs.c @@ -23,111 +23,119 @@ LOG_MODULE_REGISTER(filesystem, OCRE_LOG_LEVEL); #ifdef CONFIG_SHELL #define print(shell, level, fmt, ...) \ - do { \ - shell_fprintf(shell, level, fmt, ##__VA_ARGS__); \ - } while (false) + do { \ + shell_fprintf(shell, level, fmt, ##__VA_ARGS__); \ + } while (false) #else #define print(shell, level, fmt, ...) \ - do { \ - printk(fmt, ##__VA_ARGS__); \ - } while (false) + do { \ + printk(fmt, ##__VA_ARGS__); \ + } while (false) #endif -int core_construct_filepath(char *path, size_t len, char *name) { - return snprintf(path, len, "/lfs/ocre/images/%s.bin", name); +int core_construct_filepath(char *path, size_t len, char *name) +{ + return snprintf(path, len, "/lfs/ocre/images/%s.bin", name); } -int core_filestat(const char *path, size_t *size) { - struct fs_dirent entry; - int ret = fs_stat(path, &entry); - if (ret == 0 && size) { - *size = entry.size; - } - return ret; +int core_filestat(const char *path, size_t *size) +{ + struct fs_dirent entry; + int ret = fs_stat(path, &entry); + if (ret == 0 && size) { + *size = entry.size; + } + return ret; } -int core_fileopen(const char *path, void **handle) { - struct fs_file_t *file = core_malloc(sizeof(struct fs_file_t)); - if (!file) return -ENOMEM; - fs_file_t_init(file); - int ret = fs_open(file, path, FS_O_READ); - if (ret < 0) { - core_free(file); - return ret; - } - *handle = file; - return 0; +int core_fileopen(const char *path, void **handle) +{ + struct fs_file_t *file = core_malloc(sizeof(struct fs_file_t)); + if (!file) + return -ENOMEM; + fs_file_t_init(file); + int ret = fs_open(file, path, FS_O_READ); + if (ret < 0) { + core_free(file); + return ret; + } + *handle = file; + return 0; } -int core_fileread(void *handle, void *buffer, size_t size) { - struct fs_file_t *file = (struct fs_file_t *)handle; - return fs_read(file, buffer, size); +int core_fileread(void *handle, void *buffer, size_t size) +{ + struct fs_file_t *file = (struct fs_file_t *)handle; + return fs_read(file, buffer, size); } -int core_fileclose(void *handle) { - struct fs_file_t *file = (struct fs_file_t *)handle; - int ret = fs_close(file); - core_free(file); - return ret; +int core_fileclose(void *handle) +{ + struct fs_file_t *file = (struct fs_file_t *)handle; + int ret = fs_close(file); + core_free(file); + return ret; } -static int lsdir(const char *path) { - int res; - struct fs_dir_t dirp; - static struct fs_dirent entry; - - fs_dir_t_init(&dirp); - - /* Verify fs_opendir() */ - res = fs_opendir(&dirp, path); - if (res) { - LOG_ERR("Error opening dir %s [%d]\n", path, res); - return res; - } - - for (;;) { - // Verify fs_readdir() - res = fs_readdir(&dirp, &entry); - - // entry.name[0] == 0 means end-of-dir - if (res || entry.name[0] == 0) { - if (res < 0) { - LOG_ERR("Error reading dir [%d]\n", res); - } - break; - } - } - - // Verify fs_closedir() - fs_closedir(&dirp); - - return res; +static int lsdir(const char *path) +{ + int res; + struct fs_dir_t dirp; + static struct fs_dirent entry; + + fs_dir_t_init(&dirp); + + /* Verify fs_opendir() */ + res = fs_opendir(&dirp, path); + if (res) { + LOG_ERR("Error opening dir %s [%d]\n", path, res); + return res; + } + + for (;;) { + // Verify fs_readdir() + res = fs_readdir(&dirp, &entry); + + // entry.name[0] == 0 means end-of-dir + if (res || entry.name[0] == 0) { + if (res < 0) { + LOG_ERR("Error reading dir [%d]\n", res); + } + break; + } + } + + // Verify fs_closedir() + fs_closedir(&dirp); + + return res; } -static int littlefs_flash_erase(unsigned int id) { - const struct flash_area *pfa; - int rc; +static int littlefs_flash_erase(unsigned int id) +{ + const struct flash_area *pfa; + int rc; - rc = flash_area_open(id, &pfa); - if (rc < 0) { - LOG_ERR("FAIL: unable to find flash area %u: %d\n", id, rc); - return rc; - } + rc = flash_area_open(id, &pfa); + if (rc < 0) { + LOG_ERR("FAIL: unable to find flash area %u: %d\n", id, rc); + return rc; + } - LOG_PRINTK("Area %u at 0x%x on %s for %u bytes\n", id, (unsigned int)pfa->fa_off, pfa->fa_dev->name, - (unsigned int)pfa->fa_size); + LOG_PRINTK("Area %u at 0x%x on %s for %u bytes\n", id, (unsigned int)pfa->fa_off, pfa->fa_dev->name, + (unsigned int)pfa->fa_size); - rc = flash_area_erase(pfa, 0, pfa->fa_size); + rc = flash_area_erase(pfa, 0, pfa->fa_size); - if (rc < 0) { - LOG_ERR("Failed to erase flash: %d", rc); - } else { - LOG_INF("Successfully erased flash"); - } + if (rc < 0) { + LOG_ERR("Failed to erase flash: %d", rc); + } else { + LOG_INF("Successfully erased flash"); + } - flash_area_close(pfa); + flash_area_close(pfa); - return rc; + return rc; } #define PARTITION_NODE DT_NODELABEL(lfs1) @@ -137,134 +145,138 @@ FS_FSTAB_DECLARE_ENTRY(PARTITION_NODE); #else /* PARTITION_NODE */ FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(user_data); static struct fs_mount_t lfs_storage_mnt = { - .type = FS_LITTLEFS, - .fs_data = &user_data, - .storage_dev = (void *)FIXED_PARTITION_ID(user_data_partition), - .mnt_point = FS_MOUNT_POINT, + .type = FS_LITTLEFS, + .fs_data = &user_data, + .storage_dev = (void *)FIXED_PARTITION_ID(user_data_partition), + .mnt_point = FS_MOUNT_POINT, }; #endif /* PARTITION_NODE */ struct fs_mount_t *mp = #if DT_NODE_EXISTS(PARTITION_NODE) - &FS_FSTAB_ENTRY(PARTITION_NODE) + &FS_FSTAB_ENTRY(PARTITION_NODE) #else - &lfs_storage_mnt + &lfs_storage_mnt #endif - ; + ; -static int littlefs_mount(struct fs_mount_t *mp) { - int rc = 0; +static int littlefs_mount(struct fs_mount_t *mp) +{ + int rc = 0; - /* Do not mount if auto-mount has been enabled */ + /* Do not mount if auto-mount has been enabled */ #if !DT_NODE_EXISTS(PARTITION_NODE) || !(FSTAB_ENTRY_DT_MOUNT_FLAGS(PARTITION_NODE) & FS_MOUNT_FLAG_AUTOMOUNT) - rc = fs_mount(mp); - if (rc < 0) { - LOG_ERR("FAIL: mount id %" PRIuPTR " at %s: %d\n", (uintptr_t)mp->storage_dev, mp->mnt_point, rc); - return rc; - } - LOG_INF("%s mount: %d\n", mp->mnt_point, rc); + rc = fs_mount(mp); + if (rc < 0) { + LOG_ERR("FAIL: mount id %" PRIuPTR " at %s: %d\n", (uintptr_t)mp->storage_dev, mp->mnt_point, rc); + return rc; + } + LOG_INF("%s mount: %d\n", mp->mnt_point, rc); #else - LOG_INF("%s automounted\n", mp->mnt_point); + LOG_INF("%s automounted\n", mp->mnt_point); #endif - return rc; + return rc; } #ifdef CONFIG_APP_LITTLEFS_STORAGE_BLK_SDMMC struct fs_littlefs lfsfs; static struct fs_mount_t __mp = { - .type = FS_LITTLEFS, - .fs_data = &lfsfs, - .flags = FS_MOUNT_FLAG_USE_DISK_ACCESS, + .type = FS_LITTLEFS, + .fs_data = &lfsfs, + .flags = FS_MOUNT_FLAG_USE_DISK_ACCESS, }; struct fs_mount_t *mp = &__mp; -static int littlefs_mount(struct fs_mount_t *mp) { - static const char *disk_mount_pt = "/" CONFIG_SDMMC_VOLUME_NAME ":"; - static const char *disk_pdrv = CONFIG_SDMMC_VOLUME_NAME; +static int littlefs_mount(struct fs_mount_t *mp) +{ + static const char *disk_mount_pt = "/" CONFIG_SDMMC_VOLUME_NAME ":"; + static const char *disk_pdrv = CONFIG_SDMMC_VOLUME_NAME; - mp->storage_dev = (void *)disk_pdrv; - mp->mnt_point = disk_mount_pt; + mp->storage_dev = (void *)disk_pdrv; + mp->mnt_point = disk_mount_pt; - return fs_mount(mp); + return fs_mount(mp); } #endif /* CONFIG_APP_LITTLEFS_STORAGE_BLK_SDMMC */ -void ocre_app_storage_init() { - struct fs_dirent entry; - struct fs_statvfs sbuf; - int rc; - - rc = littlefs_mount(mp); - if (rc < 0) { - return; - } - - rc = fs_statvfs(mp->mnt_point, &sbuf); - if (rc < 0) { - LOG_ERR("FAILR statvfs: %d", rc); - return; - } - - LOG_DBG("%s: bsize = %lu ; frsize = %lu ;" - " blocks = %lu ; bfree = %lu", - mp->mnt_point, sbuf.f_bsize, sbuf.f_frsize, sbuf.f_blocks, sbuf.f_bfree); - - rc = lsdir(mp->mnt_point); - if (rc < 0) { - LOG_ERR("FAIL: lsdir %s: %d", mp->mnt_point, rc); - } - - // Create the core directories if they don't exist - if (fs_stat(OCRE_BASE_PATH, &entry) == -ENOENT) { - fs_mkdir(OCRE_BASE_PATH); - } - - if (fs_stat(APP_RESOURCE_PATH, &entry) == -ENOENT) { - fs_mkdir(APP_RESOURCE_PATH); - } - - if (fs_stat(PACKAGE_BASE_PATH, &entry) == -ENOENT) { - fs_mkdir(PACKAGE_BASE_PATH); - } - - if (fs_stat(CONFIG_PATH, &entry) == -ENOENT) { - fs_mkdir(CONFIG_PATH); - } +void ocre_app_storage_init() +{ + struct fs_dirent entry; + struct fs_statvfs sbuf; + int rc; + + rc = littlefs_mount(mp); + if (rc < 0) { + return; + } + + rc = fs_statvfs(mp->mnt_point, &sbuf); + if (rc < 0) { + LOG_ERR("FAILR statvfs: %d", rc); + return; + } + + LOG_DBG("%s: bsize = %lu ; frsize = %lu ;" + " blocks = %lu ; bfree = %lu", + mp->mnt_point, sbuf.f_bsize, sbuf.f_frsize, sbuf.f_blocks, sbuf.f_bfree); + + rc = lsdir(mp->mnt_point); + if (rc < 0) { + LOG_ERR("FAIL: lsdir %s: %d", mp->mnt_point, rc); + } + + // Create the core directories if they don't exist + if (fs_stat(OCRE_BASE_PATH, &entry) == -ENOENT) { + fs_mkdir(OCRE_BASE_PATH); + } + + if (fs_stat(APP_RESOURCE_PATH, &entry) == -ENOENT) { + fs_mkdir(APP_RESOURCE_PATH); + } + + if (fs_stat(PACKAGE_BASE_PATH, &entry) == -ENOENT) { + fs_mkdir(PACKAGE_BASE_PATH); + } + + if (fs_stat(CONFIG_PATH, &entry) == -ENOENT) { + fs_mkdir(CONFIG_PATH); + } #ifdef CONFIG_OCRE_CONTAINER_FILESYSTEM - if (fs_stat(CONTAINER_FS_PATH, &entry) == -ENOENT) { - fs_mkdir(CONTAINER_FS_PATH); - } + if (fs_stat(CONTAINER_FS_PATH, &entry) == -ENOENT) { + fs_mkdir(CONTAINER_FS_PATH); + } #endif } -static int cmd_flash_format(const struct shell *shell, size_t argc, char *argv[]) { - int rc; - fs_unmount(mp); +static int cmd_flash_format(const struct shell *shell, size_t argc, char *argv[]) +{ + int rc; + fs_unmount(mp); - // FIXME: if erasing the whole chip, could cause problems - // https://github.com/zephyrproject-rtos/zephyr/issues/56442 - rc = littlefs_flash_erase((uintptr_t)mp->storage_dev); + // FIXME: if erasing the whole chip, could cause problems + // https://github.com/zephyrproject-rtos/zephyr/issues/56442 + rc = littlefs_flash_erase((uintptr_t)mp->storage_dev); - if (rc < 0) { - print(shell, SHELL_WARNING, "Format failed: %d\n", rc); - } else { - print(shell, SHELL_NORMAL, "Format succeeded\n"); - } + if (rc < 0) { + print(shell, SHELL_WARNING, "Format failed: %d\n", rc); + } else { + print(shell, SHELL_NORMAL, "Format succeeded\n"); + } - if (rc == 0) { - LOG_INF("Mounting..."); - rc = littlefs_mount(mp); - } + if (rc == 0) { + LOG_INF("Mounting..."); + rc = littlefs_mount(mp); + } - return rc; + return rc; } SHELL_STATIC_SUBCMD_SET_CREATE(flash_commands, - SHELL_CMD(format, NULL, "Format the flash storage device (all user data will be lost)", - cmd_flash_format), - SHELL_SUBCMD_SET_END); + SHELL_CMD(format, NULL, "Format the flash storage device (all user data will be lost)", + cmd_flash_format), + SHELL_SUBCMD_SET_END); SHELL_CMD_REGISTER(user_storage, &flash_commands, "User storage management", NULL); diff --git a/src/shared/platform/zephyr/core_memory.c b/src/shared/platform/zephyr/core_memory.c index 3655ed4b..f862143c 100644 --- a/src/shared/platform/zephyr/core_memory.c +++ b/src/shared/platform/zephyr/core_memory.c @@ -9,10 +9,12 @@ #include -void *core_malloc(size_t size) { - return k_malloc(size); +void *core_malloc(size_t size) +{ + return k_malloc(size); } -void core_free(void *ptr) { - k_free(ptr); +void core_free(void *ptr) +{ + k_free(ptr); } diff --git a/src/shared/platform/zephyr/core_misc.c b/src/shared/platform/zephyr/core_misc.c index c689ee77..7bef689f 100644 --- a/src/shared/platform/zephyr/core_misc.c +++ b/src/shared/platform/zephyr/core_misc.c @@ -8,10 +8,12 @@ #include "ocre_core_external.h" #include -void core_sleep_ms(int milliseconds) { - k_msleep(milliseconds); +void core_sleep_ms(int milliseconds) +{ + k_msleep(milliseconds); } -void core_yield(void) { - k_yield(); +void core_yield(void) +{ + k_yield(); } diff --git a/src/shared/platform/zephyr/core_mq.c b/src/shared/platform/zephyr/core_mq.c index c7c88665..2e1589df 100644 --- a/src/shared/platform/zephyr/core_mq.c +++ b/src/shared/platform/zephyr/core_mq.c @@ -11,22 +11,22 @@ LOG_MODULE_DECLARE(platform_mq_component, OCRE_LOG_LEVEL); int core_mq_init(core_mq_t *mq, const char *name, size_t msg_size, uint32_t max_msgs) { - mq->msgq_buffer = k_malloc(msg_size * max_msgs); - k_msgq_init(&mq->msgq, mq->msgq_buffer, msg_size, max_msgs); - return 0; + mq->msgq_buffer = k_malloc(msg_size * max_msgs); + k_msgq_init(&mq->msgq, mq->msgq_buffer, msg_size, max_msgs); + return 0; } int core_mq_send(core_mq_t *mq, const void *data, size_t msg_len) { - int ret = k_msgq_put(&mq->msgq, data, MQ_DEFAULT_TIMEOUT); + int ret = k_msgq_put(&mq->msgq, data, MQ_DEFAULT_TIMEOUT); - if (ret != 0) { - LOG_HEXDUMP_DBG(data, msg_len, "message"); - } - return ret; + if (ret != 0) { + LOG_HEXDUMP_DBG(data, msg_len, "message"); + } + return ret; } int core_mq_recv(core_mq_t *mq, void *data) { - return k_msgq_get(&mq->msgq, data, K_FOREVER); + return k_msgq_get(&mq->msgq, data, K_FOREVER); } diff --git a/src/shared/platform/zephyr/core_mutex.c b/src/shared/platform/zephyr/core_mutex.c index bd8f8034..6657891b 100644 --- a/src/shared/platform/zephyr/core_mutex.c +++ b/src/shared/platform/zephyr/core_mutex.c @@ -8,21 +8,25 @@ #include "ocre_core_external.h" #include -int core_mutex_init(core_mutex_t *mutex) { - if (!mutex) return -1; - k_mutex_init(&mutex->native_mutex); - return 0; +int core_mutex_init(core_mutex_t *mutex) +{ + if (!mutex) + return -1; + k_mutex_init(&mutex->native_mutex); + return 0; } -int core_mutex_destroy(core_mutex_t *mutex) { - return 0; +int core_mutex_destroy(core_mutex_t *mutex) +{ + return 0; } -int core_mutex_lock(core_mutex_t *mutex) { - return k_mutex_lock(&mutex->native_mutex, K_FOREVER); +int core_mutex_lock(core_mutex_t *mutex) +{ + return k_mutex_lock(&mutex->native_mutex, K_FOREVER); } -int core_mutex_unlock(core_mutex_t *mutex) { - return k_mutex_unlock(&mutex->native_mutex); +int core_mutex_unlock(core_mutex_t *mutex) +{ + return k_mutex_unlock(&mutex->native_mutex); } - diff --git a/src/shared/platform/zephyr/core_thread.c b/src/shared/platform/zephyr/core_thread.c index 7bbd6fdd..1c81191a 100644 --- a/src/shared/platform/zephyr/core_thread.c +++ b/src/shared/platform/zephyr/core_thread.c @@ -9,27 +9,32 @@ #include #include - -static void thread_entry(void *arg1, void *arg2, void *arg3) { - core_thread_func_t func = (core_thread_func_t)arg2; - void *user_arg = arg3; - func(user_arg); +static void thread_entry(void *arg1, void *arg2, void *arg3) +{ + core_thread_func_t func = (core_thread_func_t)arg2; + void *user_arg = arg3; + func(user_arg); } -int core_thread_create(core_thread_t *thread, core_thread_func_t func, void *arg, const char *name, size_t stack_size, int priority) { - if (!thread || !func) return -1; - thread->stack = k_thread_stack_alloc(stack_size, 0); - if (!thread->stack) return -1; - thread->tid = k_thread_create(&thread->thread, thread->stack, stack_size, - thread_entry, NULL, (void *)func, arg, - priority, 0, K_NO_WAIT); - if (name) - k_thread_name_set(thread->tid, name); - return thread->tid ? 0 : -1; +int core_thread_create(core_thread_t *thread, core_thread_func_t func, void *arg, const char *name, size_t stack_size, + int priority) +{ + if (!thread || !func) + return -1; + thread->stack = k_thread_stack_alloc(stack_size, 0); + if (!thread->stack) + return -1; + thread->tid = k_thread_create(&thread->thread, thread->stack, stack_size, thread_entry, NULL, (void *)func, arg, + priority, 0, K_NO_WAIT); + if (name) + k_thread_name_set(thread->tid, name); + return thread->tid ? 0 : -1; } -void core_thread_destroy(core_thread_t *thread) { - if (!thread) return; - k_thread_abort(thread->tid); - k_thread_stack_free(thread->stack); +void core_thread_destroy(core_thread_t *thread) +{ + if (!thread) + return; + k_thread_abort(thread->tid); + k_thread_stack_free(thread->stack); } diff --git a/src/shared/platform/zephyr/core_timer.c b/src/shared/platform/zephyr/core_timer.c index 10da2d32..32d0520e 100644 --- a/src/shared/platform/zephyr/core_timer.c +++ b/src/shared/platform/zephyr/core_timer.c @@ -8,30 +8,36 @@ #include "ocre_core_external.h" #include - -static void zephyr_timer_cb(struct k_timer *ktimer) { - core_timer_t *otimer = CONTAINER_OF(ktimer, core_timer_t, timer); - if (otimer->cb) { - otimer->cb(otimer->user_data); - } +static void zephyr_timer_cb(struct k_timer *ktimer) +{ + core_timer_t *otimer = CONTAINER_OF(ktimer, core_timer_t, timer); + if (otimer->cb) { + otimer->cb(otimer->user_data); + } } -int core_timer_init(core_timer_t *timer, core_timer_callback_t cb, void *user_data) { - if (!timer) return -1; - timer->cb = cb; - timer->user_data = user_data; - k_timer_init(&timer->timer, zephyr_timer_cb, NULL); - return 0; +int core_timer_init(core_timer_t *timer, core_timer_callback_t cb, void *user_data) +{ + if (!timer) + return -1; + timer->cb = cb; + timer->user_data = user_data; + k_timer_init(&timer->timer, zephyr_timer_cb, NULL); + return 0; } -int core_timer_start(core_timer_t *timer, int timeout_ms, int period_ms) { - if (!timer) return -1; - k_timer_start(&timer->timer, K_MSEC(timeout_ms), K_MSEC(period_ms)); - return 0; +int core_timer_start(core_timer_t *timer, int timeout_ms, int period_ms) +{ + if (!timer) + return -1; + k_timer_start(&timer->timer, K_MSEC(timeout_ms), K_MSEC(period_ms)); + return 0; } -int core_timer_stop(core_timer_t *timer) { - if (!timer) return -1; - k_timer_stop(&timer->timer); - return 0; +int core_timer_stop(core_timer_t *timer) +{ + if (!timer) + return -1; + k_timer_stop(&timer->timer); + return 0; } diff --git a/src/shared/platform/zephyr/ocre_internal.cmake b/src/shared/platform/zephyr/ocre_internal.cmake index 38fbcd16..cdf9c368 100644 --- a/src/shared/platform/zephyr/ocre_internal.cmake +++ b/src/shared/platform/zephyr/ocre_internal.cmake @@ -8,23 +8,32 @@ zephyr_compile_options(-DVERSION_BUILD_MACHINE="${BUILD_MACHINE}") message("BUILD_INFO: ${BUILD_INFO}") zephyr_compile_options(-DVERSION_BUILD_INFO="${BUILD_INFO}") -# Determine the ISA of the target and set appropriately -if (DEFINED CONFIG_ISA_THUMB2) - set(TARGET_ISA THUMB) +if (CONFIG_CPU_CORTEX_M33 OR CONFIG_CPU_CORTEX_M35P OR CONFIG_CPU_CORTEX_M55 OR CONFIG_CPU_CORTEX_M85) + # ARMv8-M Mainline (Cortex-M33, M35P, M55, M85) + set (TARGET_ISA THUMBV8M) +elseif (CONFIG_CPU_CORTEX_M23) + # ARMv8-M Baseline (Cortex-M23) + set (TARGET_ISA THUMBV8M) +elseif (CONFIG_CPU_CORTEX_M7 OR CONFIG_CPU_CORTEX_M4) + # ARMv7E-M (Cortex-M4, M7) + set (TARGET_ISA THUMBV7EM) +elseif (DEFINED CONFIG_ISA_THUMB2) + # Generic Thumb-2 + set (TARGET_ISA THUMB) elseif (DEFINED CONFIG_ISA_ARM) - set(TARGET_ISA ARM) + set (TARGET_ISA ARM) elseif (DEFINED CONFIG_X86) - set(TARGET_ISA X86_32) + set (TARGET_ISA X86_32) elseif (DEFINED CONFIG_XTENSA) - set(TARGET_ISA XTENSA) + set (TARGET_ISA XTENSA) elseif (DEFINED CONFIG_RISCV) - set(TARGET_ISA RISCV32) + set (TARGET_ISA RISCV32) elseif (DEFINED CONFIG_ARCH_POSIX) - set(TARGET_ISA X86_32) + set (TARGET_ISA X86_32) else () - message(FATAL_ERROR "Unsupported ISA: ${CONFIG_ARCH}") + message (FATAL_ERROR "Unsupported ISA: ${CONFIG_ARCH}") endif () -message("TARGET ISA: ${TARGET_ISA}") +message(STATUS "TARGET ISA: ${TARGET_ISA}") add_compile_options(-O0 -Wno-unknown-attributes) @@ -33,13 +42,14 @@ set(WAMR_BUILD_PLATFORM "zephyr") set(WAMR_BUILD_TARGET ${TARGET_ISA}) set(WAMR_BUILD_INTERP 1) set(WAMR_BUILD_FAST_INTERP 0) -set(WAMR_BUILD_AOT 0) +set(WAMR_BUILD_AOT 1) set(WAMR_BUILD_JIT 0) set(WAMR_BUILD_LIBC_BUILTIN 0) set(WAMR_BUILD_LIBC_WASI 1) set(WAMR_BUILD_LIB_PTHREAD 1) set(WAMR_BUILD_REF_TYPES 1) set(WASM_ENABLE_LOG 1) +set (WAMR_BUILD_SHARED_HEAP 1) if(NOT DEFINED WAMR_BUILD_GLOBAL_HEAP_POOL) set(WAMR_BUILD_GLOBAL_HEAP_POOL 1) diff --git a/tests/groups/modbusServerValidation/clean.sh b/tests/groups/modbusServerValidation/clean.sh new file mode 100644 index 00000000..6b895bf1 --- /dev/null +++ b/tests/groups/modbusServerValidation/clean.sh @@ -0,0 +1 @@ +echo "Cleanup is complete" \ No newline at end of file diff --git a/tests/groups/modbusServerValidation/config.json b/tests/groups/modbusServerValidation/config.json new file mode 100644 index 00000000..1190912a --- /dev/null +++ b/tests/groups/modbusServerValidation/config.json @@ -0,0 +1,33 @@ +{ + "name": "Modbus Server Validation", + "description": "Test the Ocre Modbus server ", + "setup": [ + { + "name": "Modbus Server Validation Setup", + "exec": "bash setup.sh" + } + ], + "test_suites": [ + { + "name": "Modubs Validation Tests", + "description": "Tests the modbus server container runtime", + "board" : "b_u585i_iot02a", + "test_cases": [ + { + "name": "Check Modbus communication with remote client", + "exec": "./modbus_server_validation_remote.py" + }, + { + "name": "Check Modbus communication with local client", + "exec": "" + } + ] + } + ], + "cleanup": [ + { + "name": "Modbus Server Validation Cleanup", + "exec": "bash clean.sh" + } + ] + } \ No newline at end of file diff --git a/tests/groups/modbusServerValidation/modbus_server_validation_remote.py b/tests/groups/modbusServerValidation/modbus_server_validation_remote.py new file mode 100755 index 00000000..c0d8559a --- /dev/null +++ b/tests/groups/modbusServerValidation/modbus_server_validation_remote.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 + +import serial +import time +import sys +from pymodbus.client import ModbusTcpClient + +def exitSafe(conn: serial.Serial, client: ModbusTcpClient, exitCode: int): + conn.close() + client.close() + sys.exit(exitCode) + +""" +This testcase is to be used following a modbus server being installed on a board. + +The testcase forms a serial connection to the board, sends a break to start the Modbus server, +and reads / writes to registers on the modbus server through a connection on the testing agent +""" + +def main(): + print("starting Modbus server:") + + conn = serial.Serial('/dev/ttyACM0', 115200, timeout=1) + conn.reset_input_buffer() + conn.send_break(duration=1) + + # Wait for modbus server to be up and board to get networking + time.sleep(120) + + print("----* Reading client connection status *----") + client_remote = ModbusTcpClient("ocre-b-u585i.lfedge.iol.unh.edu", port=1502) + client_remote.connect() + + connection_results = [client_remote.connected, client_remote.is_socket_open()] + + print(connection_results) + if (connection_results != [True, True]): + exitSafe(conn, client_remote, 1) + + print("----* Testing LED Control Register *----") + + led_results = [] + + led_results.append(client_remote.read_holding_registers(0x00).registers[0]) # 0 + client_remote.write_register(0x00, 0x01) + time.sleep(5) + led_results.append(client_remote.read_holding_registers(0x00).registers[0]) # 1 + client_remote.write_register(0x00, 0x02) + time.sleep(5) + led_results.append(client_remote.read_holding_registers(0x00).registers[0]) # 2 + client_remote.write_register(0x00, 0x00) + time.sleep(5) + led_results.append(client_remote.read_holding_registers(0x00).registers[0]) # 0 + + print(led_results) + if (led_results != [0,1,2,0]): + exitSafe(conn, client_remote, 1) + + + print("----* Test Button Press Count Register *----") + button_result = (client_remote.read_holding_registers(0x01).registers[0]) # 0 + + if button_result != 0: + exitSafe(conn, client_remote, 1) + + + print("----* Waiting for updates to Modbus server container before continuing *---") + + # print("----* Test reading 32 bit floats *----") + # print("Acceleration X") + # print(client_remote.convert_from_registers([0x04, 0x05], client_remote.DATATYPE.FLOAT32, word_order="little")) + # print(client_remote.read_holding_registers(0x04).registers) + # print(client_remote.read_holding_registers(0x05).registers) + # print(client_remote.read_input_registers(0x04).registers) + # print(client_remote.read_input_registers(0x05).registers) + + + # print("Gyroscope X") + # print(client_remote.convert_from_registers([0x08, 0x09], client_remote.DATATYPE.FLOAT32, word_order="little")) + # print(client_remote.read_holding_registers(0x08).registers) + # print(client_remote.read_holding_registers(0x09).registers) + # print(client_remote.read_input_registers(0x08).registers) + # print(client_remote.read_input_registers(0x09).registers) + + + # print("Humidity") + # print(client_remote.convert_from_registers([0x14, 0x15], client_remote.DATATYPE.FLOAT32, word_order="little")) + # print(client_remote.read_holding_registers(0x14).registers) + # print(client_remote.read_holding_registers(0x15).registers) + # print(client_remote.read_input_registers(0x14).registers) + # print(client_remote.read_input_registers(0x15).registers) + + # print("Temperature") + # print(client_remote.convert_from_registers([0x16, 0x17], client_remote.DATATYPE.FLOAT32, word_order="little")) + # print(client_remote.read_holding_registers(0x16).registers) + # print(client_remote.read_holding_registers(0x17).registers) + # print(client_remote.read_input_registers(0x16).registers) + # print(client_remote.read_input_registers(0x17).registers) + + print("----* Closing Connection *----") + exitSafe(conn, client_remote, 0) + +if __name__ == "__main__": + main() + + diff --git a/tests/groups/modbusServerValidation/setup.sh b/tests/groups/modbusServerValidation/setup.sh new file mode 100644 index 00000000..798952e5 --- /dev/null +++ b/tests/groups/modbusServerValidation/setup.sh @@ -0,0 +1,2 @@ +# Assumes board is being flashed with both hello world and modbus-server +echo "Setup is complete" \ No newline at end of file diff --git a/wasm-micro-runtime b/wasm-micro-runtime index e1bcab4a..60253bed 160000 --- a/wasm-micro-runtime +++ b/wasm-micro-runtime @@ -1 +1 @@ -Subproject commit e1bcab4afe9a92272b6df2ec7dc51b51e6ccb672 +Subproject commit 60253bedbbbc16ff586381f3cd142f639ce23d94 diff --git a/west.yml b/west.yml index cee4e7bb..3e8d71a1 100644 --- a/west.yml +++ b/west.yml @@ -14,6 +14,7 @@ manifest: - hal_st - mbedtls - cmsis_6 - + - hal_nordic + self: - path: application + path: application