diff --git a/include/zephyr/arch/structs.h b/include/zephyr/arch/structs.h index ca452ef17d24..f7eae52f92eb 100644 --- a/include/zephyr/arch/structs.h +++ b/include/zephyr/arch/structs.h @@ -31,6 +31,12 @@ /* Per CPU architecture specifics (empty) */ struct _cpu_arch { +#ifdef __cplusplus + /* This struct will have a size 0 in C which is not allowed in C++ (it'll have a size 1). To + * prevent this, we add a 1 byte dummy variable. + */ + uint8_t dummy; +#endif }; #endif diff --git a/include/zephyr/kernel/thread.h b/include/zephyr/kernel/thread.h index bd8c97d19065..27de6f744c16 100644 --- a/include/zephyr/kernel/thread.h +++ b/include/zephyr/kernel/thread.h @@ -208,6 +208,15 @@ typedef struct k_thread_runtime_stats { uint64_t idle_cycles; #endif + +#if __cplusplus && !defined(CONFIG_SCHED_THREAD_USAGE) && \ + !defined(CONFIG_SCHED_THREAD_USAGE_ANALYSIS) && !defined(CONFIG_SCHED_THREAD_USAGE_ALL) + /* If none of the above Kconfig values are defined, this struct will have a size 0 in C + * which is not allowed in C++ (it'll have a size 1). To prevent this, we add a 1 byte dummy + * variable when the struct would otherwise be empty. + */ + uint8_t dummy; +#endif } k_thread_runtime_stats_t; struct z_poller { diff --git a/modules/Kconfig b/modules/Kconfig index db3647769b18..c582e0ea8556 100644 --- a/modules/Kconfig +++ b/modules/Kconfig @@ -84,6 +84,9 @@ comment "FFF module not available." comment "zcbor module not available." depends on !ZEPHYR_ZCBOR_MODULE +comment "CHRE module not available." + depends on !ZEPHYR_CHRE_MODULE + # This ensures that symbols are available in Kconfig for dependency checking # and referencing, while keeping the settings themselves unavailable when the # modules are not present in the workspace diff --git a/samples/modules/chre/CMakeLists.txt b/samples/modules/chre/CMakeLists.txt new file mode 100644 index 000000000000..fb4f855366c6 --- /dev/null +++ b/samples/modules/chre/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) Google LLC +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(chre_sample) + +FILE(GLOB app_sources src/*.cpp) +target_sources(app PRIVATE ${app_sources}) +target_include_directories(app PRIVATE include) diff --git a/samples/modules/chre/README.rst b/samples/modules/chre/README.rst new file mode 100644 index 000000000000..54b9244d3dca --- /dev/null +++ b/samples/modules/chre/README.rst @@ -0,0 +1,69 @@ +Android's Context Hub Runtime Environment (CHRE) +################################################ + +Android's context hub enables the use of nanoapps. A single nanoapp has 3 entry points seen in +`chre_api/chre/nanoapp.h`_: + +* A ``nanoappStart`` function used to notify the nanoapp that it is now active. +* A ``nanoappHandleEvent`` function used to notify the nanoapp tha an event of interest took place. +* A ``nanoappEnd`` function used to notify the nanoapp that it is now deactivated. + +The CHRE connects to several frameworks called Platform Abstraction Layers (PAL)s. Note that +currently, none of these are implemented for Zephyr, but they are scheduled to be added. These +frameworks include: + +#. *Audio* - a framework allowing nanoapps to get audio events. See `pal/audio.h`_ for API details. +#. *GNSS* - a framework allowing nanoapps to manage location and measurement sessions. See + `pal/gnss.h`_ for API details. +#. *Sensor* - a framework allowing nanoapps to request changes to sensors configuration get + data/bias events. See `pal/sensor.h`_ for API details. +#. *System* - a framework allowing nanoapps to make common system requests such as logging, clock, + and some basic memory allocation/deallocation. See `pal/system.h`_ for API details. +#. *WiFi* - a framework allowing nanoapps to interact with the on board WiFi. See `pal/wifi.h`_ for + API details. +#. *WWAN* - a framework allowing nanoapps to interact with the WWAN module such as getting the + current capabilities and info. See `pal/wwan.h`_ for API details. + +Building and expectations +========================= + +To build the sample use the following west command: + +.. zephyr-app-commands:: + :zephyr-app: samples/modules/chre + :board: native_posix + :goals: build + +Once built and run, the sample application should: + +#. Print a hello message +#. Notify that the event loop started via an ``inf`` level log +#. Notify that a nanoapp was started and assigned an instance/app ID of 1 via a ``dbg`` level log +#. Print a message saying that the nanoapp's start callback was called +#. Send an event of type ``1`` and no data to the nanoapp +#. Notify that the event was processed +#. Call the ``nanoappEnd`` function of the nanoapp +#. Print a message notifying that it's not possible to remove a system level nanoapp +#. Exit the event loop + +Roadmap +======= + +#. Add an implementation of the `pal/sensor.h`_ and `pal/system.h`_ to Zephyr. These will be + standalone modules that can be used independently of CHRE, but when ``CONFIG_CHRE`` is enabled + will also provide an implementation of ``chrePalSensorGetApi()`` and ``struct chrePalSystemApi``. +#. Add a directory ``chre/nanoapps`` which will host various nanoapps to be used by the Zephyr + community. These should each have their own Kconfig to enable them and set the appropriate + dependencies. The first nanoapp will be a lid angle calculator which will use 2 accelerometers. +#. Update the ``overlay.dts`` of this sample application to include 2 emulated accelerometers and + configure them to return scripted data. +#. Run this sample application and watch the nanoapp provide lid angle calculations based on 2 + accelerometers provided by the sensors PAL framework. + +.. _`chre_api/chre/nanoapp.h`: https://cs.android.com/android/platform/superproject/+/master:system/chre/chre_api/include/chre_api/chre/nanoapp.h;drc=7c60a553288d63e6e3370d679803da46dac723a4 +.. _`pal/audio.h`: https://cs.android.com/android/platform/superproject/+/master:system/chre/pal/include/chre/pal/audio.h;l=69;drc=6ca547ad175f80ce9f09f5b7b14fcc6f14565f5c +.. _`pal/gnss.h`: https://cs.android.com/android/platform/superproject/+/master:system/chre/pal/include/chre/pal/gnss.h;l=152;drc=830255234157cc7afe5201dca19a7fb71ea850fe +.. _`pal/sensor.h`: https://cs.android.com/android/platform/superproject/+/master:system/chre/pal/include/chre/pal/sensor.h;l=51;drc=23207906add05054a94dfab41b95bcfc39bedfe4 +.. _`pal/system.h`: https://cs.android.com/android/platform/superproject/+/master:system/chre/pal/include/chre/pal/system.h;l=49;drc=6ca547ad175f80ce9f09f5b7b14fcc6f14565f5c +.. _`pal/wifi.h`: https://cs.android.com/android/platform/superproject/+/master:system/chre/pal/include/chre/pal/wifi.h;l=153;drc=b673b80ed98e1b6e6360bee4ba98e2cd8f4e0935 +.. _`pal/wwan.h`: https://cs.android.com/android/platform/superproject/+/master:system/chre/pal/include/chre/pal/wwan.h;l=69;drc=629361a803cb305c8575b41614e6e071e7141a03 diff --git a/samples/modules/chre/include/apps.hpp b/samples/modules/chre/include/apps.hpp new file mode 100644 index 000000000000..7469826fc92d --- /dev/null +++ b/samples/modules/chre/include/apps.hpp @@ -0,0 +1,17 @@ +/* Copyright (c) 2021 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SAMPLES_APPLICATION_DEVELOPMENT_CHRE_INCLUDE_APPS_H_ +#define SAMPLES_APPLICATION_DEVELOPMENT_CHRE_INCLUDE_APPS_H_ + +#include "chre/core/nanoapp.h" +#include "chre/util/unique_ptr.h" + +namespace chre { + +UniquePtr initializeStaticNanoappEchoApp(); + +} /* namespace chre */ + +#endif /* SAMPLES_APPLICATION_DEVELOPMENT_CHRE_INCLUDE_APPS_H_ */ diff --git a/samples/modules/chre/prj.conf b/samples/modules/chre/prj.conf new file mode 100644 index 000000000000..709c4334fd2f --- /dev/null +++ b/samples/modules/chre/prj.conf @@ -0,0 +1,7 @@ +CONFIG_CHRE=y +CONFIG_LOG=y +CONFIG_CHRE_LOG_LEVEL_DBG=y + +CONFIG_CPLUSPLUS=y +CONFIG_STD_CPP17=y +CONFIG_LIB_CPLUSPLUS=y diff --git a/samples/modules/chre/sample.yaml b/samples/modules/chre/sample.yaml new file mode 100644 index 000000000000..932630ab3349 --- /dev/null +++ b/samples/modules/chre/sample.yaml @@ -0,0 +1,23 @@ +sample: + description: A simple echo app using Android's Context Hub Runtime + Environment (CHRE). + name: chre +tests: + sample.modules.chre: + tags: introduction + harness: console + harness_config: + type: multi_line + ordered: false + regex: + - "Hello CHRE!" + - "\\[.*\\] .* chre: EventLoop start.*" + - "\\[.*\\] .* chre: startNanoapp: Instance ID 1 assigned to app ID 0x0000000000000001.*" + - "EchoApp::nanoappStart\\(\\)" + - "EchoApp::nanoappHandleEvent\\(sender_instance_id=0, event_type=1, event_data@\\(nil\\)\\)" + - "Event \\(1\\) complete!" + - "EchoApp::nanoappEnd\\(\\)" + - "\\[.*\\] .* chre: Exiting EventLoop.*" + integration_platforms: + - native_posix + filter: not CONFIG_MINIMAL_LIBC diff --git a/samples/modules/chre/src/echoapp.cpp b/samples/modules/chre/src/echoapp.cpp new file mode 100644 index 000000000000..b90b3c12e802 --- /dev/null +++ b/samples/modules/chre/src/echoapp.cpp @@ -0,0 +1,43 @@ +/* Copyright (c) 2021 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "chre_api/chre/event.h" +#include "chre/core/event_loop_manager.h" +#include "chre/platform/static_nanoapp_init.h" +#include "chre/util/system/napp_permissions.h" + +namespace +{ +constexpr const uint64_t kAppId = 1; +constexpr const uint32_t kAppVersion = 1; + +chre::Nanoapp *nanoapp = nullptr; + +bool nanoappStart(void) +{ + printk("EchoApp::nanoappStart()\n"); + nanoapp = chre::EventLoopManagerSingleton ::get()->getEventLoop().getCurrentNanoapp(); + nanoapp->registerForBroadcastEvent(CHRE_EVENT_MESSAGE_FROM_HOST); + return true; +} + +void nanoappHandleEvent(uint32_t sender_instance_id, uint16_t event_type, const void *event_data) +{ + printk("EchoApp::nanoappHandleEvent(sender_instance_id=%u, event_type=%u, event_data@%p)\n", + sender_instance_id, event_type, event_data); +} + +void nanoappEnd() +{ + nanoapp->unregisterForBroadcastEvent(0); + nanoapp = nullptr; + printk("EchoApp::nanoappEnd()\n"); +} + +} /* anonymous namespace */ + +CHRE_STATIC_NANOAPP_INIT(EchoApp, kAppId, kAppVersion, chre::NanoappPermissions::CHRE_PERMS_NONE); diff --git a/samples/modules/chre/src/main.cpp b/samples/modules/chre/src/main.cpp new file mode 100644 index 000000000000..3b9197e75489 --- /dev/null +++ b/samples/modules/chre/src/main.cpp @@ -0,0 +1,47 @@ +/* Copyright (c) 2021 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "apps.hpp" +#include "chre/core/event_loop_manager.h" +#include "chre/target_platform/init.h" + +inline const char *boolToString(bool cond) +{ + return cond ? "SUCCESS" : "FAIL"; +} + +void main(void) +{ + auto echo_app = chre::initializeStaticNanoappEchoApp(); + auto& eventLoop = chre::EventLoopManagerSingleton::get()->getEventLoop(); + uint32_t instanceId; + + if (chre::zephyr::init()) { + printk("Failed to initialize!\n"); + return; + } + + printk("Hello CHRE!\n"); + + k_msleep(500); + printk("Starting EchoApp... %s\n", boolToString(eventLoop.startNanoapp(echo_app))); + printk("Nanoapp count=%u\n", eventLoop.getNanoappCount()); + printk("Finding instance ID... %s\n", boolToString(eventLoop.findNanoappInstanceIdByAppId(1, &instanceId))); + printk("Nanoapp count=%u\n", eventLoop.getNanoappCount()); + printk("Instance ID: %u\n", instanceId); + + printk("Sending event %u...\n", eventLoop.getNanoappCount()); + eventLoop.postEventOrDie(CHRE_EVENT_MESSAGE_FROM_HOST, nullptr, [](uint16_t eventType, void *eventData) { + printk("Event (%u) complete!\n", eventType); + }); + + k_sleep(K_MSEC(500)); + printk("Ending EchoApp... %s\n", + boolToString(eventLoop.unloadNanoapp(instanceId, false))); + chre::zephyr::deinit(); + printk("Goodbye!\n"); +} diff --git a/west.yml b/west.yml index 2975a2cb75cd..7ba469199072 100644 --- a/west.yml +++ b/west.yml @@ -28,6 +28,9 @@ manifest: - name: canopennode revision: 53d3415c14d60f8f4bfca54bfbc5d5a667d7e724 path: modules/lib/canopennode + - name: chre + revision: 0edfe2c2ec656afb910cfab8ed59a5ffd59b87c8 + path: modules/lib/chre - name: civetweb revision: 094aeb41bb93e9199d24d665ee43e9e05d6d7b1c path: modules/lib/civetweb