diff --git a/Kconfig.defaults.core b/Kconfig.defaults.core index 3c69b1fe7..53c39d789 100644 --- a/Kconfig.defaults.core +++ b/Kconfig.defaults.core @@ -70,10 +70,28 @@ configdefault INFUSE_EPOCH_TIME default y # Application management +if BOOTLOADER_MCUBOOT || BUILD_WITH_TFM configdefault STREAM_FLASH - default y if BOOTLOADER_MCUBOOT + default y configdefault IMG_MANAGER - default y if BOOTLOADER_MCUBOOT + default y + +if BT_CONN +configdefault MCUMGR + default y +configdefault MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL + default n +configdefault MCUMGR_TRANSPORT_BT + default y +configdefault MCUMGR_GRP_OS_INFUSE + default y +configdefault MCUMGR_GRP_IMG + default y +configdefault ZCBOR + default y +endif # BT_CONN +endif # BOOTLOADER_MCUBOOT || BUILD_WITH_TFM + # KV store configdefault FLASH diff --git a/Kconfig.defaults.ztest b/Kconfig.defaults.ztest index 76699d83f..d3563979b 100644 --- a/Kconfig.defaults.ztest +++ b/Kconfig.defaults.ztest @@ -8,3 +8,6 @@ configdefault ZTEST_STACK_SIZE default 2048 endif # INFUSE_SECURITY + +configdefault MCUMGR_TRANSPORT_WORKQUEUE_STACK_SIZE + default 8192 if COVERAGE_GCOV diff --git a/include/infuse/reboot.h b/include/infuse/reboot.h index eb9d29331..4ec1b6e85 100644 --- a/include/infuse/reboot.h +++ b/include/infuse/reboot.h @@ -46,6 +46,8 @@ enum infuse_reboot_reason { INFUSE_REBOOT_RPC, /* Internal LTE modem fault */ INFUSE_REBOOT_LTE_MODEM_FAULT, + /* MCUmgr request */ + INFUSE_REBOOT_MCUMGR, /* Unknown reboot reason */ INFUSE_REBOOT_UNKNOWN = 255, }; diff --git a/include/infuse/time/epoch.h b/include/infuse/time/epoch.h index 743fabc49..6cd864472 100644 --- a/include/infuse/time/epoch.h +++ b/include/infuse/time/epoch.h @@ -24,6 +24,9 @@ #include #include +/* Time conversion functions */ +#include "epoch_units.h" + #ifdef __cplusplus extern "C" { #endif @@ -145,7 +148,7 @@ static inline uint16_t epoch_time_subseconds(uint64_t epoch_time) */ static inline uint16_t epoch_time_milliseconds(uint64_t epoch_time) { - return ((uint32_t)epoch_time_subseconds(epoch_time) * 1000) / 0x10000; + return k_epoch_to_ms_near32(epoch_time_subseconds(epoch_time)); } /** @@ -309,9 +312,6 @@ void epoch_time_reset(void); #endif /* CONFIG_ZTEST */ -/* Time conversion functions */ -#include "epoch_units.h" - /** * @} */ diff --git a/include/infuse/version.h b/include/infuse/version.h index 2ad4086e7..013693db4 100644 --- a/include/infuse/version.h +++ b/include/infuse/version.h @@ -36,6 +36,17 @@ extern "C" { /* Use MCUboot semantic version definitions */ #define infuse_version mcuboot_img_sem_ver +/** + * @brief Convert version struct to sortable integer + * + * @param v struct infuse_version pointer + * + * @retval uint32_t equivalent integer + */ +#define INFUSE_VERSION_INT(v) \ + ((((uint32_t)(v)->major) << 24) | (((uint32_t)(v)->minor) << 16) | \ + ((uint32_t)(v)->revision)) + /** * @brief Get version of the currently running application * @@ -67,6 +78,34 @@ static inline struct infuse_version application_version_get(void) }; } +/** + * @brief Compare two version structures + * + * Return value follows the convention of the C library `qsort` function. + * + * @note The `build_num` field is ignored for comparison purposes. + * + * @param a First version to compare + * @param b Second version to compare + * + * @retval 1 @a a is an earlier version than @a b + * @retval -1 @a a is a later version than @a b + * @retval 0 if @a a and @a b are the same version + */ +static inline int infuse_version_compare(struct infuse_version *a, struct infuse_version *b) +{ + uint32_t a_int = INFUSE_VERSION_INT(a); + uint32_t b_int = INFUSE_VERSION_INT(b); + + if (a_int < b_int) { + return 1; + } + if (a_int > b_int) { + return -1; + } + return 0; +} + /** * @} */ diff --git a/snippets/infuse/boards/nrf5340dk_nrf5340_cpuapp_ns.overlay b/snippets/infuse/boards/nrf5340dk_nrf5340_cpuapp_ns.overlay index ba940766c..c506754fc 100644 --- a/snippets/infuse/boards/nrf5340dk_nrf5340_cpuapp_ns.overlay +++ b/snippets/infuse/boards/nrf5340dk_nrf5340_cpuapp_ns.overlay @@ -14,9 +14,9 @@ driver = "Driver_FLASH0"; complete = <&flash0>; img-bl2 = <&boot_partition>; - img-primary-secure = <&slot0_partition>; + img-primary-secure = <&slot0_s_partition>; img-primary-nonsecure = <&slot0_ns_partition>; - img-secondary-secure = <&slot1_partition>; + img-secondary-secure = <&slot1_s_partition>; img-secondary-nonsecure = <&slot1_ns_partition>; partition-ps = <&tfm_ps_partition>; partition-its = <&tfm_its_partition>; diff --git a/snippets/infuse/boards/nrf7002dk_nrf5340_cpuapp_common.dtsi b/snippets/infuse/boards/nrf7002dk_nrf5340_cpuapp_common.dtsi index 02a489a69..3cbaefe0b 100644 --- a/snippets/infuse/boards/nrf7002dk_nrf5340_cpuapp_common.dtsi +++ b/snippets/infuse/boards/nrf7002dk_nrf5340_cpuapp_common.dtsi @@ -1,7 +1,9 @@ /* MCUboot secondary on external flash */ /delete-node/ &slot0_partition; +/delete-node/ &slot0_s_partition; /delete-node/ &slot0_ns_partition; /delete-node/ &slot1_partition; +/delete-node/ &slot1_s_partition; /delete-node/ &slot1_ns_partition; / { @@ -63,9 +65,13 @@ }; slot0_partition: partition@10000 { label = "image-0"; + reg = <0x00010000 0x000F0000>; + }; + slot0_s_partition: subpartition@10000 { + label = "image-0-secure"; reg = <0x00010000 0x00030000>; }; - slot0_ns_partition: partition@40000 { + slot0_ns_partition: subpartition@40000 { label = "image-0-nonsecure"; reg = <0x00040000 0xC0000>; }; @@ -96,7 +102,11 @@ label = "image-1"; reg = <0x00000000 0x30000>; }; - slot1_ns_partition: partition@30000 { + slot1_s_partition: subpartition@0 { + label = "image-1-secure"; + reg = <0x00000000 0x30000>; + }; + slot1_ns_partition: subpartition@30000 { label = "image-1-nonsecure"; reg = <0x00030000 0xC0000>; }; diff --git a/snippets/infuse/boards/nrf7002dk_nrf5340_cpuapp_ns.overlay b/snippets/infuse/boards/nrf7002dk_nrf5340_cpuapp_ns.overlay index 4d89376ff..5a2ae0203 100644 --- a/snippets/infuse/boards/nrf7002dk_nrf5340_cpuapp_ns.overlay +++ b/snippets/infuse/boards/nrf7002dk_nrf5340_cpuapp_ns.overlay @@ -19,7 +19,7 @@ driver = "Driver_FLASH0"; complete = <&flash0>; img-bl2 = <&boot_partition>; - img-primary-secure = <&slot0_partition>; + img-primary-secure = <&slot0_s_partition>; img-primary-nonsecure = <&slot0_ns_partition>; partition-ps = <&tfm_ps_partition>; partition-its = <&tfm_its_partition>; @@ -33,7 +33,7 @@ complete = <&mx25r64>; erase-block-size = <4096>; write-block-size = <1>; - img-secondary-secure = <&slot1_partition>; + img-secondary-secure = <&slot1_s_partition>; img-secondary-nonsecure = <&slot1_ns_partition>; }; }; diff --git a/snippets/infuse/boards/nrf9151dk_nrf9151_ns.overlay b/snippets/infuse/boards/nrf9151dk_nrf9151_ns.overlay index a37e79008..3136156d2 100644 --- a/snippets/infuse/boards/nrf9151dk_nrf9151_ns.overlay +++ b/snippets/infuse/boards/nrf9151dk_nrf9151_ns.overlay @@ -13,9 +13,9 @@ driver = "Driver_FLASH0"; complete = <&flash0>; img-bl2 = <&boot_partition>; - img-primary-secure = <&slot0_partition>; + img-primary-secure = <&slot0_s_partition>; img-primary-nonsecure = <&slot0_ns_partition>; - img-secondary-secure = <&slot1_partition>; + img-secondary-secure = <&slot1_s_partition>; img-secondary-nonsecure = <&slot1_ns_partition>; partition-ps = <&tfm_ps_partition>; partition-its = <&tfm_its_partition>; diff --git a/snippets/infuse/boards/nrf9161dk_nrf9161_ns.overlay b/snippets/infuse/boards/nrf9161dk_nrf9161_ns.overlay index 2e2fe90a3..ff4aa309d 100644 --- a/snippets/infuse/boards/nrf9161dk_nrf9161_ns.overlay +++ b/snippets/infuse/boards/nrf9161dk_nrf9161_ns.overlay @@ -13,9 +13,9 @@ driver = "Driver_FLASH0"; complete = <&flash0>; img-bl2 = <&boot_partition>; - img-primary-secure = <&slot0_partition>; + img-primary-secure = <&slot0_s_partition>; img-primary-nonsecure = <&slot0_ns_partition>; - img-secondary-secure = <&slot1_partition>; + img-secondary-secure = <&slot1_s_partition>; img-secondary-nonsecure = <&slot1_ns_partition>; partition-ps = <&tfm_ps_partition>; partition-its = <&tfm_its_partition>; diff --git a/snippets/infuse/boards/tauro_nrf9151_ns.overlay b/snippets/infuse/boards/tauro_nrf9151_ns.overlay index af5a7f309..cddb88670 100644 --- a/snippets/infuse/boards/tauro_nrf9151_ns.overlay +++ b/snippets/infuse/boards/tauro_nrf9151_ns.overlay @@ -2,8 +2,10 @@ /* MCUboot secondary on external flash */ /delete-node/ &slot0_partition; +/delete-node/ &slot0_s_partition; /delete-node/ &slot0_ns_partition; /delete-node/ &slot1_partition; +/delete-node/ &slot1_s_partition; /delete-node/ &slot1_ns_partition; / { @@ -19,7 +21,7 @@ driver = "Driver_FLASH0"; complete = <&flash0>; img-bl2 = <&boot_partition>; - img-primary-secure = <&slot0_partition>; + img-primary-secure = <&slot0_s_partition>; img-primary-nonsecure = <&slot0_ns_partition>; partition-ps = <&tfm_ps_partition>; partition-its = <&tfm_its_partition>; @@ -33,7 +35,7 @@ complete = <&w25q128jv>; erase-block-size = <4096>; write-block-size = <1>; - img-secondary-secure = <&slot1_partition>; + img-secondary-secure = <&slot1_s_partition>; img-secondary-nonsecure = <&slot1_ns_partition>; }; }; @@ -105,9 +107,13 @@ }; slot0_partition: partition@10000 { label = "image-0"; + reg = <0x00010000 0x000F0000>; + }; + slot0_s_partition: subpartition@10000 { + label = "image-0-secure"; reg = <0x00010000 0x00030000>; }; - slot0_ns_partition: partition@40000 { + slot0_ns_partition: subpartition@40000 { label = "image-0-nonsecure"; reg = <0x00040000 0xC0000>; }; @@ -160,9 +166,13 @@ slot1_partition: partition@0 { label = "image-1"; + reg = <0x00000000 0xF0000>; + }; + slot1_s_partition: subpartition@0 { + label = "image-1-secure"; reg = <0x00000000 0x30000>; }; - slot1_ns_partition: partition@30000 { + slot1_ns_partition: subpartition@30000 { label = "image-1-nonsecure"; reg = <0x00030000 0xC0000>; }; diff --git a/snippets/infuse/boards/thingy53_nrf5340_cpuapp_common.dtsi b/snippets/infuse/boards/thingy53_nrf5340_cpuapp_common.dtsi index 6c6f6313a..3133f409e 100644 --- a/snippets/infuse/boards/thingy53_nrf5340_cpuapp_common.dtsi +++ b/snippets/infuse/boards/thingy53_nrf5340_cpuapp_common.dtsi @@ -116,8 +116,10 @@ /* MCUboot secondary on external flash */ /delete-node/ &slot0_partition; +/delete-node/ &slot0_s_partition; /delete-node/ &slot0_ns_partition; /delete-node/ &slot1_partition; +/delete-node/ &slot1_s_partition; /delete-node/ &slot1_ns_partition; &flash0 { @@ -132,9 +134,13 @@ }; slot0_partition: partition@10000 { label = "image-0"; + reg = <0x00010000 0xF0000>; + }; + slot0_s_partition: subpartition@10000 { + label = "image-0-secure"; reg = <0x00010000 0x30000>; }; - slot0_ns_partition: partition@40000 { + slot0_ns_partition: subpartition@40000 { label = "image-0-nonsecure"; reg = <0x00040000 0xC0000>; }; @@ -161,11 +167,16 @@ #address-cells = <1>; #size-cells = <1>; + slot1_partition: partition@0 { label = "image-1"; + reg = <0x00000000 0xF0000>; + }; + slot1_s_partition: subpartition@0 { + label = "image-1-secure"; reg = <0x00000000 0x30000>; }; - slot1_ns_partition: partition@30000 { + slot1_ns_partition: subpartition@30000 { label = "image-1-nonsecure"; reg = <0x00030000 0xC0000>; }; diff --git a/snippets/infuse/boards/thingy53_nrf5340_cpuapp_ns.overlay b/snippets/infuse/boards/thingy53_nrf5340_cpuapp_ns.overlay index 1bf999fc3..da865d9c6 100644 --- a/snippets/infuse/boards/thingy53_nrf5340_cpuapp_ns.overlay +++ b/snippets/infuse/boards/thingy53_nrf5340_cpuapp_ns.overlay @@ -19,7 +19,7 @@ driver = "Driver_FLASH0"; complete = <&flash0>; img-bl2 = <&boot_partition>; - img-primary-secure = <&slot0_partition>; + img-primary-secure = <&slot0_s_partition>; img-primary-nonsecure = <&slot0_ns_partition>; partition-ps = <&tfm_ps_partition>; partition-its = <&tfm_its_partition>; @@ -33,7 +33,7 @@ complete = <&mx25r64>; erase-block-size = <4096>; write-block-size = <1>; - img-secondary-secure = <&slot1_partition>; + img-secondary-secure = <&slot1_s_partition>; img-secondary-nonsecure = <&slot1_ns_partition>; /* Expected by Laird QSPI driver. * Ideally driver would consume pinctrl values and diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index ae4b12154..36859b4e4 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -10,4 +10,5 @@ add_subdirectory_ifdef(CONFIG_MODEM_MODULES modem/backends) add_subdirectory_ifdef(CONFIG_INFUSE_VALIDATION validation) add_subdirectory(fs) +add_subdirectory(mgmt) add_subdirectory(net) diff --git a/subsys/Kconfig b/subsys/Kconfig index 2994e5ed1..97b50a248 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -3,6 +3,7 @@ rsource "epacket/Kconfig" rsource "tdf/Kconfig" rsource "fs/Kconfig" rsource "modem/backends/Kconfig" +rsource "mgmt/Kconfig" rsource "net/Kconfig" rsource "rpc/Kconfig" rsource "task_runner/Kconfig" diff --git a/subsys/mgmt/CMakeLists.txt b/subsys/mgmt/CMakeLists.txt new file mode 100644 index 000000000..238d8095a --- /dev/null +++ b/subsys/mgmt/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory_ifdef(CONFIG_MCUMGR mcumgr) diff --git a/subsys/mgmt/Kconfig b/subsys/mgmt/Kconfig new file mode 100644 index 000000000..66499385f --- /dev/null +++ b/subsys/mgmt/Kconfig @@ -0,0 +1 @@ +rsource "mcumgr/Kconfig" diff --git a/subsys/mgmt/mcumgr/CMakeLists.txt b/subsys/mgmt/mcumgr/CMakeLists.txt new file mode 100644 index 000000000..deb6559eb --- /dev/null +++ b/subsys/mgmt/mcumgr/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_OS_INFUSE os_mgmt_infuse) diff --git a/subsys/mgmt/mcumgr/Kconfig b/subsys/mgmt/mcumgr/Kconfig new file mode 100644 index 000000000..8aa080cf9 --- /dev/null +++ b/subsys/mgmt/mcumgr/Kconfig @@ -0,0 +1,11 @@ +# Infuse-IoT mcumgr implementations + +if MCUMGR + +config MCUMGR_GRP_OS_INFUSE + bool "Infuse-IoT mcumgr handlers for OS management" + select MCUMGR_SMP_CBOR_MIN_DECODING_LEVEL_2 + depends on INFUSE_EPOCH_TIME + depends on INFUSE_REBOOT + +endif # MCUMGR diff --git a/subsys/mgmt/mcumgr/os_mgmt_infuse/CMakeLists.txt b/subsys/mgmt/mcumgr/os_mgmt_infuse/CMakeLists.txt new file mode 100644 index 000000000..a38d6c3c6 --- /dev/null +++ b/subsys/mgmt/mcumgr/os_mgmt_infuse/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library(mgmt_mcumgr_grp_os) +zephyr_library_sources(os_mgmt_infuse.c) diff --git a/subsys/mgmt/mcumgr/os_mgmt_infuse/os_mgmt_infuse.c b/subsys/mgmt/mcumgr/os_mgmt_infuse/os_mgmt_infuse.c new file mode 100644 index 000000000..644293c06 --- /dev/null +++ b/subsys/mgmt/mcumgr/os_mgmt_infuse/os_mgmt_infuse.c @@ -0,0 +1,93 @@ +/** + * @file + * @copyright 2024 Embeint Inc + * @author Jordan Yates + * + * SPDX-License-Identifier: LicenseRef-Embeint + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +static int os_mgmt_echo(struct smp_streamer *ctxt) +{ + zcbor_state_t *zsd = ctxt->reader->zs; + zcbor_state_t *zse = ctxt->writer->zs; + struct zcbor_string data = {0}; + size_t decoded; + bool ok; + + struct zcbor_map_decode_key_val echo_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("d", zcbor_tstr_decode, &data), + }; + + ok = zcbor_map_decode_bulk(zsd, echo_decode, ARRAY_SIZE(echo_decode), &decoded) == 0; + + if (!ok) { + return MGMT_ERR_EINVAL; + } + + ok = zcbor_tstr_put_lit(zse, "r") && zcbor_tstr_encode(zse, &data); + + return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE; +} + +static int os_mgmt_datetime_read(struct smp_streamer *ctxt) +{ + zcbor_state_t *zse = ctxt->writer->zs; + uint64_t now = epoch_time_now(); + char date_string[32]; + struct tm cal; + uint32_t ms; + bool ok; + + epoch_time_unix_calendar(now, &cal); + ms = k_epoch_to_ms_near32(epoch_time_subseconds(now)); + + snprintf(date_string, sizeof(date_string), "%4d-%02d-%02dT%02d:%02d:%02d.%03d", + (uint16_t)(cal.tm_year + 1900), (uint8_t)(cal.tm_mon + 1), (uint8_t)cal.tm_mday, + (uint8_t)cal.tm_hour, (uint8_t)cal.tm_min, (uint8_t)cal.tm_sec, ms); + + ok = zcbor_tstr_put_lit(zse, "datetime") && + zcbor_tstr_encode_ptr(zse, date_string, strlen(date_string)); + + return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE; +} + +static int os_mgmt_reset(struct smp_streamer *ctxt) +{ + infuse_reboot_delayed(INFUSE_REBOOT_MCUMGR, 0x00, 0x00, K_MSEC(2000)); + return MGMT_ERR_EOK; +} + +static const struct mgmt_handler os_mgmt_group_handlers[] = { + [OS_MGMT_ID_ECHO] = {os_mgmt_echo, os_mgmt_echo}, + [OS_MGMT_ID_DATETIME_STR] = {os_mgmt_datetime_read, NULL}, + [OS_MGMT_ID_RESET] = {NULL, os_mgmt_reset}, +}; + +static struct mgmt_group os_mgmt_group = { + .mg_handlers = os_mgmt_group_handlers, + .mg_handlers_count = ARRAY_SIZE(os_mgmt_group_handlers), + .mg_group_id = MGMT_GROUP_ID_OS, +}; + +static void os_mgmt_register_group(void) +{ + mgmt_register_group(&os_mgmt_group); +} + +MCUMGR_HANDLER_DEFINE(os_mgmt, os_mgmt_register_group); diff --git a/tests/lib/epoch_time/src/main.c b/tests/lib/epoch_time/src/main.c index 44bf9301a..f668c3ff8 100644 --- a/tests/lib/epoch_time/src/main.c +++ b/tests/lib/epoch_time/src/main.c @@ -136,10 +136,13 @@ ZTEST(epoch_time, test_internal_conversions) } zassert_equal(0, epoch_time_milliseconds(0)); + zassert_equal(0, epoch_time_milliseconds(32)); + zassert_equal(1, epoch_time_milliseconds(33)); zassert_equal(250, epoch_time_milliseconds((UINT16_MAX + 1) / 4)); zassert_equal(333, epoch_time_milliseconds((UINT16_MAX + 1) / 3)); zassert_equal(500, epoch_time_milliseconds((UINT16_MAX + 1) / 2)); - zassert_equal(999, epoch_time_milliseconds(UINT16_MAX)); + zassert_equal(999, epoch_time_milliseconds(UINT16_MAX - 66)); + zassert_equal(1000, epoch_time_milliseconds(UINT16_MAX)); zassert_equal(0, epoch_time_milliseconds(UINT16_MAX + 1)); } diff --git a/tests/lib/version/CMakeLists.txt b/tests/lib/version/CMakeLists.txt new file mode 100644 index 000000000..61860ef41 --- /dev/null +++ b/tests/lib/version/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(version) + +target_sources(app PRIVATE + src/main.c +) diff --git a/tests/lib/version/prj.conf b/tests/lib/version/prj.conf new file mode 100644 index 000000000..9467c2926 --- /dev/null +++ b/tests/lib/version/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/tests/lib/version/src/main.c b/tests/lib/version/src/main.c new file mode 100644 index 000000000..c16bedc44 --- /dev/null +++ b/tests/lib/version/src/main.c @@ -0,0 +1,57 @@ +/** + * @file + * @copyright 2024 Embeint Inc + * @author Jordan Yates + * + * SPDX-License-Identifier: LicenseRef-Embeint + */ + +#include + +#include + +ZTEST(version, test_version_compare) +{ + struct infuse_version a = {1, 2, 40, 10000}; + struct infuse_version b = {4, 1, 20, 0}; + struct infuse_version c = {4, 1, 20, 123}; + struct infuse_version d = {4, 1, 10, 123}; + struct infuse_version e = {4, 1, 30, 123}; + struct infuse_version f = {4, 2, 5, 123}; + + zassert_equal(1, (infuse_version_compare(&a, &b))); + zassert_equal(1, (infuse_version_compare(&a, &c))); + zassert_equal(1, (infuse_version_compare(&a, &d))); + zassert_equal(1, (infuse_version_compare(&a, &e))); + zassert_equal(1, (infuse_version_compare(&a, &f))); + + zassert_equal(1, (infuse_version_compare(&d, &c))); + zassert_equal(1, (infuse_version_compare(&d, &e))); + + zassert_equal(1, (infuse_version_compare(&c, &f))); + zassert_equal(1, (infuse_version_compare(&d, &f))); + zassert_equal(1, (infuse_version_compare(&e, &f))); + + zassert_equal(-1, (infuse_version_compare(&b, &a))); + zassert_equal(-1, (infuse_version_compare(&c, &a))); + zassert_equal(-1, (infuse_version_compare(&d, &a))); + zassert_equal(-1, (infuse_version_compare(&e, &a))); + + zassert_equal(-1, (infuse_version_compare(&c, &d))); + zassert_equal(-1, (infuse_version_compare(&e, &d))); + + zassert_equal(-1, (infuse_version_compare(&f, &c))); + zassert_equal(-1, (infuse_version_compare(&f, &d))); + zassert_equal(-1, (infuse_version_compare(&f, &e))); + + zassert_equal(0, (infuse_version_compare(&a, &a))); + zassert_equal(0, (infuse_version_compare(&b, &b))); + zassert_equal(0, (infuse_version_compare(&c, &c))); + zassert_equal(0, (infuse_version_compare(&d, &d))); + zassert_equal(0, (infuse_version_compare(&e, &e))); + + /* Build num ignored */ + zassert_equal(0, (infuse_version_compare(&b, &c))); +} + +ZTEST_SUITE(version, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/lib/version/testcase.yaml b/tests/lib/version/testcase.yaml new file mode 100644 index 000000000..45cba1d24 --- /dev/null +++ b/tests/lib/version/testcase.yaml @@ -0,0 +1,6 @@ +tests: + libraries.version: + integration_platforms: + - native_sim + - qemu_cortex_m3 + tags: infuse diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/CMakeLists.txt b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/CMakeLists.txt new file mode 100644 index 000000000..132aa56c9 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/CMakeLists.txt @@ -0,0 +1,24 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) + +# Infuse-IoT application +if(NOT infuse IN_LIST SNIPPET) + set(SNIPPET infuse ${SNIPPET} CACHE STRING "" FORCE) +endif() + + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(os_mgmt_infuse_datetime) + +FILE(GLOB app_sources + src/*.c +) + +target_sources(app PRIVATE ${app_sources}) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/mgmt/mcumgr/grp/os_mgmt/include/) diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/prj.conf b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/prj.conf new file mode 100644 index 000000000..f0e0c81b8 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/prj.conf @@ -0,0 +1,18 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_ZTEST=y +CONFIG_RTC=y +CONFIG_NET_BUF=y +CONFIG_BASE64=y +CONFIG_ZCBOR=y +CONFIG_CRC=y +CONFIG_MCUMGR=y +CONFIG_MCUMGR_TRANSPORT_DUMMY=y +CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE=256 +CONFIG_MCUMGR_GRP_OS_INFUSE=y +CONFIG_INFUSE_SDK=y +CONFIG_INFUSE_REBOOT=y +CONFIG_INFUSE_SECURE_STORAGE=n diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c new file mode 100644 index 000000000..ca8c70948 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/main.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright (c) 2023 Jamie M. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smp_test_util.h" + +#include + +#define SMP_RESPONSE_WAIT_TIME 3 +#define ZCBOR_BUFFER_SIZE 256 +#define OUTPUT_BUFFER_SIZE 256 +#define ZCBOR_HISTORY_ARRAY_SIZE 4 + +static struct net_buf *nb; +struct group_error { + uint16_t group; + uint16_t rc; + bool found; +}; + +static void cleanup_test(void *p); + +static bool mcumgr_ret_decode(zcbor_state_t *state, struct group_error *result) +{ + bool ok; + size_t decoded; + uint32_t tmp_group; + uint32_t tmp_rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("group", zcbor_uint32_decode, &tmp_group), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_uint32_decode, &tmp_rc), + }; + + result->found = false; + + ok = zcbor_map_decode_bulk(state, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + if (ok && + zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), "group") && + zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), "rc")) { + result->group = (uint16_t)tmp_group; + result->rc = (uint16_t)tmp_rc; + result->found = true; + } + + return ok; +} + +static void expect_timestring(const char *expected, int trailing_ignore) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = {0}; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = {0}; + bool received; + struct zcbor_string output = {0}; + size_t decoded = 0; + struct group_error group; + int rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &output), + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc), + ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + /* Query time and ensure it is set */ + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_datetime_get_packet(zse, false, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element"); + zassert_true(zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), + "datetime"), + "Expected to receive datetime element"); + zassert_false( + zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), "rc"), + "Did not expect to receive rc element"); + zassert_false( + zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), "err"), + "Did not expected to receive err element"); + + /* Check that the date/time is as expected */ + zassert_equal(output.len, strlen(expected), "Expected received datetime length mismatch"); + zassert_mem_equal(output.value, expected, strlen(expected) - trailing_ignore, + "Expected received datetime value mismatch"); +} + +ZTEST(os_mgmt_datetime, test_datetime_get) +{ + struct timeutil_sync_instant instant; + int accuracy = IS_ENABLED(CONFIG_COVERAGE_GCOV) ? 3 : 2; + + /* Boot time */ + epoch_time_reset(); + expect_timestring("2020-01-01T00:00:00.0xx", accuracy); + + /* Arbitrary time */ + instant.local = k_uptime_ticks(); + instant.ref = epoch_time_from_unix(1725492631, UINT16_MAX / 2); + epoch_time_set_reference(TIME_SOURCE_GNSS, &instant); + expect_timestring("2024-09-04T23:30:31.5xx", accuracy); +} + +static void cleanup_test(void *p) +{ + if (nb != NULL) { + net_buf_unref(nb); + nb = NULL; + } +} + +/* Time not set test set */ +ZTEST_SUITE(os_mgmt_datetime, NULL, NULL, NULL, cleanup_test, NULL); diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.c b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.c new file mode 100644 index 000000000..8c0a12403 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2023 Jamie M. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "smp_test_util.h" +#include +#include +#include +#include + +/* SMP header function for generating os_mgmt datetime command header with sequence number set + * to 1 + */ +void smp_make_hdr(struct smp_hdr *rsp_hdr, size_t len, bool version2, bool write) +{ + *rsp_hdr = (struct smp_hdr){ + .nh_len = sys_cpu_to_be16(len), + .nh_flags = 0, + .nh_version = (version2 == true ? SMP_MCUMGR_VERSION_2 : SMP_MCUMGR_VERSION_1), + .nh_op = (write == true ? MGMT_OP_WRITE : MGMT_OP_READ), + .nh_group = sys_cpu_to_be16(MGMT_GROUP_ID_OS), + .nh_seq = 1, + .nh_id = OS_MGMT_ID_DATETIME_STR, + }; +} + +/* Function for creating an os_mgmt datetime get command */ +bool create_mcumgr_datetime_get_packet(zcbor_state_t *zse, bool version2, uint8_t *buffer, + uint8_t *output_buffer, uint16_t *buffer_size) +{ + bool ok; + + ok = zcbor_map_start_encode(zse, 2) && zcbor_map_end_encode(zse, 2); + + *buffer_size = (zse->payload_mut - buffer); + smp_make_hdr((struct smp_hdr *)output_buffer, *buffer_size, version2, false); + memcpy(&output_buffer[sizeof(struct smp_hdr)], buffer, *buffer_size); + *buffer_size += sizeof(struct smp_hdr); + + return ok; +} diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.h b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.h new file mode 100644 index 000000000..cc6824c05 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/src/smp_test_util.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2023 Jamie M. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_SMP_TEST_UTIL_ +#define H_SMP_TEST_UTIL_ + +#include +#include +#include +#include + +/* SMP header function for generating os_mgmt datetime command header with sequence number set + * to 1 + */ +void smp_make_hdr(struct smp_hdr *rsp_hdr, size_t len, bool version2, bool write); + +/* Function for creating an os_mgmt datetime get command */ +bool create_mcumgr_datetime_get_packet(zcbor_state_t *zse, bool version2, uint8_t *buffer, + uint8_t *output_buffer, uint16_t *buffer_size); + +#endif diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/testcase.yaml b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/testcase.yaml new file mode 100644 index 000000000..0d1722355 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_datetime/testcase.yaml @@ -0,0 +1,11 @@ +# +# Copyright (c) 2024 Embeint Inc +# +# SPDX-License-Identifier: Apache-2.0 +# +tests: + mgmt.mcumgr.infuse_os.datetime: + required_snippets: + - infuse + integration_platforms: + - mps2/an385 diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_echo/CMakeLists.txt b/tests/subsys/mgmt/mcumgr/os_mgmt_echo/CMakeLists.txt new file mode 100644 index 000000000..deab54875 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_echo/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) + +# Infuse-IoT application +if(NOT infuse IN_LIST SNIPPET) + set(SNIPPET infuse ${SNIPPET} CACHE STRING "" FORCE) +endif() + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(os_mgmt_infuse_echo) + +FILE(GLOB app_sources + src/*.c +) + +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_echo/prj.conf b/tests/subsys/mgmt/mcumgr/os_mgmt_echo/prj.conf new file mode 100644 index 000000000..f7adf37d3 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_echo/prj.conf @@ -0,0 +1,18 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_ZTEST=y +CONFIG_NET_BUF=y +CONFIG_BASE64=y +CONFIG_ZCBOR=y +CONFIG_CRC=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_MCUMGR=y +CONFIG_MCUMGR_TRANSPORT_DUMMY=y +CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE=256 +CONFIG_MCUMGR_GRP_OS_INFUSE=y +CONFIG_INFUSE_SDK=y +CONFIG_INFUSE_REBOOT=y +CONFIG_INFUSE_SECURE_STORAGE=n diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_echo/src/main.c b/tests/subsys/mgmt/mcumgr/os_mgmt_echo/src/main.c new file mode 100644 index 000000000..ebc590565 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_echo/src/main.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define SMP_RESPONSE_WAIT_TIME 3 + +/* Test os_mgmt echo command with 40 bytes of data: "short MCUMGR test application message..." */ +static const uint8_t command[] = { + 0x02, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x01, 0x00, 0xbf, 0x61, 0x64, 0x78, 0x28, 0x73, + 0x68, 0x6f, 0x72, 0x74, 0x20, 0x4d, 0x43, 0x55, 0x4d, 0x47, 0x52, 0x20, 0x74, 0x65, + 0x73, 0x74, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x2e, 0x2e, 0xff, +}; + +/* Expected response from mcumgr */ +static const uint8_t expected_response[] = { + 0x03, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x01, 0x00, 0xbf, 0x61, 0x72, 0x78, 0x28, 0x73, + 0x68, 0x6f, 0x72, 0x74, 0x20, 0x4d, 0x43, 0x55, 0x4d, 0x47, 0x52, 0x20, 0x74, 0x65, + 0x73, 0x74, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x2e, 0x2e, 0xff}; + +ZTEST(os_mgmt_echo, test_echo) +{ + struct net_buf *nb; + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send test echo command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(command, sizeof(command)); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + bool received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + zassert_equal(sizeof(expected_response), nb->len, + "Expected to receive %d bytes but got %d\n", sizeof(expected_response), + nb->len); + + zassert_mem_equal(expected_response, nb->data, nb->len, "Expected received data mismatch"); +} + +ZTEST_SUITE(os_mgmt_echo, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_echo/testcase.yaml b/tests/subsys/mgmt/mcumgr/os_mgmt_echo/testcase.yaml new file mode 100644 index 000000000..d6d5e1f67 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_echo/testcase.yaml @@ -0,0 +1,11 @@ +# +# Copyright (c) 2024 Embeint Inc +# +# SPDX-License-Identifier: Apache-2.0 +# +tests: + mgmt.mcumgr.infuse_os.echo: + required_snippets: + - infuse + integration_platforms: + - mps2/an385 diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_reset/CMakeLists.txt b/tests/subsys/mgmt/mcumgr/os_mgmt_reset/CMakeLists.txt new file mode 100644 index 000000000..46c2c20ef --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_reset/CMakeLists.txt @@ -0,0 +1,24 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) + +# Infuse-IoT application +if(NOT infuse IN_LIST SNIPPET) + set(SNIPPET infuse ${SNIPPET} CACHE STRING "" FORCE) +endif() + + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(os_mgmt_infuse_reboot) + +FILE(GLOB app_sources + src/*.c +) + +target_sources(app PRIVATE ${app_sources}) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/mgmt/mcumgr/grp/os_mgmt/include/) diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_reset/prj.conf b/tests/subsys/mgmt/mcumgr/os_mgmt_reset/prj.conf new file mode 100644 index 000000000..f0e0c81b8 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_reset/prj.conf @@ -0,0 +1,18 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_ZTEST=y +CONFIG_RTC=y +CONFIG_NET_BUF=y +CONFIG_BASE64=y +CONFIG_ZCBOR=y +CONFIG_CRC=y +CONFIG_MCUMGR=y +CONFIG_MCUMGR_TRANSPORT_DUMMY=y +CONFIG_MCUMGR_TRANSPORT_DUMMY_RX_BUF_SIZE=256 +CONFIG_MCUMGR_GRP_OS_INFUSE=y +CONFIG_INFUSE_SDK=y +CONFIG_INFUSE_REBOOT=y +CONFIG_INFUSE_SECURE_STORAGE=n diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_reset/src/main.c b/tests/subsys/mgmt/mcumgr/os_mgmt_reset/src/main.c new file mode 100644 index 000000000..ea6052902 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_reset/src/main.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright (c) 2023 Jamie M. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smp_test_util.h" + +#include +#include +#include +#include + +#define SMP_RESPONSE_WAIT_TIME 3 +#define ZCBOR_BUFFER_SIZE 256 +#define OUTPUT_BUFFER_SIZE 256 +#define ZCBOR_HISTORY_ARRAY_SIZE 4 + +static struct net_buf *nb; +static void cleanup_test(void *p); + +static void send_reset(void) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = {0}; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = {0}; + uint16_t buffer_size; + size_t decoded = 0; + bool received, ok; + int rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + /* Send reset command */ + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + ok = create_mcumgr_reset_packet(zse, false, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + zassert_true(received, "Expected to receive data but timed out"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + zassert_true(ok, "Expected decode to be successful"); + zassert_equal(decoded, 0, "Did not expect any decoded elements"); + zassert_false( + zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), "rc"), + "Did not expect to receive rc element"); +} + +ZTEST(os_mgmt_reset, test_reset) +{ + KV_KEY_TYPE(KV_KEY_REBOOTS) reboots; + struct infuse_reboot_state reboot_state; + ssize_t rc; + + /* KV store should have been initialised and populated with a reboot count */ + rc = KV_STORE_READ(KV_KEY_REBOOTS, &reboots); + zassert_equal(sizeof(reboots), rc); + + switch (reboots.count) { + case 1: + /* Send reset command */ + send_reset(); + /* Wait for the reboot */ + k_sleep(K_SECONDS(3)); + zassert_unreachable("Reset command did not trigger reboot"); + break; + case 2: + /* Validate previous reboot information */ + rc = infuse_common_boot_last_reboot(&reboot_state); + zassert_equal(0, rc); + zassert_equal(INFUSE_REBOOT_MCUMGR, reboot_state.reason); + zassert_equal(0, reboot_state.param_1.program_counter); + zassert_equal(0, reboot_state.param_2.link_register); + break; + default: + zassert_unreachable("Unexpected reboot count"); + break; + } +} + +static void cleanup_test(void *p) +{ + if (nb != NULL) { + net_buf_unref(nb); + nb = NULL; + } +} + +/* Time not set test set */ +ZTEST_SUITE(os_mgmt_reset, NULL, NULL, NULL, cleanup_test, NULL); diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_reset/src/smp_test_util.c b/tests/subsys/mgmt/mcumgr/os_mgmt_reset/src/smp_test_util.c new file mode 100644 index 000000000..12eb53d3d --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_reset/src/smp_test_util.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2023 Jamie M. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "smp_test_util.h" +#include +#include +#include +#include + +/* SMP header function for generating os_mgmt datetime command header with sequence number set + * to 1 + */ +void smp_make_hdr(struct smp_hdr *rsp_hdr, size_t len, bool version2, bool write) +{ + *rsp_hdr = (struct smp_hdr){ + .nh_len = sys_cpu_to_be16(len), + .nh_flags = 0, + .nh_version = (version2 == true ? SMP_MCUMGR_VERSION_2 : SMP_MCUMGR_VERSION_1), + .nh_op = (write == true ? MGMT_OP_WRITE : MGMT_OP_READ), + .nh_group = sys_cpu_to_be16(MGMT_GROUP_ID_OS), + .nh_seq = 1, + .nh_id = OS_MGMT_ID_RESET, + }; +} + +/* Function for creating an os_mgmt reset command */ +bool create_mcumgr_reset_packet(zcbor_state_t *zse, bool version2, uint8_t *buffer, + uint8_t *output_buffer, uint16_t *buffer_size) +{ + bool ok; + + ok = zcbor_map_start_encode(zse, 2) && zcbor_map_end_encode(zse, 2); + + *buffer_size = (zse->payload_mut - buffer); + smp_make_hdr((struct smp_hdr *)output_buffer, *buffer_size, version2, true); + memcpy(&output_buffer[sizeof(struct smp_hdr)], buffer, *buffer_size); + *buffer_size += sizeof(struct smp_hdr); + + return ok; +} diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_reset/src/smp_test_util.h b/tests/subsys/mgmt/mcumgr/os_mgmt_reset/src/smp_test_util.h new file mode 100644 index 000000000..2f92f5e5a --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_reset/src/smp_test_util.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * Copyright (c) 2023 Jamie M. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_SMP_TEST_UTIL_ +#define H_SMP_TEST_UTIL_ + +#include +#include +#include +#include + +/* SMP header function for generating os_mgmt reset command header with sequence number set + * to 1 + */ +void smp_make_hdr(struct smp_hdr *rsp_hdr, size_t len, bool version2, bool write); + +/* Function for creating an os_mgmt reset command */ +bool create_mcumgr_reset_packet(zcbor_state_t *zse, bool version2, uint8_t *buffer, + uint8_t *output_buffer, uint16_t *buffer_size); + +#endif diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_reset/testcase.yaml b/tests/subsys/mgmt/mcumgr/os_mgmt_reset/testcase.yaml new file mode 100644 index 000000000..c4d54412b --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_reset/testcase.yaml @@ -0,0 +1,11 @@ +# +# Copyright (c) 2024 Embeint Inc +# +# SPDX-License-Identifier: Apache-2.0 +# +tests: + mgmt.mcumgr.infuse_os.reboot: + required_snippets: + - infuse + integration_platforms: + - mps2/an385 diff --git a/west.yml b/west.yml index a0b3013c8..177508494 100644 --- a/west.yml +++ b/west.yml @@ -10,7 +10,7 @@ manifest: projects: - name: zephyr - revision: 674485bb1c52b8474a2931ecf5d3530ef70c408b + revision: ce75610074f2c7353a75c39c736d3df4ceecc355 # Limit imported repositories to reduce clone time import: name-allowlist: @@ -25,6 +25,7 @@ manifest: - segger - tinycrypt - trusted-firmware-m + - zcbor - name: sdk-nrf path: modules/nrfconnect/sdk-nrf revision: 2fa5e92ca8ab98edf25aced93500f22bac2c3bdb