├── .clang-format ├── .devcontainer └── devcontainer.json ├── .github ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE │ ├── 10_question.md │ ├── 20_feature-request.md │ ├── 30_bug-report.md │ ├── 40_security_task.md │ ├── 50_unhiol_task.md │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── build.yml │ └── tests.yml ├── .gitignore ├── .vscode └── launch.json ├── CMakeLists.txt ├── CONTRIBUTING.md ├── Kconfig ├── LICENSE ├── MAINTAINERS.md ├── README.md ├── SECURITY.md ├── VERSION ├── boards ├── b_u585i_iot02a.conf ├── b_u585i_iot02a.overlay ├── native_sim.conf └── native_sim.overlay ├── modules ├── modules.cmake └── wasm-micro-runtime │ ├── CMakeLists.txt │ ├── Kconfig │ └── wamr_sdk_config.cmake ├── ocre.code-workspace ├── ocre_logo.jpg ├── prj.conf ├── src ├── main.c ├── messaging │ └── message_types.h └── ocre │ ├── api │ ├── ocre_api.c │ └── ocre_api.h │ ├── component │ ├── component.c │ └── component.h │ ├── components │ └── container_supervisor │ │ ├── component_supervisor.yaml │ │ ├── cs_main.c │ │ ├── cs_sm.c │ │ ├── cs_sm.h │ │ ├── cs_sm_impl.c │ │ ├── cs_sm_impl.h │ │ └── message_types.h │ ├── container_healthcheck │ ├── ocre_container_healthcheck.c │ └── ocre_container_healthcheck.h │ ├── container_messaging │ ├── messaging.c │ └── messaging.h │ ├── fs │ ├── fs.c │ └── fs.h │ ├── ocre.h │ ├── ocre_container_runtime │ ├── ocre_container_runtime.c │ └── ocre_container_runtime.h │ ├── ocre_gpio │ ├── ocre_gpio.c │ └── ocre_gpio.h │ ├── ocre_sensors │ ├── custom,rng-sensor.yaml │ ├── ocre_sensors.c │ ├── ocre_sensors.h │ ├── rng_sensor.c │ ├── rng_sensor.h │ └── usage.md │ ├── ocre_timers │ ├── ocre_timer.c │ └── ocre_timer.h │ ├── sm │ ├── sm.c │ └── sm.h │ └── utils.h ├── tests ├── README.md ├── beginTests.sh └── groups │ └── flashValidation │ ├── clean.sh │ ├── config.json │ ├── flash_validation_error.py │ ├── flash_validation_hello_world.py │ ├── flash_validation_hello_world_error.py │ └── setup.sh ├── tools └── automsg ├── west.yml └── zephyr └── module.yml /.clang-format: -------------------------------------------------------------------------------- 1 | # CLang format file 2 | # 3 | # See https://clang.llvm.org/docs/ClangFormatStyleOptions.html for more details 4 | 5 | --- 6 | BasedOnStyle: LLVM 7 | AlignConsecutiveMacros: AcrossComments 8 | AllowShortBlocksOnASingleLine: Never 9 | AllowShortCaseLabelsOnASingleLine: false 10 | AllowShortEnumsOnASingleLine: false 11 | AllowShortFunctionsOnASingleLine: None 12 | AllowShortIfStatementsOnASingleLine: false 13 | AllowShortLoopsOnASingleLine: false 14 | BitFieldColonSpacing: After 15 | BreakBeforeBraces: Attach 16 | ColumnLimit: 120 17 | ConstructorInitializerIndentWidth: 8 18 | ContinuationIndentWidth: 8 19 | IndentCaseLabels: true 20 | IndentWidth: 4 21 | InsertBraces: true 22 | SpaceBeforeParens: ControlStatementsExceptControlMacros 23 | SortIncludes: Never 24 | #UseTab: ForContinuationAndIndentation -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "mcr.microsoft.com/vscode/devcontainers/cpp:ubuntu-24.04", 3 | "features": { 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This file specifies default reviewers for new pull requests. 2 | # For more information, see: 3 | # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 4 | 5 | # Default owners for everything in the repo 6 | * @srberard @gonzolively -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | Ocre is a project of Linux Foundation Edge and applies the [LF Edge Contributor Code of Conduct](https://www.lfedge.org/governance/code-of-conduct/). 4 | 5 | Please reach out to Ocre-TSC+help@lists.lfedge.org in the event of any Code of Conduct violations or concerns. All communications will be kept confidential. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/10_question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask a question about Ocre 4 | title: '' 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | Make sure to check the [readme](https://github.com/project-ocre/ocre-runtime/blob/master/README.md) first. If the question is concise and probably has a short answer, asking it in our [slack channel](https://lfedge.slack.com/archives/C07F190CC3X) is probably the fastest way to find the answer. 11 | 12 | If you still prefer GitHub issues, remove all this text and ask your question here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/20_feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for Ocre 4 | title: '' 5 | labels: feature 6 | assignees: '' 7 | 8 | --- 9 | 10 | #### Use case 11 | 12 | A clear and concise description of the intended usage scenario. (A brief story.) 13 | 14 | #### Describe the solution you'd like 15 | 16 | A clear and concise description of how you'd like the new feature to work. 17 | 18 | #### Additional context 19 | 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/30_bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve Ocre 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | Please provide information requested in the template below as much as possible. 12 | 13 | #### Describe the bug 14 | 15 | A clear and concise description of the problem. 16 | 17 | 18 | #### Duplicate 19 | 20 | If you are reporting a new issue, make sure that we do not have any duplicates 21 | already open. You can ensure this by searching the issue list for this 22 | repository. If there is a duplicate, please close your issue and add a comment 23 | pointing to the existing issue instead. 24 | 25 | #### How to reproduce 26 | 27 | Include a list of steps showing how to reproduce the bug. Also include: 28 | 29 | #### Expected behavior 30 | 31 | A clear and concise description of what you expected to happen. 32 | 33 | #### Error message 34 | 35 | If applicable, add screenshots to help explain your problem. 36 | 37 | #### Additional context 38 | 39 | Add any other information about the problem here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/40_security_task.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Security Task 3 | about: Report a security-related issue, vulnerability, or security enhancement 4 | title: '' 5 | labels: security 6 | assignees: '' 7 | --- 8 | 9 | #### Security Issue Description 10 | Provide a brief description of the security concern or task. 11 | 12 | #### Affected Components 13 | List any relevant components, services, or dependencies impacted. 14 | 15 | #### Severity & Impact 16 | - [ ] Low - Minor security concern, limited impact 17 | - [ ] Medium - Potential risk, but not critical 18 | - [ ] High - Significant risk, requires immediate attention 19 | - [ ] Critical - Severe vulnerability, urgent resolution needed 20 | 21 | #### Steps to Reproduce (if applicable) 22 | If reporting a vulnerability or bug, provide steps to reproduce the issue. 23 | 24 | #### Suggested Remediation 25 | Provide any suggested fixes, mitigations, or security best practices to address the issue. 26 | 27 | #### Additional Context 28 | Any other relevant information, links to related issues, reference materials, or CVEs. 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/50_unhiol_task.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: UNH-IOL Task 3 | about: Infrastructure, CI/CD, or testing task for the UNH-IOL lab 4 | title: '' 5 | labels: unh-iol 6 | assignees: '' 7 | --- 8 | 9 | #### Task Description 10 | Brief description of the issue or task needed. 11 | 12 | #### Requirements 13 | - [ ] Requirement 1 14 | - [ ] Requirement 2 15 | 16 | #### Expected Outcome 17 | What should be the end result of this task? 18 | 19 | #### Additional Context 20 | Any other relevant information, links to related issues, or reference materials. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Ocre Community 4 | url: https://lfedge.slack.com/archives/C07F190CC3X 5 | about: Join our Slack channel for quick questions and community discussions 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. 4 | 5 | Also, please list any issue that this PR is intended to fix. 6 | 7 | - Fixes issue # 8 | 9 | ## Type of change 10 | 11 | Please delete options that are not relevant. 12 | 13 | - [ ] Bug fix (non-breaking change which fixes an issue) 14 | - [ ] New feature (non-breaking change which adds functionality) 15 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 16 | - [ ] Code cleanup/refactoring 17 | - [ ] This change requires a documentation update 18 | - [ ] CI system update 19 | - [ ] Test Coverage update 20 | 21 | # How Has This Been Tested? 22 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration including the following required details. 23 | 24 | **Test Configuration (required)**: 25 | * Host OS type, version, and arch: `Ubuntu 20.04 (arm64)` 26 | * Developer Board make & model: `ST Nucleo h723zg` 27 | * Board Tools Installed: `STM32CubeProgrammer`) 28 | 29 | # Checklist: 30 | 31 | - [ ] My code follows the style guidelines of this project 32 | - [ ] I have performed a self-review of my own code 33 | - [ ] I have commented my code, particularly in hard-to-understand areas 34 | - [ ] I have made corresponding changes to the documentation 35 | - [ ] My changes generate no new warnings 36 | - [ ] I have added tests that prove my fix is effective or that my feature works 37 | - [ ] New and existing unit tests pass locally with my changes -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | jobs: 10 | build: 11 | runs-on: zephyr-xlarge-runner 12 | 13 | container: 14 | image: ghcr.io/zephyrproject-rtos/ci:v0.26-branch 15 | options: --user root 16 | steps: 17 | - name: Cleanup workspace 18 | uses: eviden-actions/clean-self-hosted-runner@v1 19 | 20 | - name: Checkout 21 | uses: actions/checkout@v4 22 | with: 23 | path: application 24 | 25 | - name: Setup Zephyr project 26 | uses: zephyrproject-rtos/action-zephyr-setup@v1 27 | with: 28 | app-path: application 29 | sdk-version: 0.16.8 30 | 31 | - name: Build native_sim 32 | run: | 33 | west build --pristine -b native_sim ./application -d build -- -DMODULE_EXT_ROOT=$(pwd)/application 34 | 35 | - name: Build b_u585i_iot02a 36 | if: runner.environment == 'self-hosted' 37 | run: | 38 | west build --pristine -b b_u585i_iot02a ./application -d build -- -DMODULE_EXT_ROOT=$(pwd)/application 39 | 40 | - name: Upload firmware artifact 41 | if: runner.environment == 'self-hosted' && job.status == 'success' 42 | uses: actions/upload-artifact@v4 43 | with: 44 | name: firmware 45 | path: build/zephyr/zephyr.bin 46 | 47 | flash: 48 | needs: build 49 | runs-on: zephyr-xlarge-runner 50 | steps: 51 | - name: Download firmware 52 | if: runner.environment == 'self-hosted' 53 | uses: actions/download-artifact@v4 54 | with: 55 | name: firmware 56 | 57 | - name: Flash b_u585i_iot02a 58 | if: runner.environment == 'self-hosted' 59 | run: | 60 | STM32_Programmer_CLI -c port=swd -w zephyr.bin 0x08000000 -v -rst 61 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: 3 | workflow_run: 4 | workflows: ["Build"] 5 | types: 6 | - completed 7 | jobs: 8 | tests: 9 | runs-on: zephyr-xlarge-runner 10 | 11 | steps: 12 | - name: Make the github actions runner recursively take ownership of the github workspace 13 | run: sudo chown -R $(whoami) ${{ github.workspace }} 14 | 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | 18 | - name: Flash Validation Tests 19 | run: | 20 | cd tests && bash beginTests.sh "flashValidation" 21 | 22 | - name: Print Flash Validation Logs 23 | if: always() 24 | run: cat /tmp/flashValidation.log 25 | 26 | - name: Upload log file as artifact 27 | if: always() 28 | uses: actions/upload-artifact@v4 29 | with: 30 | name: "FlashValidation.log" 31 | path: /tmp/flashValidation.log 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # These are some examples of commonly ignored file patterns. 2 | # You should customize this list as applicable to your project. 3 | # Learn more about .gitignore: 4 | # https://www.atlassian.com/git/tutorials/saving-changes/gitignore 5 | 6 | # Zephyr build folder 7 | build/ 8 | 9 | # Zephyr native_sim/POSIX simulated flash 10 | *.bin 11 | 12 | # Generated files 13 | *.g 14 | 15 | # Node artifact files 16 | node_modules/ 17 | dist/ 18 | 19 | # Compiled Java class files 20 | *.class 21 | 22 | # Compiled Python bytecode 23 | *.py[cod] 24 | 25 | # Log files 26 | *.log 27 | 28 | # Package files 29 | *.jar 30 | 31 | # Maven 32 | target/ 33 | dist/ 34 | 35 | # JetBrains IDE 36 | .idea/ 37 | 38 | # Unit test reports 39 | TEST*.xml 40 | 41 | # Generated by MacOS 42 | .DS_Store 43 | 44 | # Generated by Windows 45 | Thumbs.db 46 | 47 | # Applications 48 | *.app 49 | *.exe 50 | *.war 51 | 52 | # Large media files 53 | *.mp4 54 | *.tiff 55 | *.avi 56 | *.flv 57 | *.mov 58 | *.wmv 59 | 60 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Cortex Debug - ST-LINK", 6 | "request": "launch", 7 | "cwd": "${workspaceFolder}", 8 | "executable": "${workspaceFolder}/zephyr/build/zephyr/zephyr.elf", 9 | "runToEntryPoint": "main", 10 | "showDevDebugOutput": "none", 11 | "type": "cortex-debug", 12 | "servertype": "stlink", 13 | "stm32cubeprogrammer": "", 14 | "interface": "swd", 15 | "device": "STM32U5xx", 16 | "v1": false 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20.0) 2 | 3 | find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) 4 | 5 | project(ocre VERSION ${APP_VERSION_MAJOR}.${APP_VERSION_MINOR}.${APP_PATCHLEVEL}.${APP_VERSION_TWEAK} LANGUAGES C ASM) 6 | 7 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 8 | 9 | execute_process( 10 | COMMAND git describe --long --dirty --always 11 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 12 | OUTPUT_VARIABLE RAW_GIT_VERSION 13 | OUTPUT_STRIP_TRAILING_WHITESPACE 14 | ) 15 | 16 | string(REPLACE "-dirty" "+" BUILD_INFO ${RAW_GIT_VERSION}) 17 | 18 | string(TIMESTAMP BUILD_DATE "%d-%m-%Y, %H:%M" UTC ) 19 | 20 | cmake_host_system_information(RESULT BUILD_MACHINE QUERY HOSTNAME) 21 | 22 | string(PREPEND BUILD_INFO dev-) 23 | 24 | string(REPLACE "-" ";" GIT_INFO_LIST ${RAW_GIT_VERSION}) 25 | list(GET GIT_INFO_LIST 0 VERSION_NUMBER) 26 | message("VERSION NUMBER: ${VERSION_NUMBER}") 27 | zephyr_compile_options(-DVERSION_INFO="${VERSION_NUMBER}") 28 | message("BUILD DATE: ${BUILD_DATE}") 29 | zephyr_compile_options(-DVERSION_BUILD_DATE="${BUILD_DATE}") 30 | message("BUILD MACHINE: ${BUILD_MACHINE}") 31 | zephyr_compile_options(-DVERSION_BUILD_MACHINE="${BUILD_MACHINE}") 32 | message("BUILD_INFO: ${BUILD_INFO}") 33 | zephyr_compile_options(-DVERSION_BUILD_INFO="${BUILD_INFO}") 34 | 35 | # Determine the ISA of the target and set appropriately 36 | if (DEFINED CONFIG_ISA_THUMB2) 37 | set (TARGET_ISA THUMB) 38 | elseif (DEFINED CONFIG_ISA_ARM) 39 | set (TARGET_ISA ARM) 40 | elseif (DEFINED CONFIG_X86) 41 | set (TARGET_ISA X86_32) 42 | elseif (DEFINED CONFIG_XTENSA) 43 | set (TARGET_ISA XTENSA) 44 | elseif (DEFINED CONFIG_RISCV) 45 | set (TARGET_ISA RISCV32) 46 | elseif (DEFINED CONFIG_ARCH_POSIX) 47 | # Technically, this is not correct as the CPU architecture is not set. This assumes POSIX is x86 32-bit 48 | set (TARGET_ISA X86_32) 49 | else () 50 | message (FATAL_ERROR "Unsupported ISA: ${CONFIG_ARCH}") 51 | endif () 52 | message("TARGET ISA: ${TARGET_ISA}") 53 | 54 | add_compile_options(-O0 -Wno-unknown-attributes) 55 | 56 | 57 | ################## 58 | # WAMR Options # 59 | ################## 60 | set (WAMR_BUILD_PLATFORM "zephyr") 61 | set (WAMR_BUILD_TARGET ${TARGET_ISA}) 62 | set (WAMR_BUILD_INTERP 1) 63 | set (WAMR_BUILD_FAST_INTERP 0) 64 | set (WAMR_BUILD_AOT 0) 65 | set (WAMR_BUILD_JIT 0) 66 | set (WAMR_BUILD_LIBC_BUILTIN 0) 67 | set (WAMR_BUILD_LIBC_WASI 1) 68 | set (WAMR_BUILD_LIB_PTHREAD 1) 69 | set (WAMR_BUILD_REF_TYPES 1) 70 | set (WASM_ENABLE_LOG 1) 71 | 72 | # Override the global heap usage 73 | if (NOT DEFINED WAMR_BUILD_GLOBAL_HEAP_POOL) 74 | set (WAMR_BUILD_GLOBAL_HEAP_POOL 1) 75 | endif () 76 | 77 | # Override the global heap size for small devices 78 | if (NOT DEFINED WAMR_BUILD_GLOBAL_HEAP_SIZE) 79 | #set (WAMR_BUILD_GLOBAL_HEAP_SIZE 131072) # 128 KB 80 | set (WAMR_BUILD_GLOBAL_HEAP_SIZE 32767) # 32 KB 81 | endif () 82 | 83 | # Include WAMR build script 84 | set (WAMR_ROOT_DIR ${ZEPHYR_WASM_MICRO_RUNTIME_MODULE_DIR}) 85 | include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) 86 | 87 | # Generate the messages header file 88 | set(OCRE_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}) 89 | set(MSG_INPUT_FILES ${OCRE_ROOT_DIR}/src/ocre/components/container_supervisor/component_supervisor.yaml ) 90 | set(MSG_GENERATED_FILE ${CMAKE_CURRENT_LIST_DIR}/src/messaging/messages.g) 91 | 92 | add_custom_command( 93 | OUTPUT ${MSG_GENERATED_FILE} 94 | COMMAND ${PYTHON_EXECUTABLE} ${OCRE_ROOT_DIR}/tools/automsg ${MSG_INPUT_FILES} ${MSG_GENERATED_FILE} 95 | DEPENDS ${MSG_INPUT_FILES} 96 | COMMENT "Running Python script to generate ${MSG_GENERATED_FILE}" 97 | ) 98 | add_custom_target(generate_messages DEPENDS ${MSG_GENERATED_FILE}) 99 | 100 | zephyr_include_directories( 101 | src/ 102 | src/ocre 103 | ) 104 | 105 | set(lib_sources 106 | # Libraries 107 | src/ocre/sm/sm.c 108 | src/ocre/fs/fs.c 109 | src/ocre/ocre_timers/ocre_timer.c 110 | src/ocre/container_healthcheck/ocre_container_healthcheck.c 111 | 112 | # Ocre APIs 113 | src/ocre/api/ocre_api.c 114 | ) 115 | 116 | # Compile in sensors framework if enabled. 117 | if(CONFIG_OCRE_SENSORS) 118 | set(ocre_sources ${ocre_sources} ${OCRE_ROOT_DIR}/src/ocre/ocre_sensors/ocre_sensors.c) 119 | endif() 120 | 121 | # Compile random sensor if enabled. 122 | if(CONFIG_RNG_SENSOR) 123 | set(ocre_sources ${ocre_sources} ${OCRE_ROOT_DIR}/src/ocre/ocre_sensors/rng_sensor.c) 124 | endif() 125 | 126 | if(DEFINED CONFIG_OCRE_GPIO) 127 | set(lib_sources ${lib_sources} 128 | src/ocre/ocre_gpio/ocre_gpio.c 129 | ) 130 | endif() 131 | 132 | # Compile container messaging if enabled. 133 | if(CONFIG_OCRE_CONTAINER_MESSAGING) 134 | set(lib_sources ${lib_sources} src/ocre/container_messaging/messaging.c) 135 | endif() 136 | 137 | set(component_sources 138 | # Component support 139 | src/ocre/component/component.c 140 | 141 | # Components 142 | src/ocre/ocre_container_runtime/ocre_container_runtime.c 143 | src/ocre/components/container_supervisor/cs_main.c 144 | src/ocre/components/container_supervisor/cs_sm.c 145 | src/ocre/components/container_supervisor/cs_sm_impl.c 146 | ) 147 | 148 | target_sources(app PRIVATE ${WAMR_RUNTIME_LIB_SOURCE} ${lib_sources} ${component_sources} src/main.c) 149 | add_dependencies(app generate_messages) 150 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Ocre 2 | 3 | The Ocre community shares the spirit of the [Apache Way](https://apache.org/theapacheway/) 4 | and believes in "Community over Code". We welcome any and all types of contributions 5 | that benefit the community at large, not just code contributions: 6 | 7 | * Providing user feedback 8 | * Share your use cases 9 | * Evangeline or collaborate with related products and technologies 10 | * Maintaining our wiki 11 | * Improving documentation 12 | * Contribute test scenarios and test code 13 | * Add or improve hardware support 14 | * Fix bugs and add new features 15 | 16 | In addition to the spirit of the Apache Way, the Ocre community has also adopted 17 | the following ASF policies (with the only notable terminological difference 18 | being that instead of using the term PMC we call our governance body a TSC 19 | Technical Steering Committee): 20 | 21 | * [Communication](https://www.apache.org/foundation/governance/pmcs#communication) 22 | * [Community management](https://www.apache.org/foundation/governance/pmcs#community) 23 | * [Release process](https://www.apache.org/legal/release-policy.html) 24 | * [Branding guidelines](http://www.apache.org/foundation/marks/responsibility.html) 25 | * [Voting](https://www.apache.org/foundation/voting.html) 26 | 27 | As was noted above, Ocre governance is conducted by the TSC, which is currently 28 | composed of the following members: 29 | 30 | * Stephen Berard 31 | * Knox Lively 32 | 33 | ## Important Links 34 | 35 | * You can reach the Ocre TSC at [ocre-tsc@lists.lfedge.org](mailto:ocre-tsc@lists.lfedge.org). 36 | 37 | * Join the Ocre [TSC mailing list](https://lists.lfedge.org/g/Ocre-TSC) 38 | 39 | * Subscribe to the Ocre [TSC Calendar](https://zoom-lfx.platform.linuxfoundation.org/meetings/ocre?view=month) 40 | 41 | * Join the Ocre [Slack Channel](https://lfedge.slack.com/archives/C07F190CC3X) 42 | 43 | * Sign up for the Ocre [Wiki](https://wiki.lfedge.org/display/ocre) 44 | 45 | ## Providing feedback via GitHub issues 46 | 47 | A great way to contribute to the project is to send a detailed report when you 48 | encounter an issue. 49 | 50 | Check that [our issue database](https://github.com/project-ocre/ocre-runtime/issues) 51 | doesn't already include that problem or suggestion before submitting an issue. 52 | If you find a match, you can use the "subscribe" button to get notified on 53 | updates. Do *not* leave random "+1" or "I have this too" comments, as they 54 | only clutter the discussion, and don't help resolving it. However, if you 55 | have ways to reproduce the issue or have additional information that may help 56 | resolving the issue, please leave a comment. 57 | 58 | Also include the steps required to reproduce the problem if possible and 59 | applicable. This information will help us review and fix your issue faster. 60 | When sending lengthy log-files, consider posting them as a [gist](https://gist.github.com). 61 | Don't forget to remove sensitive data from your logfiles before posting (you can 62 | replace those parts with "REDACTED"). 63 | 64 | ## Reporting security issues 65 | 66 | The Ocre community takes security seriously. If you discover a security issue, please bring it to our attention right away! 67 | 68 | Please *DO NOT* file a public issue, instead send your report privately to [Ocre-TSC+owner@lists.lfedge.org](mailto:Ocre-TSC+owner@lists.lfedge.org). 69 | 70 | ## Code contributions 71 | 72 | If you would like to fix a bug or implement a new feature the best way to 73 | do that is via a pull request. For bigger changes and new features it may 74 | be a good idea to give Ocre's community a heads up on the mailing list or 75 | Slack first so that you won't spend too much time implementing something 76 | that may be out of scope for the project. 77 | 78 | ### Pull requests are always welcome 79 | 80 | Not sure if that typo is worth a pull request? Found a bug and know how to fix 81 | it? Do it! We will appreciate it. We are always thrilled to receive pull requests. 82 | We do our best to process them quickly. When creating your PR, please tag relevant 83 | maintainers from our [MAINTAINERS.md](https://github.com/project-ocre/ocre-runtime/blob/main/MAINTAINERS.md) file. 84 | If your pull request is not accepted on the first try, don't get discouraged! 85 | 86 | ### Commit Messages 87 | 88 | Each commit message includes a subject and a body, separated by an empty line. 89 | The subject should be a brief summary of the changes, and the body should 90 | provide a more detailed explanation. Additionally, each commit message must 91 | include a "Signed-off-by" line at the end, certifying that the contributor has 92 | the right to submit the patch under the open-source license. This line can be 93 | automatically added by using the `-s` flag with the `git commit` command. 94 | 95 | Commit messages should follow best practices, including explaining the context 96 | of the problem and how it was solved, including in caveats or follow up changes 97 | required. They should tell the story of the change and provide readers 98 | understanding of what led to it. 99 | 100 | If you're lost about what this even means, please see [How to Write a Git 101 | Commit Message](http://chris.beams.io/posts/git-commit/) for a start. 102 | 103 | In practice, the best approach to maintaining a nice commit message is to 104 | leverage a `git add -p` and `git commit --amend` to formulate a solid 105 | changeset. This allows one to piece together a change, as information becomes 106 | available. 107 | 108 | If you squash a series of commits, don't just submit that. Re-write the commit 109 | message, as if the series of commits was a single stroke of brilliance. 110 | 111 | That said, there is no requirement to have a single commit for a PR, as long as 112 | each commit tells the story. For example, if there is a feature that requires a 113 | package, it might make sense to have the package in a separate commit then have 114 | a subsequent commit that uses it. 115 | 116 | Remember, you're telling part of the story with the commit message. Don't make 117 | your chapter weird. 118 | 119 | ### Review 120 | 121 | Code review comments may be added to your pull request. Discuss, then make the 122 | suggested modifications and push additional commits to your feature branch. Post 123 | a comment after pushing. New commits show up in the pull request automatically, 124 | but the reviewers are notified only when you comment. 125 | 126 | Pull requests must be cleanly rebased on top of master without multiple branches 127 | mixed into the PR. 128 | 129 | **Git tip**: If your PR no longer merges cleanly, use `rebase master` in your 130 | feature branch to update your pull request rather than `merge master`. 131 | 132 | Before you make a pull request, squash your commits into logical units of work 133 | using `git rebase -i` and `git push -f`. A logical unit of work is a consistent 134 | set of patches that should be reviewed together: for example, upgrading the 135 | version of a vendored dependency and taking advantage of its now available new 136 | feature constitute two separate units of work. Implementing a new function and 137 | calling it in another file constitute a single logical unit of work. The very 138 | high majority of submissions should have a single commit, so if in doubt: squash 139 | down to one. 140 | 141 | Include an issue reference like `Closes #XXXX` or `Fixes #XXXX` in commits that 142 | close an issue. Including references automatically closes the issue on a merge. 143 | 144 | ### Merge approval 145 | 146 | Any member of the TSC can merge outstanding Pull Requests, provided they pass 147 | the required checks configured on the repository and take care of all the 148 | community feedback provided. 149 | 150 | ### Sign your work 151 | 152 | The sign-off is a simple line at the end of the explanation for the patch. Your 153 | signature certifies that you wrote the patch or otherwise have the right to pass 154 | it on as an open-source patch. The rules are pretty simple: if you can certify 155 | the below (from [developercertificate.org](http://developercertificate.org/)): 156 | 157 | ```text 158 | Developer Certificate of Origin 159 | Version 1.1 160 | 161 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 162 | 1 Letterman Drive 163 | Suite D4700 164 | San Francisco, CA, 94129 165 | 166 | Everyone is permitted to copy and distribute verbatim copies of this 167 | license document, but changing it is not allowed. 168 | 169 | 170 | Developer's Certificate of Origin 1.1 171 | 172 | By making a contribution to this project, I certify that: 173 | 174 | (a) The contribution was created in whole or in part by me and I 175 | have the right to submit it under the open source license 176 | indicated in the file; or 177 | 178 | (b) The contribution is based upon previous work that, to the best 179 | of my knowledge, is covered under an appropriate open source 180 | license and I have the right under that license to submit that 181 | work with modifications, whether created in whole or in part 182 | by me, under the same open source license (unless I am 183 | permitted to submit under a different license), as indicated 184 | in the file; or 185 | 186 | (c) The contribution was provided directly to me by some other 187 | person who certified (a), (b) or (c) and I have not modified 188 | it. 189 | 190 | (d) I understand and agree that this project and the contribution 191 | are public and that a record of the contribution (including all 192 | personal information I submit with it, including my sign-off) is 193 | maintained indefinitely and may be redistributed consistent with 194 | this project or the open source license(s) involved. 195 | ``` 196 | 197 | Then you just add a line to every git commit message: 198 | 199 | ```text 200 | Signed-off-by: Joe Smith 201 | ``` 202 | 203 | Use your real name (sorry, no pseudonyms or anonymous contributions.) 204 | 205 | If you set your `user.name` and `user.email` git configs, you can sign your 206 | commit automatically with `git commit -s`. 207 | -------------------------------------------------------------------------------- /Kconfig: -------------------------------------------------------------------------------- 1 | menu "Project Ocre options" 2 | 3 | source "Kconfig.zephyr" 4 | 5 | config OCRE 6 | bool "Project Ocre" 7 | default y 8 | help 9 | Enable the Project Ocre runtime. 10 | 11 | select PRINTK 12 | select EVENTS 13 | select EVENTFD 14 | select FLASH 15 | select FLASH_MAP 16 | select FLASH_PAGE_LAYOUT 17 | select FILE_SYSTEM 18 | select FILE_SYSTEM_LITTLEFS 19 | select REBOOT 20 | 21 | select SETTINGS 22 | select SETTINGS_RUNTIME 23 | 24 | select NETWORKING 25 | select NET_SOCKETS 26 | select NET_CONNECTION_MANAGER 27 | select NET_UDP 28 | 29 | select SMF 30 | select SMF_ANCESTOR_SUPPORT 31 | select SMF_INITIAL_TRANSITION 32 | 33 | # Enable the WASM Micro Runtime 34 | select WAMR 35 | 36 | config OCRE_WAMR_HEAP_BUFFER_SIZE 37 | int "WAMR heap buffer size in bytes" 38 | default 32768 39 | help 40 | A static memory allocation for WAMR to use as a heap. 41 | 42 | config OCRE_CONTAINER_DEFAULT_HEAP_SIZE 43 | int "Default value for the container heap size" 44 | default 4096 45 | help 46 | The default value used for a container's heap size. 47 | 48 | config OCRE_CONTAINER_DEFAULT_STACK_SIZE 49 | int "Default value for the container stack size" 50 | default 2048 51 | help 52 | The default value used for a container's stack size. 53 | 54 | config OCRE_LOG_DEBUG 55 | bool "Debug logging" 56 | default n 57 | help 58 | Enable Ocre debug logging 59 | 60 | config OCRE_LOG_ERR 61 | bool "Error logging" 62 | default n 63 | help 64 | Enable Ocre debug logging 65 | 66 | config OCRE_LOG_WARN 67 | bool "Warn logging" 68 | default n 69 | help 70 | Enable Ocre debug logging 71 | 72 | config OCRE_LOG_INF 73 | bool "Info logging" 74 | default n 75 | help 76 | Enable Ocre debug logging 77 | 78 | if OCRE 79 | 80 | module = OCRE 81 | module-str = OCRE 82 | source "subsys/logging/Kconfig.template.log_config" 83 | 84 | endif 85 | 86 | config OCRE_SENSORS 87 | bool "Enable OCRE Sensors support" 88 | default n 89 | depends on SENSOR 90 | help 91 | Enable support for OCRE sensors 92 | 93 | config RNG_SENSOR 94 | bool "RNG Sensor" 95 | default n 96 | depends on OCRE_SENSORS 97 | help 98 | Enable support for the custom RNG sensor. 99 | 100 | config OCRE_WAMR_HEAP_BUFFER_SIZE 101 | int "WAMR heap buffer size in bytes" 102 | default 32768 103 | help 104 | A static memory allocation for WAMR to use as a heap. 105 | 106 | config OCRE_CONTAINER_DEFAULT_HEAP_SIZE 107 | int "Default value for the container heap size" 108 | default 4096 109 | help 110 | The default value used for a container's heap size. 111 | 112 | config OCRE_CONTAINER_DEFAULT_STACK_SIZE 113 | int "Default value for the container stack size" 114 | default 2048 115 | help 116 | The default value used for a container's stack size. 117 | 118 | config MAX_TIMERS 119 | int "Maximum number of timers" 120 | default 5 121 | help 122 | Defines the maximum number of timers available in the system. 123 | 124 | config MAX_SENSORS 125 | int "Maximum number of sensors" 126 | default 10 127 | help 128 | Defines the maximum number of sensors that can be handled. 129 | 130 | config MAX_CHANNELS_PER_SENSOR 131 | int "Maximum number of channels per sensor" 132 | default 5 133 | help 134 | Defines the maximum number of channels that each sensor can have. 135 | 136 | config OCRE_MEMORY_CHECK_ENABLED 137 | bool "Enable memory availability checking for containers" 138 | default y 139 | help 140 | Enable runtime memory checks before creating containers 141 | 142 | 143 | config OCRE_GPIO 144 | bool "OCRE GPIO Driver" 145 | default y 146 | help 147 | Enable the OCRE GPIO driver that provides a portable API layer 148 | for GPIO operations across different hardware platforms. 149 | 150 | config OCRE_GPIO_MAX_PINS 151 | int "Maximum number of GPIO pins" 152 | default 32 153 | help 154 | Maximum number of GPIO pins that can be managed by the OCRE GPIO driver. 155 | 156 | config OCRE_GPIO_MAX_PORTS 157 | int "Maximum number of GPIO ports" 158 | default 4 159 | help 160 | Maximum number of GPIO port devices that can be used by the OCRE GPIO driver. 161 | 162 | config OCRE_GPIO_PINS_PER_PORT 163 | int "Number of pins per GPIO port" 164 | default 32 165 | help 166 | Number of pins available on each GPIO port. This is used to map the 167 | logical pin numbers to physical port and pin numbers. 168 | 169 | config OCRE_CONTAINER_MESSAGING 170 | bool "Enable OCRE Container Messaging support" 171 | default n 172 | help 173 | Enable support for OCRE Container Messaging 174 | 175 | config MESSAGING_MAX_SUBSCRIPTIONS 176 | int "Number of maximum subscriptions for Container Messaging" 177 | default 10 178 | depends on OCRE_CONTAINER_MESSAGING 179 | help 180 | Number of maximum subscriptions for Container Messaging 181 | 182 | endmenu 183 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # Maintainers 2 | 3 | This page lists all active maintainers (also known as committers) of the [Ocre Project](https://www.lfedge.org/projects/ocre/), which includes this repository and the [Ocre Project Documentation Repo](https://github.com/project-ocre/project-ocre.github.io). 4 | 5 | For governance guidelines and information on becoming a committer/maintainer, see the [Ocre Wiki](https://lf-edge.atlassian.net/wiki/spaces/OCRE/overview). For general contribution guidelines, refer to [CONTRIBUTING.md](https://github.com/project-ocre/ocre-runtime/blob/master/CONTRIBUTING.md). 6 | 7 | ## Active Maintainers 8 | | Name | GitHub Username | Email | 9 | |------|-------|-----------| 10 | | Stephen Berard | @sberard | stephen@atym.io | 11 | | Knox Lively | @gonzolively | knox@atym.io | 12 | | Artur | @ArturSir | artur@atym.io | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Ocre logo](ocre_logo.jpg "Ocre") 2 | # Ocre 3 | [![Build](https://github.com/project-ocre/ocre-runtime/actions/workflows/build.yml/badge.svg)](https://github.com/project-ocre/ocre-runtime/actions/workflows/build.yml) 4 | [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9691/badge)](https://www.bestpractices.dev/projects/9691) 5 | [![License](https://img.shields.io/github/license/project-ocre/ocre-runtime?color=blue)](LICENSE) 6 | [![slack](https://img.shields.io/badge/slack-ocre-brightgreen.svg?logo=slack)](https://lfedge.slack.com/archives/C07F190CC3X) 7 | [![Stars](https://img.shields.io/github/stars/project-ocre/ocre-runtime?style=social)](Stars) 8 | 9 | Ocre is a container runtime for constrained devices. It leverages [WebAssembly](https://www.webassembly.org) and [Zephyr](https://www.zephyrproject.org/) to support OCI-type application containers in a footprint up to 2,000 times smaller than traditional Linux-based container runtimes. Our mission is to modernize the embedded applications by making it as easy to develop and securely deploy apps on constrained edge devices as it is in the cloud. 10 | 11 | ## Getting Started 12 | This guide walks you through building and running Ocre on a simulated device using Zephyr's `native_sim` target. For instructions on building and flashing Ocre to physical hardware, please refer to our [documentation](https://docs.project-ocre.org/quickstart/firmware/hardware/). 13 | 14 | The application in `./src/main.c` demonstrates basic Ocre runtime usage by writing a hello world application to flash and executing it. 15 | 16 | 17 | 1. **Install Dependencies and Zephyr SDK** 18 | 19 | Complete the [Install dependencies](https://docs.zephyrproject.org/3.7.0/develop/getting_started/index.html#install-dependencies) and the [Install the Zephyr SDK](https://docs.zephyrproject.org/3.7.0/develop/getting_started/index.html#install-the-zephyr-sdk) sections for your host operating system from the Zephyr (v3.7.0) [Getting Started Guide](https://docs.zephyrproject.org/3.7.0/develop/getting_started/index.html#getting-started-guide). 20 | 21 | 2. Create a Virtual Python Environment (`venv`) 22 | 23 | ``` 24 | mkdir runtime && cd runtime 25 | python3 -m venv .venv 26 | source .venv/bin/activate 27 | ``` 28 | 29 | **Note:** You may need to install the `python3-venv` package (or equivalent) on your host system beforehand. 30 | 31 | 3. **Install WEST** 32 | 33 | Install the [west](https://docs.zephyrproject.org/latest/develop/west/index.html) CLI tool, which is needed to build, run and manage Zephyr applications. 34 | 35 | ``` 36 | pip install west 37 | ``` 38 | 39 | 4. **Initialize the workspace** 40 | 41 | This will checkout the Ocre runtime code and initalize the workspace. 42 | ``` 43 | west init -m git@github.com:project-ocre/ocre-runtime.git 44 | ``` 45 | 46 | 5. **Update West** 47 | 48 | Next, we need to update the workspace with the latest Zephyr and WASM Micro Runtime code. 49 | 50 | ``` 51 | west update 52 | ``` 53 | 54 | 6. **Install Additional Zephyr (pip) requirements** 55 | 56 | In order to build the Ocre runtime properly, you'll need to install a few remaining requirements for Zephyr. 57 | 58 | ``` 59 | pip install -r zephyr/scripts/requirements.txt 60 | ``` 61 | 62 | 7. **Build the application** 63 | 64 | The following will build the firmware for the *virtual*, `native_sim` target which will allow you to run the Ocre runtime on a simulated device, rather than a physical board. 65 | ``` 66 | west build -b native_sim ./application -d build -- -DMODULE_EXT_ROOT=`pwd`/application 67 | ``` 68 | 8. **Run the application** 69 | 70 | Run the following command: 71 | ``` 72 | ./build/zephyr/zephyr.exe 73 | ``` 74 | 75 | --- 76 | ## License 77 | Distributed under the Apache License 2.0. See [LICENSE](https://github.com/project-ocre/ocre-runtime/blob/main/LICENSE) for more information. 78 | 79 | --- 80 | ## More Info 81 | * **[Website](https://lfedge.org/projects/ocre/)**: For a high-level overview of the Ocre project, and its goals, visit our website. 82 | * **[Docs](https://docs.project-ocre.org/)**: For more detailed information about the Ocre runtime, visit Ocre docs. 83 | * **[Wiki](https://lf-edge.atlassian.net/wiki/spaces/OCRE/overview?homepageId=14909442)**: For a full project overview, FAQs, project roadmap, and governance information, visit the Ocre Wiki. 84 | * **[Slack](https://lfedge.slack.com/archives/C07F190CC3X)**: If you need support or simply want to discuss all things Ocre, head on over to our Slack channel (`#ocre`) on LFEdge's Slack org. 85 | * **[Mailing list](https://lists.lfedge.org/g/Ocre-TSC)**: Join the Ocre Technical Steering Committee (TSC) mailing list to stay up to date with important project announcements, discussions, and meetings. 86 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | The Ocre community takes security seriously. If you discover a security issue, please bring it to our attention right away! 6 | 7 | Please DO NOT file a public issue, instead send your report privately to Ocre-TSC+owner@lists.lfedge.org. 8 | 9 | ## Security Overview 10 | 11 | The main Ocre repo's [CONTRIBUTING.md](https://github.com/project-ocre/ocre-runtime/blob/master/CONTRIBUTING.md) has additional information about contributions and security approaches. -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | VERSION_MAJOR = 0 2 | VERSION_MINOR = 99 3 | PATCHLEVEL = 0 4 | VERSION_TWEAK = 0 5 | EXTRAVERSION = dev -------------------------------------------------------------------------------- /boards/b_u585i_iot02a.conf: -------------------------------------------------------------------------------- 1 | # Critical Memory Sizes 2 | CONFIG_MAIN_STACK_SIZE=8192 3 | 4 | # ENC28J60 Ethernet driver 5 | CONFIG_GPIO=y 6 | CONFIG_SPI=y 7 | CONFIG_ETH_ENC28J60=y 8 | CONFIG_NET_L2_ETHERNET=y 9 | 10 | # hts221 sensor config 11 | CONFIG_I2C=y 12 | CONFIG_SENSOR=y 13 | CONFIG_CBPRINTF_FP_SUPPORT=y -------------------------------------------------------------------------------- /boards/b_u585i_iot02a.overlay: -------------------------------------------------------------------------------- 1 | / { 2 | devices{ 3 | rng_device: rng_0 { 4 | compatible = "custom,rng-sensor"; 5 | label = "RNG Sensor"; 6 | status = "okay"; 7 | }; 8 | }; 9 | }; 10 | 11 | &spi1 { 12 | enc28j60: ethernet@0 { 13 | status = "okay"; 14 | reg = <0>; 15 | compatible = "microchip,enc28j60"; 16 | int-gpios = <&gpioc 1 GPIO_ACTIVE_LOW>; 17 | spi-max-frequency = <10000000>; 18 | local-mac-address = [ 00 80 00 01 02 03 ]; 19 | full-duplex; 20 | }; 21 | }; 22 | 23 | &flash0 { 24 | partitions { 25 | user_data_partition: partition@100000 { 26 | label = "user_data"; 27 | reg = <0x00100000 DT_SIZE_K(256)>; 28 | }; 29 | }; 30 | }; 31 | 32 | /* Add hts221 sensor configurations */ 33 | &die_temp { 34 | status = "disabled"; 35 | }; 36 | 37 | &adc1 { 38 | status = "disabled"; 39 | }; 40 | 41 | &vref1 { 42 | status = "disabled"; 43 | }; 44 | 45 | &vbat4 { 46 | status = "disabled"; 47 | }; -------------------------------------------------------------------------------- /boards/native_sim.conf: -------------------------------------------------------------------------------- 1 | CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE=y 2 | CONFIG_NATIVE_UART_0_ON_STDINOUT=y 3 | CONFIG_UART_NATIVE_POSIX=y 4 | CONFIG_FLASH_SIMULATOR=y 5 | CONFIG_ENTROPY_GENERATOR=y 6 | CONFIG_TEST_RANDOM_GENERATOR=y 7 | 8 | CONFIG_MPU_ALLOW_FLASH_WRITE=y 9 | 10 | CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=y 11 | 12 | # Support for NET_OFFLOAD adapter 13 | CONFIG_ETH_NATIVE_POSIX=n 14 | CONFIG_NET_DRIVERS=y 15 | CONFIG_NET_SOCKETS_OFFLOAD=y 16 | CONFIG_NET_NATIVE_OFFLOADED_SOCKETS=y 17 | 18 | # The NET_OFFLOAD adapter requires setting an IP address to satisfy the Zephyr networking stack 19 | # This address is not actually used, but it must be set to a valid value. The underlying host's 20 | # networking address will be used to communicate with the network. 21 | CONFIG_NET_CONFIG_SETTINGS=y 22 | CONFIG_NET_CONFIG_MY_IPV4_ADDR="127.0.0.1" 23 | CONFIG_NET_CONFIG_MY_IPV4_GW="127.0.0.1" 24 | CONFIG_NET_CONFIG_MY_IPV4_NETMASK="255.255.255.0" 25 | 26 | CONFIG_NET_DHCPV4=n 27 | 28 | # Suppress logging from FS and LittleFS 29 | CONFIG_FS_LOG_LEVEL_OFF=y 30 | 31 | # This is required to work around an issue where "-1" causes a crash using the `native_sim` 32 | CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=262144 -------------------------------------------------------------------------------- /boards/native_sim.overlay: -------------------------------------------------------------------------------- 1 | / { 2 | chosen { 3 | zephyr,console = &uart0; 4 | zephyr,shell-uart = &uart0; 5 | zephyr,uart-mcumgr = &uart0; 6 | }; 7 | 8 | aliases { 9 | rng0 = &rng_device; 10 | }; 11 | 12 | devices{ 13 | rng_device: rng_0 { 14 | compatible = "custom,rng-sensor"; 15 | label = "RNG Sensor"; 16 | status = "okay"; 17 | }; 18 | }; 19 | }; 20 | 21 | /delete-node/ &storage_partition; 22 | /delete-node/ &scratch_partition; 23 | 24 | &flash0 { 25 | partitions { 26 | compatible = "fixed-partitions"; 27 | #address-cells = <1>; 28 | #size-cells = <1>; 29 | 30 | user_data_partition: partition@de000 { 31 | label = "user-data"; 32 | reg = <0x000de000 0x0001e000>; 33 | }; 34 | storage_partition: partition@100000 { 35 | label = "storage"; 36 | reg = <0x100000 0x00004000>; 37 | }; 38 | }; 39 | }; 40 | -------------------------------------------------------------------------------- /modules/modules.cmake: -------------------------------------------------------------------------------- 1 | set(ZEPHYR_WASM_MICRO_RUNTIME_CMAKE_DIR ${CMAKE_CURRENT_LIST_DIR}/wasm-micro-runtime) 2 | set(ZEPHYR_WASM_MICRO_RUNTIME_KCONFIG ${CMAKE_CURRENT_LIST_DIR}/wasm-micro-runtime/Kconfig) 3 | -------------------------------------------------------------------------------- /modules/wasm-micro-runtime/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8.2) 2 | 3 | 4 | # Determine the ISA of the target and set appropriately 5 | if (DEFINED CONFIG_ISA_THUMB2) 6 | set (TARGET_ISA THUMB) 7 | elseif (DEFINED CONFIG_ISA_ARM) 8 | set (TARGET_ISA ARM) 9 | elseif (DEFINED CONFIG_X86) 10 | set (TARGET_ISA X86_32) 11 | elseif (DEFINED CONFIG_XTENSA) 12 | set (TARGET_ISA XTENSA) 13 | elseif (DEFINED CONFIG_RISCV) 14 | set (TARGET_ISA RISCV32) 15 | elseif (DEFINED CONFIG_ARCH_POSIX) 16 | # Technically, this is not correct as the CPU architecture is not set. This assumes POSIX is x86 32-bit 17 | set (TARGET_ISA X86_32) 18 | else () 19 | message (FATAL_ERROR "Unsupported ISA: ${CONFIG_ARCH}") 20 | endif () 21 | message("TARGET ISA: ${TARGET_ISA}") 22 | 23 | ############################ 24 | set (WAMR_BUILD_PLATFORM "zephyr") 25 | set (WAMR_BUILD_TARGET ${TARGET_ISA}) 26 | set (WAMR_BUILD_INTERP 1) 27 | set (WAMR_BUILD_FAST_INTERP 0) 28 | set (WAMR_BUILD_AOT 0) 29 | set (WAMR_BUILD_JIT 0) 30 | set (WAMR_BUILD_LIBC_BUILTIN 1) 31 | set (WAMR_BUILD_LIBC_WASI 0) 32 | set (WAMR_BUILD_APP_FRAMEWORK 0) 33 | set (WAMR_BUILD_APP_LIST WAMR_APP_BUILD_BASE ) 34 | set (WAMR_MPU_STACK_COUNT 5) 35 | 36 | # Override the global heap usage 37 | if (NOT DEFINED WAMR_BUILD_GLOBAL_HEAP_POOL) 38 | set (WAMR_BUILD_GLOBAL_HEAP_POOL 1) 39 | endif () 40 | 41 | # Override the global heap size for small devices 42 | if (NOT DEFINED WAMR_BUILD_GLOBAL_HEAP_SIZE) 43 | #set (WAMR_BUILD_GLOBAL_HEAP_SIZE 131072) # 128 KB 44 | set (WAMR_BUILD_GLOBAL_HEAP_SIZE 32767) # 32 KB 45 | endif () 46 | 47 | set (WAMR_ROOT_DIR ${ZEPHYR_WASM_MICRO_RUNTIME_MODULE_DIR}) 48 | message("**WAMR_ROOT_DIR: ${WAMR_ROOT_DIR}") 49 | 50 | include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) 51 | -------------------------------------------------------------------------------- /modules/wasm-micro-runtime/Kconfig: -------------------------------------------------------------------------------- 1 | #mainmenu "WebAssembly Micro Runtime Configuration" 2 | 3 | -------------------------------------------------------------------------------- /modules/wasm-micro-runtime/wamr_sdk_config.cmake: -------------------------------------------------------------------------------- 1 | set (WAMR_BUILD_PLATFORM "zephyr") 2 | set (WAMR_BUILD_TARGET THUMB) 3 | set (WAMR_BUILD_INTERP 1) 4 | set (WAMR_BUILD_AOT 0) 5 | set (WAMR_BUILD_JIT 0) 6 | set (WAMR_BUILD_LIBC_BUILTIN 0) 7 | set (WAMR_BUILD_LIBC_WASI 0) 8 | set (WAMR_BUILD_APP_FRAMEWORK 0) 9 | set (WAMR_BUILD_APP_LIST WAMR_APP_BUILD_BASE) 10 | -------------------------------------------------------------------------------- /ocre.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": ".." 5 | } 6 | ], 7 | "settings": { 8 | // Hush CMake 9 | "cmake.configureOnOpen": false, 10 | // CppTools and IntelliSense 11 | "C_Cpp.workspaceParsingPriority": "medium", 12 | "C_Cpp.default.cStandard": "c11", 13 | "C_Cpp.default.browse.path": [ 14 | "${workspaceFolder}/application/src" 15 | ], 16 | "C_Cpp.intelliSenseEngine": "default", 17 | "C_Cpp.default.includePath": [ 18 | "${workspaceFolder}/application/src/ocre", 19 | "${workspaceFolder}/zephyr/include/" 20 | ], 21 | "C_Cpp.default.forcedInclude": [ 22 | "${workspaceFolder}/build/zephyr/include/generated/autoconf.h" 23 | ], 24 | "C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json", 25 | // Files 26 | "files.exclude": { 27 | "**/.git": true, 28 | "**/.svn": true, 29 | "**/.hg": true, 30 | "**/CVS": true, 31 | "**/.DS_Store": true, 32 | "**/Thumbs.db": true 33 | }, 34 | // Kconfig 35 | "kconfig.root": "${workspaceFolder}/application/Kconfig", 36 | "files.associations": { 37 | "net_private.h": "c", 38 | "socket.h": "c", 39 | "tls_internal.h": "c", 40 | "sockets_internal.h": "c", 41 | "iwasm_sm.h": "c", 42 | "*.h": "c", 43 | "*.c": "c", 44 | "*.g": "c", 45 | "*.tcc": "c", 46 | "system_error": "c", 47 | "array": "c", 48 | "functional": "c", 49 | "tuple": "c", 50 | "type_traits": "c", 51 | "utility": "c" 52 | }, 53 | "editor.formatOnType": true, 54 | }, 55 | "tasks": { 56 | "version": "2.0.0", 57 | "tasks": [ 58 | { 59 | "label": "West Build", 60 | "type": "shell", 61 | "group": { 62 | "kind": "build", 63 | "isDefault": true 64 | }, 65 | "command": "west", 66 | "args": [ 67 | "build", 68 | "--pristine", 69 | "-b", 70 | "${input:board}", 71 | "${workspaceFolder}/application", 72 | "-d", 73 | "${workspaceFolder}/build", 74 | "--", 75 | "-DMODULE_EXT_ROOT=\"${workspaceFolder}/application\"", 76 | ], 77 | "problemMatcher": [ 78 | "$gcc" 79 | ], 80 | } 81 | ], 82 | "inputs": [ 83 | { 84 | "id": "board", 85 | "type": "pickString", 86 | "options": [ 87 | "native_sim", 88 | "nucleo_h723zg", 89 | "b_u585i_iot02a", 90 | ], 91 | "default": "native_sim", 92 | "description": "See https://docs.zephyrproject.org/latest/boards/index.html" 93 | } 94 | ] 95 | }, 96 | "extensions": { 97 | "recommendations": [ 98 | "ms-vscode.cpptools-extension-pack", 99 | "ms-python.python", 100 | "ms-vscode.vscode-embedded-tools", 101 | "ms-vscode.vscode-serial-monitor", 102 | "marus25.cortex-debug", 103 | ] 104 | }, 105 | "launch": { 106 | "version": "0.2.0", 107 | "configurations": [ 108 | { 109 | "name": "Cortex Debug - ST-LINK", 110 | "cwd": "${workspaceFolder}", 111 | "executable": "${workspaceFolder}/build/zephyr/zephyr.elf", 112 | "request": "launch", 113 | "type": "cortex-debug", 114 | "runToEntryPoint": "main", 115 | "servertype": "stlink", 116 | "device": "STM32H7xx", // Changed for NUCLEO-H723ZG 117 | "interface": "swd", 118 | "showDevDebugOutput": "none", 119 | "v1": false, 120 | "stm32cubeprogrammer": "" 121 | }, 122 | { 123 | "name": "(gdb) Launch", 124 | "type": "cppdbg", 125 | "request": "launch", 126 | "program": "${workspaceFolder}/build/zephyr/zephyr.exe", 127 | "args": [ 128 | "-seed=$RANDOM", 129 | "--flash=${workspaceFolder}/flash.bin" 130 | ], 131 | "stopAtEntry": false, 132 | "cwd": "${fileDirname}", 133 | "environment": [], 134 | "externalConsole": false, 135 | "MIMode": "gdb", 136 | "setupCommands": [ 137 | { 138 | "description": "Enable pretty-printing for gdb", 139 | "text": "-enable-pretty-printing", 140 | "ignoreFailures": true 141 | }, 142 | { 143 | "description": "Set Disassembly Flavor to Intel", 144 | "text": "-gdb-set disassembly-flavor intel", 145 | "ignoreFailures": true 146 | } 147 | ] 148 | } 149 | ] 150 | } 151 | } -------------------------------------------------------------------------------- /ocre_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/project-ocre/ocre-runtime/52461d73afcdba8870555f5c3d3bb571d2b8df2d/ocre_logo.jpg -------------------------------------------------------------------------------- /prj.conf: -------------------------------------------------------------------------------- 1 | CONFIG_SHELL=y 2 | CONFIG_BOOT_BANNER=y 3 | CONFIG_SHELL_PROMPT_UART="ocre:~$ " 4 | CONFIG_NET_SHELL=y 5 | CONFIG_HWINFO=y 6 | CONFIG_NET_L2_WIFI_SHELL=n 7 | CONFIG_FILE_SYSTEM_SHELL=y 8 | 9 | CONFIG_DEBUG=n 10 | CONFIG_DEBUG_INFO=y 11 | CONFIG_DEBUG_OPTIMIZATIONS=y 12 | CONFIG_DEBUG_THREAD_INFO=y 13 | 14 | CONFIG_LOG=y 15 | CONFIG_LOG_MODE_MINIMAL=y 16 | CONFIG_ZCBOR_VERBOSE=n 17 | 18 | CONFIG_THREAD_RUNTIME_STATS=y # Needed by the latest version of WARM for time APIs 19 | 20 | # File system 21 | CONFIG_FILE_SYSTEM=y 22 | #CONFIG_DISK_ACCESS=y 23 | CONFIG_FILE_SYSTEM_LITTLEFS=y 24 | 25 | # Settings support 26 | CONFIG_SETTINGS=y 27 | CONFIG_SETTINGS_FILE=y 28 | CONFIG_SETTINGS_FILE_PATH="/lfs/settings" 29 | 30 | # Networking options 31 | CONFIG_NET_IPV4=y 32 | CONFIG_NET_IPV6=n 33 | CONFIG_NET_UDP=y 34 | CONFIG_NET_SOCKETS=y 35 | 36 | CONFIG_NET_TX_STACK_SIZE=2048 37 | CONFIG_NET_BUF_TX_COUNT=16 38 | CONFIG_NET_RX_STACK_SIZE=4096 39 | CONFIG_NET_BUF_RX_COUNT=32 40 | CONFIG_NET_MGMT_EVENT_STACK_SIZE=2048 41 | CONFIG_NET_SOCKETS_POLL_MAX=5 42 | 43 | CONFIG_NET_DHCPV4=y 44 | 45 | CONFIG_DNS_RESOLVER=y 46 | 47 | # MCU Boot options 48 | CONFIG_BOOTLOADER_MCUBOOT=n 49 | CONFIG_IMG_MANAGER=y 50 | CONFIG_MCUBOOT_IMG_MANAGER=y 51 | CONFIG_STREAM_FLASH=y 52 | CONFIG_IMG_ERASE_PROGRESSIVELY=y 53 | 54 | # System API options 55 | CONFIG_POSIX_API=y 56 | CONFIG_POSIX_MAX_FDS=10 57 | 58 | # Memory / malloc optopns 59 | CONFIG_HEAP_MEM_POOL_SIZE=8192 60 | CONFIG_MAIN_STACK_SIZE=8192 61 | CONFIG_SHELL_STACK_SIZE=8192 62 | CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=8192 63 | CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=-1 64 | 65 | 66 | # Ocre configuration 67 | CONFIG_OCRE_WAMR_HEAP_BUFFER_SIZE=512000 68 | CONFIG_OCRE_CONTAINER_DEFAULT_HEAP_SIZE=4096 69 | CONFIG_OCRE_CONTAINER_DEFAULT_STACK_SIZE=4096 70 | CONFIG_LOG_TRACE_SHORT_TIMESTAMP=y 71 | 72 | # Ocre Feature Options 73 | CONFIG_SENSOR=y 74 | CONFIG_RNG_SENSOR=y 75 | 76 | CONFIG_OCRE_CONTAINER_MESSAGING=y 77 | CONFIG_MESSAGING_MAX_SUBSCRIPTIONS=10 78 | 79 | CONFIG_DEVICE_DT_METADATA=y 80 | CONFIG_DEVICE_DEPS=y 81 | 82 | 83 | CONFIG_MAX_TIMERS=5 84 | CONFIG_MAX_SENSORS=10 85 | CONFIG_MAX_CHANNELS_PER_SENSOR=5 86 | 87 | CONFIG_OCRE_MEMORY_CHECK_ENABLED=n 88 | CONFIG_OCRE_GPIO=n 89 | 90 | -------------------------------------------------------------------------------- /src/messaging/message_types.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef OCRE_MESSAGING_TYPES_H 9 | #define OCRE_MESSAGING_TYPES_H 10 | 11 | struct base {}; 12 | 13 | #endif -------------------------------------------------------------------------------- /src/ocre/api/ocre_api.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #define _GNU_SOURCE 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "bh_platform.h" 18 | 19 | #include "ocre_api.h" 20 | #include "../ocre_timers/ocre_timer.h" 21 | #include "../ocre_sensors/ocre_sensors.h" 22 | #include "../ocre_gpio/ocre_gpio.h" 23 | #include "../container_messaging/messaging.h" 24 | 25 | int _ocre_posix_uname(wasm_exec_env_t exec_env, struct _ocre_posix_utsname *name) { 26 | struct utsname info; 27 | wasm_module_inst_t module_inst = get_module_inst(exec_env); 28 | 29 | if (!wasm_runtime_validate_native_addr(module_inst, name, sizeof(struct _ocre_posix_utsname))) { 30 | return -1; 31 | } 32 | 33 | if (uname(&info) != 0) { 34 | return -1; 35 | } 36 | 37 | memset(name, 0, sizeof(struct _ocre_posix_utsname)); 38 | 39 | snprintf(name->sysname, OCRE_API_POSIX_BUF_SIZE, "%s (%s)", OCRE_SYSTEM_NAME, info.sysname); 40 | snprintf(name->release, OCRE_API_POSIX_BUF_SIZE, "%s (%s)", APP_VERSION_STRING, info.release); 41 | snprintf(name->version, OCRE_API_POSIX_BUF_SIZE, "%s", info.version); 42 | 43 | // ARM Processors are special cased as they are so popular 44 | #ifdef CONFIG_ARM 45 | #ifdef CONFIG_CPU_CORTEX_M0 46 | strlcat(name->machine, "ARM Cortex-M0", OCRE_API_POSIX_BUF_SIZE); 47 | #elif CONFIG_CPU_CORTEX_M3 48 | strlcat(name->machine, "ARM Cortex-M3", OCRE_API_POSIX_BUF_SIZE); 49 | #elif CONFIG_CPU_CORTEX_M4 50 | strlcat(name->machine, "ARM Cortex-M4", OCRE_API_POSIX_BUF_SIZE); 51 | #elif CONFIG_CPU_CORTEX_M7 52 | strlcat(name->machine, "ARM Cortex-M7", OCRE_API_POSIX_BUF_SIZE); 53 | #elif CONFIG_CPU_CORTEX_M33 54 | strlcat(name->machine, "ARM Cortex-M33", OCRE_API_POSIX_BUF_SIZE); 55 | #elif CONFIG_CPU_CORTEX_M23 56 | strlcat(name->machine, "ARM Cortex-M23", OCRE_API_POSIX_BUF_SIZE); 57 | #elif CONFIG_CPU_CORTEX_M55 58 | strlcat(name->machine, "ARM Cortex-M55", OCRE_API_POSIX_BUF_SIZE); 59 | #endif 60 | #else 61 | // Other processors, use value returned from uname() 62 | strlcat(name->machine, info.machine, OCRE_API_POSIX_BUF_SIZE); 63 | #endif 64 | 65 | strlcat(name->nodename, info.nodename, OCRE_API_POSIX_BUF_SIZE); 66 | 67 | return 0; 68 | } 69 | /** 70 | * @brief Pause execution for a specified time 71 | * 72 | * @param exec_env WASM execution environment 73 | * @param milliseconds Number of milliseconds to sleep 74 | * @return 0 on success 75 | */ 76 | int ocre_sleep(wasm_exec_env_t exec_env, int milliseconds) { 77 | k_msleep(milliseconds); 78 | return 0; 79 | } 80 | 81 | // Ocre Runtime API 82 | NativeSymbol ocre_api_table[] = { 83 | {"uname", _ocre_posix_uname, "(*)i", NULL}, 84 | 85 | {"ocre_sleep", ocre_sleep, "(i)i", NULL}, 86 | 87 | // Container Messaging API 88 | #ifdef CONFIG_OCRE_CONTAINER_MESSAGING 89 | {"ocre_msg_system_init", ocre_msg_system_init, "()", NULL}, 90 | {"ocre_publish_message", ocre_publish_message, "(***i)i", NULL}, 91 | {"ocre_subscribe_message", ocre_subscribe_message, "(**)i", NULL}, 92 | #endif 93 | 94 | // Sensor API 95 | #ifdef CONFIG_OCRE_SENSORS 96 | // Sensor API 97 | {"ocre_sensors_init", ocre_sensors_init, "()i", NULL}, 98 | {"ocre_sensors_discover", ocre_sensors_discover, "()i", NULL}, 99 | {"ocre_sensors_open", ocre_sensors_open, "(i)i", NULL}, 100 | {"ocre_sensors_get_handle", ocre_sensors_get_handle, "(i)i", NULL}, 101 | {"ocre_sensors_get_channel_count", ocre_sensors_get_channel_count, "(i)i", NULL}, 102 | {"ocre_sensors_get_channel_type", ocre_sensors_get_channel_type, "(ii)i", NULL}, 103 | {"ocre_sensors_read", ocre_sensors_read, "(ii)i", NULL}, 104 | #endif 105 | // Timer API 106 | {"ocre_timer_create", ocre_timer_create, "(i)i", NULL}, 107 | {"ocre_timer_start", ocre_timer_start, "(iii)i", NULL}, 108 | {"ocre_timer_stop", ocre_timer_stop, "(i)i", NULL}, 109 | {"ocre_timer_delete", ocre_timer_delete, "(i)i", NULL}, 110 | {"ocre_timer_get_remaining", ocre_timer_get_remaining, "(i)i", NULL}, 111 | {"ocre_timer_set_dispatcher", ocre_timer_set_dispatcher, "(i)v", NULL}, 112 | 113 | #ifdef CONFIG_OCRE_GPIO 114 | // GPIO API 115 | {"ocre_gpio_init", ocre_gpio_wasm_init, "()i", NULL}, 116 | {"ocre_gpio_configure", ocre_gpio_wasm_configure, "(iii)i", NULL}, 117 | {"ocre_gpio_pin_set", ocre_gpio_wasm_set, "(iii)i", NULL}, 118 | {"ocre_gpio_pin_get", ocre_gpio_wasm_get, "(ii)i", NULL}, 119 | {"ocre_gpio_pin_toggle", ocre_gpio_wasm_toggle, "(ii)i", NULL}, 120 | {"ocre_gpio_register_callback", ocre_gpio_wasm_register_callback, "(ii)i", NULL}, 121 | {"ocre_gpio_unregister_callback", ocre_gpio_wasm_unregister_callback, "(ii)i", NULL}, 122 | #endif 123 | }; 124 | 125 | int ocre_api_table_size = sizeof(ocre_api_table) / sizeof(NativeSymbol); -------------------------------------------------------------------------------- /src/ocre/api/ocre_api.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #include "wasm_export.h" 9 | 10 | #ifndef OCRE_API_H 11 | #define OCRE_API_H 12 | 13 | #define OCRE_API_POSIX_BUF_SIZE 75 14 | 15 | #ifndef OCRE_SYSTEM_NAME 16 | #define OCRE_SYSTEM_NAME "Project Ocre" 17 | #endif 18 | 19 | struct _ocre_posix_utsname { 20 | char sysname[OCRE_API_POSIX_BUF_SIZE]; 21 | char nodename[OCRE_API_POSIX_BUF_SIZE]; 22 | char release[OCRE_API_POSIX_BUF_SIZE]; 23 | char version[OCRE_API_POSIX_BUF_SIZE]; 24 | char machine[OCRE_API_POSIX_BUF_SIZE]; 25 | char domainname[OCRE_API_POSIX_BUF_SIZE]; 26 | }; 27 | 28 | int _ocre_posix_uname(wasm_exec_env_t exec_env, struct _ocre_posix_utsname *name); 29 | 30 | extern NativeSymbol ocre_api_table[]; 31 | extern int ocre_api_table_size; 32 | #endif -------------------------------------------------------------------------------- /src/ocre/component/component.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #include 9 | #include 10 | LOG_MODULE_DECLARE(device_manager_component, OCRE_LOG_LEVEL); 11 | 12 | #include "component.h" 13 | 14 | void ocre_component_init(struct ocre_component *component) { 15 | k_msgq_init(&component->msgq, component->msgq_buffer, sizeof(struct ocre_message), MSG_QUEUE_DEPTH); 16 | } 17 | 18 | int ocre_component_send(struct ocre_component *component, struct ocre_message *msg) { 19 | int ret = k_msgq_put(&component->msgq, msg, K_NO_WAIT); 20 | 21 | if (ret != 0) { 22 | LOG_HEXDUMP_DBG(msg, sizeof(struct ocre_message), "message"); 23 | } 24 | 25 | return ret; 26 | } -------------------------------------------------------------------------------- /src/ocre/component/component.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef OCRE_COMPONENT_H 9 | #define OCRE_COMPONENT_H 10 | 11 | #include 12 | #include 13 | 14 | #define MSG_QUEUE_DEPTH 16 15 | 16 | #define COMPONENT_SEND_SIMPLE(c, e) \ 17 | struct ocre_message _msg = {.event = e}; \ 18 | ocre_component_send(c, &_msg) 19 | 20 | struct ocre_component { 21 | struct ocre_message msg; /*!< Message struct for reading messages into */ 22 | struct k_msgq msgq; /*!< Message queue to read from */ 23 | char __aligned(4) msgq_buffer[MSG_QUEUE_DEPTH * sizeof(struct ocre_message)]; /*!< Message queue buffer */ 24 | }; 25 | 26 | void ocre_component_init(struct ocre_component *component); 27 | 28 | int ocre_component_send(struct ocre_component *component, struct ocre_message *msg); 29 | 30 | #endif -------------------------------------------------------------------------------- /src/ocre/components/container_supervisor/component_supervisor.yaml: -------------------------------------------------------------------------------- 1 | component: container_supervisor 2 | events: 3 | - name: QUERY 4 | type: query 5 | - name: INSTALL 6 | type: install 7 | - name: UNINSTALL 8 | type: uninstall 9 | - name: APP_MANAGER_RESPONSE 10 | type: app_manager_response 11 | # Any events not listed get a message type of "base_message" -------------------------------------------------------------------------------- /src/ocre/components/container_supervisor/cs_main.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #include 9 | 10 | #include 11 | #include "cs_sm.h" 12 | 13 | LOG_MODULE_REGISTER(ocre_cs_component, OCRE_LOG_LEVEL); 14 | 15 | #define OCRE_CS_THREAD_STACK_SIZE 4096 16 | #define OCRE_CS_THREAD_PRIORITY 0 17 | 18 | K_THREAD_STACK_DEFINE(ocre_cs_stack, OCRE_CS_THREAD_STACK_SIZE); 19 | k_tid_t ocre_cs_tid = NULL; 20 | struct k_thread ocre_cs_thread; 21 | 22 | static void ocre_cs_main(void *ctx, void *arg1, void *arg2) { 23 | LOG_INF("Container Supervisor started."); 24 | int ret = _ocre_cs_run(ctx); 25 | LOG_ERR("Container Supervisor exited: %d", ret); 26 | } 27 | 28 | // Function to start the thread 29 | void start_ocre_cs_thread(ocre_cs_ctx *ctx) { 30 | ocre_cs_tid = k_thread_create(&ocre_cs_thread, ocre_cs_stack, OCRE_CS_THREAD_STACK_SIZE, ocre_cs_main, ctx, NULL, NULL, 31 | OCRE_CS_THREAD_PRIORITY, 0, K_NO_WAIT); 32 | k_thread_name_set(ocre_cs_tid, "Ocre Container Supervisor"); 33 | } 34 | 35 | void destroy_ocre_cs_thread(void) { 36 | k_thread_abort(&ocre_cs_thread); 37 | } -------------------------------------------------------------------------------- /src/ocre/components/container_supervisor/cs_sm.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #include 9 | #include 10 | LOG_MODULE_DECLARE(ocre_cs_component, OCRE_LOG_LEVEL); 11 | 12 | #include "cs_sm.h" 13 | #include "cs_sm_impl.h" 14 | #include 15 | 16 | #include "../../ocre_sensors/ocre_sensors.h" 17 | 18 | // Define state machine and component 19 | struct ocre_component ocre_cs_component; 20 | state_machine_t ocre_cs_state_machine; 21 | 22 | /* State event handlers */ 23 | static void runtime_uninitialized_entry(void *o) { 24 | #if OCRE_CS_DEBUG_ON 25 | LOG_INF("HELLO runtime_uninitialized_entry"); 26 | #endif 27 | struct ocre_message event = {.event = EVENT_CS_INITIALIZE}; 28 | ocre_component_send(&ocre_cs_component, &event); 29 | } 30 | 31 | static void runtime_uninitialized_run(void *o) { 32 | #if OCRE_CS_DEBUG_ON 33 | LOG_INF("HELLO runtime_uninitialized_run"); 34 | #endif 35 | struct ocre_message *msg = SM_GET_EVENT(o); 36 | 37 | switch (msg->event) { 38 | case EVENT_CS_INITIALIZE: 39 | LOG_INF("Transitioning from state STATE_RUNTIME_UNINITIALIZED_RUN to state STATE_RUNTIME_RUNNING"); 40 | sm_transition(&ocre_cs_state_machine, STATE_RUNTIME_RUNNING); 41 | break; 42 | 43 | default: 44 | 45 | LOG_INF("EVENT:%d", msg->event); 46 | break; 47 | } 48 | SM_MARK_EVENT_HANDLED(o); 49 | } 50 | 51 | static void runtime_running_entry(void *o) { 52 | #if OCRE_CS_DEBUG_ON 53 | LOG_INF("HELLO runtime_running_entry"); 54 | #endif 55 | } 56 | 57 | static void runtime_running_run(void *o) { 58 | #if OCRE_CS_DEBUG_ON 59 | LOG_INF("HELLO runtime_running_run"); 60 | #endif 61 | struct ocre_message *msg = SM_GET_EVENT(o); 62 | ocre_cs_ctx *ctx = SM_GET_CUSTOM_CTX(o); 63 | ocre_container_runtime_cb callback = NULL; 64 | switch (msg->event) { 65 | case EVENT_CREATE_CONTAINER: { 66 | LOG_INF("EVENT_CREATE_CONTAINER"); 67 | if (CS_create_container(ctx, msg->containerId) == CONTAINER_STATUS_CREATED) { 68 | LOG_INF("Created container in slot:%d", msg->containerId); 69 | } else { 70 | LOG_INF("Failed to create container in slot:%d", msg->containerId); 71 | } 72 | break; 73 | } 74 | case EVENT_RUN_CONTAINER: { 75 | LOG_INF("EVENT_RUN_CONTAINER"); 76 | if (CS_run_container(ctx, &msg->containerId) == CONTAINER_STATUS_RUNNING) { 77 | LOG_INF("Started container in slot:%d", msg->containerId); 78 | } else { 79 | LOG_INF("Failed to run container in slot:%d", msg->containerId); 80 | } 81 | break; 82 | } 83 | case EVENT_STOP_CONTAINER: { 84 | LOG_INF("EVENT_STOP_CONTAINER"); 85 | CS_stop_container(ctx, msg->containerId, callback); 86 | break; 87 | } 88 | case EVENT_DESTROY_CONTAINER: { 89 | LOG_INF("EVENT_DESTROY_CONTAINER"); 90 | CS_destroy_container(ctx, msg->containerId, callback); 91 | break; 92 | } 93 | case EVENT_RESTART_CONTAINER: { 94 | LOG_INF("EVENT_RESTART_CONTAINER"); 95 | CS_restart_container(ctx, msg->containerId, callback); 96 | break; 97 | } 98 | case EVENT_CS_DESTROY: 99 | LOG_INF("EVENT_CS_DESTROY"); 100 | sm_transition(&ocre_cs_state_machine, STATE_RUNTIME_UNINITIALIZED); 101 | break; 102 | default: 103 | break; 104 | } 105 | 106 | SM_MARK_EVENT_HANDLED(o); 107 | } 108 | 109 | static void runtime_error_run(void *o) { 110 | #if OCRE_CS_DEBUG_ON 111 | LOG_INF("HELLO runtime_error_run"); 112 | #endif 113 | } 114 | 115 | static const struct smf_state hsm[] = { 116 | [STATE_RUNTIME_UNINITIALIZED] = 117 | SMF_CREATE_STATE(runtime_uninitialized_entry, runtime_uninitialized_run, NULL, NULL, NULL), 118 | [STATE_RUNTIME_RUNNING] = SMF_CREATE_STATE(runtime_running_entry, runtime_running_run, NULL, NULL, NULL), 119 | [STATE_RUNTIME_ERROR] = SMF_CREATE_STATE(NULL, runtime_error_run, NULL, NULL, NULL)}; 120 | 121 | // Entry point for running the state machine 122 | int _ocre_cs_run(ocre_cs_ctx *ctx) { 123 | ocre_component_init(&ocre_cs_component); 124 | 125 | sm_init(&ocre_cs_state_machine, &ocre_cs_component.msgq, &ocre_cs_component.msg, ctx, hsm); 126 | 127 | return sm_run(&ocre_cs_state_machine, STATE_RUNTIME_UNINITIALIZED); 128 | } 129 | -------------------------------------------------------------------------------- /src/ocre/components/container_supervisor/cs_sm.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef OCRE_IWASM_H 9 | #define OCRE_IWASM_H 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #define OCRE_CS_DEBUG_ON 0 19 | 20 | extern struct ocre_component ocre_cs_component; 21 | extern state_machine_t ocre_cs_state_machine; // TODO This needs to get encapsulated into the 22 | // sm. it's only here so components can operate 23 | // timers. timers need to be encapsulated. 24 | 25 | enum CONTAINER_RUNTIME_STATE { 26 | STATE_RUNTIME_UNINITIALIZED, 27 | STATE_RUNTIME_RUNNING, 28 | STATE_RUNTIME_ERROR 29 | }; 30 | 31 | enum OCRE_CS_EVENT { 32 | // CS Events 33 | EVENT_CS_INITIALIZE, 34 | EVENT_CS_DESTROY, 35 | EVENT_CS_ERROR, 36 | 37 | // Container related events 38 | EVENT_CREATE_CONTAINER, 39 | EVENT_RUN_CONTAINER, 40 | EVENT_STOP_CONTAINER, 41 | EVENT_DESTROY_CONTAINER, 42 | EVENT_RESTART_CONTAINER, 43 | EVENT_ERROR 44 | }; 45 | void start_ocre_cs_thread(ocre_cs_ctx *ctx); 46 | 47 | void destroy_ocre_cs_thread(void); 48 | 49 | int _ocre_cs_run(); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/ocre/components/container_supervisor/cs_sm_impl.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef OCRE_CS_SM_IMPL_H 9 | #define OCRE_CS_SM_IMPL_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "../../api/ocre_api.h" 16 | #include 17 | 18 | // ----------------------------------------------------------------------------- 19 | // Function prototypes for OCRE container runtime and container management 20 | // ----------------------------------------------------------------------------- 21 | 22 | // RUNTIME 23 | 24 | /** 25 | * @brief Initialize the container runtime environment. 26 | * 27 | * This function sets up the runtime environment for OCRE containers. 28 | * 29 | * @param ctx Pointer to the container runtime context. 30 | * @param args Pointer to initialization arguments. 31 | * @return ocre_container_runtime_status_t Status of the initialization. 32 | */ 33 | ocre_container_runtime_status_t CS_runtime_init(ocre_cs_ctx *ctx, ocre_container_init_arguments_t *args); 34 | 35 | /** 36 | * @brief Destroy the container runtime environment. 37 | * 38 | * This function cleans up and releases any resources used by the container runtime. 39 | * 40 | * @return ocre_container_runtime_status_t Status of the destruction process. 41 | */ 42 | ocre_container_runtime_status_t CS_runtime_destroy(void); 43 | 44 | // CONTAINER 45 | 46 | /** 47 | * @brief Create a new container. 48 | * 49 | * This function creates a container with the specified container ID and associates it with the context. 50 | * 51 | * @param ctx Pointer to the container runtime context. 52 | * @param container_id The ID of the container to be created. 53 | * @return ocre_container_status_t Status of the container creation. 54 | */ 55 | ocre_container_status_t CS_create_container(ocre_cs_ctx *ctx, int container_id); 56 | 57 | /** 58 | * @brief Run a container. 59 | * 60 | * This function starts the execution of a container based on its container ID. 61 | * 62 | * @param ctx Pointer to the container runtime context. 63 | * @param container_id The ID of the container to be run. 64 | * @return ocre_container_status_t Status of the container execution. 65 | */ 66 | ocre_container_status_t CS_run_container(ocre_cs_ctx *ctx, int *container_id); 67 | 68 | /** 69 | * @brief Get the status of a container. 70 | * 71 | * This function retrieves the current status of the container. 72 | * 73 | * @param ctx Pointer to the container runtime context. 74 | * @param container_id The ID of the container whose status is being queried. 75 | * @return ocre_container_status_t Status of the container. 76 | */ 77 | ocre_container_status_t CS_get_container_status(ocre_cs_ctx *ctx, int container_id); 78 | 79 | /** 80 | * @brief Stop a container. 81 | * 82 | * This function stops the execution of the container and invokes a callback function when completed. 83 | * 84 | * @param ctx Pointer to the container runtime context. 85 | * @param container_id The ID of the container to be stopped. 86 | * @param callback Callback function to be invoked after stopping the container. 87 | * @return ocre_container_status_t Status of the stop operation. 88 | */ 89 | ocre_container_status_t CS_stop_container(ocre_cs_ctx *ctx, int container_id, ocre_container_runtime_cb callback); 90 | 91 | /** 92 | * @brief Destroy a container. 93 | * 94 | * This function removes and destroys the specified container from the runtime. 95 | * 96 | * @param ctx Pointer to the container runtime context. 97 | * @param container_id The ID of the container to be destroyed. 98 | * @param callback Callback function to be invoked after destroying the container. 99 | * @return ocre_container_status_t Status of the container destruction. 100 | */ 101 | ocre_container_status_t CS_destroy_container(ocre_cs_ctx *ctx, int container_id, ocre_container_runtime_cb callback); 102 | 103 | /** 104 | * @brief Restart a container. 105 | * 106 | * This function restarts a container by stopping and then running it again. 107 | * 108 | * @param ctx Pointer to the container runtime context. 109 | * @param container_id The ID of the container to be restarted. 110 | * @param callback Callback function to be invoked after restarting the container. 111 | * @return ocre_container_status_t Status of the container restart. 112 | */ 113 | ocre_container_status_t CS_restart_container(ocre_cs_ctx *ctx, int container_id, ocre_container_runtime_cb callback); 114 | 115 | /** 116 | * @brief context initialization 117 | * 118 | * This function initialize the container runtime context. 119 | * 120 | * @param ctx Pointer to the container runtime context. 121 | * @return POSIX style return if the container runtime context was initialized right 0 else -n 122 | */ 123 | int CS_ctx_init(ocre_cs_ctx *ctx); 124 | 125 | #endif // OCRE_CS_SM_IMPL_H 126 | -------------------------------------------------------------------------------- /src/ocre/components/container_supervisor/message_types.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef OCRE_CS_MESSAGING_TYPES_H 9 | #define OCRE_CS_MESSAGING_TYPES_H 10 | 11 | struct install { 12 | char name[16]; // timer 12 | int ocre_healthcheck_expiry(struct k_timer *timer, ocre_healthcheck *WDT) { 13 | if (WDT == NULL) { 14 | return -1; // Error: Null pointer 15 | } 16 | if (WDT->enabled && (WDT->is_alive_cnt <= WDT->is_alive_cnt_last)) { 17 | // TODOA:-- containers[current_container_id].container_runtime_status = CONTAINER_STATUS_UNRESPONSIVE; 18 | WDT->is_alive_cnt = 0; 19 | WDT->is_alive_cnt_last = WDT->is_alive_cnt; 20 | return 1; // Health check failed, container is unresponsive 21 | } 22 | 23 | WDT->is_alive_cnt_last = WDT->is_alive_cnt; 24 | 25 | return 0; // Health check passed 26 | } 27 | 28 | int ocre_healthcheck_init(ocre_healthcheck *WDT, int timeout) { 29 | if (WDT == NULL) { 30 | return -1; // Error: Null pointer 31 | } 32 | 33 | WDT->timeout = timeout; 34 | WDT->enabled = 1; 35 | WDT->is_alive_cnt = 0; 36 | WDT->is_alive_cnt_last = WDT->is_alive_cnt; 37 | k_timer_init(&WDT->timer, (k_timer_expiry_t)ocre_healthcheck_expiry, NULL); 38 | 39 | return 0; 40 | } 41 | 42 | int ocre_healthcheck_reinit(ocre_healthcheck *WDT) { 43 | if (WDT == NULL) { 44 | return -1; // Error: Null pointer 45 | } 46 | 47 | WDT->enabled = 1; 48 | WDT->is_alive_cnt = 0; 49 | WDT->is_alive_cnt_last = WDT->is_alive_cnt; 50 | k_timer_init(&WDT->timer, (k_timer_expiry_t)ocre_healthcheck_expiry, NULL); 51 | 52 | return 0; 53 | } 54 | int ocre_healthcheck_restart(ocre_healthcheck *WDT) { 55 | WDT->is_alive_cnt = 0; 56 | WDT->is_alive_cnt_last = WDT->is_alive_cnt; 57 | k_timer_start(&WDT->timer, K_MSEC(WDT->timeout), K_NO_WAIT); 58 | return 0; 59 | } 60 | 61 | int ocre_healthcheck_start(ocre_healthcheck *WDT) { 62 | k_timer_start(&WDT->timer, K_MSEC(WDT->timeout), K_NO_WAIT); 63 | return 0; 64 | } 65 | 66 | int ocre_healthcheck_stop(ocre_healthcheck *WDT) { 67 | k_timer_stop(&WDT->timer); 68 | WDT->enabled = 0; 69 | return 0; 70 | } 71 | 72 | int ocre_get_healthcheck_remaining(ocre_healthcheck *WDT) { 73 | k_timer_remaining_get(&WDT->timer); 74 | return 0; 75 | } 76 | 77 | // health check of container if it does not respond restart the container 78 | int on_ocre_healthcheck(ocre_healthcheck *WDT) { 79 | // TODOA:-- k_timer_start(&WDT->timer, K_MSEC(WDT->timeout), K_NO_WAIT); 80 | // because the start of already runing timer will get it back to initial values 81 | // actually a reset or trigger for watchdog 82 | // and the expiry function is not called 83 | WDT->is_alive_cnt += 1; 84 | 85 | return 1; 86 | } 87 | -------------------------------------------------------------------------------- /src/ocre/container_healthcheck/ocre_container_healthcheck.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef OCRE_WATCHDOG_H 9 | #define OCRE_WATCHDOG_H 10 | 11 | #include 12 | 13 | /** 14 | * Structure to hold the OCRE health check parameters. 15 | */ 16 | typedef struct ocre_healthcheck { 17 | uint32_t interval; 18 | uint32_t timeout; 19 | bool enabled; 20 | uint32_t is_alive_cnt; 21 | uint32_t is_alive_cnt_last; 22 | struct k_timer timer; 23 | } ocre_healthcheck; 24 | 25 | /** 26 | * Initializes the OCRE health check structure. 27 | * 28 | * @param WDT Pointer to the OCRE health check structure. 29 | * @param timeout Timeout value for the watchdog timer in milliseconds. 30 | * 31 | * @return 0 on success, -1 on error (e.g., null pointer). 32 | */ 33 | int ocre_healthcheck_init(ocre_healthcheck *WDT, int timeout); 34 | 35 | /** 36 | * Reset/Trigger the OCRE health check structure. 37 | * 38 | * @param WDT Pointer to the OCRE health check structure. 39 | * 40 | * @return 0 on success, -1 on error (e.g., null pointer). 41 | */ 42 | int ocre_healthcheck_reinit(ocre_healthcheck *WDT); 43 | 44 | /** 45 | * Starts the OCRE health check timer. 46 | * 47 | * @param WDT Pointer to the OCRE health check structure. 48 | * 49 | * @return 0 on success, -1 on error (e.g., null pointer). 50 | */ 51 | int ocre_healthcheck_start(ocre_healthcheck *WDT); 52 | 53 | /** 54 | * Stops the OCRE health check timer. 55 | * 56 | * @param WDT Pointer to the OCRE health check structure. 57 | * 58 | * @return 0 on success, -1 on error (e.g., null pointer). 59 | */ 60 | int ocre_healthcheck_stop(ocre_healthcheck *WDT); 61 | 62 | /** 63 | * Gets the remaining time for the OCRE health check timer. 64 | * 65 | * @param WDT Pointer to the OCRE health check structure. 66 | * 67 | * @return Remaining time in milliseconds, or -1 on error (e.g., null pointer). 68 | */ 69 | int ocre_get_healthcheck_remaining(ocre_healthcheck *WDT); 70 | 71 | /** 72 | * Handles the health check, called cyclically to monitor the container. 73 | * 74 | * @param WDT Pointer to the OCRE health check structure. 75 | * 76 | * @return 1 if health check is alive, 0 otherwise. 77 | */ 78 | int on_ocre_healthcheck(ocre_healthcheck *WDT); 79 | 80 | /** 81 | * Expiry function called by the timer, checks if the container is responsive. 82 | * 83 | * @param WDT Pointer to the OCRE health check structure. 84 | * 85 | * @return 1 if health check failed, 0 otherwise. 86 | */ 87 | int ocre_healthcheck_expiry(struct k_timer *timer, ocre_healthcheck *WDT); 88 | 89 | #endif -------------------------------------------------------------------------------- /src/ocre/container_messaging/messaging.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "messaging.h" 7 | 8 | LOG_MODULE_DECLARE(ocre_container_messaging, OCRE_LOG_LEVEL); 9 | 10 | #define QUEUE_SIZE 100 11 | #define STACK_SIZE 1024 12 | #define PRIORITY 5 13 | #define WASM_STACK_SIZE (8 * 1024) 14 | 15 | K_MSGQ_DEFINE(ocre_msg_queue, sizeof(ocre_msg_t), QUEUE_SIZE, 4); 16 | 17 | // Structure to hold the subscription information 18 | typedef struct { 19 | char *topic; 20 | wasm_function_inst_t handler; 21 | wasm_module_inst_t module_inst; 22 | wasm_exec_env_t exec_env; 23 | } ocre_subscription_t; 24 | 25 | static ocre_subscription_t subscriptions[CONFIG_MESSAGING_MAX_SUBSCRIPTIONS]; 26 | static int subscription_count = 0; 27 | static bool msg_system_is_init = false; 28 | 29 | static uint32_t allocate_wasm_memory(wasm_module_inst_t module_inst, const void *src, size_t size) { 30 | void *native_addr = NULL; 31 | uint64_t wasm_ptr = wasm_runtime_module_malloc(module_inst, size, &native_addr); 32 | if (!wasm_ptr || !native_addr) { 33 | LOG_ERR("Failed to allocate memory in WASM"); 34 | return 0; 35 | } 36 | if (src) { 37 | memcpy(native_addr, src, size); 38 | } 39 | return (uint32_t)wasm_ptr; 40 | } 41 | 42 | static void free_wasm_message(wasm_module_inst_t module_inst, uint32_t *ptr_array, uint16_t count) { 43 | for (uint16_t i = 0; i < count; i++) { 44 | if (ptr_array[i]) { 45 | wasm_runtime_module_free(module_inst, ptr_array[i]); 46 | } 47 | } 48 | } 49 | 50 | void subscriber_thread(void *arg1, void *arg2, void *arg3) { 51 | ocre_msg_t msg; 52 | while (1) { 53 | if (k_msgq_get(&ocre_msg_queue, &msg, K_FOREVER) == 0) { 54 | for (int i = 0; i < subscription_count; i++) { 55 | if (strcmp(subscriptions[i].topic, msg.topic) == 0) { 56 | 57 | wasm_module_inst_t module_inst = subscriptions[i].module_inst; 58 | if (!module_inst) { 59 | LOG_ERR("Invalid module instance"); 60 | continue; 61 | } 62 | 63 | uint32_t allocated_pointers[4] = {0}; 64 | // Allocate memory for ocre_msg_t 65 | allocated_pointers[0] = allocate_wasm_memory(module_inst, NULL, sizeof(ocre_msg_t)); 66 | if (allocated_pointers[0] == 0) { 67 | LOG_ERR("Failed to allocate memory for message structure in WASM"); 68 | continue; 69 | } 70 | 71 | // Allocate memory for topic 72 | allocated_pointers[1] = allocate_wasm_memory(module_inst, msg.topic, strlen(msg.topic) + 1); 73 | if (allocated_pointers[1] == 0) { 74 | LOG_ERR("Failed to allocate memory for topic in WASM"); 75 | free_wasm_message(module_inst, allocated_pointers, 1); 76 | continue; 77 | } 78 | 79 | // Allocate memory for content_type 80 | allocated_pointers[2] = 81 | allocate_wasm_memory(module_inst, msg.content_type, strlen(msg.content_type) + 1); 82 | if (allocated_pointers[2] == 0) { 83 | LOG_ERR("Failed to allocate memory for content_type in WASM"); 84 | free_wasm_message(module_inst, allocated_pointers, 2); 85 | continue; 86 | } 87 | 88 | // Allocate memory for payload 89 | allocated_pointers[3] = allocate_wasm_memory(module_inst, msg.payload, msg.payload_len); 90 | if (allocated_pointers[3] == 0) { 91 | LOG_ERR("Failed to allocate memory for payload in WASM"); 92 | free_wasm_message(module_inst, allocated_pointers, 3); 93 | continue; 94 | } 95 | 96 | // Populate the WASM message structure 97 | ocre_msg_t *wasm_msg = 98 | (ocre_msg_t *)wasm_runtime_addr_app_to_native(module_inst, allocated_pointers[0]); 99 | wasm_msg->mid = msg.mid; 100 | wasm_msg->topic = (char *)allocated_pointers[1]; 101 | wasm_msg->content_type = (char *)allocated_pointers[2]; 102 | wasm_msg->payload = (void *)allocated_pointers[3]; 103 | wasm_msg->payload_len = msg.payload_len; 104 | 105 | // Call the WASM function 106 | uint32_t args[1] = {allocated_pointers[0]}; 107 | if (!wasm_runtime_call_wasm(subscriptions[i].exec_env, subscriptions[i].handler, 1, args)) { 108 | const char *error = wasm_runtime_get_exception(module_inst); 109 | LOG_ERR("Failed to call WASM function: %s", error ? error : "Unknown error"); 110 | } else { 111 | LOG_INF("Function executed successfully"); 112 | } 113 | 114 | // Free allocated WASM memory 115 | free_wasm_message(module_inst, allocated_pointers, 4); 116 | } 117 | } 118 | } 119 | } 120 | } 121 | 122 | // Define the stack area for the subscriber thread 123 | K_THREAD_STACK_DEFINE(subscriber_stack_area, STACK_SIZE); 124 | struct k_thread subscriber_thread_data; 125 | 126 | // Initialize the message system 127 | void ocre_msg_system_init() { 128 | if (msg_system_is_init) { 129 | LOG_WRN("Messaging System is already initialized"); 130 | return; 131 | } 132 | 133 | k_tid_t tid = k_thread_create(&subscriber_thread_data, subscriber_stack_area, 134 | K_THREAD_STACK_SIZEOF(subscriber_stack_area), subscriber_thread, NULL, NULL, NULL, 135 | PRIORITY, 0, K_NO_WAIT); 136 | 137 | if (!tid) { 138 | LOG_ERR("Failed to create container messaging thread"); 139 | return; 140 | } 141 | k_thread_name_set(tid, "container_messaging"); 142 | msg_system_is_init = true; 143 | } 144 | 145 | int ocre_publish_message(wasm_exec_env_t exec_env, char *topic, char *content_type, void *payload, int payload_len) { 146 | LOG_INF("---------------_ocre_publish_message: topic: %s [%zu], content_type: %s, payload_len: %u ", topic, 147 | strlen(topic), content_type, payload_len); 148 | 149 | if (!msg_system_is_init) { 150 | LOG_ERR("Messaging system not initialized"); 151 | return -1; 152 | } 153 | 154 | if (!topic || (topic[0] == '\0')) { 155 | LOG_ERR("topic is NULL or empty, please check function parameters!"); 156 | return -1; 157 | } 158 | 159 | if (!content_type || (content_type[0] == '\0')) { 160 | LOG_ERR("content_type is NULL or empty, please check function parameters!"); 161 | return -1; 162 | } 163 | 164 | if (!payload || payload_len == 0) { 165 | LOG_ERR("payload is NULL or payload_len is 0, please check function parameters!"); 166 | return -1; 167 | } 168 | 169 | static uint64_t message_id = 0; 170 | ocre_msg_t msg = {.mid = message_id, 171 | .topic = topic, 172 | .content_type = content_type, 173 | .payload = payload, 174 | .payload_len = payload_len}; 175 | 176 | message_id++; 177 | 178 | if (k_msgq_put(&ocre_msg_queue, &msg, K_NO_WAIT) != 0) { 179 | // Handle message queue full scenario 180 | LOG_ERR("Message queue is full, could not publish message\n"); 181 | return -1; 182 | } 183 | 184 | return 0; 185 | } 186 | 187 | int ocre_subscribe_message(wasm_exec_env_t exec_env, char *topic, char *handler_name) { 188 | LOG_INF("---------------_ocre_subscribe_message---------------"); 189 | 190 | if (!msg_system_is_init) { 191 | LOG_ERR("Messaging system not initialized"); 192 | return -1; 193 | } 194 | 195 | if (subscription_count < CONFIG_MESSAGING_MAX_SUBSCRIPTIONS) { 196 | 197 | if (!topic || (topic[0] == '\0')) { 198 | LOG_ERR("topic is NULL or empty, please check function parameters!"); 199 | return -1; 200 | } 201 | 202 | if (!handler_name || (handler_name[0] == '\0')) { 203 | LOG_ERR("handler_name is NULL or empty, please check function parameters!"); 204 | return -1; 205 | } 206 | 207 | wasm_module_inst_t current_module_inst = wasm_runtime_get_module_inst(exec_env); 208 | wasm_function_inst_t handler_function = wasm_runtime_lookup_function(current_module_inst, handler_name); 209 | if (!handler_function) { 210 | LOG_ERR("Failed to find %s in WASM module", handler_name); 211 | return -1; 212 | } 213 | 214 | subscriptions[subscription_count].topic = topic; 215 | subscriptions[subscription_count].handler = handler_function; 216 | subscriptions[subscription_count].exec_env = exec_env; 217 | subscriptions[subscription_count].module_inst = current_module_inst; 218 | 219 | LOG_INF("WASM messaging callback function set successfully"); 220 | 221 | subscription_count++; 222 | } else { 223 | LOG_ERR("Maximum subscriptions reached, could not subscribe to topic"); 224 | return -1; 225 | } 226 | 227 | return 0; 228 | } 229 | -------------------------------------------------------------------------------- /src/ocre/container_messaging/messaging.h: -------------------------------------------------------------------------------- 1 | 2 | #include "wasm_export.h" 3 | 4 | /** 5 | * @typedef ocre_msg 6 | * 7 | * Structure of ocre messages 8 | * 9 | */ 10 | typedef struct ocre_msg { 11 | // message id - increments on each message 12 | uint64_t mid; 13 | 14 | // url of the request 15 | char *topic; 16 | 17 | // payload format (MIME type??) 18 | char *content_type; 19 | 20 | // payload of the request 21 | void *payload; 22 | 23 | // length in bytes of the payload 24 | int payload_len; 25 | } ocre_msg_t; 26 | 27 | /** 28 | * @brief Initialize OCRE Messaging System. 29 | * 30 | */ 31 | void ocre_msg_system_init(); 32 | 33 | /** 34 | * @brief Publish a message to the specified target. 35 | * 36 | * @param topic the name of the topic on which to publish the message 37 | * @param content_type the content type of the message; it is recommended to use a MIME type 38 | * @param payload a buffer containing the message contents 39 | * @param payload_len the length of the payload buffer 40 | */ 41 | int ocre_publish_message(wasm_exec_env_t exec_env, char *topic, char *content_type, void *payload, int payload_len); 42 | 43 | /** 44 | * @brief Subscribe to messages on the specified topic. 45 | * 46 | * @param topic the name of the topic on which to subscribe 47 | * @param handler_name name of callback function that will be called when a message is received on this topic 48 | */ 49 | int ocre_subscribe_message(wasm_exec_env_t exec_env, char *topic, char *handler_name); 50 | -------------------------------------------------------------------------------- /src/ocre/fs/fs.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #include 9 | #include 10 | LOG_MODULE_REGISTER(filesystem, OCRE_LOG_LEVEL); 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "fs.h" 20 | 21 | #define MAX_PATH_LEN LFS_NAME_MAX 22 | 23 | #ifdef CONFIG_SHELL 24 | #define print(shell, level, fmt, ...) \ 25 | do { \ 26 | shell_fprintf(shell, level, fmt, ##__VA_ARGS__); \ 27 | } while (false) 28 | #else 29 | #define print(shell, level, fmt, ...) \ 30 | do { \ 31 | printk(fmt, ##__VA_ARGS__); \ 32 | } while (false) 33 | #endif 34 | 35 | static int lsdir(const char *path) { 36 | int res; 37 | struct fs_dir_t dirp; 38 | static struct fs_dirent entry; 39 | 40 | fs_dir_t_init(&dirp); 41 | 42 | /* Verify fs_opendir() */ 43 | res = fs_opendir(&dirp, path); 44 | if (res) { 45 | LOG_ERR("Error opening dir %s [%d]\n", path, res); 46 | return res; 47 | } 48 | 49 | for (;;) { 50 | // Verify fs_readdir() 51 | res = fs_readdir(&dirp, &entry); 52 | 53 | // entry.name[0] == 0 means end-of-dir 54 | if (res || entry.name[0] == 0) { 55 | if (res < 0) { 56 | LOG_ERR("Error reading dir [%d]\n", res); 57 | } 58 | break; 59 | } 60 | } 61 | 62 | // Verify fs_closedir() 63 | fs_closedir(&dirp); 64 | 65 | return res; 66 | } 67 | 68 | static int littlefs_flash_erase(unsigned int id) { 69 | const struct flash_area *pfa; 70 | int rc; 71 | 72 | rc = flash_area_open(id, &pfa); 73 | if (rc < 0) { 74 | LOG_ERR("FAIL: unable to find flash area %u: %d\n", id, rc); 75 | return rc; 76 | } 77 | 78 | LOG_PRINTK("Area %u at 0x%x on %s for %u bytes\n", id, (unsigned int)pfa->fa_off, pfa->fa_dev->name, 79 | (unsigned int)pfa->fa_size); 80 | 81 | rc = flash_area_erase(pfa, 0, pfa->fa_size); 82 | 83 | if (rc < 0) { 84 | LOG_ERR("Failed to erase flash: %d", rc); 85 | } else { 86 | LOG_INF("Successfully erased flash"); 87 | } 88 | 89 | flash_area_close(pfa); 90 | 91 | return rc; 92 | } 93 | 94 | #define PARTITION_NODE DT_NODELABEL(lfs1) 95 | 96 | #if DT_NODE_EXISTS(PARTITION_NODE) 97 | FS_FSTAB_DECLARE_ENTRY(PARTITION_NODE); 98 | #else /* PARTITION_NODE */ 99 | FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(user_data); 100 | static struct fs_mount_t lfs_storage_mnt = { 101 | .type = FS_LITTLEFS, 102 | .fs_data = &user_data, 103 | .storage_dev = (void *)FIXED_PARTITION_ID(user_data_partition), 104 | .mnt_point = FS_MOUNT_POINT, 105 | }; 106 | #endif /* PARTITION_NODE */ 107 | 108 | struct fs_mount_t *mp = 109 | #if DT_NODE_EXISTS(PARTITION_NODE) 110 | &FS_FSTAB_ENTRY(PARTITION_NODE) 111 | #else 112 | &lfs_storage_mnt 113 | #endif 114 | ; 115 | 116 | static int littlefs_mount(struct fs_mount_t *mp) { 117 | int rc = 0; 118 | 119 | /* Do not mount if auto-mount has been enabled */ 120 | #if !DT_NODE_EXISTS(PARTITION_NODE) || !(FSTAB_ENTRY_DT_MOUNT_FLAGS(PARTITION_NODE) & FS_MOUNT_FLAG_AUTOMOUNT) 121 | rc = fs_mount(mp); 122 | if (rc < 0) { 123 | LOG_ERR("FAIL: mount id %" PRIuPTR " at %s: %d\n", (uintptr_t)mp->storage_dev, mp->mnt_point, rc); 124 | return rc; 125 | } 126 | LOG_INF("%s mount: %d\n", mp->mnt_point, rc); 127 | #else 128 | LOG_INF("%s automounted\n", mp->mnt_point); 129 | #endif 130 | 131 | return rc; 132 | } 133 | 134 | #ifdef CONFIG_APP_LITTLEFS_STORAGE_BLK_SDMMC 135 | struct fs_littlefs lfsfs; 136 | static struct fs_mount_t __mp = { 137 | .type = FS_LITTLEFS, 138 | .fs_data = &lfsfs, 139 | .flags = FS_MOUNT_FLAG_USE_DISK_ACCESS, 140 | }; 141 | 142 | struct fs_mount_t *mp = &__mp; 143 | 144 | static int littlefs_mount(struct fs_mount_t *mp) { 145 | static const char *disk_mount_pt = "/" CONFIG_SDMMC_VOLUME_NAME ":"; 146 | static const char *disk_pdrv = CONFIG_SDMMC_VOLUME_NAME; 147 | 148 | mp->storage_dev = (void *)disk_pdrv; 149 | mp->mnt_point = disk_mount_pt; 150 | 151 | return fs_mount(mp); 152 | } 153 | #endif /* CONFIG_APP_LITTLEFS_STORAGE_BLK_SDMMC */ 154 | 155 | void ocre_app_storage_init() { 156 | struct fs_dirent entry; 157 | struct fs_statvfs sbuf; 158 | int rc; 159 | 160 | rc = littlefs_mount(mp); 161 | if (rc < 0) { 162 | return; 163 | } 164 | 165 | rc = fs_statvfs(mp->mnt_point, &sbuf); 166 | if (rc < 0) { 167 | LOG_ERR("FAILR statvfs: %d", rc); 168 | return; 169 | } 170 | 171 | LOG_DBG("%s: bsize = %lu ; frsize = %lu ;" 172 | " blocks = %lu ; bfree = %lu", 173 | mp->mnt_point, sbuf.f_bsize, sbuf.f_frsize, sbuf.f_blocks, sbuf.f_bfree); 174 | 175 | rc = lsdir(mp->mnt_point); 176 | if (rc < 0) { 177 | LOG_ERR("FAIL: lsdir %s: %d", mp->mnt_point, rc); 178 | } 179 | 180 | // Create the core directories if they don't exist 181 | if (fs_stat(OCRE_BASE_PATH, &entry) == -ENOENT) { 182 | fs_mkdir(OCRE_BASE_PATH); 183 | } 184 | 185 | if (fs_stat(APP_RESOURCE_PATH, &entry) == -ENOENT) { 186 | fs_mkdir(APP_RESOURCE_PATH); 187 | } 188 | 189 | if (fs_stat(PACKAGE_BASE_PATH, &entry) == -ENOENT) { 190 | fs_mkdir(PACKAGE_BASE_PATH); 191 | } 192 | 193 | if (fs_stat(CONFIG_PATH, &entry) == -ENOENT) { 194 | fs_mkdir(CONFIG_PATH); 195 | } 196 | } 197 | 198 | static int cmd_flash_format(const struct shell *shell, size_t argc, char *argv[]) { 199 | int rc; 200 | fs_unmount(mp); 201 | 202 | // FIXME: if erasing the whole chip, could cause problems 203 | // https://github.com/zephyrproject-rtos/zephyr/issues/56442 204 | rc = littlefs_flash_erase((uintptr_t)mp->storage_dev); 205 | 206 | if (rc < 0) { 207 | print(shell, SHELL_WARNING, "Format failed: %d\n", rc); 208 | } else { 209 | print(shell, SHELL_NORMAL, "Format succeeded\n"); 210 | } 211 | 212 | if (rc == 0) { 213 | LOG_INF("Mounting..."); 214 | rc = littlefs_mount(mp); 215 | } 216 | 217 | return rc; 218 | } 219 | 220 | SHELL_STATIC_SUBCMD_SET_CREATE(flash_commands, 221 | SHELL_CMD(format, NULL, "Format the flash storage device (all user data will be lost)", 222 | cmd_flash_format), 223 | SHELL_SUBCMD_SET_END); 224 | 225 | SHELL_CMD_REGISTER(user_storage, &flash_commands, "User storage management", NULL); 226 | -------------------------------------------------------------------------------- /src/ocre/fs/fs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef OCRE_FILESYSTEM_H 9 | #define OCRE_FILESYSTEM_H 10 | 11 | void ocre_app_storage_init(); 12 | 13 | // clang-format off 14 | #define FS_MOUNT_POINT "/lfs" 15 | #define OCRE_BASE_PATH FS_MOUNT_POINT "/ocre" 16 | 17 | #define APP_RESOURCE_PATH OCRE_BASE_PATH "/images" 18 | #define PACKAGE_BASE_PATH OCRE_BASE_PATH "/manifests" 19 | #define CONFIG_PATH OCRE_BASE_PATH "/config/" 20 | 21 | #define APP_RESOURCE_PATH_FMT APP_RESOURCE_PATH "/%s.bin" 22 | #define TEMP_RESOURCE_PATH_FMT APP_RESOURCE_PATH "/%s.tmp" 23 | #define PACKAGE_RESOURCE_PATH_FMT PACKAGE_BASE_PATH "/pkg-%d" 24 | #define CONFIG_PATH_FMT CONFIG_PATH "/%s.bin" 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/ocre/ocre.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef OCRE_H 9 | #define OCRE_H 10 | 11 | #include 12 | 13 | #if CONFIG_OCRE_LOG_DEBUG 14 | #define OCRE_LOG_LEVEL LOG_LEVEL_DBG 15 | #elif CONFIG_OCRE_LOG_ERR 16 | #define OCRE_LOG_LEVEL LOG_LEVEL_ERR 17 | #elif CONFIG_OCRE_LOG_WARN 18 | #define OCRE_LOG_LEVEL LOG_LEVEL_WRN 19 | #elif CONFIG_OCRE_LOG_INF 20 | #define OCRE_LOG_LEVEL LOG_LEVEL_INF 21 | #else 22 | #define OCRE_LOG_LEVEL LOG_LEVEL_NONE 23 | #endif 24 | 25 | #endif -------------------------------------------------------------------------------- /src/ocre/ocre_container_runtime/ocre_container_runtime.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifdef UNIT_TESTING 9 | #include "../../application/tests/ocre_container_runtime/stubs/components/container_supervisor/cs_sm_impl.h" 10 | #include "../../application/tests/ocre_container_runtime/stubs/components/container_supervisor/cs_sm.h" 11 | #include "../../application/tests/ocre_container_runtime/stubs/wasm/wasm.h" 12 | #include "../../application/tests/ocre_container_runtime/stubs/ocre/fs/fs.h" 13 | #else 14 | #include 15 | #include 16 | #include 17 | #include "../components/container_supervisor/cs_sm.h" 18 | #include "../components/container_supervisor/cs_sm_impl.h" 19 | // WAMR includes 20 | // #include "coap_ext.h" 21 | #include "../api/ocre_api.h" 22 | #endif 23 | 24 | #include 25 | #include 26 | 27 | LOG_MODULE_DECLARE(ocre_cs_component, OCRE_LOG_LEVEL); 28 | 29 | #include "ocre_container_runtime.h" 30 | 31 | ocre_container_runtime_status_t ocre_container_runtime_init(ocre_cs_ctx *ctx, ocre_container_init_arguments_t *args) { 32 | // Zeroing the context 33 | if (CS_runtime_init(ctx, args) != RUNTIME_STATUS_INITIALIZED) { 34 | LOG_ERR("Failed to initialize container runtime"); 35 | return RUNTIME_STATUS_ERROR; 36 | } 37 | 38 | CS_ctx_init(ctx); 39 | ctx->current_container_id = 0; 40 | ctx->download_count = 0; 41 | 42 | start_ocre_cs_thread(ctx); 43 | k_sleep(K_MSEC(1000)); // Hack to allow the thread to start prior to continuing 44 | 45 | return RUNTIME_STATUS_INITIALIZED; 46 | } 47 | 48 | ocre_container_status_t ocre_container_runtime_destroy(void) { 49 | wasm_runtime_destroy(); 50 | destroy_ocre_cs_thread(); 51 | return RUNTIME_STATUS_DESTROYED; 52 | } 53 | 54 | ocre_container_status_t ocre_container_runtime_create_container(ocre_cs_ctx *ctx, ocre_container_data_t *container_data, 55 | int *container_id, ocre_container_runtime_cb callback) { 56 | int i; 57 | uint8_t validity_flag = false; 58 | // Find available slot for new container 59 | for (i = 0; i < MAX_CONTAINERS; i++) { 60 | if ((ctx->containers[i].container_runtime_status == CONTAINER_STATUS_UNKNOWN) || 61 | (ctx->containers[i].container_runtime_status == CONTAINER_STATUS_DESTROYED)) { 62 | *container_id = i; 63 | validity_flag = true; 64 | break; 65 | } 66 | } 67 | 68 | if (validity_flag == false) { 69 | LOG_ERR("No available slots, unable to create container"); 70 | return CONTAINER_STATUS_ERROR; 71 | } 72 | LOG_INF("Request to create new container in slot:%d", *container_id); 73 | 74 | struct ocre_message event = {.event = EVENT_CREATE_CONTAINER}; 75 | ocre_container_data_t Data; 76 | event.containerId = *container_id; 77 | Data = *container_data; 78 | ctx->containers[*container_id].ocre_container_data = Data; 79 | ctx->download_count++; 80 | 81 | ocre_component_send(&ocre_cs_component, &event); 82 | return CONTAINER_STATUS_CREATED; 83 | } 84 | 85 | ocre_container_status_t ocre_container_runtime_run_container(ocre_cs_ctx *ctx, int container_id, 86 | ocre_container_runtime_cb callback) { 87 | if (container_id < 0 || container_id >= MAX_CONTAINERS) { 88 | LOG_ERR("Invalid container ID: %d", container_id); 89 | return CONTAINER_STATUS_ERROR; 90 | } 91 | 92 | LOG_INF("Request to run container in slot:%d", container_id); 93 | struct ocre_message event = {.event = EVENT_RUN_CONTAINER}; 94 | event.containerId = container_id; 95 | ocre_component_send(&ocre_cs_component, &event); 96 | return CONTAINER_STATUS_RUNNING; 97 | } 98 | 99 | ocre_container_status_t ocre_container_runtime_get_container_status(ocre_cs_ctx *ctx, int container_id) { 100 | if (container_id < 0 || container_id >= MAX_CONTAINERS) { 101 | LOG_ERR("Invalid container ID: %d", container_id); 102 | return CONTAINER_STATUS_ERROR; 103 | } 104 | 105 | return ctx->containers[container_id].container_runtime_status; 106 | } 107 | 108 | ocre_container_status_t ocre_container_runtime_stop_container(ocre_cs_ctx *ctx, int container_id, 109 | ocre_container_runtime_cb callback) { 110 | if (container_id < 0 || container_id >= MAX_CONTAINERS) { 111 | LOG_ERR("Invalid container ID: %d", container_id); 112 | return CONTAINER_STATUS_ERROR; 113 | } 114 | LOG_INF("Request to stop container in slot:%d", container_id); 115 | struct ocre_message event = {.event = EVENT_STOP_CONTAINER}; 116 | event.containerId = container_id; 117 | ocre_component_send(&ocre_cs_component, &event); 118 | return CONTAINER_STATUS_STOPPED; 119 | } 120 | 121 | ocre_container_status_t ocre_container_runtime_destroy_container(ocre_cs_ctx *ctx, int container_id, 122 | ocre_container_runtime_cb callback) { 123 | if (container_id < 0 || container_id >= MAX_CONTAINERS) { 124 | LOG_ERR("Invalid container ID: %d", container_id); 125 | return CONTAINER_STATUS_ERROR; 126 | } 127 | LOG_INF("Request to destroy container in slot:%d", container_id); 128 | struct ocre_message event = {.event = EVENT_DESTROY_CONTAINER}; 129 | event.containerId = container_id; 130 | ocre_component_send(&ocre_cs_component, &event); 131 | return CONTAINER_STATUS_DESTROYED; 132 | } 133 | 134 | ocre_container_status_t ocre_container_runtime_restart_container(ocre_cs_ctx *ctx, int container_id, 135 | ocre_container_runtime_cb callback) { 136 | if (container_id < 0 || container_id >= MAX_CONTAINERS) { 137 | LOG_ERR("Invalid container ID: %d", container_id); 138 | return CONTAINER_STATUS_ERROR; 139 | } 140 | LOG_INF("Request to restart container in slot:%d", container_id); 141 | struct ocre_message event = {.event = EVENT_RESTART_CONTAINER}; 142 | event.containerId = container_id; 143 | ocre_component_send(&ocre_cs_component, &event); 144 | return ctx->containers[container_id].container_runtime_status; 145 | } 146 | -------------------------------------------------------------------------------- /src/ocre/ocre_container_runtime/ocre_container_runtime.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef OCRE_CONTAINER_RUNTIME_H 9 | #define OCRE_CONTAINER_RUNTIME_H 10 | 11 | #ifdef UNIT_TESTING 12 | #include "../../application/tests/ocre_container_runtime/stubs/container_healthcheck/ocre_container_healthcheck.h" 13 | #include "../../application/tests/ocre_container_runtime/stubs/k_sem/k_sem.h" 14 | #else 15 | #include 16 | #include 17 | #include "../container_healthcheck/ocre_container_healthcheck.h" 18 | #include 19 | #include 20 | #endif 21 | 22 | #include 23 | 24 | #include "wasm_export.h" 25 | 26 | #define OCRE_CR_DEBUG_ON 0 // Debug flag for container runtime (0: OFF, 1: ON) 27 | #define MAX_CONTAINERS 10 // Maximum number of containers supported by the runtime !!! Can be configurable 28 | #define FILE_PATH_MAX 256 // Maximum file path length 29 | #define OCRE_CR_INIT_TIMEOUT 500 // Timeout to wait for the container registry to initialize 30 | 31 | /** 32 | * @brief Structure containing the runtime arguments for a container runtime. 33 | */ 34 | typedef struct ocre_runtime_arguments_t { 35 | uint32_t size; ///< Size of the buffer. 36 | char *buffer; ///< Pointer to the buffer containing the WASM module. 37 | char error_buf[128]; ///< Buffer to store error messages. 38 | wasm_module_t module; ///< Handle to the loaded WASM module. 39 | wasm_module_inst_t module_inst; ///< Handle to the instantiated WASM module. 40 | wasm_function_inst_t func; ///< Handle to the function to be executed within the WASM module. 41 | wasm_exec_env_t exec_env; ///< Execution environment for the WASM function. 42 | uint32_t stack_size; ///< Stack size for the WASM module. 43 | uint32_t heap_size; ///< Heap size for the WASM module. 44 | } ocre_runtime_arguments_t; 45 | 46 | /** 47 | * @brief Enum representing the permission types for containers. 48 | * NOT USED YET 49 | */ 50 | typedef enum { 51 | OCRE_CONTAINER_PERM_READ_ONLY, ///< Container has read-only permissions. 52 | OCRE_CONTAINER_PERM_READ_WRITE, ///< Container has read and write permissions. 53 | OCRE_CONTAINER_PERM_EXECUTE ///< Container has execute permissions. 54 | } ocre_container_permissions_t; 55 | 56 | /** 57 | * @brief Enum representing the possible status of the container runtime 58 | */ 59 | typedef enum { 60 | RUNTIME_STATUS_UNKNOWN, ///< Status is unknown. 61 | RUNTIME_STATUS_INITIALIZED, ///< Runtime has been initialized. 62 | RUNTIME_STATUS_DESTROYED, ///< Runtime has been destroyed 63 | RUNTIME_STATUS_ERROR ///< An error occurred with the container. 64 | } ocre_container_runtime_status_t; 65 | 66 | /** 67 | * @brief Enum representing the possible status of a container. 68 | */ 69 | typedef enum { 70 | CONTAINER_STATUS_UNKNOWN, ///< Status is unknown. 71 | CONTAINER_STATUS_CREATED, ///< Container has been created. 72 | CONTAINER_STATUS_RUNNING, ///< Container is currently running. 73 | CONTAINER_STATUS_STOPPED, ///< Container has been stopped. 74 | CONTAINER_STATUS_DESTROYED, ///< Container has been destroyed. 75 | CONTAINER_STATUS_UNRESPONSIVE, ///< Container is unresponsive. -> For Healthcheck 76 | CONTAINER_STATUS_ERROR, ///< An error occurred with the container. 77 | } ocre_container_status_t; 78 | 79 | typedef struct ocre_container_runtime_init_arguments_t { 80 | uint32_t default_stack_size; ///< Stack size for the WASM module. 81 | uint32_t default_heap_size; ///< Heap size for the WASM module. 82 | int maximum_containers; ///< Maximum number of containers allowed. 83 | NativeSymbol *ocre_api_functions; 84 | } ocre_container_init_arguments_t; 85 | 86 | /** 87 | * @brief Structure representing the data associated with a container. 88 | */ 89 | typedef struct ocre_container_data_t { 90 | char name[16]; // 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "ocre_gpio.h" 14 | #include "wasm_export.h" 15 | #include 16 | #include 17 | #include 18 | 19 | LOG_MODULE_DECLARE(ocre_cs_component, OCRE_LOG_LEVEL); 20 | 21 | #define GPIO_STACK_SIZE 2048 22 | #define GPIO_THREAD_PRIORITY 5 23 | #define WASM_STACK_SIZE (8 * 1024) 24 | 25 | typedef struct { 26 | bool in_use; 27 | uint32_t id; 28 | const struct device *port; 29 | gpio_pin_t pin_number; 30 | ocre_gpio_direction_t direction; 31 | struct gpio_callback gpio_cb_data; 32 | ocre_gpio_callback_t user_callback; 33 | } gpio_pin_ocre; 34 | 35 | static K_THREAD_STACK_DEFINE(gpio_thread_stack, GPIO_STACK_SIZE); 36 | static struct k_thread gpio_thread; 37 | static k_tid_t gpio_thread_id; 38 | 39 | K_MSGQ_DEFINE(gpio_msgq, sizeof(uint32_t) * 2, 10, 4); 40 | 41 | // GPIO pin management 42 | static gpio_pin_ocre gpio_pins[CONFIG_OCRE_GPIO_MAX_PINS] = {0}; 43 | static wasm_function_inst_t gpio_dispatcher_func = NULL; 44 | static bool gpio_system_initialized = false; 45 | static wasm_module_inst_t current_module_inst = NULL; 46 | static wasm_exec_env_t shared_exec_env = NULL; 47 | 48 | // Define GPIO port devices structure - will be populated at runtime 49 | static const struct device *gpio_ports[CONFIG_OCRE_GPIO_MAX_PORTS] = {NULL}; 50 | 51 | // Board-specific GPIO port device definitions 52 | #if defined(CONFIG_BOARD_B_U585I_IOT02A) 53 | // STM32U5 board configuration 54 | #define GPIO_PORT_A DT_NODELABEL(gpioa) 55 | #define GPIO_PORT_B DT_NODELABEL(gpiob) 56 | #define GPIO_PORT_C DT_NODELABEL(gpioc) 57 | #define GPIO_PORT_D DT_NODELABEL(gpiod) 58 | #define GPIO_PORT_E DT_NODELABEL(gpioe) 59 | #define GPIO_PORT_F DT_NODELABEL(gpiof) 60 | #define GPIO_PORT_G DT_NODELABEL(gpiog) 61 | #define GPIO_PORT_H DT_NODELABEL(gpioh) 62 | static const char *gpio_port_names[CONFIG_OCRE_GPIO_MAX_PORTS] = {"GPIOA", "GPIOB", "GPIOC", "GPIOD", 63 | "GPIOE", "GPIOF", "GPIOG", "GPIOH"}; 64 | #elif defined(CONFIG_BOARD_ESP32C3_DEVKITM) 65 | // ESP32C3 board configuration 66 | #define GPIO_PORT_0 DT_NODELABEL(gpio0) 67 | static const char *gpio_port_names[CONFIG_OCRE_GPIO_MAX_PORTS] = {"GPIO0"}; 68 | #else 69 | // Generic fallback configuration 70 | #if DT_NODE_EXISTS(DT_NODELABEL(gpio0)) 71 | #define GPIO_PORT_0 DT_NODELABEL(gpio0) 72 | #endif 73 | #if DT_NODE_EXISTS(DT_NODELABEL(gpioa)) 74 | #define GPIO_PORT_A DT_NODELABEL(gpioa) 75 | #endif 76 | #if DT_NODE_EXISTS(DT_NODELABEL(gpio)) 77 | #define GPIO_PORT_G DT_NODELABEL(gpio) 78 | #endif 79 | static const char *gpio_port_names[CONFIG_OCRE_GPIO_MAX_PORTS] = {"GPIO"}; 80 | #endif 81 | 82 | void ocre_gpio_cleanup_container(wasm_module_inst_t module_inst) { 83 | if (!gpio_system_initialized || !module_inst) { 84 | LOG_ERR("GPIO system not properly initialized"); 85 | return; 86 | } 87 | 88 | if (module_inst != current_module_inst) { 89 | LOG_WRN("Cleanup requested for non-active module instance"); 90 | return; 91 | } 92 | 93 | int cleaned_count = 0; 94 | for (int i = 0; i < CONFIG_OCRE_GPIO_MAX_PINS; i++) { 95 | if (gpio_pins[i].in_use) { 96 | if (gpio_pins[i].direction == OCRE_GPIO_DIR_INPUT && gpio_pins[i].user_callback) { 97 | gpio_pin_interrupt_configure(gpio_pins[i].port, gpio_pins[i].pin_number, GPIO_INT_DISABLE); 98 | gpio_remove_callback(gpio_pins[i].port, &gpio_pins[i].gpio_cb_data); 99 | } 100 | gpio_pins[i].in_use = false; 101 | gpio_pins[i].id = 0; 102 | cleaned_count++; 103 | } 104 | } 105 | 106 | LOG_INF("Cleaned up %d GPIO pins for container", cleaned_count); 107 | } 108 | 109 | static void gpio_thread_fn(void *arg1, void *arg2, void *arg3) { 110 | uint32_t msg_data[2]; // [0] = pin_id, [1] = state 111 | 112 | while (1) { 113 | if (k_msgq_get(&gpio_msgq, &msg_data, K_FOREVER) == 0) { 114 | if (!gpio_dispatcher_func || !current_module_inst || !shared_exec_env) { 115 | LOG_ERR("GPIO system not properly initialized"); 116 | continue; 117 | } 118 | 119 | uint32_t pin_id = msg_data[0]; 120 | uint32_t state = msg_data[1]; 121 | 122 | LOG_DBG("Processing GPIO pin event: %d, state: %d", pin_id, state); 123 | uint32_t args[2] = {pin_id, state}; 124 | 125 | bool call_success = wasm_runtime_call_wasm(shared_exec_env, gpio_dispatcher_func, 2, args); 126 | 127 | if (!call_success) { 128 | const char *error = wasm_runtime_get_exception(current_module_inst); 129 | LOG_ERR("Failed to call WASM function: %s", error ? error : "Unknown error"); 130 | } else { 131 | LOG_INF("Successfully called WASM function for GPIO pin %d", pin_id); 132 | } 133 | } 134 | } 135 | } 136 | 137 | static void gpio_callback_handler(const struct device *port, struct gpio_callback *cb, gpio_port_pins_t pins) { 138 | for (int i = 0; i < CONFIG_OCRE_GPIO_MAX_PINS; i++) { 139 | if (gpio_pins[i].in_use && &gpio_pins[i].gpio_cb_data == cb && gpio_pins[i].port == port) { 140 | if (pins & BIT(gpio_pins[i].pin_number)) { 141 | int state = gpio_pin_get(port, gpio_pins[i].pin_number); 142 | if (state >= 0) { 143 | uint32_t msg_data[2] = {gpio_pins[i].id, (uint32_t)state}; 144 | if (k_msgq_put(&gpio_msgq, &msg_data, K_NO_WAIT) != 0) { 145 | LOG_ERR("Failed to queue GPIO callback for ID: %d", gpio_pins[i].id); 146 | } 147 | } 148 | } 149 | } 150 | } 151 | } 152 | 153 | void ocre_gpio_set_module_inst(wasm_module_inst_t module_inst) { 154 | current_module_inst = module_inst; 155 | if (shared_exec_env) { 156 | wasm_runtime_destroy_exec_env(shared_exec_env); 157 | } 158 | shared_exec_env = wasm_runtime_create_exec_env(module_inst, WASM_STACK_SIZE); 159 | } 160 | 161 | void ocre_gpio_set_dispatcher(wasm_exec_env_t exec_env) { 162 | if (!current_module_inst) { 163 | LOG_ERR("No active WASM module instance"); 164 | return; 165 | } 166 | 167 | wasm_function_inst_t func = wasm_runtime_lookup_function(current_module_inst, "gpio_callback"); 168 | if (!func) { 169 | LOG_ERR("Failed to find 'gpio_callback' in WASM module"); 170 | return; 171 | } 172 | 173 | gpio_dispatcher_func = func; 174 | LOG_INF("WASM GPIO dispatcher function set successfully"); 175 | } 176 | 177 | static gpio_pin_ocre *get_gpio_from_id(int id) { 178 | if (id < 0 || id >= CONFIG_OCRE_GPIO_MAX_PINS) { 179 | return NULL; 180 | } 181 | return &gpio_pins[id]; 182 | } 183 | 184 | int ocre_gpio_init(void) { 185 | if (gpio_system_initialized) { 186 | LOG_INF("GPIO already initialized"); 187 | return 0; 188 | } 189 | 190 | // Initialize GPIO ports array based on board 191 | int port_count = 0; 192 | 193 | #if defined(CONFIG_BOARD_B_U585I_IOT02A) 194 | // STM32U5 board initialization 195 | if (DT_NODE_EXISTS(GPIO_PORT_A)) { 196 | gpio_ports[0] = DEVICE_DT_GET(GPIO_PORT_A); 197 | if (!device_is_ready(gpio_ports[0])) { 198 | LOG_ERR("GPIOA not ready"); 199 | } else { 200 | LOG_INF("GPIOA initialized"); 201 | port_count++; 202 | } 203 | } 204 | 205 | if (DT_NODE_EXISTS(GPIO_PORT_B)) { 206 | gpio_ports[1] = DEVICE_DT_GET(GPIO_PORT_B); 207 | if (!device_is_ready(gpio_ports[1])) { 208 | LOG_ERR("GPIOB not ready"); 209 | } else { 210 | LOG_INF("GPIOB initialized"); 211 | port_count++; 212 | } 213 | } 214 | 215 | if (DT_NODE_EXISTS(GPIO_PORT_C)) { 216 | gpio_ports[2] = DEVICE_DT_GET(GPIO_PORT_C); 217 | if (!device_is_ready(gpio_ports[2])) { 218 | LOG_ERR("GPIOC not ready"); 219 | } else { 220 | LOG_INF("GPIOC initialized"); 221 | port_count++; 222 | } 223 | } 224 | 225 | if (DT_NODE_EXISTS(GPIO_PORT_D)) { 226 | gpio_ports[3] = DEVICE_DT_GET(GPIO_PORT_D); 227 | if (!device_is_ready(gpio_ports[3])) { 228 | LOG_ERR("GPIOD not ready"); 229 | } else { 230 | LOG_INF("GPIOD initialized"); 231 | port_count++; 232 | } 233 | } 234 | 235 | if (DT_NODE_EXISTS(GPIO_PORT_E)) { 236 | gpio_ports[4] = DEVICE_DT_GET(GPIO_PORT_E); 237 | if (!device_is_ready(gpio_ports[4])) { 238 | LOG_ERR("GPIOE not ready"); 239 | } else { 240 | LOG_INF("GPIOE initialized"); 241 | port_count++; 242 | } 243 | } 244 | 245 | if (DT_NODE_EXISTS(GPIO_PORT_F)) { 246 | gpio_ports[5] = DEVICE_DT_GET(GPIO_PORT_F); 247 | if (!device_is_ready(gpio_ports[5])) { 248 | LOG_ERR("GPIOF not ready"); 249 | } else { 250 | LOG_INF("GPIOF initialized"); 251 | port_count++; 252 | } 253 | } 254 | 255 | if (DT_NODE_EXISTS(GPIO_PORT_G)) { 256 | gpio_ports[6] = DEVICE_DT_GET(GPIO_PORT_G); 257 | if (!device_is_ready(gpio_ports[6])) { 258 | LOG_ERR("GPIOG not ready"); 259 | } else { 260 | LOG_INF("GPIOG initialized"); 261 | port_count++; 262 | } 263 | } 264 | 265 | if (DT_NODE_EXISTS(GPIO_PORT_H)) { 266 | gpio_ports[7] = DEVICE_DT_GET(GPIO_PORT_H); 267 | if (!device_is_ready(gpio_ports[7])) { 268 | LOG_ERR("GPIOH not ready"); 269 | } else { 270 | LOG_INF("GPIOH initialized"); 271 | port_count++; 272 | } 273 | } 274 | #elif defined(CONFIG_BOARD_ESP32C3_DEVKITM) 275 | // ESP32C3 board initialization 276 | if (DT_NODE_EXISTS(GPIO_PORT_0)) { 277 | gpio_ports[0] = DEVICE_DT_GET(GPIO_PORT_0); 278 | if (!device_is_ready(gpio_ports[0])) { 279 | LOG_ERR("GPIO0 not ready"); 280 | } else { 281 | LOG_INF("GPIO0 initialized"); 282 | port_count++; 283 | } 284 | } 285 | /* ADD BOARDS HERE */ 286 | #else 287 | // Generic fallback initialization 288 | // #if defined(GPIO_PORT_0) 289 | // #if DT_NODE_EXISTS(GPIO_PORT_0) 290 | // gpio_ports[0] = DEVICE_DT_GET(GPIO_PORT_0); 291 | // LOG_INF("No Board Choosen Generic fallback initialization %s\n", gpio_ports[0]); 292 | // port_count = 1; 293 | // #endif 294 | // #endif 295 | 296 | #if defined(GPIO_PORT_A) 297 | #if DT_NODE_EXISTS(GPIO_PORT_A) 298 | gpio_ports[0] = DEVICE_DT_GET(GPIO_PORT_A); 299 | LOG_INF("No Board Choosen Generic fallback initialization %s\n", gpio_ports[0]); 300 | port_count = 1; 301 | #endif 302 | #endif 303 | 304 | #if defined(GPIO_PORT_G) 305 | #if DT_NODE_EXISTS(GPIO_PORT_G) 306 | gpio_ports[0] = DEVICE_DT_GET(GPIO_PORT_G); 307 | LOG_INF("No Board Choosen Generic fallback initialization %s\n", gpio_ports[0]); 308 | port_count = 1; 309 | #endif 310 | #endif 311 | #endif 312 | 313 | if (port_count == 0) { 314 | LOG_ERR("No GPIO ports were initialized\n"); 315 | return -ENODEV; 316 | } 317 | 318 | // Start GPIO thread for callbacks 319 | gpio_thread_id = k_thread_create(&gpio_thread, gpio_thread_stack, K_THREAD_STACK_SIZEOF(gpio_thread_stack), 320 | gpio_thread_fn, NULL, NULL, NULL, GPIO_THREAD_PRIORITY, 0, K_NO_WAIT); 321 | if (!gpio_thread_id) { 322 | LOG_ERR("Failed to create GPIO thread"); 323 | return -ENOMEM; 324 | } 325 | 326 | k_thread_name_set(gpio_thread_id, "gpio_thread"); 327 | LOG_INF("GPIO system initialized with %d ports", port_count); 328 | gpio_system_initialized = true; 329 | return 0; 330 | } 331 | 332 | int ocre_gpio_configure(const ocre_gpio_config_t *config) { 333 | if (!gpio_system_initialized) { 334 | LOG_ERR("GPIO not initialized"); 335 | return -ENODEV; 336 | } 337 | 338 | if (config == NULL) { 339 | LOG_ERR("NULL config pointer"); 340 | return -EINVAL; 341 | } 342 | 343 | if (config->pin < 0 || config->pin >= CONFIG_OCRE_GPIO_MAX_PINS) { 344 | LOG_ERR("Invalid GPIO pin number: %d", config->pin); 345 | return -EINVAL; 346 | } 347 | 348 | // Map logical pin to physical port/pin 349 | int port_idx = config->pin / CONFIG_OCRE_GPIO_PINS_PER_PORT; 350 | gpio_pin_t pin_number = config->pin % CONFIG_OCRE_GPIO_PINS_PER_PORT; 351 | 352 | if (port_idx >= CONFIG_OCRE_GPIO_MAX_PORTS || gpio_ports[port_idx] == NULL) { 353 | LOG_ERR("Invalid GPIO port index: %d", port_idx); 354 | return -EINVAL; 355 | } 356 | 357 | // Configure Zephyr GPIO 358 | gpio_flags_t flags = 0; 359 | 360 | if (config->direction == OCRE_GPIO_DIR_INPUT) { 361 | flags = GPIO_INPUT; 362 | } else if (config->direction == OCRE_GPIO_DIR_OUTPUT) { 363 | flags = GPIO_OUTPUT; 364 | } else { 365 | LOG_ERR("Invalid GPIO direction"); 366 | return -EINVAL; 367 | } 368 | 369 | int ret = gpio_pin_configure(gpio_ports[port_idx], pin_number, flags); 370 | if (ret != 0) { 371 | LOG_ERR("Failed to configure GPIO pin: %d", ret); 372 | return ret; 373 | } 374 | 375 | // Update our tracking information 376 | gpio_pins[config->pin].in_use = true; 377 | gpio_pins[config->pin].id = config->pin; 378 | gpio_pins[config->pin].port = gpio_ports[port_idx]; 379 | gpio_pins[config->pin].pin_number = pin_number; 380 | gpio_pins[config->pin].direction = config->direction; 381 | gpio_pins[config->pin].user_callback = NULL; 382 | 383 | LOG_DBG("Configured GPIO pin %d: port=%s, pin=%d, direction=%d", config->pin, gpio_port_names[port_idx], pin_number, 384 | config->direction); 385 | 386 | return 0; 387 | } 388 | 389 | int ocre_gpio_pin_set(int pin, ocre_gpio_pin_state_t state) { 390 | gpio_pin_ocre *gpio = get_gpio_from_id(pin); 391 | 392 | if (!gpio_system_initialized) { 393 | LOG_ERR("GPIO system not initialized when trying to set pin %d", pin); 394 | return -ENODEV; 395 | } 396 | 397 | if (!gpio || !gpio->in_use) { 398 | LOG_ERR("Invalid or unconfigured GPIO pin: %d", pin); 399 | return -EINVAL; 400 | } 401 | 402 | if (gpio->direction != OCRE_GPIO_DIR_OUTPUT) { 403 | LOG_ERR("Cannot set state of input pin: %d", pin); 404 | return -EINVAL; 405 | } 406 | 407 | LOG_INF("Setting GPIO pin %d (port=%p, pin=%d) to state %d", pin, gpio->port, gpio->pin_number, state); 408 | 409 | int ret = gpio_pin_set(gpio->port, gpio->pin_number, state); 410 | if (ret != 0) { 411 | LOG_ERR("Failed to set GPIO pin %d: %d", pin, ret); 412 | return ret; 413 | } 414 | 415 | LOG_INF("Successfully set GPIO pin %d to state %d", pin, state); 416 | return 0; 417 | } 418 | 419 | ocre_gpio_pin_state_t ocre_gpio_pin_get(int pin) { 420 | gpio_pin_ocre *gpio = get_gpio_from_id(pin); 421 | 422 | if (!gpio_system_initialized) { 423 | return -ENODEV; 424 | } 425 | 426 | if (!gpio || !gpio->in_use) { 427 | LOG_ERR("Invalid or unconfigured GPIO pin: %d", pin); 428 | return -EINVAL; 429 | } 430 | 431 | int value = gpio_pin_get(gpio->port, gpio->pin_number); 432 | if (value < 0) { 433 | LOG_ERR("Failed to get GPIO pin %d state: %d", pin, value); 434 | return value; 435 | } 436 | 437 | return value ? OCRE_GPIO_PIN_SET : OCRE_GPIO_PIN_RESET; 438 | } 439 | 440 | int ocre_gpio_pin_toggle(int pin) { 441 | gpio_pin_ocre *gpio = get_gpio_from_id(pin); 442 | 443 | if (!gpio_system_initialized) { 444 | return -ENODEV; 445 | } 446 | 447 | if (!gpio || !gpio->in_use) { 448 | LOG_ERR("Invalid or unconfigured GPIO pin: %d", pin); 449 | return -EINVAL; 450 | } 451 | 452 | if (gpio->direction != OCRE_GPIO_DIR_OUTPUT) { 453 | LOG_ERR("Cannot toggle state of input pin: %d", pin); 454 | return -EINVAL; 455 | } 456 | 457 | int ret = gpio_pin_toggle(gpio->port, gpio->pin_number); 458 | if (ret != 0) { 459 | LOG_ERR("Failed to toggle GPIO pin %d: %d", pin, ret); 460 | return ret; 461 | } 462 | 463 | return 0; 464 | } 465 | 466 | int ocre_gpio_register_callback(int pin, ocre_gpio_callback_t callback) { 467 | gpio_pin_ocre *gpio = get_gpio_from_id(pin); 468 | 469 | if (!gpio_system_initialized) { 470 | return -ENODEV; 471 | } 472 | 473 | if (!gpio || !gpio->in_use) { 474 | LOG_ERR("Invalid or unconfigured GPIO pin: %d", pin); 475 | return -EINVAL; 476 | } 477 | 478 | if (gpio->direction != OCRE_GPIO_DIR_INPUT) { 479 | LOG_ERR("Cannot register callback on output pin: %d", pin); 480 | return -EINVAL; 481 | } 482 | 483 | // Configure the interrupt 484 | int ret = gpio_pin_interrupt_configure(gpio->port, gpio->pin_number, GPIO_INT_EDGE_BOTH); 485 | if (ret != 0) { 486 | LOG_ERR("Failed to configure GPIO interrupt: %d", ret); 487 | return ret; 488 | } 489 | 490 | // Initialize the callback structure 491 | gpio_init_callback(&gpio->gpio_cb_data, gpio_callback_handler, BIT(gpio->pin_number)); 492 | ret = gpio_add_callback(gpio->port, &gpio->gpio_cb_data); 493 | if (ret != 0) { 494 | LOG_ERR("Failed to add GPIO callback: %d", ret); 495 | return ret; 496 | } 497 | 498 | // Store the user callback 499 | gpio->user_callback = callback; 500 | LOG_DBG("Registered callback for GPIO pin %d", pin); 501 | 502 | return 0; 503 | } 504 | 505 | int ocre_gpio_unregister_callback(int pin) { 506 | gpio_pin_ocre *gpio = get_gpio_from_id(pin); 507 | 508 | if (!gpio_system_initialized) { 509 | return -ENODEV; 510 | } 511 | 512 | if (!gpio || !gpio->in_use) { 513 | LOG_ERR("Invalid or unconfigured GPIO pin: %d", pin); 514 | return -EINVAL; 515 | } 516 | 517 | if (!gpio->user_callback) { 518 | LOG_WRN("No callback registered for pin %d", pin); 519 | return 0; 520 | } 521 | 522 | // Disable interrupt and remove callback 523 | int ret = gpio_pin_interrupt_configure(gpio->port, gpio->pin_number, GPIO_INT_DISABLE); 524 | if (ret != 0) { 525 | LOG_ERR("Failed to disable GPIO interrupt: %d", ret); 526 | return ret; 527 | } 528 | 529 | ret = gpio_remove_callback(gpio->port, &gpio->gpio_cb_data); 530 | if (ret != 0) { 531 | LOG_ERR("Failed to remove GPIO callback: %d", ret); 532 | return ret; 533 | } 534 | 535 | gpio->user_callback = NULL; 536 | LOG_DBG("Unregistered callback for GPIO pin %d", pin); 537 | 538 | return 0; 539 | } 540 | 541 | int get_pin_id(int port, int pin) { 542 | // Ensure the pin is valid within the specified port 543 | if (pin < 0 || pin >= CONFIG_OCRE_GPIO_PINS_PER_PORT) { 544 | printf("Invalid pin number\n"); 545 | return -1; // Return -1 for invalid pin number 546 | } 547 | 548 | // Calculate the pin ID 549 | int pin_id = port * CONFIG_OCRE_GPIO_PINS_PER_PORT + pin; 550 | return pin_id; 551 | } 552 | 553 | // WASM-exposed functions for GPIO control 554 | int ocre_gpio_wasm_init(wasm_exec_env_t exec_env) { 555 | return ocre_gpio_init(); 556 | } 557 | 558 | int ocre_gpio_wasm_configure(wasm_exec_env_t exec_env, int port, int P_pin, int direction) { 559 | if (!gpio_system_initialized) { 560 | LOG_ERR("GPIO system not initialized"); 561 | return -ENODEV; 562 | } 563 | int pin = get_pin_id(port, P_pin); 564 | ocre_gpio_config_t config; 565 | config.pin = pin; 566 | config.direction = direction; 567 | 568 | return ocre_gpio_configure(&config); 569 | } 570 | 571 | int ocre_gpio_wasm_set(wasm_exec_env_t exec_env, int port, int P_pin, int state) { 572 | int pin = get_pin_id(port, P_pin); 573 | return ocre_gpio_pin_set(pin, state ? OCRE_GPIO_PIN_SET : OCRE_GPIO_PIN_RESET); 574 | } 575 | 576 | int ocre_gpio_wasm_get(wasm_exec_env_t exec_env, int port, int P_pin) { 577 | int pin = get_pin_id(port, P_pin); 578 | return ocre_gpio_pin_get(pin); 579 | } 580 | 581 | int ocre_gpio_wasm_toggle(wasm_exec_env_t exec_env, int port, int P_pin) { 582 | int pin = get_pin_id(port, P_pin); 583 | return ocre_gpio_pin_toggle(pin); 584 | } 585 | 586 | int ocre_gpio_wasm_register_callback(wasm_exec_env_t exec_env, int port, int P_pin) { 587 | int pin = get_pin_id(port, P_pin); 588 | ocre_gpio_set_dispatcher(exec_env); 589 | 590 | // For WASM, we don't need an actual callback function pointer 591 | // as we'll use the dispatcher to call the appropriate WASM function 592 | return ocre_gpio_register_callback(pin, NULL); 593 | } 594 | 595 | int ocre_gpio_wasm_unregister_callback(wasm_exec_env_t exec_env, int port, int P_pin) { 596 | int pin = get_pin_id(port, P_pin); 597 | return ocre_gpio_unregister_callback(pin); 598 | } 599 | -------------------------------------------------------------------------------- /src/ocre/ocre_gpio/ocre_gpio.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef OCRE_GPIO_H 9 | #define OCRE_GPIO_H 10 | 11 | #include 12 | #include 13 | #include "wasm_export.h" 14 | 15 | // Default configuration values if not provided by Kconfig 16 | #ifndef CONFIG_OCRE_GPIO_MAX_PINS 17 | #define CONFIG_OCRE_GPIO_MAX_PINS 32 18 | #endif 19 | 20 | #ifndef CONFIG_OCRE_GPIO_MAX_PORTS 21 | #define CONFIG_OCRE_GPIO_MAX_PORTS 8 22 | #endif 23 | 24 | #ifndef CONFIG_OCRE_GPIO_PINS_PER_PORT 25 | #define CONFIG_OCRE_GPIO_PINS_PER_PORT 16 26 | #endif 27 | 28 | /** 29 | * GPIO pin state 30 | */ 31 | typedef enum { 32 | OCRE_GPIO_PIN_RESET = 0, 33 | OCRE_GPIO_PIN_SET = 1 34 | } ocre_gpio_pin_state_t; 35 | 36 | /** 37 | * GPIO pin direction 38 | */ 39 | typedef enum { 40 | OCRE_GPIO_DIR_INPUT = 0, 41 | OCRE_GPIO_DIR_OUTPUT = 1 42 | } ocre_gpio_direction_t; 43 | 44 | /** 45 | * GPIO configuration structure 46 | */ 47 | typedef struct { 48 | int pin; /**< GPIO pin number (logical) */ 49 | ocre_gpio_direction_t direction; /**< Pin direction */ 50 | } ocre_gpio_config_t; 51 | 52 | /** 53 | * GPIO callback function type 54 | */ 55 | typedef void (*ocre_gpio_callback_t)(int pin, ocre_gpio_pin_state_t state); 56 | 57 | /** 58 | * Initialize GPIO subsystem. 59 | * 60 | * @return 0 on success, negative error code on failure 61 | */ 62 | int ocre_gpio_init(void); 63 | 64 | /** 65 | * Configure a GPIO pin. 66 | * 67 | * @param config GPIO pin configuration 68 | * @return 0 on success, negative error code on failure 69 | */ 70 | int ocre_gpio_configure(const ocre_gpio_config_t *config); 71 | 72 | /** 73 | * Set GPIO pin state. 74 | * 75 | * @param pin GPIO pin identifier 76 | * @param state Desired pin state 77 | * @return 0 on success, negative error code on failure 78 | */ 79 | int ocre_gpio_pin_set(int pin, ocre_gpio_pin_state_t state); 80 | 81 | /** 82 | * Get GPIO pin state. 83 | * 84 | * @param pin GPIO pin identifier 85 | * @return Pin state or negative error code 86 | */ 87 | ocre_gpio_pin_state_t ocre_gpio_pin_get(int pin); 88 | 89 | /** 90 | * Toggle GPIO pin state. 91 | * 92 | * @param pin GPIO pin identifier 93 | * @return 0 on success, negative error code on failure 94 | */ 95 | int ocre_gpio_pin_toggle(int pin); 96 | 97 | /** 98 | * Register callback for GPIO pin state changes. 99 | * 100 | * @param pin GPIO pin identifier 101 | * @param callback Callback function 102 | * @return 0 on success, negative error code on failure 103 | */ 104 | int ocre_gpio_register_callback(int pin, ocre_gpio_callback_t callback); 105 | 106 | /** 107 | * Unregister GPIO pin callback. 108 | * 109 | * @param pin GPIO pin identifier 110 | * @return 0 on success, negative error code on failure 111 | */ 112 | int ocre_gpio_unregister_callback(int pin); 113 | 114 | /** 115 | * Clean up GPIO resources for a WASM container. 116 | * 117 | * @param module_inst WASM module instance 118 | */ 119 | void ocre_gpio_cleanup_container(wasm_module_inst_t module_inst); 120 | 121 | /** 122 | * Set the active WASM module instance for GPIO operations. 123 | * 124 | * @param module_inst WASM module instance 125 | */ 126 | void ocre_gpio_set_module_inst(wasm_module_inst_t module_inst); 127 | 128 | /** 129 | * Set the WASM function that will handle GPIO callbacks. 130 | * 131 | * @param exec_env WASM execution environment 132 | */ 133 | void ocre_gpio_set_dispatcher(wasm_exec_env_t exec_env); 134 | 135 | // WASM-exposed GPIO functions 136 | int ocre_gpio_wasm_init(wasm_exec_env_t exec_env); 137 | int ocre_gpio_wasm_configure(wasm_exec_env_t exec_env, int port, int P_pin, int direction); 138 | int ocre_gpio_wasm_set(wasm_exec_env_t exec_env, int port, int P_pin, int state); 139 | int ocre_gpio_wasm_get(wasm_exec_env_t exec_env, int port, int P_pin); 140 | int ocre_gpio_wasm_toggle(wasm_exec_env_t exec_env, int port, int P_pin); 141 | int ocre_gpio_wasm_register_callback(wasm_exec_env_t exec_env, int port, int P_pin); 142 | int ocre_gpio_wasm_unregister_callback(wasm_exec_env_t exec_env, int port, int P_pin); 143 | 144 | #endif /* OCRE_GPIO_H */ -------------------------------------------------------------------------------- /src/ocre/ocre_sensors/custom,rng-sensor.yaml: -------------------------------------------------------------------------------- 1 | # custom,rng-sensor.yaml 2 | 3 | title: Custom RNG Sensor 4 | 5 | description: | 6 | This is a custom RNG sensor device binding for generating random numbers. 7 | 8 | compatible: "custom,rng-sensor" 9 | 10 | include: base.yaml 11 | 12 | properties: 13 | label: 14 | type: string 15 | required: true 16 | description: Label for the sensor device. 17 | -------------------------------------------------------------------------------- /src/ocre/ocre_sensors/ocre_sensors.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | LOG_MODULE_DECLARE(ocre_sensors, OCRE_LOG_LEVEL); 13 | 14 | #include "ocre_sensors.h" 15 | 16 | #define DEVICE_NODE DT_PATH(devices) 17 | #define HAS_DEVICE_NODES DT_NODE_EXISTS(DEVICE_NODE) && DT_PROP_LEN(DEVICE_NODE, device_list) > 1 18 | #if (CONFIG_OCRE_SENSORS) && (HAS_DEVICE_NODES) 19 | #define EXTRACT_LABELS(node_id, prop, idx) DT_PROP_BY_PHANDLE_IDX_OR(node_id, prop, idx, label, "undefined") 20 | static const char *sensor_discovery_names[] = { 21 | DT_FOREACH_PROP_ELEM_SEP(DEVICE_NODE, device_list, EXTRACT_LABELS, (, ))}; 22 | static int sensor_names_count = sizeof(sensor_discovery_names) / sizeof(sensor_discovery_names[0]); 23 | #else 24 | static const char *sensor_discovery_names[] = {}; 25 | static int sensor_names_count = 0; 26 | #endif 27 | 28 | typedef struct { 29 | const struct device *device; 30 | ocre_sensor_t info; 31 | bool in_use; 32 | } ocre_sensor_internal_t; 33 | 34 | static ocre_sensor_internal_t sensors[CONFIG_MAX_SENSORS] = {0}; 35 | static int sensor_count = 0; 36 | static char sensor_names[CONFIG_MAX_SENSORS][CONFIG_MAX_SENSOR_NAME_LENGTH]; 37 | 38 | static int set_opened_channels(const struct device *dev, sensor_channel_t *channels) { 39 | if (!channels) { 40 | LOG_ERR("Channels array is NULL"); 41 | return -1; 42 | } 43 | 44 | int count = 0; 45 | struct sensor_value value = {}; 46 | 47 | for (int channel = 0; channel < SENSOR_CHAN_ALL && count < CONFIG_MAX_CHANNELS_PER_SENSOR; channel++) { 48 | if (sensor_channel_get(dev, channel, &value) == 0) { 49 | channels[count] = channel; 50 | count++; 51 | } 52 | } 53 | return count; 54 | } 55 | 56 | int ocre_sensors_init(wasm_exec_env_t exec_env) { 57 | memset(sensors, 0, sizeof(sensors)); 58 | memset(sensor_names, 0, sizeof(sensor_names)); 59 | sensor_count = 0; 60 | return 0; 61 | } 62 | 63 | int ocre_sensors_open(wasm_exec_env_t exec_env, ocre_sensor_handle_t handle) { 64 | if (handle < 0 || handle >= sensor_count || !sensors[handle].in_use) { 65 | LOG_ERR("Invalid sensor handle: %d", handle); 66 | return -1; 67 | } 68 | 69 | if (!device_is_ready(sensors[handle].device)) { 70 | LOG_ERR("Device %s is not ready", sensors[handle].info.sensor_name); 71 | return -2; 72 | } 73 | 74 | return 0; 75 | } 76 | 77 | int ocre_sensors_discover(wasm_exec_env_t exec_env) { 78 | const struct device *dev = NULL; 79 | size_t device_count = z_device_get_all_static(&dev); 80 | 81 | if (!dev) { 82 | LOG_ERR("Device list is NULL. Possible memory corruption!"); 83 | return -1; 84 | } 85 | if (device_count == 0) { 86 | LOG_ERR("No static devices found"); 87 | return -1; 88 | } 89 | 90 | LOG_INF("Total static devices found: %zu", device_count); 91 | 92 | for (size_t i = 0; i < device_count && sensor_count < CONFIG_MAX_SENSORS; i++) { 93 | if (!dev[i].name) { 94 | LOG_ERR("Device %zu has NULL name, skipping!", i); 95 | continue; 96 | } 97 | 98 | LOG_INF("Checking device: %s", dev[i].name); 99 | 100 | // Check if device name is in the sensor discovery list 101 | bool sensor_found = false; 102 | for (int j = 0; j < sensor_names_count; j++) { 103 | if (strcmp(dev[i].name, sensor_discovery_names[j]) == 0) { 104 | sensor_found = true; 105 | break; 106 | } 107 | } 108 | if (!sensor_found) { 109 | LOG_WRN("Skipping device, not in sensor list: %s", dev[i].name); 110 | continue; 111 | } 112 | 113 | // if (!device_is_ready(&dev[i])) { 114 | // LOG_WRN("Device %s is not ready, skipping", dev[i].name); 115 | // continue; 116 | // } 117 | 118 | const struct sensor_driver_api *api = (const struct sensor_driver_api *)dev[i].api; 119 | if (!api || !api->channel_get) { 120 | LOG_WRN("Device %s does not support sensor API or channel_get, skipping", dev[i].name); 121 | continue; 122 | } 123 | 124 | // Ensure we don't exceed sensor limit 125 | if (sensor_count >= CONFIG_MAX_SENSORS) { 126 | LOG_WRN("Max sensor limit reached, skipping device: %s", dev[i].name); 127 | continue; 128 | } 129 | 130 | // Initialize the sensor 131 | ocre_sensor_internal_t *sensor = &sensors[sensor_count]; 132 | sensor->device = &dev[i]; 133 | sensor->in_use = true; 134 | sensor->info.handle = sensor_count; 135 | 136 | strncpy(sensor_names[sensor_count], dev[i].name, CONFIG_MAX_SENSOR_NAME_LENGTH - 1); 137 | sensor_names[sensor_count][CONFIG_MAX_SENSOR_NAME_LENGTH - 1] = '\0'; 138 | sensor->info.sensor_name = sensor_names[sensor_count]; 139 | 140 | // Get supported channels 141 | sensor->info.num_channels = set_opened_channels(&dev[i], sensor->info.channels); 142 | if (sensor->info.num_channels <= 0) { 143 | LOG_WRN("Device %s does not have opened channels, skipping", dev[i].name); 144 | continue; 145 | } 146 | 147 | LOG_INF("Device has %d channels", sensor->info.num_channels); 148 | sensor_count++; 149 | } 150 | 151 | LOG_INF("Discovered %d sensors", sensor_count); 152 | return sensor_count; 153 | } 154 | 155 | int ocre_sensors_get_handle(wasm_exec_env_t exec_env, int sensor_id) { 156 | if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use) { 157 | return -1; 158 | } 159 | return sensors[sensor_id].info.handle; 160 | } 161 | 162 | int ocre_sensors_get_name(wasm_exec_env_t exec_env, int sensor_id, char *buffer, int buffer_size) { 163 | if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use || !buffer) { 164 | return -1; 165 | } 166 | 167 | int name_len = strlen(sensors[sensor_id].info.sensor_name); 168 | if (name_len >= buffer_size) { 169 | return -2; 170 | } 171 | 172 | strncpy(buffer, sensors[sensor_id].info.sensor_name, buffer_size - 1); 173 | buffer[buffer_size - 1] = '\0'; 174 | return name_len; 175 | } 176 | 177 | int ocre_sensors_get_channel_count(wasm_exec_env_t exec_env, int sensor_id) { 178 | if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use) { 179 | return -1; 180 | } 181 | return sensors[sensor_id].info.num_channels; 182 | } 183 | 184 | int ocre_sensors_get_channel_type(wasm_exec_env_t exec_env, int sensor_id, int channel_index) { 185 | if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use || channel_index < 0 || 186 | channel_index >= sensors[sensor_id].info.num_channels) { 187 | return -1; 188 | } 189 | return sensors[sensor_id].info.channels[channel_index]; 190 | } 191 | 192 | int ocre_sensors_read(wasm_exec_env_t exec_env, int sensor_id, int channel_type) { 193 | if (sensor_id < 0 || sensor_id >= sensor_count || !sensors[sensor_id].in_use) { 194 | return -1; 195 | } 196 | 197 | const struct device *dev = sensors[sensor_id].device; 198 | struct sensor_value value = {}; 199 | 200 | if (sensor_sample_fetch(dev) < 0) { 201 | return -1; 202 | } 203 | 204 | if (sensor_channel_get(dev, channel_type, &value) < 0) { 205 | return -1; 206 | } 207 | 208 | return value.val1 * 1000 + value.val2 / 1000; 209 | } -------------------------------------------------------------------------------- /src/ocre/ocre_sensors/ocre_sensors.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef OCRE_SENSORS_H 9 | #define OCRE_SENSORS_H 10 | 11 | #include 12 | #include 13 | 14 | #define CONFIG_MAX_SENSOR_NAME_LENGTH 125 15 | 16 | typedef int32_t ocre_sensor_handle_t; 17 | 18 | /** 19 | * @brief Enum representing different sensor channels 20 | */ 21 | typedef enum { 22 | SENSOR_CHANNEL_ACCELERATION, 23 | SENSOR_CHANNEL_GYRO, 24 | SENSOR_CHANNEL_MAGNETIC_FIELD, 25 | SENSOR_CHANNEL_LIGHT, 26 | SENSOR_CHANNEL_PRESSURE, 27 | SENSOR_CHANNEL_PROXIMITY, 28 | SENSOR_CHANNEL_HUMIDITY, 29 | SENSOR_CHANNEL_TEMPERATURE, 30 | // Add more channels as needed 31 | } sensor_channel_t; 32 | 33 | /** 34 | * @brief Structure representing a sensor instance 35 | */ 36 | typedef struct ocre_sensor_t { 37 | ocre_sensor_handle_t handle; 38 | char *sensor_name; 39 | int num_channels; 40 | sensor_channel_t channels[]; 41 | } ocre_sensor_t; 42 | /** 43 | * @brief Initialize the sensor system 44 | * 45 | * @param exec_env WASM execution environment 46 | * @return 0 on success 47 | */ 48 | int ocre_sensors_init(wasm_exec_env_t exec_env); 49 | /** 50 | * @brief Discover available sensors 51 | * 52 | * @param exec_env WASM execution environment 53 | * @return Number of discovered sensors, negative error code on failure 54 | */ 55 | int ocre_sensors_discover(wasm_exec_env_t exec_env); 56 | /** 57 | * @brief Open a sensor for use 58 | * 59 | * @param exec_env WASM execution environment 60 | * @param handle Handle of the sensor to open 61 | * @return 0 on success, negative error code on failure 62 | */ 63 | int ocre_sensors_open(wasm_exec_env_t exec_env, ocre_sensor_handle_t handle); 64 | /** 65 | * @brief Get the handle of a sensor 66 | * 67 | * @param exec_env WASM execution environment 68 | * @param sensor_id ID of the sensor 69 | * @return Sensor handle on success, negative error code on failure 70 | */ 71 | int ocre_sensors_get_handle(wasm_exec_env_t exec_env, int sensor_id); 72 | /** 73 | * @brief Get the number of channels available in a sensor 74 | * 75 | * @param exec_env WASM execution environment 76 | * @param sensor_id ID of the sensor 77 | * @return Number of channels on success, negative error code on failure 78 | */ 79 | int ocre_sensors_get_channel_count(wasm_exec_env_t exec_env, int sensor_id); 80 | /** 81 | * @brief Get the type of a specific sensor channel 82 | * 83 | * @param exec_env WASM execution environment 84 | * @param sensor_id ID of the sensor 85 | * @param channel_index Index of the channel 86 | * @return Channel type on success, negative error code on failure 87 | */ 88 | int ocre_sensors_get_channel_type(wasm_exec_env_t exec_env, int sensor_id, int channel_index); 89 | /** 90 | * @brief Read data from a sensor channel 91 | * 92 | * @param exec_env WASM execution environment 93 | * @param sensor_id ID of the sensor 94 | * @param channel_type Type of the channel to read 95 | * @return Sensor value in integer format, negative error code on failure 96 | */ 97 | int ocre_sensors_read(wasm_exec_env_t exec_env, int sensor_id, int channel_type); 98 | 99 | #endif /* OCRE_SENSORS_H */ 100 | -------------------------------------------------------------------------------- /src/ocre/ocre_sensors/rng_sensor.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include "rng_sensor.h" 12 | 13 | #define DT_DRV_COMPAT custom_rng_sensor 14 | 15 | /* Define the sensor channels */ 16 | static enum sensor_channel rng_sensor_channels[] __attribute__((unused)) = { 17 | SENSOR_CHAN_CUSTOM + 1, /* Define a custom channel */ 18 | }; 19 | 20 | /* Define the sensor data structure */ 21 | struct rng_sensor_data { 22 | struct sensor_value value; 23 | }; 24 | 25 | /* Define the sensor driver API functions */ 26 | 27 | /* Function to get sensor data */ 28 | static int rng_sensor_sample_fetch(const struct device *dev, enum sensor_channel chan) { 29 | struct rng_sensor_data *data = dev->data; 30 | 31 | /* Generate a random 32-bit number */ 32 | uint32_t random_number = sys_rand16_get(); 33 | 34 | /* Store the random number in sensor_value */ 35 | data->value.val1 = random_number; /* Integer part */ 36 | data->value.val2 = 0; /* Fractional part */ 37 | 38 | return 0; 39 | } 40 | 41 | /* Function to retrieve sensor data */ 42 | static int rng_sensor_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { 43 | struct rng_sensor_data *data = dev->data; 44 | 45 | if (chan != SENSOR_CHAN_CUSTOM + 1) { 46 | return -ENOTSUP; 47 | } 48 | 49 | *val = data->value; 50 | 51 | return 0; 52 | } 53 | 54 | /* Define the sensor driver API */ 55 | static const struct sensor_driver_api rng_sensor_api = { 56 | .sample_fetch = rng_sensor_sample_fetch, 57 | .channel_get = rng_sensor_channel_get, 58 | }; 59 | 60 | /* Initialization function */ 61 | int rng_sensor_init(const struct device *dev) { 62 | /* Initialization code if needed */ 63 | return 0; 64 | } 65 | 66 | // /* Define the sensor device */ 67 | #if DT_NODE_EXISTS(DT_DRV_INST(0)) 68 | static struct rng_sensor_data rng_sensor_data; 69 | 70 | DEVICE_DT_DEFINE(DT_DRV_INST(0), rng_sensor_init, NULL, &rng_sensor_data, NULL, POST_KERNEL, 71 | CONFIG_SENSOR_INIT_PRIORITY, &rng_sensor_api); 72 | #endif 73 | -------------------------------------------------------------------------------- /src/ocre/ocre_sensors/rng_sensor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef RNG_SENSOR_H 9 | #define RNG_SENSOR_H 10 | 11 | #include 12 | #include 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | #define SENSOR_CHAN_CUSTOM 1 18 | int rng_sensor_init(const struct device *dev); 19 | 20 | #ifdef __cplusplus 21 | } 22 | #endif 23 | 24 | #endif /* RNG_SENSOR_H */ -------------------------------------------------------------------------------- /src/ocre/ocre_sensors/usage.md: -------------------------------------------------------------------------------- 1 | 1. Initializing the Sensor Environment 2 | 3 | ``` 4 | ocre_sensors_status_t status; 5 | 6 | status = ocre_sensors_init(); 7 | 8 | if (status != SENSOR_API_STATUS_INITIALIZED) { 9 | 10 | // Handle initialization error 11 | 12 | } 13 | ``` 14 | 15 | 2. Discovering Sensors 16 | 17 | ``` 18 | ocre_sensor_t sensors[MAX_SENSORS]; 19 | 20 | status = ocre_sensors_discover_sensors(sensors); 21 | 22 | if (status != SENSOR_API_STATUS_INITIALIZED) { 23 | 24 | // Handle discovery error 25 | 26 | } 27 | ``` 28 | 29 | 3. Opening a Sensor Channel 30 | 31 | ``` 32 | ocre_sensor_handle_t sensor_handle; 33 | 34 | status = ocre_sensors_open_channel(&sensor_handle); 35 | 36 | if (status != 0) { 37 | 38 | // Handle channel open error 39 | 40 | } 41 | ``` 42 | 43 | 4. Reading Sensor Data 44 | 45 | ``` 46 | ocre_sensors_sample_t sample = sensor_read_sample(&sensor_handle); 47 | ``` 48 | 49 | 50 | 51 | 5. Accessing Specific Sensor Channels 52 | 53 | ``` 54 | sensor_channel_t temperature = sensor_get_channel(sample, SENSOR_CHANNEL_TEMPERATURE); 55 | ``` 56 | 57 | 6. Setting a Sensor Trigger 58 | 59 | ``` 60 | int subscription_id; 61 | 62 | status = ocre_sensors_set_trigger(sensor_handle, SENSOR_CHANNEL_TEMPERATURE, DATA_READY, my_callback, &subscription_id); 63 | 64 | if (status != 0) { 65 | 66 | // Handle trigger set error 67 | 68 | } 69 | ``` 70 | 71 | 7. Clearing a Sensor Trigger 72 | 73 | ``` 74 | status = ocre_sensors_clear_trigger(sensor_handle, SENSOR_CHANNEL_TEMPERATURE, subscription_id); 75 | 76 | if (status != 0) { 77 | 78 | // Handle trigger clear error 79 | 80 | }``` 81 | 82 | 8. Cleaning Up the Sensor Environment 83 | 84 | ```status = ocre_sensors_cleanup(); 85 | 86 | if (status != 0) { 87 | 88 | // Handle cleanup error 89 | 90 | } 91 | ``` 92 | 93 | Usage 94 | 95 | ``` 96 | 97 | #include 98 | 99 | #include 100 | 101 | #include "ocre_sensors.h" 102 | 103 | 104 | 105 | // Define the callback function to handle trigger events 106 | 107 | void my_callback(ocre_sensor_handle_t sensor_handle, sensor_channel_t channel, const ocre_sensor_value *data, void *ptr) { 108 | 109 | printf("Trigger event on sensor %d, channel %d\n", sensor_handle.id, channel); 110 | 111 | printf("Sensor data: Integer = %d, Floating = %d\n", data->integer, data->floating); 112 | 113 | } 114 | 115 | 116 | 117 | // Main function demonstrating the use of the Ocre Sensors API 118 | 119 | void main(void) { 120 | 121 | ocre_sensors_status_t status; 122 | 123 | ocre_sensor_t sensors[MAX_SENSORS]; // Array to hold discovered sensors 124 | 125 | ocre_sensor_handle_t sensor_handle; // Handle for the sensor to be used 126 | 127 | int subscription_id; // ID for the trigger subscription 128 | 129 | 130 | 131 | // Step 1: Initialize the sensors environment 132 | 133 | status = ocre_sensors_init(); 134 | 135 | if (status != SENSOR_API_STATUS_INITIALIZED) { 136 | 137 | printf("Failed to initialize sensors. Status: %d\n", status); 138 | 139 | return; 140 | 141 | } 142 | 143 | 144 | 145 | // Step 2: Discover available sensors 146 | 147 | status = ocre_sensors_discover_sensors(sensors); 148 | 149 | if (status != SENSOR_API_STATUS_INITIALIZED) { 150 | 151 | printf("Failed to discover sensors. Status: %d\n", status); 152 | 153 | return; 154 | 155 | } 156 | 157 | 158 | 159 | // Step 3: Open a channel for the first discovered sensor 160 | 161 | sensor_handle = sensors[0].handle; // Assuming at least one sensor is available 162 | 163 | status = ocre_sensors_open_channel(&sensor_handle); 164 | 165 | if (status != 0) { 166 | 167 | printf("Failed to open sensor channel. Status: %d\n", status); 168 | 169 | return; 170 | 171 | } 172 | 173 | 174 | 175 | // Step 4: Read a sample from the sensor 176 | 177 | ocre_sensors_sample_t sample = sensor_read_sample(&sensor_handle); 178 | 179 | sensor_channel_t temperature = sensor_get_channel(sample, SENSOR_CHANNEL_TEMPERATURE); 180 | 181 | printf("Current temperature: %d\n", temperature); 182 | 183 | 184 | 185 | // Step 5: Set a trigger on the temperature channel 186 | 187 | status = ocre_sensors_set_trigger(sensor_handle, SENSOR_CHANNEL_TEMPERATURE, DATA_READY, my_callback, &subscription_id); 188 | 189 | if (status != 0) { 190 | 191 | printf("Failed to set trigger. Status: %d\n", status); 192 | 193 | return; 194 | 195 | } 196 | 197 | 198 | 199 | // Simulate waiting for trigger events (replace with actual logic as needed) 200 | 201 | k_sleep(K_SECONDS(10)); // Wait for 10 seconds to allow triggers to occur 202 | 203 | 204 | 205 | // Step 6: Clear the trigger subscription 206 | 207 | status = ocre_sensors_clear_trigger(sensor_handle, SENSOR_CHANNEL_TEMPERATURE, subscription_id); 208 | 209 | if (status != 0) { 210 | 211 | printf("Failed to clear trigger. Status: %d\n", status); 212 | 213 | return; 214 | 215 | } 216 | 217 | 218 | 219 | // Step 7: Clean up the sensors environment 220 | 221 | status = ocre_sensors_cleanup(); 222 | 223 | if (status != 0) { 224 | 225 | printf("Failed to clean up sensors. Status: %d\n", status); 226 | 227 | return; 228 | 229 | } 230 | 231 | 232 | 233 | printf("Sensor operations completed successfully.\n"); 234 | 235 | } 236 | ``` -------------------------------------------------------------------------------- /src/ocre/ocre_timers/ocre_timer.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #include 9 | #include "ocre_timer.h" 10 | #include "wasm_export.h" 11 | #include 12 | #include 13 | LOG_MODULE_DECLARE(ocre_cs_component, OCRE_LOG_LEVEL); 14 | #include 15 | #include 16 | #include 17 | 18 | #define TIMER_STACK_SIZE 2048 19 | #define TIMER_THREAD_PRIORITY 5 20 | #define WASM_STACK_SIZE (8 * 1024) 21 | 22 | typedef struct { 23 | struct k_timer timer; 24 | bool in_use; 25 | uint32_t id; 26 | } k_timer_ocre; 27 | 28 | static K_THREAD_STACK_DEFINE(timer_thread_stack, TIMER_STACK_SIZE); 29 | static struct k_thread timer_thread; 30 | static k_tid_t timer_thread_id; 31 | 32 | K_MSGQ_DEFINE(timer_msgq, sizeof(uint32_t), 10, 4); 33 | 34 | // Timer management 35 | static k_timer_ocre timers[CONFIG_MAX_TIMERS] = {0}; 36 | static wasm_function_inst_t timer_dispatcher_func = NULL; 37 | static bool timer_system_initialized = false; 38 | static wasm_module_inst_t current_module_inst = NULL; 39 | static wasm_exec_env_t shared_exec_env = NULL; 40 | 41 | void ocre_timer_cleanup_container(wasm_module_inst_t module_inst) { 42 | if (!timer_system_initialized || !module_inst) { 43 | LOG_ERR("Timer system not properly initialized"); 44 | return; 45 | } 46 | 47 | // Only clean up timers if they belong to the specified module instance 48 | if (module_inst != current_module_inst) { 49 | LOG_WRN("Cleanup requested for non-active module instance"); 50 | return; 51 | } 52 | 53 | int cleaned_count = 0; 54 | for (int i = 0; i < CONFIG_MAX_TIMERS; i++) { 55 | if (timers[i].in_use) { 56 | k_timer_stop(&timers[i].timer); 57 | timers[i].in_use = false; 58 | timers[i].id = 0; 59 | cleaned_count++; 60 | } 61 | } 62 | 63 | LOG_INF("Cleaned up %d timers for container", cleaned_count); 64 | } 65 | 66 | // Thread function to process timer callbacks 67 | static void timer_thread_fn(void *arg1, void *arg2, void *arg3) { 68 | uint32_t timer_id; 69 | 70 | while (1) { 71 | // Wait for a timer message 72 | if (k_msgq_get(&timer_msgq, &timer_id, K_FOREVER) == 0) { 73 | if (!timer_dispatcher_func || !current_module_inst || !shared_exec_env) { 74 | LOG_ERR("Timer system not properly initialized"); 75 | continue; 76 | } 77 | 78 | LOG_DBG("Processing timer ID: %d", timer_id); 79 | uint32_t args[1] = {timer_id}; 80 | 81 | // Execute the WASM callback 82 | bool call_success = wasm_runtime_call_wasm(shared_exec_env, timer_dispatcher_func, 1, args); 83 | 84 | if (!call_success) { 85 | const char *error = wasm_runtime_get_exception(current_module_inst); 86 | LOG_ERR("Failed to call WASM function: %s", error ? error : "Unknown error"); 87 | } else { 88 | LOG_INF("Successfully called WASM function for timer %d", timer_id); 89 | } 90 | } 91 | } 92 | } 93 | 94 | static void wasm_timer_callback(struct k_timer *timer) { 95 | for (int i = 0; i < CONFIG_MAX_TIMERS; i++) { 96 | if (&timers[i].timer == timer && timers[i].in_use) { 97 | // Send timer ID to the processing thread 98 | if (k_msgq_put(&timer_msgq, &timers[i].id, K_NO_WAIT) != 0) { 99 | LOG_ERR("Failed to queue timer callback for ID: %d", timers[i].id); 100 | } 101 | break; 102 | } 103 | } 104 | } 105 | 106 | void ocre_timer_set_module_inst(wasm_module_inst_t module_inst) { 107 | current_module_inst = module_inst; 108 | if (shared_exec_env) { 109 | wasm_runtime_destroy_exec_env(shared_exec_env); 110 | } 111 | shared_exec_env = wasm_runtime_create_exec_env(module_inst, WASM_STACK_SIZE); 112 | } 113 | 114 | static k_timer_ocre *get_timer_from_id(ocre_timer_t id) { 115 | if (id == 0 || id > CONFIG_MAX_TIMERS) { 116 | return NULL; 117 | } 118 | return &timers[id - 1]; 119 | } 120 | 121 | void ocre_timer_init(void) { 122 | if (!timer_system_initialized) { 123 | // Initialize timer array 124 | for (int i = 0; i < CONFIG_MAX_TIMERS; i++) { 125 | timers[i].in_use = false; 126 | timers[i].id = 0; 127 | } 128 | 129 | // Create the timer processing thread 130 | timer_thread_id = k_thread_create(&timer_thread, timer_thread_stack, K_THREAD_STACK_SIZEOF(timer_thread_stack), 131 | timer_thread_fn, NULL, NULL, NULL, TIMER_THREAD_PRIORITY, 0, K_NO_WAIT); 132 | 133 | if (timer_thread_id == NULL) { 134 | LOG_ERR("Failed to create timer thread"); 135 | return; 136 | } 137 | 138 | k_thread_name_set(timer_thread_id, "timer_thread"); 139 | timer_system_initialized = true; 140 | LOG_INF("Timer system initialized with dedicated thread"); 141 | } 142 | } 143 | 144 | int ocre_timer_create(wasm_exec_env_t exec_env, int id) { 145 | if (!timer_system_initialized || !current_module_inst) { 146 | LOG_ERR("Timer system not properly initialized"); 147 | errno = EINVAL; 148 | return -1; 149 | } 150 | 151 | if (id <= 0 || id > CONFIG_MAX_TIMERS) { 152 | LOG_ERR("Invalid timer ID: %d (Expected between 1-%d)", id, CONFIG_MAX_TIMERS); 153 | errno = EINVAL; 154 | return -1; 155 | } 156 | 157 | k_timer_ocre *timer = get_timer_from_id(id); 158 | if (timer->in_use) { 159 | LOG_ERR("Timer ID %d is already in use", id); 160 | errno = EEXIST; 161 | return -1; 162 | } 163 | 164 | ocre_timer_set_dispatcher(exec_env); 165 | k_timer_init(&timer->timer, wasm_timer_callback, NULL); 166 | timer->in_use = true; 167 | timer->id = id; 168 | 169 | LOG_INF("Timer created successfully: ID %d", id); 170 | return 0; 171 | } 172 | 173 | int ocre_timer_delete(wasm_exec_env_t exec_env, ocre_timer_t id) { 174 | k_timer_ocre *timer = get_timer_from_id(id); 175 | if (!timer || !timer->in_use) { 176 | LOG_ERR("ERROR: timer %d not found or not in use\n", id); 177 | errno = EINVAL; 178 | return -1; 179 | } 180 | 181 | k_timer_stop(&timer->timer); 182 | timer->in_use = false; 183 | return 0; 184 | } 185 | 186 | int ocre_timer_start(wasm_exec_env_t exec_env, ocre_timer_t id, int interval, int is_periodic) { 187 | LOG_INF("Timer start called for ID: %d\n", id); 188 | k_timer_ocre *timer = get_timer_from_id(id); 189 | if (!timer || !timer->in_use) { 190 | LOG_ERR("ERROR: timer %d not found or not in use\n", id); 191 | errno = EINVAL; 192 | return -1; 193 | } 194 | 195 | if (interval <= 0) { 196 | LOG_ERR("Invalid interval: %d\n", interval); 197 | errno = EINVAL; 198 | return -1; 199 | } 200 | 201 | k_timeout_t start_timeout = K_MSEC(interval); 202 | k_timeout_t repeat_timeout = is_periodic ? K_MSEC(interval) : K_NO_WAIT; 203 | 204 | k_timer_start(&timer->timer, start_timeout, repeat_timeout); 205 | return 0; 206 | } 207 | 208 | int ocre_timer_stop(wasm_exec_env_t exec_env, ocre_timer_t id) { 209 | k_timer_ocre *timer = get_timer_from_id(id); 210 | if (!timer || !timer->in_use) { 211 | LOG_ERR("ERROR: timer %d not found or not in use\n", id); 212 | errno = EINVAL; 213 | return -1; 214 | } 215 | 216 | k_timer_stop(&timer->timer); 217 | return 0; 218 | } 219 | 220 | int ocre_timer_get_remaining(wasm_exec_env_t exec_env, ocre_timer_t id) { 221 | k_timer_ocre *timer = get_timer_from_id(id); 222 | if (!timer) { 223 | LOG_ERR("ERROR: Timer ID %d not found", id); 224 | errno = EINVAL; 225 | return -1; 226 | } 227 | if (!timer->in_use) { 228 | LOG_ERR("ERROR: Timer ID %d is not in use", id); 229 | errno = EINVAL; 230 | return -1; 231 | } 232 | k_ticks_t remaining_ticks = k_timer_remaining_ticks(&timer->timer); 233 | uint32_t remaining_ms = k_ticks_to_ms_floor64(remaining_ticks); 234 | 235 | return (int)remaining_ms; 236 | } 237 | void ocre_timer_set_dispatcher(wasm_exec_env_t exec_env) { 238 | if (!current_module_inst) { 239 | LOG_ERR("No active WASM module instance"); 240 | return; 241 | } 242 | 243 | wasm_function_inst_t func = wasm_runtime_lookup_function(current_module_inst, "timer_callback"); 244 | if (!func) { 245 | LOG_ERR("Failed to find 'timer_callback' in WASM module"); 246 | return; 247 | } 248 | 249 | timer_dispatcher_func = func; 250 | LOG_INF("WASM timer dispatcher function set successfully"); 251 | } -------------------------------------------------------------------------------- /src/ocre/ocre_timers/ocre_timer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef OCRE_TIMER_H 9 | #define OCRE_TIMER_H 10 | 11 | #include 12 | #include "wasm_export.h" 13 | 14 | /** 15 | * @typedef ocre_timer_t 16 | * @brief Timer identifier type 17 | */ 18 | typedef int ocre_timer_t; 19 | 20 | void ocre_timer_init(void); 21 | 22 | void ocre_timer_cleanup_container(wasm_module_inst_t module_inst); 23 | 24 | void ocre_timer_set_module_inst(wasm_module_inst_t module_inst); 25 | 26 | /** 27 | * @brief Creates a timer with the specified ID 28 | * 29 | * @param id Timer identifier (must be between 1 and MAX_TIMERS) 30 | * @return 0 on success, -1 on error with errno set 31 | * @retval EINVAL Invalid timer ID 32 | * @retval EEXIST Timer ID already in use 33 | */ 34 | int ocre_timer_create(wasm_exec_env_t exec_env, int id); 35 | 36 | /** 37 | * @brief Deletes a timer 38 | * 39 | * 40 | * @param id Timer identifier 41 | * @return 0 on success, -1 on error with errno set 42 | * @retval EINVAL Invalid timer ID or timer not found 43 | */ 44 | int ocre_timer_delete(wasm_exec_env_t exec_env, ocre_timer_t id); 45 | 46 | /** 47 | * @brief Starts a timer 48 | * 49 | * @param id Timer identifier 50 | * @param interval Timer interval in milliseconds 51 | * @param is_periodic True for periodic timer, false for one-shot 52 | * @return 0 on success, -1 on error with errno set 53 | * @retval EINVAL Invalid timer ID or timer not found 54 | */ 55 | int ocre_timer_start(wasm_exec_env_t exec_env, ocre_timer_t id, int interval, int is_periodic); 56 | 57 | /** 58 | * @brief Stops a timer 59 | * 60 | * @param id Timer identifier 61 | * @return 0 on success, -1 on error with errno set 62 | * @retval EINVAL Invalid timer ID or timer not found 63 | */ 64 | int ocre_timer_stop(wasm_exec_env_t exec_env, ocre_timer_t id); 65 | 66 | /** 67 | * @brief Gets the remaining time for a timer 68 | * 69 | * @param id Timer identifier 70 | * @return Remaining time in milliseconds, or -1 on error with errno set 71 | * @retval EINVAL Invalid timer ID or timer not found 72 | */ 73 | int ocre_timer_get_remaining(wasm_exec_env_t exec_env, ocre_timer_t id); 74 | 75 | /** 76 | * @brief Sets the WASM dispatcher function for timer callbacks 77 | * 78 | * @param func WASM function instance to be called when timer expires 79 | */ 80 | void ocre_timer_set_dispatcher(wasm_exec_env_t exec_env); 81 | 82 | #endif /* OCRE_TIMER_H */ 83 | -------------------------------------------------------------------------------- /src/ocre/sm/sm.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #include 9 | #include 10 | LOG_MODULE_REGISTER(state_machine, OCRE_LOG_LEVEL); 11 | 12 | #include "sm.h" 13 | #include 14 | 15 | void sm_init(state_machine_t *sm, struct k_msgq *msgq, void *msg, void *custom_ctx, const struct smf_state *hsm) { 16 | sm->hsm = hsm; 17 | sm->msgq = msgq; 18 | sm->ctx.event.msg = msg; 19 | sm->ctx.custom_ctx = custom_ctx; 20 | } 21 | 22 | int sm_run(state_machine_t *sm, int initial_state) { 23 | int ret; 24 | 25 | smf_set_initial(SMF_CTX(&sm->ctx), &sm->hsm[initial_state]); 26 | 27 | while (true) { 28 | k_msgq_get(sm->msgq, sm->ctx.event.msg, K_FOREVER); 29 | sm->ctx.event.handled = false; 30 | 31 | ret = smf_run_state(SMF_CTX(&sm->ctx)); 32 | 33 | if (ret) { 34 | LOG_ERR("State machine error: %d", ret); 35 | break; 36 | } 37 | 38 | if (!sm->ctx.event.handled) { 39 | LOG_ERR("Unhandled event"); 40 | } 41 | 42 | // Yield the current thread to allow the queue events to be processed 43 | k_yield(); 44 | } 45 | 46 | return ret; 47 | } 48 | 49 | int sm_transition(state_machine_t *sm, int target_state) { 50 | if (!sm->hsm) { 51 | LOG_ERR("State machine has not been initialized"); 52 | return -EINVAL; 53 | } 54 | 55 | smf_set_state(SMF_CTX(&sm->ctx), &sm->hsm[target_state]); 56 | 57 | return 0; 58 | } 59 | 60 | int sm_init_event_timer(state_machine_t *sm, int timer_id, void *timer_cb) { 61 | if (timer_id < 0 || timer_id >= MAX_TIMERS) { 62 | LOG_ERR("Invalid timer id: %d", timer_id); 63 | return -EINVAL; 64 | } 65 | 66 | k_timer_init(&sm->timers[timer_id], timer_cb, NULL); 67 | return 0; 68 | } 69 | 70 | int sm_set_event_timer(state_machine_t *sm, int timer_id, k_timeout_t duration, k_timeout_t period) { 71 | if (timer_id < 0 || timer_id >= MAX_TIMERS) { 72 | LOG_ERR("Invalid timer id: %d", timer_id); 73 | return -EINVAL; 74 | } 75 | 76 | k_timer_start(&sm->timers[timer_id], duration, period); 77 | return 0; 78 | } 79 | 80 | int sm_clear_event_timer(state_machine_t *sm, int timer_id) { 81 | if (timer_id < 0 || timer_id >= MAX_TIMERS) { 82 | LOG_ERR("Invalid timer id: %d", timer_id); 83 | return -EINVAL; 84 | } 85 | 86 | k_timer_stop(&sm->timers[timer_id]); 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /src/ocre/sm/sm.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef SM_H 9 | #define SM_H 10 | 11 | #include 12 | #include 13 | 14 | #define MAX_TIMERS 3 15 | 16 | #define SM_RETURN_IF_EVENT_HANDLED(o) \ 17 | if (((struct sm_ctx *)o)->event.handled) \ 18 | return 19 | #define SM_MARK_EVENT_HANDLED(o) ((struct sm_ctx *)o)->event.handled = true 20 | #define SM_GET_EVENT(o) ((struct sm_ctx *)o)->event.msg 21 | #define SM_GET_CUSTOM_CTX(o) ((struct sm_ctx *)o)->custom_ctx 22 | 23 | #define EVENT_LOG_MSG(fmt, event) LOG_DBG(fmt, event) 24 | 25 | struct sm_ctx { 26 | struct smf_ctx ctx; 27 | struct { 28 | bool handled; 29 | void *msg; 30 | } event; 31 | void *custom_ctx; 32 | }; 33 | 34 | typedef struct state_machine { 35 | struct k_msgq *msgq; 36 | struct k_timer timers[MAX_TIMERS]; 37 | struct sm_ctx ctx; 38 | const struct smf_state *hsm; 39 | } state_machine_t; 40 | 41 | int sm_transition(state_machine_t *sm, int target_state); 42 | 43 | int sm_init_event_timer(state_machine_t *sm, int timer_id, void *timer_cb); 44 | 45 | int sm_set_event_timer(state_machine_t *sm, int timer_id, k_timeout_t duration, k_timeout_t period); 46 | 47 | int sm_clear_event_timer(state_machine_t *sm, int timer_id); 48 | 49 | int sm_dispatch_event(state_machine_t *sm, void *msg); 50 | 51 | int sm_run(state_machine_t *sm, int initial_state); 52 | 53 | void sm_init(state_machine_t *sm, struct k_msgq *msgq, void *msg, void *custom_ctx, const struct smf_state *hsm); 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/ocre/utils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @copyright Copyright © contributors to Project Ocre, 3 | * which has been established as Project Ocre a Series of LF Projects, LLC 4 | * 5 | * SPDX-License-Identifier: Apache-2.0 6 | */ 7 | 8 | #ifndef OCRE_UTILS_H_ 9 | #define OCRE_UTILS_H 10 | 11 | #include 12 | 13 | /** 14 | * Converts a length-64 array of characters representing a sha256 into 15 | * a length-32 binary representation byte array . 16 | */ 17 | int sha256str_to_bytes(uint8_t *bytes, const uint8_t *str) { 18 | uint8_t tmp; 19 | for (int i = 0; i < 64; i++) { 20 | if (str[i] >= '0' && str[i] <= '9') { 21 | tmp = str[i] - '0'; 22 | } else if (str[i] >= 'a' && str[i] <= 'z') { 23 | tmp = str[i] - 'a' + 10; 24 | } else if (str[i] >= 'A' && str[i] <= 'Z') { 25 | tmp = str[i] - 'A' + 10; 26 | } else { 27 | return -1; 28 | } 29 | 30 | if (i % 2 == 0) { 31 | bytes[i / 2] = tmp << 4; 32 | } else { 33 | bytes[i / 2] |= tmp; 34 | } 35 | } 36 | 37 | return 0; 38 | } 39 | 40 | /** 41 | * Converts a length-32 byte array of a sha256 binary representaton 42 | * into a 64-byte length (plus null-terminator) string. 43 | */ 44 | int sha256bytes_to_str(const uint8_t *bytes, uint8_t *str) { 45 | uint8_t tmp[2]; 46 | for (int i = 0; i < 32; i++) { 47 | tmp[0] = (bytes[i] & 0xF0) >> 4; 48 | tmp[1] = (bytes[i] & 0x0F); 49 | 50 | for (int j = 0; j < 2; j++) { 51 | if (tmp[j] >= 0x0 && tmp[j] <= 0x9) { 52 | tmp[j] += '0'; 53 | } else if (tmp[j] >= 0xA && tmp[j] <= 0xF) { 54 | tmp[j] += ('a' - 0xA); 55 | } else { 56 | return -1; 57 | } 58 | } 59 | 60 | str[2 * i] = tmp[0]; 61 | str[2 * i + 1] = tmp[1]; 62 | } 63 | 64 | // Null terminator 65 | str[64] = '\0'; 66 | 67 | return 0; 68 | } 69 | 70 | #endif -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | In the Ocre testing framework, the Ocre execution is comprised of test groups, test suites, and test cases. 4 | 5 | Test groups represent a group of test suites which have the same environmental prerequisites, and require a 6 | common setup and teardown process, e.g. the Flash Validation test group requires that the DUT board has been 7 | flashed with the Ocre runtime. Test groups will block each other on failure, meaning that if a test group 8 | fails, all subsequent test groups will be skipped. 9 | 10 | Test suites act as a way to logically split up test cases. For instance, in a test group for container workloads, 11 | Test suite A might contain testcases for single container workloads, and test suite B might contain testcases for 12 | multi-container workloads. Test suites are non blocking on one another on failure. 13 | 14 | Test cases are the individual tests, and are literally a python or bash script (or any other language) which runs 15 | some arbitrary code according to the test plan, and then exits / returns an exit code of 0 on success and 1 on 16 | failure. 17 | 18 | ## Adding Test Groups, Test Suites, and Test Cases. 19 | 20 | To add a test group, you must create a new directory under the /tests/ dir, named after the new test group. Then, 21 | add a config.json file in the directory according to the format given below. Finally, add a step to the 22 | /.github/workflows/tests.yml file which runs the beginTests.sh against your new test group. 23 | 24 | To add a new testcase, the only requirement is that the testcase script file be placed under a testgroup dir, and 25 | that it exits with 0 on success and 1 on failure. 26 | 27 | 28 | ```json 29 | { 30 | "name": "Name of test group", 31 | "description": "Helpful description of the test group", 32 | "setup": [ 33 | { 34 | "name": "Name of script", 35 | "exec": "execution command" 36 | } 37 | ], 38 | "test_suites": [ 39 | { 40 | "name": "Name of test suite", 41 | "description": "Quick description", 42 | "test_cases": [ 43 | { 44 | "name": "Name of test case", 45 | "description": "Quick description", 46 | "exec": "execution command" 47 | } 48 | ] 49 | } 50 | ], 51 | "cleanup": [ 52 | { 53 | "name": "Name of script", 54 | "exec": "execution command" 55 | } 56 | ] 57 | } 58 | ``` 59 | 60 | Execution commands are run with `bash -c "execution command"`. 61 | -------------------------------------------------------------------------------- /tests/beginTests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TG=$1 4 | LOGFILE="/tmp/$TG.log" 5 | 6 | clStr() { 7 | ARG=$1 8 | echo "${ARG:1:-1}" 9 | } 10 | 11 | CONF=groups/$TG/config.json 12 | NAME=$(clStr "$(cat $CONF | jq .name)") 13 | DESCRIPTION=$(clStr "$(cat $CONF | jq .description)") 14 | 15 | rm $LOGFILE > /dev/null 2>&1 16 | touch $LOGFILE 17 | echo "Beginning test group $NAME" >> $LOGFILE 18 | echo $DESCRIPTION >> $LOGFILE 19 | echo >> $LOGFILE 20 | 21 | parseJSON() { 22 | echo $(cat $CONF | jq .$1) 23 | } 24 | 25 | parseJSON2() { 26 | echo $(echo $1 | jq .$2) 27 | } 28 | 29 | parseJSONArray() { 30 | echo $(cat $CONF | jq -r ".$1[] | @base64") 31 | } 32 | 33 | parseJSONArray2() { 34 | echo $(echo $1 | jq -r ".$2[] | @base64") 35 | } 36 | 37 | printHeader() { 38 | LEN=${#1} 39 | FORMAT="" 40 | for ((i = 1; i <= $LEN; i ++)); do 41 | FORMAT+="=" 42 | done 43 | 44 | echo $1 >> $LOGFILE 45 | echo $FORMAT >> $LOGFILE 46 | echo >> $LOGFILE 47 | } 48 | 49 | CWD=$(pwd) 50 | 51 | # Setup 52 | echo "Entering Setup..." >> $LOGFILE 53 | echo >> $LOGFILE 54 | for RAW_ROW in $(parseJSONArray "setup"); do 55 | ROW=$(echo $RAW_ROW | base64 -di) 56 | printHeader "Script: $(clStr "$(parseJSON2 "$ROW" "name")")" 57 | cd groups/$TG 58 | bash -c "bash -c $(parseJSON2 "$ROW" "exec")" &>> $LOGFILE 59 | cd $CWD 60 | echo >> $LOGFILE 61 | done 62 | 63 | # Tests 64 | TEST_GROUP_RESULT=0 65 | echo "Entering Testing..." >> $LOGFILE 66 | echo >> $LOGFILE 67 | for RAW_ROW in $(parseJSONArray "test_suites"); do 68 | ROW=$(echo $RAW_ROW | base64 -di) 69 | 70 | if [[ "$(parseJSON2 "$ROW" "test_cases")" != "null" ]]; then 71 | printHeader "Test Suite: $(clStr "$(parseJSON2 "$ROW" "name")")" >> $LOGFILE 72 | for RAW_TEST_ROW in $(parseJSONArray2 "$ROW" "test_cases"); do 73 | TEST_ROW=$(echo $RAW_TEST_ROW | base64 -di) 74 | 75 | if [[ "$(parseJSON2 "$TEST_ROW" "exec")" != "null" ]]; then 76 | printHeader "Test Case: $(clStr "$(parseJSON2 "$TEST_ROW" "name")")" >> $LOGFILE 77 | cd groups/$TG 78 | bash -c "bash -c $(parseJSON2 "$TEST_ROW" "exec")" &>> $LOGFILE 79 | TESTCASE_RESULT=$? 80 | cd $CWD 81 | echo >> $LOGFILE 82 | if [ "$TESTCASE_RESULT" -eq 0 ]; then 83 | echo $'TEST PASSED\n' >> $LOGFILE 84 | else 85 | echo $'TEST FAILED\n' >> $LOGFILE 86 | TEST_GROUP_RESULT=1 87 | fi 88 | else 89 | echo "Could not figure out what to do with test block $(parseJSON2 "$TEST_ROW" "name")" >> $LOGFILE 90 | exit 1 91 | fi 92 | done 93 | else 94 | echo "Could not figure out what to do with test block $(parseJSON2 "$ROW" "name")" >> $LOGFILE 95 | exit 1 96 | fi 97 | done 98 | 99 | # Setup 100 | echo "Entering Cleanup..." >> $LOGFILE 101 | echo >> $LOGFILE 102 | for RAW_ROW in $(parseJSONArray "cleanup"); do 103 | ROW=$(echo $RAW_ROW | base64 -di) 104 | printHeader "Script: $(clStr "$(parseJSON2 "$ROW" "name")")" 105 | cd groups/$TG 106 | bash -c "bash -c $(parseJSON2 "$ROW" "exec")" &>> $LOGFILE 107 | cd $CWD 108 | echo >> $LOGFILE 109 | done 110 | 111 | echo "Test suite is complete" >> $LOGFILE 112 | 113 | if [ $TEST_GROUP_RESULT -eq 0 ]; then 114 | echo "$NAME test group passed" 115 | else 116 | echo "$NAME test group failed" 117 | fi 118 | 119 | exit $TEST_GROUP_RESULT -------------------------------------------------------------------------------- /tests/groups/flashValidation/clean.sh: -------------------------------------------------------------------------------- 1 | echo "Cleanup is complete" -------------------------------------------------------------------------------- /tests/groups/flashValidation/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Flash Validation", 3 | "description": "Test the Ocre runtime after the flash is complete", 4 | "setup": [ 5 | { 6 | "name": "Flash Validation Setup", 7 | "exec": "bash setup.sh" 8 | } 9 | ], 10 | "test_suites": [ 11 | { 12 | "name": "Runtime Validation Tests", 13 | "description": "Sends a break to the runtime and checks for the expected output", 14 | "test_cases": [ 15 | { 16 | "name": "Check Runtime Hello World", 17 | "exec": "./flash_validation_hello_world.py" 18 | }, 19 | { 20 | "name": "Check Runetime Error", 21 | "exec": "./flash_validation_error.py" 22 | }, 23 | { 24 | "name": "Check Runtime Hello World With Error", 25 | "exec": "./flash_validation_hello_world_error.py" 26 | } 27 | ] 28 | } 29 | ], 30 | "cleanup": [ 31 | { 32 | "name": "Flash Validation Cleanup", 33 | "exec": "bash clean.sh" 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /tests/groups/flashValidation/flash_validation_error.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import serial 4 | import time 5 | import sys 6 | 7 | """ 8 | This testcase is to be used following the flashing of the Ocre runtime to a board. 9 | 10 | The testcase forms a serial connection to the board, sends a break and checks that 11 | there are no instance of the error prefix "E: " in the output returned from the break. 12 | """ 13 | 14 | def main(): 15 | conn = serial.Serial('/dev/ttyACM0', 115200, timeout=1) 16 | conn.send_break(duration=1) 17 | 18 | time.sleep(1) 19 | 20 | print('**** READING RESPONSE FROM BREAK ****\n') 21 | 22 | response = conn.read(1024).decode(errors='ignore') 23 | print(response) 24 | 25 | print('**** CLOSING CONNECTION ****\n') 26 | 27 | conn.close() 28 | 29 | if "E:" not in response: 30 | sys.exit(0) 31 | sys.exit(1) 32 | 33 | 34 | if __name__ == "__main__": 35 | main() 36 | -------------------------------------------------------------------------------- /tests/groups/flashValidation/flash_validation_hello_world.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import serial 4 | import time 5 | import sys 6 | 7 | """ 8 | This testcase is to be used following the flashing of the Ocre runtime to a board. 9 | 10 | The testcase forms a serial connection to the board, sends a break and checks that 11 | the string Hello World! appears in the output of that break command. 12 | """ 13 | 14 | def main(): 15 | conn = serial.Serial('/dev/ttyACM0', 115200, timeout=1) 16 | conn.send_break(duration=1) 17 | 18 | time.sleep(1) 19 | 20 | print('**** READING RESPONSE FROM BREAK ****\n') 21 | 22 | response = conn.read(1024).decode(errors='ignore') 23 | print(response) 24 | 25 | print('**** CLOSING CONNECTION ****\n') 26 | 27 | conn.close() 28 | 29 | if "Hello World!" in response: 30 | sys.exit(0) 31 | sys.exit(1) 32 | 33 | 34 | if __name__ == "__main__": 35 | main() -------------------------------------------------------------------------------- /tests/groups/flashValidation/flash_validation_hello_world_error.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import serial 4 | import time 5 | import sys 6 | 7 | """ 8 | This testcase is to be used following the flashing of the Ocre runtime to a board. 9 | 10 | The testcase forms a serial connection to the board, sends a break and checks that 11 | the string Hello World! appears in the output of that break command, and without any 12 | instances of the error prefix "E: ". 13 | """ 14 | 15 | def main(): 16 | conn = serial.Serial('/dev/ttyACM0', 115200, timeout=1) 17 | conn.send_break(duration=1) 18 | 19 | time.sleep(1) 20 | 21 | print('**** READING RESPONSE FROM BREAK ****\n') 22 | 23 | response = conn.read(1024).decode(errors='ignore') 24 | print(response) 25 | 26 | print('**** CLOSING CONNECTION ****\n') 27 | 28 | conn.close() 29 | 30 | if "Hello World!" in response and "E:" not in response: 31 | sys.exit(0) 32 | sys.exit(1) 33 | 34 | 35 | if __name__ == "__main__": 36 | main() 37 | -------------------------------------------------------------------------------- /tests/groups/flashValidation/setup.sh: -------------------------------------------------------------------------------- 1 | echo "Setup is complete" -------------------------------------------------------------------------------- /tools/automsg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import yaml 5 | 6 | ocre_msg_file_template = """\ 7 | 8 | /** 9 | * @copyright Copyright © contributors to Project Ocre, 10 | * which has been established as Project Ocre a Series of LF Projects, LLC 11 | * 12 | * SPDX-License-Identifier: Apache-2.0 13 | * 14 | * @file messages.h 15 | * 16 | * @details This file contains all message types that components may send to one another. 17 | * DO NOT EDIT THIS FILE. The file is auto-generated at build-time. 18 | * 19 | * How to add messages: 20 | * 1. Define message types in the component, for example, components/your-component/message_types.h 21 | * 2. Create a .yaml definition that maps your message type to a message name 22 | * 3. Build! You can now use the message types in the component implementation 23 | */ 24 | 25 | #ifndef OCRE_MESSAGES_H_G 26 | #define OCRE_MESSAGES_H_G 27 | 28 | #include 29 | 30 | #include 31 | {includes} 32 | 33 | struct base_msg {{ 34 | int msg_id; 35 | int *from; 36 | struct base msg; 37 | }}; 38 | 39 | {message_wrappers} 40 | 41 | {ocre_message} 42 | 43 | #endif""" 44 | 45 | component_message_type_includes_template = """\ 46 | #include 47 | """ 48 | 49 | msg_wrapper_template = """ 50 | struct {message_name} {{ 51 | int msg_id; 52 | int *from; 53 | struct {message_type} msg; 54 | }}; 55 | """ 56 | 57 | ocre_message = """\ 58 | struct ocre_message {{ 59 | uint32_t event; 60 | uint32_t containerId; 61 | union {{ 62 | {message_unions} 63 | }} components; 64 | }};""" 65 | 66 | msg_union_template = """\ 67 | union {{ 68 | {messages} 69 | struct base_msg base_msg; 70 | }} {component}; 71 | """ 72 | 73 | msg_union_member_template = """\ 74 | struct {message_name} {message_name}; 75 | """ 76 | 77 | def automsg(infiles, outfile): 78 | wrapped_messages = set() 79 | unioned_component = set() 80 | component_message_type_includes = set() 81 | 82 | for filepath in infiles: 83 | with open(filepath, 'r') as f: 84 | messages = yaml.safe_load(f) 85 | 86 | component = messages['component'] 87 | unioned_messages = set() 88 | 89 | component_message_type_includes.add(component_message_type_includes_template.format(component=component)) 90 | 91 | for event in messages['events']: 92 | name = "{}_msg".format(event['type']) 93 | type = event['type'] 94 | 95 | wrapped_messages.add(msg_wrapper_template.format(message_name=name, message_type=type)) 96 | unioned_messages.add(msg_union_member_template.format(message_name=name)) 97 | unioned_component.add(msg_union_template.format(component=component, messages=''.join(unioned_messages).strip('\n'))) 98 | 99 | ocre_msg = ocre_message.format(message_unions=''.join(unioned_component).strip('\n')) 100 | 101 | ocre_msg_file = ocre_msg_file_template.format( 102 | includes=''.join(component_message_type_includes).strip('\n'), 103 | message_wrappers=''.join(wrapped_messages).strip('\n'), 104 | ocre_message=ocre_msg) 105 | 106 | with open(outfile, 'w') as f: 107 | f.write(ocre_msg_file) 108 | 109 | if __name__ == '__main__': 110 | parser = argparse.ArgumentParser() 111 | parser.add_argument("infiles", nargs='+') 112 | parser.add_argument("outfile", type=str) 113 | args = parser.parse_args() 114 | 115 | automsg(args.infiles, args.outfile) 116 | -------------------------------------------------------------------------------- /west.yml: -------------------------------------------------------------------------------- 1 | manifest: 2 | projects: 3 | - name: zephyr 4 | revision: v3.7-branch 5 | url: https://github.com/zephyrproject-rtos/zephyr 6 | west-commands: scripts/west-commands.yml 7 | import: true 8 | - name: wasm-micro-runtime 9 | revision: dev/zephyr_file_socket 10 | url: https://github.com/bytecodealliance/wasm-micro-runtime 11 | path: wasm-micro-runtime 12 | 13 | self: 14 | path: application 15 | -------------------------------------------------------------------------------- /zephyr/module.yml: -------------------------------------------------------------------------------- 1 | name: project-ocre 2 | 3 | build: 4 | cmake-ext: True 5 | 6 | --------------------------------------------------------------------------------