From 5992d7c1ad739577e0aebe3109a3beccd61e8024 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Fri, 17 Oct 2025 15:36:59 -0400 Subject: [PATCH 01/38] tests: Add initial test case for Modbus server Includes new test group for the modbus server, alongside the initial test case where the modbus server is coneceted to by a client on the github action's runner. Currently, the github actions runner connects to the modbus server to read and write to the LED and Button register(s). Will need to update test case as registers are implemented in the modbus server container. This commit also includes changes in tests.yml in order to run the test group and store the github artifact. Signed-off-by: Matthew Gee --- .github/workflows/tests.yml | 16 +++ tests/groups/modbusServerValidation/clean.sh | 1 + .../groups/modbusServerValidation/config.json | 33 ++++++ .../modbusServer_validation_remote.py | 105 ++++++++++++++++++ tests/groups/modbusServerValidation/setup.sh | 2 + 5 files changed, 157 insertions(+) create mode 100644 tests/groups/modbusServerValidation/clean.sh create mode 100644 tests/groups/modbusServerValidation/config.json create mode 100644 tests/groups/modbusServerValidation/modbusServer_validation_remote.py create mode 100644 tests/groups/modbusServerValidation/setup.sh diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e2a4fec3..ff673b06 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,3 +29,19 @@ jobs: with: name: "FlashValidation.log" path: /tmp/flashValidation.log + + - name: Modbus Server 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 + 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..228b0ef3 --- /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": "./modbusServer_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/modbusServer_validation_remote.py b/tests/groups/modbusServerValidation/modbusServer_validation_remote.py new file mode 100644 index 00000000..5fcd3525 --- /dev/null +++ b/tests/groups/modbusServerValidation/modbusServer_validation_remote.py @@ -0,0 +1,105 @@ +#!/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.send_break(duration=1) + + # Wait for modbus server to be up + time.sleep(5) + + print("----* Reading client connection status *----") + client_remote = ModbusTcpClient("132.177.122.245", 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 From b7b2b7f21a7002f40de8ba4836d0a09c357b3aac Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Tue, 21 Oct 2025 17:45:17 -0400 Subject: [PATCH 02/38] tests: Change Modbus IP to DNS hostname Changes the modbus server test from using a DHCP IP address to a DNS hostname we can manage seperatly from the codebase. Signed-off-by: Matthew Gee --- .../modbusServerValidation/modbusServer_validation_remote.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/groups/modbusServerValidation/modbusServer_validation_remote.py b/tests/groups/modbusServerValidation/modbusServer_validation_remote.py index 5fcd3525..0da33ef0 100644 --- a/tests/groups/modbusServerValidation/modbusServer_validation_remote.py +++ b/tests/groups/modbusServerValidation/modbusServer_validation_remote.py @@ -27,7 +27,7 @@ def main(): time.sleep(5) print("----* Reading client connection status *----") - client_remote = ModbusTcpClient("132.177.122.245", port=1502) + 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()] From f61fd560a2e7d8ae2aad3d6017b5279d9dbdd764 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Wed, 22 Oct 2025 15:06:48 -0400 Subject: [PATCH 03/38] tests: Recactor build.yml to support modbus tests Moved the generation of wasm files to a seperate step and upload wasms as artifacts, future steps should download these wasm artificats instead of building locally. Includes addition of Github actions job to flash b_u585i_i0t02a board with the Modbus image by pulling the wasm file artifact and running west build. Affected github actions jobs are: - build-and-run-zephyr-sample - build-and-run-linux-sample - modbus-server-validation-tests Adds the following github action jobs: - build-wasm-files - flash-zephyr-modbus_server-b_u585i_iot02a Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 143 ++++++++++++++++++++++++------------ 1 file changed, 98 insertions(+), 45 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f16ba86d..21e5c47e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -142,19 +142,25 @@ jobs: run: | STM32_Programmer_CLI -c port=swd -e all -w zephyr.bin 0x08000000 -v -rst - build-and-run-linux-sample: - runs-on: ubuntu-latest + # Build and upload wasm files as artifacts + build-wasm-files: + runs-on: zephyr-xlarge-runner + 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" + - name: generic-filesystem-full path: generic/filesystem-full - # Add here more samples + - name: b_u585i-modbus-server + path: board_specific/b_u585i_iot02a/modbus-server steps: + - name: Cleanup workspace + uses: eviden-actions/clean-self-hosted-runner@v1 + - name: Checkout current repository uses: actions/checkout@v4 with: @@ -166,9 +172,19 @@ jobs: repository: project-ocre/ocre-sdk path: ocre-sdk - - name: Install build tools and WASI SDK + - 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 build-essential cmake + 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 @@ -190,6 +206,43 @@ jobs: make env: WASI_SDK_PATH: /opt/wasi-sdk + + - name: Upload .wasm artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: "{{ matrix.sample.name }}.wasm" + path: "/tmp/built-wasm/{{ matrix.sample.name }}.wasm" + + build-and-run-linux-sample: + needs: build-wasm-files + runs-on: ubuntu-latest + strategy: + matrix: + sample: + - name: generic-hello-world + expected: "powered by Ocre" + - name: generic-filesystem-full + expected: "Directory listing for" + # Add here more samples + steps: + - 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 + if: runner.environment == 'self-hosted' + uses: actions/download-artifact@v4 + with: + name: "{{ matrix.sample.name }}.wasm" + path: /tmp/built-wasm/ - name: Update Submodules working-directory: application @@ -206,7 +259,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 }}.wasm chmod +x app stdbuf -oL -eL timeout 20s ./app $WASM_FILE | tee "${{ matrix.sample.name }}_run.log" @@ -217,7 +270,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 @@ -225,13 +281,10 @@ jobs: strategy: matrix: sample: - - name: hello-world + - name: generic-hello-world expected: "powered by Ocre" - path: generic/hello-world - - name: filesystem-full + - name: generic-filesystem-full expected: "Directory listing for" - path: generic/filesystem-full - # Add here more samples steps: - name: Cleanup workspace uses: eviden-actions/clean-self-hosted-runner@v1 @@ -253,34 +306,12 @@ 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 }}.wasm" + path: /tmp/built-wasm/ - name: Update Submodules working-directory: application @@ -290,10 +321,12 @@ 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 }}.wasm west build --pristine -b native_sim ./application -d build -- \ -DMODULE_EXT_ROOT=$(pwd)/application \ -DOCRE_INPUT_FILE=$WASM_FILE + env: + WASI_SDK_PATH: /opt/wasi-sdk - name: Run Sample ${{ matrix.sample.name }} working-directory: build/zephyr/ @@ -316,6 +349,7 @@ jobs: echo "[FAIL] ${{ matrix.sample.name }} did not produce expected log: ${{ matrix.sample.expected }}" exit 1 fi + flash-validation-tests: needs: flash-zephyr-base-b_u585i_iot02a runs-on: zephyr-xlarge-runner @@ -338,8 +372,27 @@ jobs: name: "FlashValidation.log" path: /tmp/flashValidation.log + + flash-zephyr-modbus_server-b_u585i_iot02a: + needs: 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: b_u585i-modbus-server.wasm + + - name: Flash b_u585i_iot02a + if: runner.environment == 'self-hosted' + run: | + WASM_FILE=$GITHUB_WORKSPACE/b_u585i-modbus-server.wasm + west build --pristine -b native_sim ./application -d build -- \ + -DMODULE_EXT_ROOT=$(pwd)/application \ + -DOCRE_INPUT_FILE=$WASM_FILE + modbus-server-validation-tests: - needs: flash-zephyr-base-b_u585i_iot02a + needs: flash-zephyr-modbus_server-b_u585i_iot02a runs-on: zephyr-xlarge-runner steps: - name: Checkout From bfa8dd35fda34c82ea21beec5b11b6e021c07fb2 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Wed, 22 Oct 2025 16:17:05 -0400 Subject: [PATCH 04/38] tests: Fix wasm build github action Added step to update submodules of git branch to prevent errors in github action job "build-wasm-files". Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 21e5c47e..27b38f79 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -172,6 +172,11 @@ jobs: repository: project-ocre/ocre-sdk path: ocre-sdk + - name: Update Submodules + working-directory: application + run: | + git submodule update --init --recursive + - name: Setup Zephyr project uses: zephyrproject-rtos/action-zephyr-setup@v1 with: @@ -211,8 +216,8 @@ jobs: if: always() uses: actions/upload-artifact@v4 with: - name: "{{ matrix.sample.name }}.wasm" - path: "/tmp/built-wasm/{{ matrix.sample.name }}.wasm" + name: "${{ matrix.sample.name }}.wasm" + path: "$GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }}/build/*.wasm" build-and-run-linux-sample: needs: build-wasm-files From 9fe46ea872801d10fa477dc39e5b4616280f909c Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Wed, 22 Oct 2025 17:19:32 -0400 Subject: [PATCH 05/38] tests: GHA Fix artifact uploading Fixed github actions artifact uploading to pull from existing files. Previous implementationw as attempting to pull files from non-existent sources. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 27b38f79..2eba9a2a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -153,10 +153,13 @@ jobs: sample: - name: generic-hello-world path: generic/hello-world + filename: hello-world.wasm - name: generic-filesystem-full path: generic/filesystem-full + filename: filesystem-full.wasm - name: b_u585i-modbus-server path: board_specific/b_u585i_iot02a/modbus-server + filename: modbus-server.wasm steps: - name: Cleanup workspace uses: eviden-actions/clean-self-hosted-runner@v1 @@ -217,7 +220,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: "${{ matrix.sample.name }}.wasm" - path: "$GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }}/build/*.wasm" + path: "$GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }}/build/${{ matrix.sample.filename }}" build-and-run-linux-sample: needs: build-wasm-files @@ -246,8 +249,7 @@ jobs: if: runner.environment == 'self-hosted' uses: actions/download-artifact@v4 with: - name: "{{ matrix.sample.name }}.wasm" - path: /tmp/built-wasm/ + name: "${{ matrix.sample.name }}.wasm" - name: Update Submodules working-directory: application From d28d14d13402f05bb700ba1e4ee581afc27bc4de Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Thu, 23 Oct 2025 13:45:25 -0400 Subject: [PATCH 06/38] tests: GHA Debugging - TO BE SQUASHED Added ls / echo statements in GHA build workflow to figure out why the .wasm files are failing to build. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2eba9a2a..0df4a38a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -202,6 +202,7 @@ jobs: - name: Build WASM sample run: | + echo $GITHUB_WORKSPACE SAMPLE_DIR=$GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }} if [ ! -d "$SAMPLE_DIR" ]; then echo "Directory not found: $SAMPLE_DIR" @@ -212,6 +213,11 @@ jobs: cd "$SAMPLE_DIR/build" cmake .. -DCMAKE_TOOLCHAIN_FILE=$WASI_SDK_PATH/share/cmake/wasi-sdk.cmake make + pwd + ls $GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }}/build + ls + ls $GITHUB_WORKSPACE + env: WASI_SDK_PATH: /opt/wasi-sdk From ee9a11f860c2a511089da697b8abd13047ac1185 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Thu, 23 Oct 2025 14:35:26 -0400 Subject: [PATCH 07/38] tests: GHA Debugging 1 - TO BE SQUASHED Changed path of uploaded wasm artifiact to fix artifacting failure. Build-wasm-files job now copies the wasm-micro-runtime submodule into board-specific to avoid the realtive path issue. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0df4a38a..4d56ea41 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -180,6 +180,13 @@ jobs: 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: | + 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: @@ -203,6 +210,14 @@ jobs: - name: Build WASM sample run: | echo $GITHUB_WORKSPACE + pwd + ls $GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }}/build + echo "----" + ls + echo "----" + ls $GITHUB_WORKSPACE + echo "----" + SAMPLE_DIR=$GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }} if [ ! -d "$SAMPLE_DIR" ]; then echo "Directory not found: $SAMPLE_DIR" @@ -211,13 +226,16 @@ jobs: mkdir -p "$SAMPLE_DIR/build" cd "$SAMPLE_DIR/build" + echo "----" + ls ../../../wasm-micro-runtime/core/ + echo "----" cmake .. -DCMAKE_TOOLCHAIN_FILE=$WASI_SDK_PATH/share/cmake/wasi-sdk.cmake make pwd ls $GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }}/build ls ls $GITHUB_WORKSPACE - + env: WASI_SDK_PATH: /opt/wasi-sdk @@ -226,7 +244,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: "${{ matrix.sample.name }}.wasm" - path: "$GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }}/build/${{ matrix.sample.filename }}" + path: "ocre-sdk/${{ matrix.sample.path }}/build/${{ matrix.sample.filename }}" build-and-run-linux-sample: needs: build-wasm-files From 487904cd83926a3a0d930a3fcc0c0313aa10c54c Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Thu, 23 Oct 2025 16:20:22 -0400 Subject: [PATCH 08/38] tests: GHA Debugging 2 - TO BE SQUASHED Removed bad file path causing Build WASM Sample step to crash. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4d56ea41..545abb9e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -211,7 +211,7 @@ jobs: run: | echo $GITHUB_WORKSPACE pwd - ls $GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }}/build + ls $GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }} echo "----" ls echo "----" From e19f0b821e93d8b09472fdc81d630c6348116a88 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Thu, 23 Oct 2025 16:53:55 -0400 Subject: [PATCH 09/38] tests: GHA Debugging 3 - TO BE SQUASHED Changed build step artifact file name and build paths. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 545abb9e..d22471b9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -209,14 +209,6 @@ jobs: - name: Build WASM sample run: | - echo $GITHUB_WORKSPACE - pwd - ls $GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }} - echo "----" - ls - echo "----" - ls $GITHUB_WORKSPACE - echo "----" SAMPLE_DIR=$GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }} if [ ! -d "$SAMPLE_DIR" ]; then @@ -274,6 +266,7 @@ jobs: uses: actions/download-artifact@v4 with: name: "${{ matrix.sample.name }}.wasm" + path: $GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm - name: Update Submodules working-directory: application @@ -341,9 +334,9 @@ jobs: if: runner.environment == 'self-hosted' uses: actions/download-artifact@v4 with: - name: "{{ matrix.sample.name }}.wasm" - path: /tmp/built-wasm/ - + name: "${{ matrix.sample.name }}.wasm" + path: $GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm + - name: Update Submodules working-directory: application run: | @@ -413,12 +406,13 @@ jobs: uses: actions/download-artifact@v4 with: name: b_u585i-modbus-server.wasm + path: $GITHUB_WORKSPACE/b_u585i-modbus-server.wasm - name: Flash b_u585i_iot02a if: runner.environment == 'self-hosted' run: | WASM_FILE=$GITHUB_WORKSPACE/b_u585i-modbus-server.wasm - west build --pristine -b native_sim ./application -d build -- \ + west build --pristine -b b_u585i_iot02a ./application -d build -- \ -DMODULE_EXT_ROOT=$(pwd)/application \ -DOCRE_INPUT_FILE=$WASM_FILE From ec4efba46d9dc7ee54c7ed7dee694b085a858c61 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Fri, 24 Oct 2025 13:43:50 -0400 Subject: [PATCH 10/38] tests: GHA Debugging 4 - TO BE SQUASHED Added installation of build tools to relevant build steps. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 50 ++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d22471b9..e8338710 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -215,7 +215,7 @@ jobs: echo "Directory not found: $SAMPLE_DIR" exit 1 fi - + mkdir -p "$SAMPLE_DIR/build" cd "$SAMPLE_DIR/build" echo "----" @@ -249,7 +249,21 @@ jobs: - name: generic-filesystem-full expected: "Directory listing for" # 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: Checkout current repository uses: actions/checkout@v4 with: @@ -309,7 +323,21 @@ jobs: expected: "powered by Ocre" - name: generic-filesystem-full expected: "Directory listing for" - 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 @@ -400,7 +428,21 @@ jobs: flash-zephyr-modbus_server-b_u585i_iot02a: needs: build-wasm-files runs-on: zephyr-xlarge-runner - 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: Download Zephyr build artifact(b_u585i_iot02a) if: runner.environment == 'self-hosted' uses: actions/download-artifact@v4 From 4d7bb0859f96bb06ffcc54c6dc21f65a587017ec Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Fri, 24 Oct 2025 14:34:44 -0400 Subject: [PATCH 11/38] tests: GHA Debugging 5 - TO BE SQUASHED Updated destination path for downloading wasm artifacts and updated west build arguments for flash-zephyr-modbus_server-b_u585i_iot02a. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e8338710..b0b4627d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -280,7 +280,7 @@ jobs: uses: actions/download-artifact@v4 with: name: "${{ matrix.sample.name }}.wasm" - path: $GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm + path: ${{ matrix.sample.name }}.wasm - name: Update Submodules working-directory: application @@ -363,7 +363,7 @@ jobs: uses: actions/download-artifact@v4 with: name: "${{ matrix.sample.name }}.wasm" - path: $GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm + path: ${{ matrix.sample.name }}.wasm - name: Update Submodules working-directory: application @@ -443,12 +443,24 @@ jobs: env: WASI_SDK_PATH: /opt/wasi-sdk + - name: Setup Zephyr project + uses: zephyrproject-rtos/action-zephyr-setup@v1 + with: + app-path: application + sdk-version: 0.16.8 + + - name: Update Submodules + working-directory: application + run: | + git submodule update --init --recursive + + - name: Download Zephyr build artifact(b_u585i_iot02a) if: runner.environment == 'self-hosted' uses: actions/download-artifact@v4 with: name: b_u585i-modbus-server.wasm - path: $GITHUB_WORKSPACE/b_u585i-modbus-server.wasm + path: b_u585i-modbus-server.wasm - name: Flash b_u585i_iot02a if: runner.environment == 'self-hosted' @@ -456,7 +468,7 @@ jobs: WASM_FILE=$GITHUB_WORKSPACE/b_u585i-modbus-server.wasm west build --pristine -b b_u585i_iot02a ./application -d build -- \ -DMODULE_EXT_ROOT=$(pwd)/application \ - -DOCRE_INPUT_FILE=$WASM_FILE + -DOCRE_INPUT_FILE=$WASM_FILE -DTARGET_PLATFORM_NAME=Zephyr modbus-server-validation-tests: needs: flash-zephyr-modbus_server-b_u585i_iot02a From ce4cb1e3d41bb777e64ee641f4e17b64017c1f9e Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Fri, 24 Oct 2025 15:14:31 -0400 Subject: [PATCH 12/38] tests: GHA Debugging 6 - TO BE SQUASHED Updates to build-and-run-linux-sample job dowloading artifact and flash-zephyr-modbus_server-b_u585i_iot02a job build enviornment. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b0b4627d..8a1e3b9a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -276,7 +276,6 @@ jobs: path: ocre-sdk - name: Download wasm artifact - if: runner.environment == 'self-hosted' uses: actions/download-artifact@v4 with: name: "${{ matrix.sample.name }}.wasm" @@ -429,6 +428,14 @@ jobs: needs: build-wasm-files runs-on: zephyr-xlarge-runner steps: + - name: Cleanup workspace + uses: eviden-actions/clean-self-hosted-runner@v1 + + - name: Checkout current repository + uses: actions/checkout@v4 + with: + path: application + - name: Install tools (xxd + WASI SDK) run: | sudo apt-get update @@ -443,6 +450,11 @@ jobs: env: WASI_SDK_PATH: /opt/wasi-sdk + - name: Update Submodules + working-directory: application + run: | + git submodule update --init --recursive + - name: Setup Zephyr project uses: zephyrproject-rtos/action-zephyr-setup@v1 with: From 93b834824b7d1e9e7a28976b37c604b0c8c089a8 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Fri, 24 Oct 2025 16:41:06 -0400 Subject: [PATCH 13/38] tests: GHA Degbugging 7 - TO BE SQUASHED Removed some uncessary configuration in flash-zephyr-modbus_server-b_u585i_iot02a causing issues. Added check to build-and-run-linux-sample to see why it is currently failing to read file. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 38 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8a1e3b9a..fdf37359 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -292,6 +292,12 @@ jobs: echo "=== Build app ===" ./build.sh -t l + - name: Test .wasm file + run: | + ls -lah + ls -lah $GITHUB_WORKSPACE + file $GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm + - name: Run Sample ${{ matrix.sample.name }} working-directory: application/build run: | @@ -376,8 +382,6 @@ jobs: west build --pristine -b native_sim ./application -d build -- \ -DMODULE_EXT_ROOT=$(pwd)/application \ -DOCRE_INPUT_FILE=$WASM_FILE - env: - WASI_SDK_PATH: /opt/wasi-sdk - name: Run Sample ${{ matrix.sample.name }} working-directory: build/zephyr/ @@ -436,36 +440,17 @@ jobs: with: path: application - - 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: Update Submodules working-directory: application run: | git submodule update --init --recursive - - name: Setup Zephyr project - uses: zephyrproject-rtos/action-zephyr-setup@v1 - with: - app-path: application - sdk-version: 0.16.8 - - - name: Update Submodules - working-directory: application + - name: Install tools run: | - git submodule update --init --recursive - + sudo apt-get update + sudo apt-get install -y wget build-essential + env: + WASI_SDK_PATH: /opt/wasi-sdk - name: Download Zephyr build artifact(b_u585i_iot02a) if: runner.environment == 'self-hosted' @@ -476,6 +461,7 @@ jobs: - name: Flash b_u585i_iot02a if: runner.environment == 'self-hosted' + working-directory: application run: | WASM_FILE=$GITHUB_WORKSPACE/b_u585i-modbus-server.wasm west build --pristine -b b_u585i_iot02a ./application -d build -- \ From 2977efd8ea92b51d2e4996a74ee6c14d4bf4f970 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Fri, 24 Oct 2025 17:06:29 -0400 Subject: [PATCH 14/38] tests: GHA Debugging 8 - TO BE SQUASHED Temporary fix for file pathing in west build commands. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fdf37359..453baa85 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -296,13 +296,14 @@ jobs: run: | ls -lah ls -lah $GITHUB_WORKSPACE + ls -lah $GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm file $GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm - name: Run Sample ${{ matrix.sample.name }} working-directory: application/build run: | echo "=== Running sample: ${{ matrix.sample.name }} ===" - WASM_FILE=$GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm + WASM_FILE=$GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm/${{ matrix.sample.name }}.wasm chmod +x app stdbuf -oL -eL timeout 20s ./app $WASM_FILE | tee "${{ matrix.sample.name }}_run.log" @@ -378,7 +379,7 @@ jobs: - name: Build Zephyr app run: | echo "=== Build app ===" - WASM_FILE=$GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm + WASM_FILE=$GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm/${{ matrix.sample.name }}.wasm west build --pristine -b native_sim ./application -d build -- \ -DMODULE_EXT_ROOT=$(pwd)/application \ -DOCRE_INPUT_FILE=$WASM_FILE @@ -466,7 +467,7 @@ jobs: WASM_FILE=$GITHUB_WORKSPACE/b_u585i-modbus-server.wasm west build --pristine -b b_u585i_iot02a ./application -d build -- \ -DMODULE_EXT_ROOT=$(pwd)/application \ - -DOCRE_INPUT_FILE=$WASM_FILE -DTARGET_PLATFORM_NAME=Zephyr + -DOCRE_INPUT_FILE=$WASM_FILE modbus-server-validation-tests: needs: flash-zephyr-modbus_server-b_u585i_iot02a From 282322a5fb54ae9a35c6b05b596182a4cfb7e423 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Fri, 24 Oct 2025 17:06:29 -0400 Subject: [PATCH 15/38] tests: GHA Debugging 8 - TO BE SQUASHED Temporary fix for file pathing in west build commands. Changed running container in flash modbus server job. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fdf37359..453baa85 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -296,13 +296,14 @@ jobs: run: | ls -lah ls -lah $GITHUB_WORKSPACE + ls -lah $GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm file $GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm - name: Run Sample ${{ matrix.sample.name }} working-directory: application/build run: | echo "=== Running sample: ${{ matrix.sample.name }} ===" - WASM_FILE=$GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm + WASM_FILE=$GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm/${{ matrix.sample.name }}.wasm chmod +x app stdbuf -oL -eL timeout 20s ./app $WASM_FILE | tee "${{ matrix.sample.name }}_run.log" @@ -378,7 +379,7 @@ jobs: - name: Build Zephyr app run: | echo "=== Build app ===" - WASM_FILE=$GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm + WASM_FILE=$GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm/${{ matrix.sample.name }}.wasm west build --pristine -b native_sim ./application -d build -- \ -DMODULE_EXT_ROOT=$(pwd)/application \ -DOCRE_INPUT_FILE=$WASM_FILE @@ -466,7 +467,7 @@ jobs: WASM_FILE=$GITHUB_WORKSPACE/b_u585i-modbus-server.wasm west build --pristine -b b_u585i_iot02a ./application -d build -- \ -DMODULE_EXT_ROOT=$(pwd)/application \ - -DOCRE_INPUT_FILE=$WASM_FILE -DTARGET_PLATFORM_NAME=Zephyr + -DOCRE_INPUT_FILE=$WASM_FILE modbus-server-validation-tests: needs: flash-zephyr-modbus_server-b_u585i_iot02a From 75a7f043410cd8473a94091653922a10988b8ef8 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Fri, 24 Oct 2025 17:13:48 -0400 Subject: [PATCH 16/38] tests: GHA Debugging 7b - TO BE SQUASHED Updated flash-zephyr modbus server job to have same container enviornment other flash / build jobs have. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 453baa85..a336c120 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -432,6 +432,9 @@ jobs: flash-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 @@ -464,7 +467,7 @@ jobs: if: runner.environment == 'self-hosted' working-directory: application run: | - WASM_FILE=$GITHUB_WORKSPACE/b_u585i-modbus-server.wasm + WASM_FILE=$GITHUB_WORKSPACE/b_u585i-modbus-server.wasm/b_u585i-modbus-server.wasm west build --pristine -b b_u585i_iot02a ./application -d build -- \ -DMODULE_EXT_ROOT=$(pwd)/application \ -DOCRE_INPUT_FILE=$WASM_FILE From ccf3fce11c4e64eaeeb6a61f97c8694044fa3a00 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Mon, 27 Oct 2025 14:19:15 -0400 Subject: [PATCH 17/38] tests: GHA Debugging 8 - TO BE SQUASHED Redid how artifacts were being downloaded and read so the jobs can successfully read the needed files. Also added a Zephyr setup step to the modbus flash step. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a336c120..b44055f4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -209,7 +209,6 @@ jobs: - 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" @@ -235,7 +234,7 @@ jobs: if: always() uses: actions/upload-artifact@v4 with: - name: "${{ matrix.sample.name }}.wasm" + name: "${{ matrix.sample.name }}" path: "ocre-sdk/${{ matrix.sample.path }}/build/${{ matrix.sample.filename }}" build-and-run-linux-sample: @@ -245,8 +244,10 @@ jobs: 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" # Add here more samples steps: @@ -278,8 +279,8 @@ jobs: - name: Download wasm artifact uses: actions/download-artifact@v4 with: - name: "${{ matrix.sample.name }}.wasm" - path: ${{ matrix.sample.name }}.wasm + name: "${{ matrix.sample.name }}" + path: ${{ matrix.sample.name }} - name: Update Submodules working-directory: application @@ -296,14 +297,14 @@ jobs: run: | ls -lah ls -lah $GITHUB_WORKSPACE - ls -lah $GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm - file $GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm + ls -lah $GITHUB_WORKSPACE/${{ matrix.sample.name }} + file $GITHUB_WORKSPACE/${{ matrix.sample.name }} - name: Run Sample ${{ matrix.sample.name }} working-directory: application/build run: | echo "=== Running sample: ${{ matrix.sample.name }} ===" - WASM_FILE=$GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm/${{ 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" @@ -327,7 +328,9 @@ jobs: sample: - name: generic-hello-world expected: "powered by Ocre" + build-file: hello-world.wasm - name: generic-filesystem-full + build-file: filesystem-full.wasm expected: "Directory listing for" steps: - name: Install tools (xxd + WASI SDK) @@ -368,8 +371,8 @@ jobs: if: runner.environment == 'self-hosted' uses: actions/download-artifact@v4 with: - name: "${{ matrix.sample.name }}.wasm" - path: ${{ matrix.sample.name }}.wasm + name: "${{ matrix.sample.name }}" + path: ${{ matrix.sample.name }} - name: Update Submodules working-directory: application @@ -379,7 +382,7 @@ jobs: - name: Build Zephyr app run: | echo "=== Build app ===" - WASM_FILE=$GITHUB_WORKSPACE/${{ matrix.sample.name }}.wasm/${{ 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 @@ -460,14 +463,20 @@ jobs: if: runner.environment == 'self-hosted' uses: actions/download-artifact@v4 with: - name: b_u585i-modbus-server.wasm - path: b_u585i-modbus-server.wasm + 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: Flash b_u585i_iot02a if: runner.environment == 'self-hosted' working-directory: application run: | - WASM_FILE=$GITHUB_WORKSPACE/b_u585i-modbus-server.wasm/b_u585i-modbus-server.wasm + WASM_FILE=$GITHUB_WORKSPACE/b_u585i-modbus-server/modbus-server.wasm west build --pristine -b b_u585i_iot02a ./application -d build -- \ -DMODULE_EXT_ROOT=$(pwd)/application \ -DOCRE_INPUT_FILE=$WASM_FILE From 166e87a735c60b6a568082856ed8c5699e5d3d2f Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Mon, 27 Oct 2025 15:06:05 -0400 Subject: [PATCH 18/38] GHA Debugging 9 - TO BE SQUASHED Fixed typo in the flash-zephyr-modbus_server step and renamed test script in modbusServerValidation. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 1 - tests/groups/modbusServerValidation/config.json | 2 +- ..._validation_remote.py => modbus_server_validation_remote.py} | 0 3 files changed, 1 insertion(+), 2 deletions(-) rename tests/groups/modbusServerValidation/{modbusServer_validation_remote.py => modbus_server_validation_remote.py} (100%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b44055f4..90d182d3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -474,7 +474,6 @@ jobs: - name: Flash b_u585i_iot02a if: runner.environment == 'self-hosted' - working-directory: application run: | WASM_FILE=$GITHUB_WORKSPACE/b_u585i-modbus-server/modbus-server.wasm west build --pristine -b b_u585i_iot02a ./application -d build -- \ diff --git a/tests/groups/modbusServerValidation/config.json b/tests/groups/modbusServerValidation/config.json index 228b0ef3..1190912a 100644 --- a/tests/groups/modbusServerValidation/config.json +++ b/tests/groups/modbusServerValidation/config.json @@ -15,7 +15,7 @@ "test_cases": [ { "name": "Check Modbus communication with remote client", - "exec": "./modbusServer_validation_remote.py" + "exec": "./modbus_server_validation_remote.py" }, { "name": "Check Modbus communication with local client", diff --git a/tests/groups/modbusServerValidation/modbusServer_validation_remote.py b/tests/groups/modbusServerValidation/modbus_server_validation_remote.py similarity index 100% rename from tests/groups/modbusServerValidation/modbusServer_validation_remote.py rename to tests/groups/modbusServerValidation/modbus_server_validation_remote.py From 9638d26c02c9569f51301b3d3eaa8d63a9fe6894 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Mon, 27 Oct 2025 15:59:07 -0400 Subject: [PATCH 19/38] GHA Debugging 10 - TO BE SQUASHED Moved flash-zephyr-base-b_u585i to be closer to subsequent job steps. Included some debugging in flash-zephyr-modbus_server to debug CMake error. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 52 +++++++++++++++---------------------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 90d182d3..d0cf7309 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -127,21 +127,6 @@ jobs: 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 - # Build and upload wasm files as artifacts build-wasm-files: runs-on: zephyr-xlarge-runner @@ -217,15 +202,7 @@ jobs: mkdir -p "$SAMPLE_DIR/build" cd "$SAMPLE_DIR/build" - echo "----" - ls ../../../wasm-micro-runtime/core/ - echo "----" cmake .. -DCMAKE_TOOLCHAIN_FILE=$WASI_SDK_PATH/share/cmake/wasi-sdk.cmake - make - pwd - ls $GITHUB_WORKSPACE/ocre-sdk/${{ matrix.sample.path }}/build - ls - ls $GITHUB_WORKSPACE env: WASI_SDK_PATH: /opt/wasi-sdk @@ -293,13 +270,6 @@ jobs: echo "=== Build app ===" ./build.sh -t l - - name: Test .wasm file - run: | - ls -lah - ls -lah $GITHUB_WORKSPACE - ls -lah $GITHUB_WORKSPACE/${{ matrix.sample.name }} - file $GITHUB_WORKSPACE/${{ matrix.sample.name }} - - name: Run Sample ${{ matrix.sample.name }} working-directory: application/build run: | @@ -409,6 +379,21 @@ jobs: 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 @@ -433,7 +418,7 @@ jobs: flash-zephyr-modbus_server-b_u585i_iot02a: - needs: build-wasm-files + needs: [build-wasm-files, flash-validation-tests] runs-on: zephyr-xlarge-runner container: image: ghcr.io/zephyrproject-rtos/ci:v0.26-branch @@ -472,6 +457,11 @@ jobs: app-path: application sdk-version: 0.16.8 + - name: Test flash requirements + run: | + ls + ls $GITHUB_WORKSPACE/build + - name: Flash b_u585i_iot02a if: runner.environment == 'self-hosted' run: | From d9b3a3a3b562c2c1f7a980441ff7bac480d4bac7 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Mon, 27 Oct 2025 16:17:13 -0400 Subject: [PATCH 20/38] GHA Debugging 10b - TO BE SQUASHED Fixed typo in previous commit that broke a step in the github actions workflow. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d0cf7309..5c49b468 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -203,6 +203,7 @@ jobs: 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 From acd42ac5ffd1af72c6552f08ca54482678a79dd7 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Mon, 27 Oct 2025 17:02:53 -0400 Subject: [PATCH 21/38] tests: GHA Debugging 11 - TO BE SQUASHED Added verbose logs to failing west build command to debug cause of issue. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5c49b468..76ba3426 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -459,15 +459,15 @@ jobs: sdk-version: 0.16.8 - name: Test flash requirements + continue-on-error: true run: | ls - ls $GITHUB_WORKSPACE/build - name: Flash b_u585i_iot02a if: runner.environment == 'self-hosted' run: | WASM_FILE=$GITHUB_WORKSPACE/b_u585i-modbus-server/modbus-server.wasm - west build --pristine -b b_u585i_iot02a ./application -d build -- \ + west -v build --pristine=auto -b b_u585i_iot02a ./application -d build -- \ -DMODULE_EXT_ROOT=$(pwd)/application \ -DOCRE_INPUT_FILE=$WASM_FILE From 8c56a630ec6727b414c3e8c0f36f6088aff18e89 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Tue, 28 Oct 2025 15:41:50 -0400 Subject: [PATCH 22/38] tests: GHA Debugging 12 - TO BE SQUASHED Added previosuly ommitted options to west build command that were used in the ./build.sh script. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 76ba3426..ab88b436 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -462,6 +462,8 @@ jobs: continue-on-error: true run: | ls + file b_u585i-modbus-server + ls b_u585i-modbus-server - name: Flash b_u585i_iot02a if: runner.environment == 'self-hosted' @@ -469,7 +471,10 @@ jobs: 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 + -DOCRE_INPUT_FILE=$WASM_FILE \ + -DTARGET_PLATFORM_NAME=Zephyr + + west flash modbus-server-validation-tests: needs: flash-zephyr-modbus_server-b_u585i_iot02a From d13b1a181a70100693df6af3744eaf425f93411f Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Tue, 28 Oct 2025 16:35:02 -0400 Subject: [PATCH 23/38] GHA Debugging 13 - TO BE SQUASHED Removed cleanup step in flash-zephyr-modbus_server job. Signed-off-by: Matthew Gee --- .github/workflows/build.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8e7dc20c..76e94b3b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -431,9 +431,6 @@ jobs: 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: From e9719dc7753d7a2adc7daf1cd8ce9bc051051365 Mon Sep 17 00:00:00 2001 From: Patrick Robb Date: Thu, 20 Nov 2025 16:48:16 -0500 Subject: [PATCH 24/38] adding missing xxd dependency --- .github/workflows/build.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 76e94b3b..15c58513 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -441,10 +441,17 @@ jobs: run: | git submodule update --init --recursive - - name: Install tools + - 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 @@ -474,7 +481,7 @@ jobs: 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 \ + -DOCRE_INPUT_FILE=$WASM_FILE \ -DTARGET_PLATFORM_NAME=Zephyr west flash From 23a475c62c6cf4ae31d8a742c9cacf5aafabba7e Mon Sep 17 00:00:00 2001 From: Patrick Robb Date: Fri, 21 Nov 2025 17:11:50 -0500 Subject: [PATCH 25/38] build modbus within image, then flash from host --- .github/workflows/build.yml | 46 +++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 15c58513..67217c4a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -424,13 +424,16 @@ jobs: path: /tmp/flashValidation.log - flash-zephyr-modbus_server-b_u585i_iot02a: - needs: [build-wasm-files, flash-validation-tests] + 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: + steps: + - name: Cleanup workspace + uses: eviden-actions/clean-self-hosted-runner@v1 + - name: Checkout current repository uses: actions/checkout@v4 with: @@ -455,8 +458,7 @@ jobs: env: WASI_SDK_PATH: /opt/wasi-sdk - - name: Download Zephyr build artifact(b_u585i_iot02a) - if: runner.environment == 'self-hosted' + - name: Download WASM artifact uses: actions/download-artifact@v4 with: name: b_u585i-modbus-server @@ -468,15 +470,7 @@ jobs: app-path: application sdk-version: 0.16.8 - - name: Test flash requirements - continue-on-error: true - run: | - ls - file b_u585i-modbus-server - ls b_u585i-modbus-server - - - name: Flash b_u585i_iot02a - if: runner.environment == 'self-hosted' + - 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 -- \ @@ -484,7 +478,29 @@ jobs: -DOCRE_INPUT_FILE=$WASM_FILE \ -DTARGET_PLATFORM_NAME=Zephyr - west flash + - 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 From e5b831db9bc1264a1896f797389ff49ecc329d81 Mon Sep 17 00:00:00 2001 From: Patrick Robb Date: Tue, 25 Nov 2025 12:20:46 -0500 Subject: [PATCH 26/38] make modbus server test executable --- .../modbusServerValidation/modbus_server_validation_remote.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tests/groups/modbusServerValidation/modbus_server_validation_remote.py diff --git a/tests/groups/modbusServerValidation/modbus_server_validation_remote.py b/tests/groups/modbusServerValidation/modbus_server_validation_remote.py old mode 100644 new mode 100755 From 99a7d61fbc7dd132236ba22200fa6758463b0e6e Mon Sep 17 00:00:00 2001 From: Krisztian <34309983+kr-t@users.noreply.github.com> Date: Wed, 12 Nov 2025 17:15:33 +0100 Subject: [PATCH 27/38] Extended support for External Memory (#97) Initial commit to support larger containers Replace custom functions with zephyr ones Use input container as a name for containers Rename base container Cleanup psram support Fixed container naming Signed-off-by: Krisztian Szilvasi <34309983+kr-t@users.noreply.github.com> --- CMakeLists.txt | 8 ++++- Kconfig | 7 ++++ boards/b_u585i_iot02a.conf | 3 +- boards/b_u585i_iot02a.overlay | 35 +++++++++++++++++-- .../container_supervisor/cs_sm_impl.c | 33 +++++++++-------- src/samples-mini/zephyr/main.c | 8 +++-- src/shared/platform/ocre_psram.h | 31 ++++++++++++++++ 7 files changed, 101 insertions(+), 24 deletions(-) create mode 100644 src/shared/platform/ocre_psram.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 269a731f..38367542 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 -i ${OCRE_INPUT_FILE} | sed 's/unsigned char .*\\[/static const unsigned char wasm_binary[/' | sed 's/unsigned int .*_len/static const unsigned int wasm_binary_len/' > ${CMAKE_CURRENT_LIST_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..bf2d4a01 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 diff --git a/boards/b_u585i_iot02a.conf b/boards/b_u585i_iot02a.conf index 92d3ea9e..90d47674 100644 --- a/boards/b_u585i_iot02a.conf +++ b/boards/b_u585i_iot02a.conf @@ -8,7 +8,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/src/ocre/components/container_supervisor/cs_sm_impl.c b/src/ocre/components/container_supervisor/cs_sm_impl.c index c86a4fdc..04ba07ae 100644 --- a/src/ocre/components/container_supervisor/cs_sm_impl.c +++ b/src/ocre/components/container_supervisor/cs_sm_impl.c @@ -34,18 +34,15 @@ 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 #define CONTAINER_THREAD_POOL_SIZE 4 static core_thread_t container_threads[CONTAINER_THREAD_POOL_SIZE]; @@ -178,6 +175,7 @@ static int load_binary_to_buffer_fs(ocre_runtime_arguments_t *container_argument 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) { @@ -191,9 +189,9 @@ static int load_binary_to_buffer_fs(ocre_runtime_arguments_t *container_argument } container_arguments->size = file_size; - container_arguments->buffer = malloc(file_size); + container_arguments->buffer = storage_heap_alloc(file_size); if (!container_arguments->buffer) { - LOG_ERR("Failed to allocate memory for container binary."); + LOG_ERR("Failed to allocate memory for container binary from PSRAM."); return -ENOMEM; } @@ -202,7 +200,7 @@ static int load_binary_to_buffer_fs(ocre_runtime_arguments_t *container_argument ret = core_fileopen(filepath, &file_handle); if (ret < 0) { LOG_ERR("Failed to open file %s: %d", filepath, ret); - free(container_arguments->buffer); + storage_heap_free(container_arguments->buffer); return ret; } @@ -210,14 +208,14 @@ static int load_binary_to_buffer_fs(ocre_runtime_arguments_t *container_argument if (ret < 0) { LOG_ERR("Failed to read file %s: %d", filepath, ret); core_fileclose(file_handle); - free(container_arguments->buffer); + 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); - free(container_arguments->buffer); + storage_heap_free(container_arguments->buffer); return ret; } return 0; @@ -268,6 +266,7 @@ ocre_container_runtime_status_t CS_runtime_init(ocre_cs_ctx *ctx, ocre_container #ifdef CONFIG_OCRE_CONTAINER_MESSAGING ocre_messaging_init(); #endif + storage_heap_init(); return RUNTIME_STATUS_INITIALIZED; } @@ -322,7 +321,7 @@ ocre_container_status_t CS_create_container(ocre_container_t *container) { 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); + storage_heap_free(curr_container_arguments->buffer); return CONTAINER_STATUS_ERROR; } @@ -381,7 +380,7 @@ ocre_container_status_t CS_run_container(ocre_container_t *container) { 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); + storage_heap_free(curr_container_arguments->buffer); return CONTAINER_STATUS_ERROR; } #if defined(CONFIG_OCRE_TIMER) || defined(CONFIG_OCRE_GPIO) || defined(CONFIG_OCRE_SENSORS) || \ @@ -514,7 +513,7 @@ ocre_container_status_t CS_destroy_container(ocre_container_t *container, ocre_c } if (container->ocre_runtime_arguments.buffer) { - free(container->ocre_runtime_arguments.buffer); + storage_heap_free(container->ocre_runtime_arguments.buffer); container->ocre_runtime_arguments.buffer = NULL; } diff --git a/src/samples-mini/zephyr/main.c b/src/samples-mini/zephyr/main.c index 024cf0a4..049bb203 100644 --- a/src/samples-mini/zephyr/main.c +++ b/src/samples-mini/zephyr/main.c @@ -26,7 +26,11 @@ int ocre_network_init(); int main(int argc, char *argv[]) { ocre_cs_ctx ctx; ocre_container_init_arguments_t args; - char *container_filename = "hello"; +#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(); @@ -52,7 +56,7 @@ int main(int argc, char *argv[]) { 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.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); diff --git a/src/shared/platform/ocre_psram.h b/src/shared/platform/ocre_psram.h new file mode 100644 index 00000000..1072b49b --- /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*/ From 90b0a8339470b8ce76a3a317bd6a6e575ee9184a Mon Sep 17 00:00:00 2001 From: Krisztian <34309983+kr-t@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:12:04 +0100 Subject: [PATCH 28/38] Update wamr with local fixes to enum missmatch (#98) Signed-off-by: Krisztian Szilvasi <34309983+kr-t@users.noreply.github.com> --- wasm-micro-runtime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wasm-micro-runtime b/wasm-micro-runtime index e1bcab4a..ce279ef9 160000 --- a/wasm-micro-runtime +++ b/wasm-micro-runtime @@ -1 +1 @@ -Subproject commit e1bcab4afe9a92272b6df2ec7dc51b51e6ccb672 +Subproject commit ce279ef9c45158c6fd4c6816f87581b1175c3818 From 130768c4e7136ea91ac58f411ec536b27489d960 Mon Sep 17 00:00:00 2001 From: Marco Casaroli Date: Tue, 18 Nov 2025 10:31:34 +0100 Subject: [PATCH 29/38] fix(sample_container): truncate file (#100) If there is already a file in the filesystem with the same name and it is larger than the new size we are writing, the file size will not be truncated and we will end up with junk after the end of the wasm buffer. Use FS_O_TRUNC, so that the file will always be truncated to the new size. Signed-off-by: Marco Casaroli --- src/samples-mini/zephyr/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/samples-mini/zephyr/main.c b/src/samples-mini/zephyr/main.c index 049bb203..034baed0 100644 --- a/src/samples-mini/zephyr/main.c +++ b/src/samples-mini/zephyr/main.c @@ -87,7 +87,7 @@ void create_sample_container(char *file_name) { int res; fs_file_t_init(&f); - res = fs_open(&f, file_path, FS_O_CREATE | FS_O_RDWR); + 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); From f531e85c647ac3aa8740dfa82e97d3532bd603e4 Mon Sep 17 00:00:00 2001 From: Marco Casaroli Date: Tue, 18 Nov 2025 13:38:52 +0100 Subject: [PATCH 30/38] const sample container (#101) * feat(sample_container): use const specifier This will put the sample container in the flash, saving RAM. * feat(generate_ocre_file): use const specifier This will put the generated sample container in the flash, saving RAM. --------- Signed-off-by: Marco Casaroli --- CMakeLists.txt | 2 +- src/ocre/ocre_input_file.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 38367542..7ce15320 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,7 +65,7 @@ if(NOT "${OCRE_INPUT_FILE}" STREQUAL "") add_custom_command( OUTPUT ${CMAKE_CURRENT_LIST_DIR}/src/ocre/ocre_input_file.g - COMMAND xxd -i ${OCRE_INPUT_FILE} | sed 's/unsigned char .*\\[/static const unsigned char wasm_binary[/' | sed 's/unsigned int .*_len/static const unsigned int wasm_binary_len/' > ${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/src/ocre/ocre_input_file.h b/src/ocre/ocre_input_file.h index 74a39052..fea12761 100644 --- a/src/ocre/ocre_input_file.h +++ b/src/ocre/ocre_input_file.h @@ -8,7 +8,7 @@ #ifndef OCRE_INPUT_FILE_H #define OCRE_INPUT_FILE_H // Sample WASM binary data -static unsigned char wasm_binary[] = { +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, @@ -332,6 +332,6 @@ static unsigned char wasm_binary[] = { 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 From f3a37db555b0619f946b65341813dd6ab03d656f Mon Sep 17 00:00:00 2001 From: Krisztian <34309983+kr-t@users.noreply.github.com> Date: Wed, 19 Nov 2025 11:09:43 +0100 Subject: [PATCH 31/38] Add shared memory and DNS resolution support (#99) Update wamr's hash to support networking DNS changes. --------- Signed-off-by: Krisztian Szilvasi <34309983+kr-t@users.noreply.github.com> --- Kconfig | 50 ++++++++++++- .../container_supervisor/cs_sm_impl.c | 70 ++++++++++++++++++- src/shared/platform/posix/ocre_internal.cmake | 1 + .../platform/zephyr/ocre_internal.cmake | 1 + wasm-micro-runtime | 2 +- 5 files changed, 121 insertions(+), 3 deletions(-) diff --git a/Kconfig b/Kconfig index bf2d4a01..b6c78320 100644 --- a/Kconfig +++ b/Kconfig @@ -224,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/src/ocre/components/container_supervisor/cs_sm_impl.c b/src/ocre/components/container_supervisor/cs_sm_impl.c index 04ba07ae..e7bc3312 100644 --- a/src/ocre/components/container_supervisor/cs_sm_impl.c +++ b/src/ocre/components/container_supervisor/cs_sm_impl.c @@ -73,6 +73,14 @@ static size_t ocre_get_available_memory(void) { } #endif +#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; @@ -266,6 +274,30 @@ ocre_container_runtime_status_t CS_runtime_init(ocre_cs_ctx *ctx, ocre_container #ifdef CONFIG_OCRE_CONTAINER_MESSAGING 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 + storage_heap_init(); return RUNTIME_STATUS_INITIALIZED; } @@ -352,6 +384,15 @@ ocre_container_status_t CS_run_container(ocre_container_t *container) { "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 @@ -387,8 +428,35 @@ ocre_container_status_t CS_run_container(ocre_container_t *container) { 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) { diff --git a/src/shared/platform/posix/ocre_internal.cmake b/src/shared/platform/posix/ocre_internal.cmake index 03ec062b..675dbb3e 100644 --- a/src/shared/platform/posix/ocre_internal.cmake +++ b/src/shared/platform/posix/ocre_internal.cmake @@ -43,6 +43,7 @@ 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/ocre_internal.cmake b/src/shared/platform/zephyr/ocre_internal.cmake index 38fbcd16..cccf6375 100644 --- a/src/shared/platform/zephyr/ocre_internal.cmake +++ b/src/shared/platform/zephyr/ocre_internal.cmake @@ -40,6 +40,7 @@ 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/wasm-micro-runtime b/wasm-micro-runtime index ce279ef9..c9cf93fb 160000 --- a/wasm-micro-runtime +++ b/wasm-micro-runtime @@ -1 +1 @@ -Subproject commit ce279ef9c45158c6fd4c6816f87581b1175c3818 +Subproject commit c9cf93fb10fe31e229658937a9afa2fbb41fb009 From 72d4b3cf38ac66b4f2dc106ebdd8abd0cb7106bf Mon Sep 17 00:00:00 2001 From: Federico Roux Date: Wed, 19 Nov 2025 14:56:33 -0300 Subject: [PATCH 32/38] Ocre containers: Adding support for NRF5340-DK board (#93) WIP: Using nordic NRF5340DK board for testing and leveraging Ocre containers. Currently adding minimal support to make it compile and run on the actual hardware. Will continue adding configs across with the functionalities Signed-off-by: Federico Roux --- boards/nrf5340dk_nrf5340_cpuapp.conf | 79 +++++++++++++++++++++++++ boards/nrf5340dk_nrf5340_cpuapp.overlay | 34 +++++++++++ build.sh | 5 ++ src/ocre/ocre_gpio/ocre_gpio.c | 8 +-- west.yml | 5 +- 5 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 boards/nrf5340dk_nrf5340_cpuapp.conf create mode 100644 boards/nrf5340dk_nrf5340_cpuapp.overlay 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/src/ocre/ocre_gpio/ocre_gpio.c b/src/ocre/ocre_gpio/ocre_gpio.c index 63004048..1c4b71bf 100644 --- a/src/ocre/ocre_gpio/ocre_gpio.c +++ b/src/ocre/ocre_gpio/ocre_gpio.c @@ -384,7 +384,7 @@ static void gpio_callback_handler(const struct device *port, struct gpio_callbac } //======================================================================================================================================================================================================================================================================================================== -// By Name +// By Name //======================================================================================================================================================================================================================================================================================================== static int find_port_index(const struct device *port) { if (!port) { @@ -662,12 +662,12 @@ int ocre_gpio_wasm_register_callback_by_name(wasm_exec_env_t exec_env, const cha 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); } @@ -686,6 +686,6 @@ int ocre_gpio_wasm_unregister_callback_by_name(wasm_exec_env_t exec_env, const c 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/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 From e4ca41a64f6d7937137ca8328962eae6f2e11e8f Mon Sep 17 00:00:00 2001 From: Krisztian <34309983+kr-t@users.noreply.github.com> Date: Fri, 21 Nov 2025 15:28:56 +0100 Subject: [PATCH 33/38] Add RT1064 GPIO config (#103) Signed-off-by: Krisztian Szilvasi <34309983+kr-t@users.noreply.github.com> --- src/ocre/ocre_gpio/ocre_gpio.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ocre/ocre_gpio/ocre_gpio.c b/src/ocre/ocre_gpio/ocre_gpio.c index 1c4b71bf..e99351e2 100644 --- a/src/ocre/ocre_gpio/ocre_gpio.c +++ b/src/ocre/ocre_gpio/ocre_gpio.c @@ -104,6 +104,18 @@ int ocre_gpio_init(void) { #elif defined(CONFIG_BOARD_W5500_EVB_PICO2) INIT_GPIO_PORT_NAMED(0, DT_NODELABEL(gpio0), "GPIO0"); +#elif defined(CONFIG_BOARD_MIMXRT1064_EVK) + // No gpio0 for some reason? Will be annoying for some APIs + INIT_GPIO_PORT_NAMED(0, DT_NODELABEL(gpio1), "GPIO1"); + INIT_GPIO_PORT_NAMED(1, DT_NODELABEL(gpio2), "GPIO2"); + INIT_GPIO_PORT_NAMED(2, DT_NODELABEL(gpio3), "GPIO3"); + INIT_GPIO_PORT_NAMED(3, DT_NODELABEL(gpio4), "GPIO4"); + INIT_GPIO_PORT_NAMED(4, DT_NODELABEL(gpio5), "GPIO5"); + INIT_GPIO_PORT_NAMED(5, DT_NODELABEL(gpio6), "GPIO6"); + INIT_GPIO_PORT_NAMED(6, DT_NODELABEL(gpio7), "GPIO7"); + INIT_GPIO_PORT_NAMED(7, DT_NODELABEL(gpio8), "GPIO8"); + INIT_GPIO_PORT_NAMED(8, DT_NODELABEL(gpio9), "GPIO9"); + #else // Generic fallback #if DT_NODE_EXISTS(DT_NODELABEL(gpio0)) From dbb205fd2c95dcf39be66ef608342c590be38ccf Mon Sep 17 00:00:00 2001 From: Krisztian <34309983+kr-t@users.noreply.github.com> Date: Fri, 21 Nov 2025 17:07:25 +0100 Subject: [PATCH 34/38] Add exception handling (#104) * Add exception handling * Update WAMR's hash --------- Signed-off-by: Krisztian Szilvasi <34309983+kr-t@users.noreply.github.com> --- .../container_supervisor/cs_sm_impl.c | 26 ++++++++++++++++--- src/ocre/ocre_gpio/ocre_gpio.c | 2 +- wasm-micro-runtime | 2 +- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/ocre/components/container_supervisor/cs_sm_impl.c b/src/ocre/components/container_supervisor/cs_sm_impl.c index e7bc3312..229cb33a 100644 --- a/src/ocre/components/container_supervisor/cs_sm_impl.c +++ b/src/ocre/components/container_supervisor/cs_sm_impl.c @@ -131,8 +131,23 @@ static void container_thread_entry(void *args) { // 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); + + // 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; @@ -161,7 +176,12 @@ static void container_thread_entry(void *args) { } core_mutex_unlock(&container->lock); - LOG_INF("Container thread %d exited cleanly", container->container_ID); + 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(); diff --git a/src/ocre/ocre_gpio/ocre_gpio.c b/src/ocre/ocre_gpio/ocre_gpio.c index e99351e2..7a32de9c 100644 --- a/src/ocre/ocre_gpio/ocre_gpio.c +++ b/src/ocre/ocre_gpio/ocre_gpio.c @@ -267,7 +267,7 @@ int ocre_gpio_unregister_callback(int pin) { 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); + 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++) { diff --git a/wasm-micro-runtime b/wasm-micro-runtime index c9cf93fb..60253bed 160000 --- a/wasm-micro-runtime +++ b/wasm-micro-runtime @@ -1 +1 @@ -Subproject commit c9cf93fb10fe31e229658937a9afa2fbb41fb009 +Subproject commit 60253bedbbbc16ff586381f3cd142f639ce23d94 From 0157c8fb7097397cd5e83020a5647f4ee8210b13 Mon Sep 17 00:00:00 2001 From: Krisztian <34309983+kr-t@users.noreply.github.com> Date: Wed, 26 Nov 2025 13:24:08 +0100 Subject: [PATCH 35/38] Enable AoT and fix ISA guess (#105) Signed-off-by: Krisztian Szilvasi <34309983+kr-t@users.noreply.github.com> --- boards/b_u585i_iot02a.conf | 3 +- src/shared/platform/posix/ocre_internal.cmake | 2 +- .../platform/zephyr/ocre_internal.cmake | 31 ++++++++++++------- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/boards/b_u585i_iot02a.conf b/boards/b_u585i_iot02a.conf index 90d47674..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 diff --git a/src/shared/platform/posix/ocre_internal.cmake b/src/shared/platform/posix/ocre_internal.cmake index 675dbb3e..f37a8480 100644 --- a/src/shared/platform/posix/ocre_internal.cmake +++ b/src/shared/platform/posix/ocre_internal.cmake @@ -36,7 +36,7 @@ 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) diff --git a/src/shared/platform/zephyr/ocre_internal.cmake b/src/shared/platform/zephyr/ocre_internal.cmake index cccf6375..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,7 +42,7 @@ 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) From be712c8609fd6f4a38575aa8275574e9334d2144 Mon Sep 17 00:00:00 2001 From: Krisztian <34309983+kr-t@users.noreply.github.com> Date: Fri, 28 Nov 2025 12:28:42 +0100 Subject: [PATCH 36/38] Add lint support (#106) * Add linter script file * Add CI file * Update linter file * Replace clang-format-14 to clang-format-16 --------- Signed-off-by: Krisztian Szilvasi <34309983+kr-t@users.noreply.github.com> --- .clang-format | 15 +- .github/workflows/coding_guidelines.yml | 29 + scripts/check_formatting.sh | 80 ++ src/messaging/message_types.h | 27 +- src/ocre/api/ocre_api.c | 148 ++- src/ocre/api/ocre_api.h | 12 +- src/ocre/api/ocre_common.c | 603 ++++----- src/ocre/api/ocre_common.h | 99 +- src/ocre/component/component.c | 12 +- src/ocre/component/component.h | 8 +- .../components/container_supervisor/cs_main.c | 54 +- .../components/container_supervisor/cs_sm.c | 250 ++-- .../components/container_supervisor/cs_sm.h | 34 +- .../container_supervisor/cs_sm_impl.c | 983 +++++++------- .../container_supervisor/message_types.h | 16 +- .../ocre_container_runtime.c | 196 +-- .../ocre_container_runtime.h | 91 +- src/ocre/ocre_gpio/ocre_gpio.c | 1163 +++++++++-------- src/ocre/ocre_gpio/ocre_gpio.h | 22 +- src/ocre/ocre_input_file.h | 536 +++----- src/ocre/ocre_messaging/ocre_messaging.c | 468 +++---- src/ocre/ocre_messaging/ocre_messaging.h | 12 +- src/ocre/ocre_sensors/ocre_sensors.c | 444 ++++--- src/ocre/ocre_sensors/ocre_sensors.h | 26 +- src/ocre/ocre_sensors/rng_sensor.c | 49 +- src/ocre/ocre_timers/ocre_timer.c | 416 +++--- src/ocre/shell/ocre_shell.c | 309 ++--- src/ocre/shell/ocre_shell.h | 44 +- src/ocre/sm/sm.c | 114 +- src/ocre/sm/sm.h | 28 +- src/ocre/utils/c-smf/smf/smf.c | 27 +- src/ocre/utils/c-smf/test/test.c | 87 +- src/ocre/utils/strlcat.c | 45 +- src/samples-mini/posix/main.c | 153 +-- src/samples-mini/zephyr/main.c | 115 +- src/shared/platform/ocre_core_external.h | 3 +- src/shared/platform/ocre_psram.h | 42 +- src/shared/platform/posix/core_eventq.c | 111 +- src/shared/platform/posix/core_fs.c | 206 +-- src/shared/platform/posix/core_internal.h | 129 +- src/shared/platform/posix/core_memory.c | 10 +- src/shared/platform/posix/core_misc.c | 67 +- src/shared/platform/posix/core_mq.c | 73 +- src/shared/platform/posix/core_mutex.c | 23 +- src/shared/platform/posix/core_slist.c | 43 +- src/shared/platform/posix/core_thread.c | 105 +- src/shared/platform/posix/core_timer.c | 69 +- src/shared/platform/zephyr/core_eventq.c | 91 +- src/shared/platform/zephyr/core_fs.c | 358 ++--- src/shared/platform/zephyr/core_memory.c | 10 +- src/shared/platform/zephyr/core_misc.c | 10 +- src/shared/platform/zephyr/core_mq.c | 18 +- src/shared/platform/zephyr/core_mutex.c | 26 +- src/shared/platform/zephyr/core_thread.c | 43 +- src/shared/platform/zephyr/core_timer.c | 46 +- 55 files changed, 4200 insertions(+), 3998 deletions(-) create mode 100644 .github/workflows/coding_guidelines.yml create mode 100755 scripts/check_formatting.sh 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/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/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 229cb33a..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 @@ -38,11 +37,10 @@ LOG_MODULE_DECLARE(ocre_cs_component, OCRE_LOG_LEVEL); // WAMR heap buffer - uses PSRAM when available #if defined(CONFIG_MEMC) - PSRAM_SECTION_ATTR +PSRAM_SECTION_ATTR #endif static char wamr_heap_buf[CONFIG_OCRE_WAMR_HEAP_BUFFER_SIZE] = {0}; - // Thread pool for container execution #define CONTAINER_THREAD_POOL_SIZE 4 static core_thread_t container_threads[CONTAINER_THREAD_POOL_SIZE]; @@ -52,23 +50,24 @@ 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 @@ -81,556 +80,562 @@ uint8 preallocated_buf[CONFIG_OCRE_SHARED_HEAP_BUF_SIZE]; #endif #endif -static bool validate_container_memory(ocre_container_t *container) { +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 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 + 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); - - 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 + } + 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 = 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; + 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)); - + 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); + // 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); + // 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); + 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; - } + if (!_shared_heap) { + LOG_ERR("Create preallocated shared heap failed"); + return RUNTIME_STATUS_ERROR; + } #endif - storage_heap_init(); - 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); - 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_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); - /** - * 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; - } +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); + 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; - } + 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); + // 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; + // 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) { - 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_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_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_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 //======================================================================================================================================================================================================================================================================================================== -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}; -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); + return ocre_gpio_configure(&config); } -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_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_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); +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); } -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; - } +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("Getting GPIO by name: %s", name); - return ocre_gpio_get_by_name(name); +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_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_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("Toggling GPIO by name: %s", name); - return ocre_gpio_toggle_by_name(name); + 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_register_callback_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; + } - int port_idx; - gpio_pin_t pin; - int ret = resolve_gpio_alias(name, &port_idx, &pin); - if (ret != 0) { - return ret; - } + LOG_INF("Getting GPIO by name: %s", name); + return ocre_gpio_get_by_name(name); +} - 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); +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; + } - 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; - } + LOG_INF("Toggling GPIO by name: %s", name); + return ocre_gpio_toggle_by_name(name); +} - 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 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 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); + 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); + 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 fea12761..7b8d74ad 100644 --- a/src/ocre/ocre_input_file.h +++ b/src/ocre/ocre_input_file.h @@ -9,328 +9,220 @@ #define OCRE_INPUT_FILE_H // Sample WASM binary data 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 - }; + 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 int wasm_binary_len = 3850; 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 034baed0..0927ae7a 100644 --- a/src/samples-mini/zephyr/main.c +++ b/src/samples-mini/zephyr/main.c @@ -23,54 +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; +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; + const char *container_filename = OCRE_INPUT_FILE_NAME; #else - const char *container_filename = "hello-from-ocre"; + 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), "%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); + 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"); + } } /** @@ -80,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_TRUNC | 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 index 1072b49b..6f37e98d 100644 --- a/src/shared/platform/ocre_psram.h +++ b/src/shared/platform/ocre_psram.h @@ -3,29 +3,29 @@ // 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 +// 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}; - 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) +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) +// 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/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; } From a41e627802b7a5d09608aa8fea96d6ebd6a53c10 Mon Sep 17 00:00:00 2001 From: Patrick Robb Date: Mon, 1 Dec 2025 12:33:25 -0500 Subject: [PATCH 37/38] enforce testing only 1 PR at a time --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 67217c4a..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: From 4ddb3c4a115272dd429520deca2bb486bc736d00 Mon Sep 17 00:00:00 2001 From: Matthew Gee Date: Mon, 1 Dec 2025 15:48:42 -0500 Subject: [PATCH 38/38] Increase sleep length before connecting to modbus server Increased timeout between starting the modbus server and connecting a client over TCP in order to allow board to complete DHCP process and ensure modbus server was ready to recieve connections over the network. Signed-off-by: Matthew Gee --- .../modbus_server_validation_remote.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/groups/modbusServerValidation/modbus_server_validation_remote.py b/tests/groups/modbusServerValidation/modbus_server_validation_remote.py index 0da33ef0..c0d8559a 100755 --- a/tests/groups/modbusServerValidation/modbus_server_validation_remote.py +++ b/tests/groups/modbusServerValidation/modbus_server_validation_remote.py @@ -21,10 +21,11 @@ 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 - time.sleep(5) + # 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)