From 0345abbb51a24f559e1c0a41362d77e57bc45d41 Mon Sep 17 00:00:00 2001 From: Jamie Smith Date: Sun, 1 Jun 2025 10:00:10 -0700 Subject: [PATCH 1/8] Upgrade Ambiq Apollo3 linker script --- .../TOOLCHAIN_GCC_ARM/AMA3B1KK.ld | 112 +++++++++--------- .../TARGET_Apollo3/device/serial_api.c | 8 +- targets/cmsis_mcu_descriptions.json5 | 8 +- targets/targets.json5 | 9 +- 4 files changed, 71 insertions(+), 66 deletions(-) diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TOOLCHAIN_GCC_ARM/AMA3B1KK.ld b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TOOLCHAIN_GCC_ARM/AMA3B1KK.ld index 63a15320c14..cd57dd7231d 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TOOLCHAIN_GCC_ARM/AMA3B1KK.ld +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TOOLCHAIN_GCC_ARM/AMA3B1KK.ld @@ -22,23 +22,17 @@ */ /* stack: dynamic */ /* heap: dynamic */ -#define MBED_APP_START 0x0000C000 -#define MBED_APP_LENGTH 0x000F4000 -#define MBED_RAM_START 0x10000000 -#define MBED_RAM_SIZE 384K -#define MBED_BOOT_STACK_SIZE 0x400 -#define MBED_RAM0_START MBED_RAM_START -#define MBED_RAM0_SIZE 0x100 -#define MBED_RAM1_START (MBED_RAM0_START + MBED_RAM0_SIZE) -#define MBED_RAM1_SIZE (MBED_RAM_SIZE - (MBED_RAM0_SIZE)) + +#if !defined(MBED_CONF_TARGET_BOOT_STACK_SIZE) + #define MBED_CONF_TARGET_BOOT_STACK_SIZE 0x400 +#endif ENTRY(Reset_Handler) MEMORY { - FLASH (rx) : ORIGIN = MBED_APP_START, LENGTH = MBED_APP_LENGTH /*Modified from 0xC000 to work with SparkFun SVL*/ - RAM_NVIC (rwx) : ORIGIN = MBED_RAM0_START, LENGTH = MBED_RAM0_SIZE - RAM (rwx) : ORIGIN = MBED_RAM1_START, LENGTH = MBED_RAM1_SIZE + FLASH (rx) : ORIGIN = MBED_CONFIGURED_ROM_BANK_IROM1_START, LENGTH = MBED_CONFIGURED_ROM_BANK_IROM1_SIZE + RAM (rwx) : ORIGIN = MBED_RAM_BANK_IRAM1_START, LENGTH = MBED_RAM_BANK_IRAM1_SIZE } SECTIONS @@ -99,50 +93,50 @@ SECTIONS __etext = ALIGN(8); - .data : AT (__etext) - { - __data_start__ = .; - *(.data*) - - . = ALIGN(8); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - - . = ALIGN(8); - /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - - . = ALIGN(8); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - KEEP(*(SORT(.fini_array.*))) - KEEP(*(.fini_array)) - PROVIDE_HIDDEN (__fini_array_end = .); - - KEEP(*(.jcr*)) - . = ALIGN(8); - /* All data end */ - __data_end__ = .; - - } > RAM - - /* Uninitialized data section - * This region is not initialized by the C/C++ library and can be used to - * store state across soft reboots. */ - .uninitialized (NOLOAD): - { - . = ALIGN(32); - __uninitialized_start = .; - *(.uninitialized) - KEEP(*(.keep.uninitialized)) - . = ALIGN(32); - __uninitialized_end = .; - } > RAM + .data : AT (__etext) + { + __data_start__ = .; + *(.data*) + + . = ALIGN(8); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(8); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(8); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(8); + /* All data end */ + __data_end__ = .; + + } > RAM + + /* Uninitialized data section + * This region is not initialized by the C/C++ library and can be used to + * store state across soft reboots. */ + .uninitialized (NOLOAD): + { + . = ALIGN(32); + __uninitialized_start = .; + *(.uninitialized) + KEEP(*(.keep.uninitialized)) + . = ALIGN(32); + __uninitialized_end = .; + } > RAM /* bss: zero-initialized symbols */ @@ -160,6 +154,8 @@ SECTIONS __bss_end__ = .; } > RAM + ASSERT(__bss_end__ <= ORIGIN(RAM) + LENGTH(RAM) - MBED_CONF_TARGET_BOOT_STACK_SIZE, "Size of globals + stack exceeds size of SRAM!") + /* heap: RAM memory that can be dynamically allocated in the upward direction (increasing memory addresses) */ /* _sheap is used to identify the beginning of available dynamic memory */ .heap (NOLOAD): @@ -168,7 +164,7 @@ SECTIONS __end__ = .; PROVIDE( end = . ); _sheap = .; - . = ORIGIN(RAM) + LENGTH(RAM) - MBED_BOOT_STACK_SIZE-8; + . = ORIGIN(RAM) + LENGTH(RAM) - MBED_CONF_TARGET_BOOT_STACK_SIZE; __HeapLimit = .; } >RAM @@ -185,7 +181,7 @@ SECTIONS /* Set stack top to end of RAM, and stack limit move down by * size of stack_dummy section*/ __StackTop = ORIGIN(RAM) + LENGTH(RAM)-8; - __StackLimit = __StackTop - MBED_BOOT_STACK_SIZE; + __StackLimit = __StackTop - MBED_CONF_TARGET_BOOT_STACK_SIZE; PROVIDE(__stack = __StackTop); PROVIDE(_sstack = __StackTop); } diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/serial_api.c b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/serial_api.c index 83d23f34834..2aa68311e2e 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/serial_api.c +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/serial_api.c @@ -21,6 +21,8 @@ * SOFTWARE. */ +#include "mbed-target-config.h" + #if DEVICE_SERIAL #include "serial_api.h" @@ -121,9 +123,9 @@ void uart_configure_pin_function(PinName pin, UARTName uart, const PinMap *map); void serial_init(serial_t *obj, PinName tx, PinName rx) { // determine the UART to use - UARTName uart_tx = (UARTName)pinmap_peripheral(tx, serial_tx_pinmap()); - UARTName uart_rx = (UARTName)pinmap_peripheral(rx, serial_rx_pinmap()); - UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx); + uint32_t uart_tx = pinmap_peripheral(tx, serial_tx_pinmap()); + uint32_t uart_rx = pinmap_peripheral(rx, serial_rx_pinmap()); + uint32_t uart = pinmap_merge(uart_tx, uart_rx); MBED_ASSERT((int)uart != NC); obj->serial.uart_control = &ap3_uart_control[uart]; obj->serial.uart_control->inst = uart; diff --git a/targets/cmsis_mcu_descriptions.json5 b/targets/cmsis_mcu_descriptions.json5 index acdac2090a2..5287e6b8028 100644 --- a/targets/cmsis_mcu_descriptions.json5 +++ b/targets/cmsis_mcu_descriptions.json5 @@ -195,8 +195,8 @@ "write": true }, "default": true, - "size": 393216, - "start": 268435456, + "size": 0x60000, + "start": 0x10000000, "startup": false }, "IROM1": { @@ -210,8 +210,8 @@ "write": false }, "default": false, - "size": 999424, - "start": 49152, + "size": 0x100000, + "start": 0, "startup": true } }, diff --git a/targets/targets.json5 b/targets/targets.json5 index c524cbad9ee..8239804c07b 100644 --- a/targets/targets.json5 +++ b/targets/targets.json5 @@ -9654,7 +9654,14 @@ mode is recommended for target MCUs with small amounts of flash and RAM.", "inherits": ["FAMILY_Apollo3"], "macros_add": ["AM_PACKAGE_BGA", "MBED_TICKLESS"], "device_name": "AMA3B1KK-KBR", - "is_mcu_family_target": true + "is_mcu_family_target": true, + "memory_bank_config": { + // Leave room for the SparkFun SVL bootloader in flash + "IROM1": { + "start": 0x10000, + "size": 0xF0000 + } + } }, "SFE_ARTEMIS": { // AKA SparkFun RedBoard Artemis "inherits": ["AMA3B1KK"], From 7699293387c7cfc211da1619e7a97b7837b00b7c Mon Sep 17 00:00:00 2001 From: Jamie Smith Date: Wed, 18 Jun 2025 01:45:02 -0700 Subject: [PATCH 2/8] Add PYOCD, fix conflict between RAM and RAM vectors that was making boot fail --- .../TARGET_Apollo3/TARGET_SFE_ARTEMIS/PinNames.h | 13 +++---------- .../TARGET_Apollo3/TOOLCHAIN_GCC_ARM/AMA3B1KK.ld | 9 +++++++++ .../TOOLCHAIN_GCC_ARM/startup_gcc.c | 3 +++ targets/upload_method_cfg/SFE_ARTEMIS.cmake | 16 ++++++++++++++++ 4 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 targets/upload_method_cfg/SFE_ARTEMIS.cmake diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS/PinNames.h b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS/PinNames.h index 477b8aec98d..ea48f9afc17 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS/PinNames.h +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS/PinNames.h @@ -74,16 +74,6 @@ typedef enum A8 = D8, A9 = D9, A10 = D10, - - // LEDs - LED_BLUE = AM_BSP_GPIO_LED_BLUE, - - // mbed original LED naming - LED1 = AM_BSP_GPIO_LED0, - LED2 = A5, - - // LED naming by digital pin number - LED13 = AM_BSP_GPIO_LED13, // I2C I2C_SCL = AM_BSP_QWIIC_I2C_SCL_PIN, @@ -111,6 +101,9 @@ typedef enum NC = NC_VAL } PinName; +// LEDs +#define LED1 D13 // Blue LED + #if defined(MBED_CONF_TARGET_STDIO_UART_TX) #define STDIO_UART_TX MBED_CONF_TARGET_STDIO_UART_TX #else diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TOOLCHAIN_GCC_ARM/AMA3B1KK.ld b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TOOLCHAIN_GCC_ARM/AMA3B1KK.ld index cd57dd7231d..4712651295e 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TOOLCHAIN_GCC_ARM/AMA3B1KK.ld +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TOOLCHAIN_GCC_ARM/AMA3B1KK.ld @@ -27,6 +27,8 @@ #define MBED_CONF_TARGET_BOOT_STACK_SIZE 0x400 #endif +#include "../device/cmsis_nvic.h" + ENTRY(Reset_Handler) MEMORY @@ -93,6 +95,13 @@ SECTIONS __etext = ALIGN(8); + /* Reserve space for vector table in RAM at runtime */ + .ram_vectors (NOLOAD): + { + FILL(0); + . += NVIC_NUM_VECTORS*4; + } > RAM + .data : AT (__etext) { __data_start__ = .; diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TOOLCHAIN_GCC_ARM/startup_gcc.c b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TOOLCHAIN_GCC_ARM/startup_gcc.c index abd1f7e9113..e541d46fdcf 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TOOLCHAIN_GCC_ARM/startup_gcc.c +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TOOLCHAIN_GCC_ARM/startup_gcc.c @@ -263,6 +263,9 @@ void Reset_Handler(void) "isb\n"); #endif + // Clear PRIMASK if set by the bootloader (it seems to leave this set) + __set_PRIMASK(0); + // // Start mbed boot sequence https://os.mbed.com/docs/mbed-os/v5.15/reference/bootstrap.html // SystemInit(); // _start(); diff --git a/targets/upload_method_cfg/SFE_ARTEMIS.cmake b/targets/upload_method_cfg/SFE_ARTEMIS.cmake new file mode 100644 index 00000000000..ea2fa6da90f --- /dev/null +++ b/targets/upload_method_cfg/SFE_ARTEMIS.cmake @@ -0,0 +1,16 @@ +# Mbed OS upload method configuration file for target NUMAKER_PFM_M487. +# To change any of these parameters from their default values, set them in your build script between where you +# include mbed_toolchain_setup and where you add mbed-os as a subdirectory. + +# Notes: +# 1. Support for this device exists in PyOCD main branch but has not been released yet (as of Jun 2025). +# To use PyOCD, you need to manually install it from the git repository by running (inside the Mbed OS venv): +# pip install git+https://github.com/pyocd/pyOCD.git + +set(UPLOAD_METHOD_DEFAULT NONE) + +# Config options for PYOCD +# ------------------------------------------------------------- +set(PYOCD_UPLOAD_ENABLED TRUE) +set(PYOCD_TARGET_NAME ama3b1kk_kbr) +set(PYOCD_CLOCK_SPEED 4000k) From 4f6f18ee61b87cd98e0351f9e85a828ca65d9c24 Mon Sep 17 00:00:00 2001 From: Jamie Smith Date: Thu, 19 Jun 2025 13:46:34 -0700 Subject: [PATCH 3/8] Add pre-sync delay, fixing inability for greentea to work on Ambiq Apollo3 --- tools/python/mbed_os_tools/test/__init__.py | 12 +++- .../conn_primitive_serial.py | 2 +- .../test/host_tests_conn_proxy/conn_proxy.py | 67 +++++++++++-------- .../host_tests_runner/host_test_default.py | 8 ++- 4 files changed, 55 insertions(+), 34 deletions(-) diff --git a/tools/python/mbed_os_tools/test/__init__.py b/tools/python/mbed_os_tools/test/__init__.py index b693537585f..25045382c5d 100644 --- a/tools/python/mbed_os_tools/test/__init__.py +++ b/tools/python/mbed_os_tools/test/__init__.py @@ -25,6 +25,7 @@ import importlib import sys from argparse import ArgumentParser, SUPPRESS +from typing import Any from . import host_tests_plugins from .host_tests_registry import HostRegistry # noqa: F401 from .host_tests import BaseHostTest, event_callback # noqa: F401 @@ -46,7 +47,7 @@ def get_plugin_caps(methods=None): return result -def init_host_test_cli_params(): +def init_host_test_cli_params() -> Any: """! Function creates CLI parser object and returns populated options object. @return Function returns 'options' object returned from OptionParser class @details Options object later can be used to populate host test selector script. @@ -102,6 +103,15 @@ def init_host_test_cli_params(): metavar="SYNC_TIMEOUT", ) + parser.add_argument( + "--sync-predelay", + dest="sync_predelay", + default=0, + type=float, + help="Wait this amount of time (in floating point seconds) after opening the serial port before sending sync.", + metavar="SYNC_PREDELAY", + ) + parser.add_argument( "-f", "--image-path", diff --git a/tools/python/mbed_os_tools/test/host_tests_conn_proxy/conn_primitive_serial.py b/tools/python/mbed_os_tools/test/host_tests_conn_proxy/conn_primitive_serial.py index bc8d48d1767..8536784fa54 100644 --- a/tools/python/mbed_os_tools/test/host_tests_conn_proxy/conn_primitive_serial.py +++ b/tools/python/mbed_os_tools/test/host_tests_conn_proxy/conn_primitive_serial.py @@ -109,7 +109,7 @@ def reset_dev_via_serial(self, delay=1): self.logger.prn_inf("wait for it...") return result - def read(self, count): + def read(self, count) -> bytes: """! Read data from serial port RX buffer """ # TIMEOUT: Since read is called in a loop, wait for self.timeout period before calling serial.read(). See # comment on serial.Serial() call above about timeout. diff --git a/tools/python/mbed_os_tools/test/host_tests_conn_proxy/conn_proxy.py b/tools/python/mbed_os_tools/test/host_tests_conn_proxy/conn_proxy.py index 014507d2445..334a211e66a 100644 --- a/tools/python/mbed_os_tools/test/host_tests_conn_proxy/conn_proxy.py +++ b/tools/python/mbed_os_tools/test/host_tests_conn_proxy/conn_proxy.py @@ -13,19 +13,19 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import annotations + +from typing import Any import re import sys import uuid -from time import time +from time import time, sleep from ..host_tests_logger import HtrunLogger from .conn_primitive_serial import SerialConnectorPrimitive from .conn_primitive_remote import RemoteConnectorPrimitive from .conn_primitive_fastmodel import FastmodelConnectorPrimitive +from queue import Empty as QueueEmpty # Queue here refers to the module, not a class -if (sys.version_info > (3, 0)): - from queue import Empty as QueueEmpty # Queue here refers to the module, not a class -else: - from Queue import Empty as QueueEmpty class KiViBufferWalker(): """! Simple auxiliary class used to walk through a buffer and search for KV tokens """ @@ -35,14 +35,16 @@ def __init__(self): self.kvl = [] self.re_kv = re.compile(self.KIVI_REGEX) - def append(self, payload): + def append(self, payload: bytes): """! Append stream buffer with payload and process. Returns non-KV strings""" logger = HtrunLogger('CONN') try: self.buff += payload.decode('utf-8') except UnicodeDecodeError: - logger.prn_wrn("UnicodeDecodeError encountered!") - self.buff += payload.decode('utf-8','ignore') + decoded_payload = payload.decode('utf-8','ignore') + logger.prn_wrn(f"UnicodeDecodeError encountered! Raw bytes were {payload!r} and they decoded to \"{decoded_payload}\"") + self.buff += decoded_payload + lines = self.buff.split('\n') self.buff = lines[-1] # remaining lines.pop(-1) @@ -64,9 +66,12 @@ def append(self, payload): if len(after) > 0: # not a K,V pair part discarded.append(after) + logger.prn_inf("found KV pair in stream: {{%s;%s}}, queued..."% (key, value)) else: # not a K,V pair discarded.append(line) + logger.prn_rxd(line) + return discarded def search(self): @@ -121,7 +126,7 @@ def conn_primitive_factory(conn_resource, config, event_queue, logger): return connector -def conn_process(event_queue, dut_event_queue, config): +def conn_process(event_queue, dut_event_queue, config: dict[str, Any]): def __notify_conn_lost(): error_msg = connector.error() @@ -143,12 +148,20 @@ def __notify_sync_failed(): # Configuration of conn_opriocess behaviour sync_behavior = int(config.get('sync_behavior', 1)) sync_timeout = config.get('sync_timeout', 1.0) + sync_predelay: float = config["sync_predelay"] conn_resource = config.get('conn_resource', 'serial') - last_sync = False + syncs_sent = 0 # Create connector instance with proper configuration connector = conn_primitive_factory(conn_resource, config, event_queue, logger) + # If requested, wait after opening serial port (done in conn_primitive_factory()) but before sending + # sync word. This is needed for certain targets (e.g. Ambiq Apollo3) which get reset when the port is opened + # and then need time to boot up. + if sync_predelay > 0: + logger.prn_inf(f"Pre-sync delay for {sync_predelay:.02f} sec...") + sleep(sync_predelay) + # If the connector failed, stop the process now if not connector.connected(): logger.prn_err("Failed to connect to resource") @@ -164,7 +177,7 @@ def __notify_sync_failed(): # We will ignore all kv pairs before we get sync back sync_uuid_discovered = False - def __send_sync(timeout=None): + def __send_sync(timeout=None) -> str | None: sync_uuid = str(uuid.uuid4()) # Handshake, we will send {{sync;UUID}} preamble and wait for mirrored reply if timeout: @@ -203,7 +216,7 @@ def __send_sync(timeout=None): if sync_uuid: sync_uuid_list.append(sync_uuid) - sync_behavior -= 1 + syncs_sent += 1 else: __notify_conn_lost() return 0 @@ -217,7 +230,7 @@ def __send_sync(timeout=None): sync_uuid = __send_sync() if sync_uuid: sync_uuid_list.append(sync_uuid) - sync_behavior -= 1 + syncs_sent += 1 else: __notify_conn_lost() return 0 @@ -256,7 +269,6 @@ def __send_sync(timeout=None): # Stream data stream KV parsing print_lines = kv_buffer.append(data) for line in print_lines: - logger.prn_rxd(line) event_queue.put(('__rxd_line', line, time())) while kv_buffer.search(): key, value, timestamp = kv_buffer.pop_kv() @@ -281,30 +293,27 @@ def __send_sync(timeout=None): if not sync_uuid_discovered: # Resending __sync after 'sync_timeout' secs (default 1 sec) - # to target platform. If 'sync_behavior' counter is != 0 we + # to target platform. If 'syncs_remaining' is less than 'sync_behavior' we # will continue to send __sync packets to target platform. - # If we specify 'sync_behavior' < 0 we will send 'forever' - # (or until we get reply) + # Or if 'sync_behavior' < 0 we will send 'forever' (or until we get reply) - if sync_behavior != 0: - time_to_sync_again = time() - loop_timer - if time_to_sync_again > sync_timeout: + time_to_sync_again = time() - loop_timer + if time_to_sync_again > sync_timeout: + if sync_behavior < 0 or (sync_behavior > 0 and syncs_sent < sync_behavior): + # No response to sync but sync can be retried sync_uuid = __send_sync(timeout=time_to_sync_again) if sync_uuid: sync_uuid_list.append(sync_uuid) - sync_behavior -= 1 + syncs_sent += 1 loop_timer = time() - #Sync behavior will be zero and if last sync fails we should report connection - #lost - if sync_behavior == 0: - last_sync = True else: __notify_conn_lost() break - elif last_sync == True: - #SYNC lost connection event : Device not responding, send sync failed - __notify_sync_failed() - break + + else: + # No response, connection failed + __notify_sync_failed() + break return 0 diff --git a/tools/python/mbed_os_tools/test/host_tests_runner/host_test_default.py b/tools/python/mbed_os_tools/test/host_tests_runner/host_test_default.py index 27bc9e9c285..2c043a60c18 100644 --- a/tools/python/mbed_os_tools/test/host_tests_runner/host_test_default.py +++ b/tools/python/mbed_os_tools/test/host_tests_runner/host_test_default.py @@ -176,7 +176,8 @@ def callback__notify_prn(key, value, timestamp): "image_path" : self.mbed.image_path, "skip_reset": self.options.skip_reset, "tags" : self.options.tag_filters, - "sync_timeout": self.options.sync_timeout + "sync_timeout": self.options.sync_timeout, + "sync_predelay": self.options.sync_predelay, } if self.options.global_resource_mgr: @@ -332,8 +333,9 @@ def process_code_coverage(key, value, timestamp): self.logger.prn_inf("sync KV found, uuid=%s, timestamp=%f"% (str(value), timestamp)) elif key == '__notify_sync_failed': # This event is sent by conn_process, SYNC failed - self.logger.prn_err(value) - self.logger.prn_wrn("stopped to consume events due to %s event"% key) + self.logger.prn_err("stopped consuming events due to %s event"% key) + if value is not None: + self.logger.prn_err(value) callbacks_consume = False result = self.RESULT_SYNC_FAILED event_queue.put(('__exit_event_queue', 0, time())) From 2225139fa2f9f7187df5f04dbc83e227f64b8ccf Mon Sep 17 00:00:00 2001 From: Jamie Smith Date: Thu, 19 Jun 2025 13:58:38 -0700 Subject: [PATCH 4/8] Start on sync predelay option --- extern/greentea-client/mbed_lib.json5 | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 extern/greentea-client/mbed_lib.json5 diff --git a/extern/greentea-client/mbed_lib.json5 b/extern/greentea-client/mbed_lib.json5 new file mode 100644 index 00000000000..95506bce3bb --- /dev/null +++ b/extern/greentea-client/mbed_lib.json5 @@ -0,0 +1,24 @@ +{ + // Config file for Mbed's Greentea unit test runner + "name": "greentea-client", + + // Config options + "config": { + "sync-predelay": { + "help": "Wait this amount of time (in floating point seconds) after opening the serial port before sending sync.", + "value": null + }, + }, + + // Per-target overrides + "target_overides": { + "AMA3B1KK": { + // These boards have the serial port DTR line tied to the MCU reset, so the MCU will restart when + // the serial port is opened. It appears that if there is serial port activity within 200ms of opening the port + // (see here https://github.com/sparkfun/Apollo3_Uploader_SVL/blob/fc89de7f8163fe755021ca88e779e2963209e5a6/bootloader/src/main.c#L330) + // the MCU will get stuck in the bootloader and not boot. Based on testing, we need to wait about 300ms + // for the MCU to fully boot and be ready to accept the sync word. + "sync-predelay": 0.3 + } + } +} From 93cd27a9eebaf1812dd40a17fbe13b71778b3610 Mon Sep 17 00:00:00 2001 From: Jamie Smith Date: Fri, 20 Jun 2025 14:11:42 -0700 Subject: [PATCH 5/8] Tests passing on Artemis! There was some missing undocumented lp ticker behavior, I added docs and tests for it. --- .../hal/apollo3/hci_drv_apollo3.c | 2 +- extern/greentea-client/mbed_lib.json5 | 2 +- .../FEATURE_LWIP/feature_lwip_is_deprecated.c | 27 - .../feature_nanostack_is_deprecated.c | 27 - .../frameworks/greentea-client/CMakeLists.txt | 17 - features/frameworks/greentea-client/README.md | 94 --- .../greentea-client/greentea_metrics.h | 40 - .../greentea-client/test_env.h | 129 --- .../frameworks/greentea-client/mbed_lib.json | 3 - .../source/greentea_metrics.cpp | 249 ------ .../source/greentea_test_env.cpp | 744 ------------------ features/frameworks/utest/CMakeLists.txt | 2 +- hal/include/hal/lp_ticker_api.h | 26 +- hal/include/hal/us_ticker_api.h | 21 +- .../TESTS/mbed_hal/common_tickers/main.cpp | 60 +- .../TESTS/mbed_platform/stats_sys/main.cpp | 48 +- .../TARGET_Apollo3/device/isr.c | 1 - .../TARGET_Apollo3/device/lp_ticker.c | 25 +- .../TARGET_Apollo3/device/sleep.c | 10 + .../TARGET_Apollo3/device/us_ticker.c | 1 + targets/upload_method_cfg/SFE_ARTEMIS.cmake | 4 +- tools/cmake/mbed_greentea.cmake | 5 + .../test/host_tests_conn_proxy/conn_proxy.py | 3 +- 23 files changed, 154 insertions(+), 1386 deletions(-) delete mode 100644 features/deprecated_warnings/FEATURE_LWIP/feature_lwip_is_deprecated.c delete mode 100644 features/deprecated_warnings/FEATURE_NANOSTACK/feature_nanostack_is_deprecated.c delete mode 100644 features/frameworks/greentea-client/CMakeLists.txt delete mode 100644 features/frameworks/greentea-client/README.md delete mode 100644 features/frameworks/greentea-client/greentea-client/greentea_metrics.h delete mode 100644 features/frameworks/greentea-client/greentea-client/test_env.h delete mode 100644 features/frameworks/greentea-client/mbed_lib.json delete mode 100644 features/frameworks/greentea-client/source/greentea_metrics.cpp delete mode 100644 features/frameworks/greentea-client/source/greentea_test_env.cpp diff --git a/connectivity/drivers/ble/FEATURE_BLE/TARGET_Ambiq_Micro/hal/apollo3/hci_drv_apollo3.c b/connectivity/drivers/ble/FEATURE_BLE/TARGET_Ambiq_Micro/hal/apollo3/hci_drv_apollo3.c index e9cbfa096ee..d988c13bf86 100644 --- a/connectivity/drivers/ble/FEATURE_BLE/TARGET_Ambiq_Micro/hal/apollo3/hci_drv_apollo3.c +++ b/connectivity/drivers/ble/FEATURE_BLE/TARGET_Ambiq_Micro/hal/apollo3/hci_drv_apollo3.c @@ -511,7 +511,7 @@ HciDrvRadioBoot(bool bColdBoot) CRITICAL_PRINT("INTEN: %d\n", BLEIF->INTEN_b.BLECSSTAT); CRITICAL_PRINT("INTENREG: %d\n", BLEIF->INTEN); - NVIC_SetVector(BLE_IRQn, HciDrvIntService); + NVIC_SetVector(BLE_IRQn, (uint32_t)HciDrvIntService); NVIC_EnableIRQ(BLE_IRQn); // diff --git a/extern/greentea-client/mbed_lib.json5 b/extern/greentea-client/mbed_lib.json5 index 95506bce3bb..28fd656a931 100644 --- a/extern/greentea-client/mbed_lib.json5 +++ b/extern/greentea-client/mbed_lib.json5 @@ -11,7 +11,7 @@ }, // Per-target overrides - "target_overides": { + "target_overrides": { "AMA3B1KK": { // These boards have the serial port DTR line tied to the MCU reset, so the MCU will restart when // the serial port is opened. It appears that if there is serial port activity within 200ms of opening the port diff --git a/features/deprecated_warnings/FEATURE_LWIP/feature_lwip_is_deprecated.c b/features/deprecated_warnings/FEATURE_LWIP/feature_lwip_is_deprecated.c deleted file mode 100644 index 729da247b99..00000000000 --- a/features/deprecated_warnings/FEATURE_LWIP/feature_lwip_is_deprecated.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2018 Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "platform/mbed_toolchain.h" - - -MBED_DEPRECATED_SINCE("5.10", "FEATURE_LWIP is deprecated. You do not need to enable it anymore in mbed_app.json") -static void feature_lwip(void) { } -void dummy_feature_lwip_is_deprecated(void) -{ - feature_lwip(); -} diff --git a/features/deprecated_warnings/FEATURE_NANOSTACK/feature_nanostack_is_deprecated.c b/features/deprecated_warnings/FEATURE_NANOSTACK/feature_nanostack_is_deprecated.c deleted file mode 100644 index a612dc1a9e3..00000000000 --- a/features/deprecated_warnings/FEATURE_NANOSTACK/feature_nanostack_is_deprecated.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2018 Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "platform/mbed_toolchain.h" - - -MBED_DEPRECATED_SINCE("5.10", "FEATURE_NANOSTACK is deprecated. You do not need to enable it anymore in mbed_app.json") -static void feature_nanostack(void) { } -void dummy_feature_nanostack_is_deprecated(void) -{ - feature_nanostack(); -} diff --git a/features/frameworks/greentea-client/CMakeLists.txt b/features/frameworks/greentea-client/CMakeLists.txt deleted file mode 100644 index da506505e41..00000000000 --- a/features/frameworks/greentea-client/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2020 ARM Limited. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -add_library(mbed-greentea STATIC EXCLUDE_FROM_ALL) -target_include_directories(mbed-greentea - PUBLIC - . - greentea-client -) - -target_sources(mbed-greentea - PRIVATE - source/greentea_metrics.cpp - source/greentea_test_env.cpp -) - -target_link_libraries(mbed-greentea PUBLIC mbed-core-flags) diff --git a/features/frameworks/greentea-client/README.md b/features/frameworks/greentea-client/README.md deleted file mode 100644 index d67e41ac38f..00000000000 --- a/features/frameworks/greentea-client/README.md +++ /dev/null @@ -1,94 +0,0 @@ -# Table of contents - -* [greentea-client](#greentea-client) - * [Concepts](#concepts) - * [Test suite](#test-suite) - * [Test case](#test-case) - * [key-value protocol](#key-value-protocol) -* [Test example](#test-examplel) - -# greentea-client - -*Note*: This copy of greentea-client is used only with Mbed CLI 1. Mbed CLI 2 -will use the standalone greentea-client, automatically fetched by CMake [in the -`extern/` directory](../../../extern/README.md). - -`greentea-client` is a client library for [the Greentea test tool](https://github.com/ARMmbed/mbed-os-tools/tree/master/packages/mbed-greentea) when used in an [Mbed OS](https://os.mbed.com/) project. - -This package implements the client side of the key-value protocol used for communication between the device under test (DUT) and the host. The `Greentea` tool implements the protocol's host behavior. We use [utest](https://github.com/ARMmbed/mbed-os/blob/master/features/frameworks/utest/README.md) as our test harness. - -``` - DUT <--- serial port connection ---> host - (client) . (host) - . -[greentea-client] . [conn_process] [htrun] - ===== . ================ ========= - | . | | - | . | | - | {{ key ; value }} | | - |------------------------->| (key, value, timestamp) | - | . |------------------------>| - | . | | - | . | | - | . | | - | . | | - | . | | - | . | (key, value, timestamp) | - | {{ key ; value }} |<------------------------| - |<-------------------------| | - | . | | - . -``` - -## Concepts - -### Test suite - -A test suite is a binary containing test cases we execute on hardware. The test suite has a beginning and an end (like the `main()` function would. The test suite may pass, fail or be in an error state (for example, if the test suite times out or there was a serial port connection problem). - -### Test case - -A test case is contained within a test suite. You can have multiple test cases within a test suite. `unity` assert macros are used to run the checks during the test case. Your test cases may pass, fail or be in an error state. - -### Key-value protocol - -The key-value protocol is a protocol specific to the `Greentea` test tool. It is used to send messages (events) between the DUT and the host. Each message consists of a _key_ and _value_ pair. A message is surrounded by double curly braces. The key and value are separated by a semicolon (`;`). - -For example, the `{{timeout;120}}}` string is a key-value message where the key `timeout` has the value `120`. Both `greentea-client` and `Greentea` understand this format and can detect key-value messages in a data stream. - -## Test example - -```c++ -#include "mbed.h" -#include "greentea-client/test_env.h" -#include "utest/utest.h" -#include "unity/unity.h" - -void test_case_1_func() { - // Test case #1 body - // Here you can run your test cases and assertions - TEST_ASSERT_TRUE(true); - TEST_ASSERT_FALSE(false); -} - -void test_case_2_func() { - // Test case #2 body - // Here you can run your test cases and assertions - TEST_ASSERT_TRUE(true); - TEST_ASSERT_FALSE(false); -} - -const Case cases[] = { - Case("Test case #1 name", test_case_1_func), - Case("Test case #1 name", test_case_2_func) -}; - -status_t greentea_setup(const size_t number_of_cases) { - GREENTEA_SETUP(5, "default_auto"); - return greentea_test_setup_handler(number_of_cases); -} - -void main(int, char*[]) { - Harness::run(specification); -} -``` diff --git a/features/frameworks/greentea-client/greentea-client/greentea_metrics.h b/features/frameworks/greentea-client/greentea-client/greentea_metrics.h deleted file mode 100644 index 5c0f5d734d5..00000000000 --- a/features/frameworks/greentea-client/greentea-client/greentea_metrics.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * mbed Microcontroller Library - * Copyright (c) 2006-2019 ARM Limited - * - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "platform/mbed_toolchain.h" - -/** \addtogroup frameworks */ -/** @{*/ -#ifndef GREENTEA_METRICS_H -#define GREENTEA_METRICS_H - -/** - * Setup platform specific metrics - */ -MBED_DEPRECATED_SINCE("mbed-os-6.14", "Greentea metrics API are deprecated") -void greentea_metrics_setup(void); - -/** - * Report and cleanup platform specifc metrics - */ -MBED_DEPRECATED_SINCE("mbed-os-6.14", "Greentea metrics API are deprecated") -void greentea_metrics_report(void); - -#endif - -/** @}*/ diff --git a/features/frameworks/greentea-client/greentea-client/test_env.h b/features/frameworks/greentea-client/greentea-client/test_env.h deleted file mode 100644 index b21db6b181a..00000000000 --- a/features/frameworks/greentea-client/greentea-client/test_env.h +++ /dev/null @@ -1,129 +0,0 @@ - -/** \addtogroup frameworks */ -/** @{*/ -/* - * Copyright (c) 2013-2016, ARM Limited, All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef GREENTEA_CLIENT_TEST_ENV_H_ -#define GREENTEA_CLIENT_TEST_ENV_H_ - -#ifdef __cplusplus -#define MBED_GREENTEA_CLIENT_VERSION_STRING "1.3.0" - -#include - -/** - * Auxilary macros - */ -#ifndef NL -#define NL "\n" -#endif -#ifndef RCNL -#define RCNL "\r\n" -#endif - -/** - * Ensure compatibility with utest - */ -#define TEST_ENV_TESTCASE_COUNT GREENTEA_TEST_ENV_TESTCASE_COUNT -#define TEST_ENV_TESTCASE_START GREENTEA_TEST_ENV_TESTCASE_START -#define TEST_ENV_TESTCASE_FINISH GREENTEA_TEST_ENV_TESTCASE_FINISH -#define TEST_ENV_TESTCASE_SUMMARY GREENTEA_TEST_ENV_TESTCASE_SUMMARY - -/** - * Default length for UUID buffers (used during the sync process) - */ -#define GREENTEA_UUID_LENGTH 48 - -/** - * Generic test suite transport protocol keys - */ -extern const char* GREENTEA_TEST_ENV_END; -extern const char* GREENTEA_TEST_ENV_EXIT; -extern const char* GREENTEA_TEST_ENV_SYNC; -extern const char* GREENTEA_TEST_ENV_TIMEOUT; -extern const char* GREENTEA_TEST_ENV_HOST_TEST_NAME; -extern const char* GREENTEA_TEST_ENV_HOST_TEST_VERSION; - -/** - * Test suite success code strings - */ -extern const char* GREENTEA_TEST_ENV_SUCCESS; -extern const char* GREENTEA_TEST_ENV_FAILURE; - -/** - * Test case transport protocol start/finish keys - */ -extern const char* GREENTEA_TEST_ENV_TESTCASE_NAME; -extern const char* GREENTEA_TEST_ENV_TESTCASE_COUNT; -extern const char* GREENTEA_TEST_ENV_TESTCASE_START; -extern const char* GREENTEA_TEST_ENV_TESTCASE_FINISH; -extern const char* GREENTEA_TEST_ENV_TESTCASE_SUMMARY; - -/** - * Code Coverage (LCOV) transport protocol keys - */ -extern const char* GREENTEA_TEST_ENV_LCOV_START; - -/** - * Greentea-client related API for communication with host side - */ -void GREENTEA_SETUP_UUID(const int timeout, const char *host_test_name, char *buffer, size_t size); -void GREENTEA_TESTSUITE_RESULT(const int); -void GREENTEA_TESTCASE_START(const char *test_case_name); -void GREENTEA_TESTCASE_FINISH(const char *test_case_name, const size_t passes, const size_t failed); - -/** - * Test suite result related notification API - */ -void greentea_send_kv(const char *, const int); -void greentea_send_kv(const char *, const int, const int); -void greentea_send_kv(const char *, const char *, const int); -void greentea_send_kv(const char *, const char *, const int, const int); - -#ifdef MBED_CFG_DEBUG_OPTIONS_COVERAGE -/** - * Code Coverage API - */ -void greentea_notify_coverage_start(const char *path); -void greentea_notify_coverage_end(); -#endif // MBED_CFG_DEBUG_OPTIONS_COVERAGE - -#endif // __cplusplus - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Greentea-client C API - */ -void GREENTEA_SETUP(const int timeout, const char * host_test); -void greentea_send_kv(const char * key, const char * val); -int greentea_parse_kv(char * key, char * val, - const int key_len, const int val_len); -int greentea_getc(); -void greentea_putc(int c); -void greentea_write_string(const char *str); - -#ifdef __cplusplus -} -#endif - -#endif // GREENTEA_CLIENT_TEST_ENV_H_ - -/** @}*/ diff --git a/features/frameworks/greentea-client/mbed_lib.json b/features/frameworks/greentea-client/mbed_lib.json deleted file mode 100644 index 368181c1f29..00000000000 --- a/features/frameworks/greentea-client/mbed_lib.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "name": "greentea-client" -} diff --git a/features/frameworks/greentea-client/source/greentea_metrics.cpp b/features/frameworks/greentea-client/source/greentea_metrics.cpp deleted file mode 100644 index 8437c8d89c9..00000000000 --- a/features/frameworks/greentea-client/source/greentea_metrics.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (c) 2013-2016, ARM Limited, All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "greentea-client/test_env.h" -#include "greentea-client/greentea_metrics.h" -#include "platform/mbed_stats.h" -#include - -#if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) - -#include "rtos/Mutex.h" -#include "rtos/Thread.h" -#include "rtos/Kernel.h" -#include "mbed_stats.h" -#include "cmsis_os2.h" -#include "platform/SingletonPtr.h" -#include "platform/CircularBuffer.h" -using namespace mbed; -using namespace rtos; - -#define THREAD_BUF_COUNT 16 - -typedef struct { - uint32_t entry; - uint32_t stack_size; - uint32_t max_stack; - const char *stack_name; -} thread_info_t; - -// Mutex to protect "buf" -static SingletonPtr mutex; -static char buf[128]; -static SingletonPtr > queue; -#endif - -#if defined(MBED_CPU_STATS_ENABLED) -static void send_CPU_info(void); -#endif - -#if defined(MBED_HEAP_STATS_ENABLED ) && MBED_HEAP_STATS_ENABLED -static void send_heap_info(void); -#endif -#if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) -static void send_stack_info(void); -static void on_thread_terminate(osThreadId_t id); -static void enqeue_thread_info(osThreadId_t id); -static void deque_and_print_thread_info(void); - -// sprintf uses a lot of stack so use these instead -static uint32_t print_str(char *buf, const char *value); -static uint32_t print_hex(char *buf, uint32_t value); -static uint32_t print_dec(char *buf, uint32_t value); -#endif - -void greentea_metrics_setup() -{ -#if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) - Kernel::attach_thread_terminate_hook(on_thread_terminate); -#endif -} - -void greentea_metrics_report() -{ -#if defined(MBED_HEAP_STATS_ENABLED ) && MBED_HEAP_STATS_ENABLED - send_heap_info(); -#endif -#if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) - send_stack_info(); - Kernel::attach_thread_terminate_hook(NULL); -#endif -#if defined(MBED_CPU_STATS_ENABLED) - send_CPU_info(); -#endif -} - -#if defined(MBED_CPU_STATS_ENABLED) -static void send_CPU_info() -{ - mbed_stats_cpu_t stats; - mbed_stats_cpu_get(&stats); - - greentea_send_kv("__cpu_info up time", stats.uptime); - greentea_send_kv("__cpu_info sleep time", stats.sleep_time); - greentea_send_kv("__cpu_info deepsleep time", stats.deep_sleep_time); - greentea_send_kv("__cpu_info % sleep/deep", (stats.sleep_time * 100) / stats.uptime, (stats.deep_sleep_time * 100) / stats.uptime); -} -#endif - -#if defined(MBED_HEAP_STATS_ENABLED ) && MBED_HEAP_STATS_ENABLED -static void send_heap_info() -{ - mbed_stats_heap_t heap_stats; - mbed_stats_heap_get(&heap_stats); - greentea_send_kv("max_heap_usage",heap_stats.max_size); - greentea_send_kv("reserved_heap",heap_stats.reserved_size); -} -#endif - -#if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) -MBED_UNUSED static void send_stack_info() -{ - mutex->lock(); - - // Flush any queued stack entries - while (!queue->empty()) { - deque_and_print_thread_info(); - } - - // Print info for all other threads - uint32_t thread_n = osThreadGetCount(); - osThreadId_t *threads = new (std::nothrow) osThreadId_t[thread_n]; - // Don't fail on lack of memory - if (!threads) { - goto end; - } - thread_n = osThreadEnumerate(threads, thread_n); - - for(size_t i = 0; i < thread_n; i++) { - enqeue_thread_info(threads[i]); - deque_and_print_thread_info(); - } - - delete[] threads; - -end: - mutex->unlock(); -} - -MBED_UNUSED static void on_thread_terminate(osThreadId_t id) -{ - mutex->lock(); - - // There should always be space in the queue - enqeue_thread_info(id); - - // If queue is full then print out a single entry - if (queue->full()) { - deque_and_print_thread_info(); - } - - mutex->unlock(); -} - -static void enqeue_thread_info(osThreadId_t id) -{ - thread_info_t thread_info = {}; - - thread_info.entry = (uint32_t)id; - thread_info.stack_size = osThreadGetStackSize(id); - thread_info.max_stack = thread_info.stack_size - osThreadGetStackSpace(id); - thread_info.stack_name = osThreadGetName(id); - queue->push(thread_info); -} - -static void deque_and_print_thread_info() -{ - thread_info_t thread_info; - bool ret = queue->pop(thread_info); - MBED_ASSERT(ret); - uint32_t pos = 0; - buf[pos++] = '\"'; - pos += print_str(buf + pos, thread_info.stack_name); - buf[pos++] = '\"'; - buf[pos++] = ','; - buf[pos++] = '\"'; - pos += print_hex(buf + pos, thread_info.entry); - buf[pos++] = '\"'; - buf[pos++] = ','; - pos += print_dec(buf + pos, thread_info.max_stack); - buf[pos++] = ','; - pos += print_dec(buf + pos, thread_info.stack_size); - buf[pos++] = 0; - greentea_send_kv("__thread_info", buf); -} - -static uint32_t print_str(char *buf, const char *value) -{ - uint32_t pos = 0; - for (pos = 0; pos < strlen(value); pos++) { - buf[pos] = value[pos]; - } - return pos; -} - - -static uint32_t print_hex(char *buf, uint32_t value) -{ - uint32_t pos = 0; - buf[pos] = '0'; - pos++; - buf[pos] = 'x'; - pos++; - for (int i = 8; i >= 0; i--) { - uint32_t val = (value >> (4 * i)) & 0xF; - if (val <= 9) { - buf[pos] = '0' + val; - pos++; - } else { - buf[pos] = 'a' + val - 10; - pos++; - } - } - return pos; -} - -static uint32_t print_dec(char *buf, uint32_t value) -{ - uint32_t pos = 0; - - // The value 0 is special case - if (0 == value) { - buf[pos] = '0'; - pos++; - return pos; - } - - // Write out value in reverse order - while (value != 0) { - uint32_t next = value / 10; - buf[pos] = '0' + (value - next * 10); - value = next; - pos++; - } - - // Reverse order - for (uint32_t i = 0; i < pos / 2; i++) { - char temp = buf[i]; - buf[i] = buf[pos - 1 - i]; - buf[pos - 1 - i] = temp; - } - - return pos; -} - -#endif diff --git a/features/frameworks/greentea-client/source/greentea_test_env.cpp b/features/frameworks/greentea-client/source/greentea_test_env.cpp deleted file mode 100644 index 9915bb4c56b..00000000000 --- a/features/frameworks/greentea-client/source/greentea_test_env.cpp +++ /dev/null @@ -1,744 +0,0 @@ -/* - * Copyright (c) 2013-2016, ARM Limited, All Rights Reserved - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include "greentea-client/test_env.h" -#include "greentea-client/greentea_metrics.h" -#include "mbed_trace.h" -#include "platform/mbed_retarget.h" - -/** - * Generic test suite transport protocol keys - */ -const char* GREENTEA_TEST_ENV_END = "end"; -const char* GREENTEA_TEST_ENV_EXIT = "__exit"; -const char* GREENTEA_TEST_ENV_SYNC = "__sync"; -const char* GREENTEA_TEST_ENV_TIMEOUT = "__timeout"; -const char* GREENTEA_TEST_ENV_HOST_TEST_NAME = "__host_test_name"; -const char* GREENTEA_TEST_ENV_HOST_TEST_VERSION = "__version"; - -/** - * Test suite success code strings - */ -const char* GREENTEA_TEST_ENV_SUCCESS = "success"; -const char* GREENTEA_TEST_ENV_FAILURE = "failure"; - -/** - * Test case transport protocol start/finish keys - */ -const char* GREENTEA_TEST_ENV_TESTCASE_NAME = "__testcase_name"; -const char* GREENTEA_TEST_ENV_TESTCASE_COUNT = "__testcase_count"; -const char* GREENTEA_TEST_ENV_TESTCASE_START = "__testcase_start"; -const char* GREENTEA_TEST_ENV_TESTCASE_FINISH = "__testcase_finish"; -const char* GREENTEA_TEST_ENV_TESTCASE_SUMMARY = "__testcase_summary"; -// Code Coverage (LCOV) transport protocol keys -const char* GREENTEA_TEST_ENV_LCOV_START = "__coverage_start"; - -/** - * Auxilary functions - */ -static void greentea_notify_timeout(const int); -static void greentea_notify_hosttest(const char *); -static void greentea_notify_completion(const int); -static void greentea_notify_version(); - -/** \brief Handle the handshake with the host - * \details This is contains the shared handhshake functionality that is used between - * GREENTEA_SETUP and GREENTEA_SETUP_UUID. - * This function is blocking. - */ -void _GREENTEA_SETUP_COMMON(const int timeout, const char *host_test_name, char *buffer, size_t size) { - greentea_metrics_setup(); - // Key-value protocol handshake function. Waits for {{__sync;...}} message - // Sync preamble: "{{__sync;0dad4a9d-59a3-4aec-810d-d5fb09d852c1}}" - // Example value of sync_uuid == "0dad4a9d-59a3-4aec-810d-d5fb09d852c1" - - char _key[8] = {0}; - - while (1) { - greentea_parse_kv(_key, buffer, sizeof(_key), size); - greentea_write_string("mbedmbedmbedmbedmbedmbedmbedmbed\r\n"); - if (strcmp(_key, GREENTEA_TEST_ENV_SYNC) == 0) { - // Found correct __sync message - greentea_send_kv(_key, buffer); - break; - } - } - -#ifdef MBED_CONF_MBED_TRACE_ENABLE - mbed_trace_init(); -#endif - - greentea_notify_version(); - greentea_notify_timeout(timeout); - greentea_notify_hosttest(host_test_name); -} - -/** \brief Handshake with host and send setup data (timeout and host test name) - * \details This function will send preamble to master. - * After host test name is received master will invoke host test script - * and add host test's callback handlers to main event loop - * This function is blocking. - */ -extern "C" void GREENTEA_SETUP(const int timeout, const char *host_test_name) { -#if ! defined(NO_GREENTEA) - char _value[GREENTEA_UUID_LENGTH] = {0}; - _GREENTEA_SETUP_COMMON(timeout, host_test_name, _value, GREENTEA_UUID_LENGTH); -#endif -} - -/** \brief Handshake with host and send setup data (timeout and host test name). Allows you to preserve sync UUID. - * \details This function will send preamble to master. - * After host test name is received master will invoke host test script - * and add host test's callback handlers to main event loop - * This function is blocking. - * This function differs from GREENTEA_SETUP because it allows you to - * preserve the UUID sent during the sync process. - */ -void GREENTEA_SETUP_UUID(const int timeout, const char *host_test_name, char *buffer, size_t size) { - _GREENTEA_SETUP_COMMON(timeout, host_test_name, buffer, size); -} - -/** \brief Notify host (__exit message) side that test suite execution was complete - * \result Test suite result - * \details If __exit is not received by host side we will assume TIMEOUT - */ -void GREENTEA_TESTSUITE_RESULT(const int result) { - greentea_notify_completion(result); -} - -/** - * Test Case support - */ - -/** \brief Notify host side that test case started - * \details test_case_name Test case name - */ -void GREENTEA_TESTCASE_START(const char *test_case_name) { - greentea_send_kv(GREENTEA_TEST_ENV_TESTCASE_START, test_case_name); -} - -/** \brief Notify host side that test case finished - * \details test_case_name Test case name - * \details result Test case result (0 -OK, non zero...) - */ -void GREENTEA_TESTCASE_FINISH(const char *test_case_name, const size_t passes, const size_t failed) { - greentea_send_kv(GREENTEA_TEST_ENV_TESTCASE_FINISH, test_case_name, passes, failed); -} - -/** - ***************************************************************************** - * Auxilary functions and key-value protocol support - ***************************************************************************** - */ - - -/** - ***************************************************************************** - * LCOV support - ***************************************************************************** - */ -#ifdef MBED_CFG_DEBUG_OPTIONS_COVERAGE -extern "C" void __gcov_flush(void); -extern bool coverage_report; - -/** - * \brief Send code coverage (gcov/LCOV) notification to master - * - * Generates preamble of message sent to notify host about code coverage data dump. - * - * This function is used by Mbed OS - * (see: mbed-os/platform/mbed_retarget.cpp) to generate code coverage - * messages to host. When code coverage feature is turned on slave will - * print-out code coverage data in form of key-value protocol. - * Message with code coverage data will contain message name, path to code - * coverage output file host will touch and fill with code coverage binary - * payload. Coverage payload is encoded as stream of ASCII coded bytes ("%02X"). - * - * \param path to file with code coverage payload (set by gcov instrumentation) - * - */ -void greentea_notify_coverage_start(const char *path) { - printf("{{%s;%s;", GREENTEA_TEST_ENV_LCOV_START, path); -} - -/** - * \brief Sufix for code coverage message to master (closing statement) - * - * This function is used by Mbed OS - * (see: mbed-os/platform/mbed_retarget.cpp) to generate code coverage - * messages to host. When code coverage feature is turned on slave will - * print-out code coverage data in form of key-value protocol. - * Message with code coverage data will contain message name, path to code - * coverage output file host will touch and fill with code coverage binary - * payload. Coverage payload is encoded as stream of ASCII coded bytes ("%02X"). - * - * Companion function greentea_notify_coverage_start() defines code coverage message structure - * - */ -void greentea_notify_coverage_end() { - printf("}}" NL); -} - -#endif - -/** - ***************************************************************************** - * Key-value protocol support - ***************************************************************************** - */ - -/** - * \brief Write the preamble characters to the serial port - * - * This function writes the preamble "{{" which is required - * for key-value comunication between the target and the host. - * This uses greentea_putc which allows the direct writing of characters - * using the write() method. - * This suite of functions are provided to allow for serial communication - * to the host from within a thread/ISR. - */ -static void greentea_write_preamble() -{ - greentea_putc('{'); - greentea_putc('{'); -} - -/** - * \brief Write the postamble characters to the serial port - * - * This function writes the postamble "{{\n" which is required - * for key-value comunication between the target and the host. - * This uses greentea_putc which allows the direct writing of characters - * using the write() method. - * This suite of functions are provided to allow for serial communication - * to the host from within a thread/ISR. - * - */ -static void greentea_write_postamble() -{ - greentea_putc('}'); - greentea_putc('}'); - greentea_putc('\r'); - greentea_putc('\n'); -} - -/** - * \brief Write an int to the serial port - * - * This function writes an integer value from the target - * to the host. The integer value is converted to a string and - * and then written character by character directly to the serial - * port using the console. - * sprintf() is used to convert the int to a string. Sprintf if - * inherently thread safe so can be used. - * - * \param val - integer value - * - */ -#define MAX_INT_STRING_LEN 15 -static void greentea_write_int(const int val) -{ - char intval[MAX_INT_STRING_LEN]; - unsigned int i = 0; - sprintf(intval, "%d", val); - while (intval[i] != '\0') { - greentea_putc(intval[i]); - i++; - } -} - -/** - * \brief Encapsulate and send key-value message from DUT to host - * - * This function uses underlying functions to write directly - * to the serial port, (CONSOLE_TX). This allows KVs to be used - * from within interrupt context. - * - * \param key Message key (message/event name) - * \param value Message payload, string value - * - */ -extern "C" void greentea_send_kv(const char *key, const char *val) { - if (key && val) { - greentea_write_preamble(); - greentea_write_string(key); - greentea_putc(';'); - greentea_write_string(val); - greentea_write_postamble(); - } -} - -/** - * \brief Encapsulate and send key-value message from DUT to host - * - * This function uses underlying functions to write directly - * to the serial port, (CONSOLE_TX). This allows KVs to be used - * from within interrupt context. - * Last value is an integer to avoid integer to string conversion - * made by the user. - * - * \param key Message key (message/event name) - * \param value Message payload, integer value - * - */ -void greentea_send_kv(const char *key, const int val) { - if (key) { - greentea_write_preamble(); - greentea_write_string(key); - greentea_putc(';'); - greentea_write_int(val); - greentea_write_postamble(); - } -} - -/** - * \brief Encapsulate and send key-value-value message from DUT to host - * - * This function uses underlying functions to write directly - * to the serial port, (CONSOLE_TX). This allows KVs to be used - * from within interrupt context. - * Last value is an integer to avoid integer to string conversion - * made by the user. - * - * \param key Message key (message/event name) - * \param value Message payload, string value - * \param result Send additional integer formatted data - * - */ -void greentea_send_kv(const char *key, const char *val, const int result) { - if (key) { - greentea_write_preamble(); - greentea_write_string(key); - greentea_putc(';'); - greentea_write_string(val); - greentea_putc(';'); - greentea_write_int(result); - greentea_write_postamble(); - - } -} - -/** - * \brief Encapsulate and send key-value-value-value message from DUT to host - * - * This function uses underlying functions to write directly - * to the serial port, (CONSOLE_TX). This allows KVs to be used - * from within interrupt context. - * Last 2 values are integers to avoid integer to string conversion - * made by the user. - * - * Names of the parameters: this function is used to send test case - * name with number of passes and failures to host. But it can be used - * to send any key-value-value-value (string-string-integer-integer) - * set to host. - * - * \param key Message key (message/event name) - * \param value Message payload, string value - * \param passes Send additional integer formatted data - * \param failures Send additional integer formatted data - * - */ -void greentea_send_kv(const char *key, const char *val, const int passes, const int failures) { - if (key) { - greentea_write_preamble(); - greentea_write_string(key); - greentea_putc(';'); - greentea_write_string(val); - greentea_putc(';'); - greentea_write_int(passes); - greentea_putc(';'); - greentea_write_int(failures); - greentea_write_postamble(); - } -} - -/** - * \brief Encapsulate and send key-value-value message from DUT to host - * - * This function uses underlying functions to write directly - * to the serial port, (CONSOLE_TX). This allows key-value-value to be used - * from within interrupt context. - * Both values are integers to avoid integer to string conversion - * made by the user. - * - * Names of the parameters: this function is used to send number - * of passes and failures to host. But it can be used to send any - * key-value-value (string-integer-integer) message to host. - * - * \param key Message key (message/event name) - * \param value Message payload, integer value - * \param passes Send additional integer formatted data - * \param failures Send additional integer formatted data - * - */ -void greentea_send_kv(const char *key, const int passes, const int failures) { - if (key) { - greentea_write_preamble(); - greentea_write_string(key); - greentea_putc(';'); - greentea_write_int(passes); - greentea_putc(';'); - greentea_write_int(failures); - greentea_write_postamble(); - } -} - -/** - * \brief Send message with timeout to master in seconds - * - * GREENTEA_TEST_ENV_TIMEOUT message is part of preamble - * sent from DUT to host during synchronisation (beginning of test - * suite execution). - * - * Notification about total test suite timeout. Timeout is measured - * from the moment of GREENTEA_TEST_ENV_TIMEOUT reception by host. - * If timeout is reached host (and host test) will be stopped and - * control will return to Greentea. - * - * \param timeout Test suite timeout in seconds - * - */ -static void greentea_notify_timeout(const int timeout) { - greentea_send_kv(GREENTEA_TEST_ENV_TIMEOUT, timeout); -} - -/** - * \brief Send host test name to master - * - * GREENTEA_TEST_ENV_HOST_TEST_NAME message is part of preamble - * sent from DUT to host during synchronisation (beginning of test - * suite execution). - * - * Host test Python script implements host side callbacks - * for key-value events sent from DUT to host. Host test's - * callbacks are registered after GREENTEA_TEST_ENV_HOST_TEST_NAME - * message reaches host. - * - * \param host_test_name Host test name, host test will be loaded by mbedhtrun - */ -static void greentea_notify_hosttest(const char *host_test_name) { - greentea_send_kv(GREENTEA_TEST_ENV_HOST_TEST_NAME, host_test_name); -} - -/** - * \brief Send to master information that test suite finished its execution - * - * GREENTEA_TEST_ENV_END and GREENTEA_TEST_ENV_EXIT messages - * are sent just before test suite execution finishes (noting - * else to do). You can place it just before you return from your - * main() function. - * - * Code coverage: If MEBD_CFG_DEBUG_OPTIONS_COVERAGE is set in the - * project via build configuration function will output series - * of code coverage messages GREENTEA_TEST_ENV_LCOV_START with code - * coverage binary data. This data is captured by Greentea and can - * be used to generate LCOV reports. - * - * \param result Test suite result from DUT (0 - FAIl, !0 - SUCCESS) - * - */ -static void greentea_notify_completion(const int result) { - const char *val = result ? GREENTEA_TEST_ENV_SUCCESS : GREENTEA_TEST_ENV_FAILURE; -#ifdef MBED_CFG_DEBUG_OPTIONS_COVERAGE - coverage_report = true; - __gcov_flush(); - coverage_report = false; -#endif - greentea_metrics_report(); - greentea_send_kv(GREENTEA_TEST_ENV_END, val); - greentea_send_kv(GREENTEA_TEST_ENV_EXIT, 0); -} - -/** - * \brief Send to master greentea-client version - */ -static void greentea_notify_version() { - greentea_send_kv(GREENTEA_TEST_ENV_HOST_TEST_VERSION, MBED_GREENTEA_CLIENT_VERSION_STRING); -} - -/** - ***************************************************************************** - * Parse engine for KV values which replaces scanf - ***************************************************************************** - * - * Example usage: - * - * char key[10]; - * char value[48]; - * - * greentea_parse_kv(key, value, 10, 48); - * greentea_parse_kv(key, value, 10, 48); - * - */ - - -static int gettok(char *, const int); -static int getNextToken(char *, const int); -static int HandleKV(char *, char *, const int, const int); -static int isstring(int); - -/** - * \brief Current token of key-value protocol's tokenizer - */ -static int CurTok = 0; - -/** - * \enum Token enumeration for key-value protocol tokenizer - * - * This enum is used by key-value protocol tokenizer - * to detect parts of protocol in stream. - * - * tok_eof ::= EOF (end of file) - * tok_open ::= "{{" - * tok_close ::= "}}" - * tok_semicolon ::= ";" - * tok_string ::= [a-zA-Z0-9_-!@#$%^&*()]+ // See isstring() function - * - */ -enum Token { - tok_eof = -1, - tok_open = -2, - tok_close = -3, - tok_semicolon = -4, - tok_string = -5 -}; - -/** - * \brief parse input string for key-value pairs: {{key;value}} - * This function should replace scanf() used to - * check for incoming messages from master. All data - * parsed and rejected is discarded. - * - * \param out_key Ouput data with key - * \param out_value Ouput data with value - * \param out_key_size out_key total size - * \param out_value_size out_value total data - * - * success != 0 when key-value pair was found - * success == 0 when end of the stream was found - * - */ -extern "C" int greentea_parse_kv(char *out_key, - char *out_value, - const int out_key_size, - const int out_value_size) { - getNextToken(0, 0); - while (1) { - switch (CurTok) { - case tok_eof: - return 0; - - case tok_open: - if (HandleKV(out_key, out_value, out_key_size, out_value_size)) { - // We've found {{ KEY ; VALUE }} expression - return 1; - } - break; - - default: - // Load next token and pray... - getNextToken(0, 0); - break; - } - } -} - -/** - * \brief Get next token from stream - * - * Key-value TOKENIZER feature - * - * This function is used by key-value parser determine - * if key-value message is embedded in stream data. - * - * \param str Output parameters to store token string value - * \param str_size Size of 'str' parameter in bytes (characters) - * - */ -static int getNextToken(char *str, const int str_size) { - return CurTok = gettok(str, str_size); -} - -/** - * \brief Check if character is punctuation character - * - * Auxilary key-value TOKENIZER function - * - * Defines if character is in subset of allowed punctuation - * characters which can be part of a key or value string. - * Not allowed characters are: ";{}" - * - * \param c Input character to check - * \return Return 1 if character is allowed punctuation character, otherwise return false - * - */ -static int ispunctuation(int c) { - static const char punctuation[] = "_-!@#$%^&*()=+:<>,./?\\\"'"; // No ";{}" - for (size_t i=0; i< sizeof(punctuation); ++i) { - if (c == punctuation[i]) { - return 1; - } - } - return 0; -} - -/** - * \brief Check if character is string token character - * - * Auxilary key-value TOKENIZER function - * - * Defines if character is in subset of allowed string - * token characters. - * String defines set of characters which can be a key or value string. - * - * Allowed subset includes: - * - Alphanumerical characters - * - Digits - * - White spaces and - * - subset of punctuation characters. - * - * \param c Input character to check - * \return Return 1 if character is allowed punctuation character, otherwise return false - * - */ -static int isstring(int c) { - return (isalpha(c) || - isdigit(c) || - isspace(c) || - ispunctuation(c)); -} - -/** - * \brief TOKENIZER of key-value protocol - * - * Actual key-value TOKENIZER engine - * - * TOKENIZER defines #Token enum to map recognized tokens to integer values. - * - * ::= EOF (end of file) - * ::= "{{" - * ::= "}}" - * ::= ";" - * ::= [a-zA-Z0-9_-!@#$%^&*()]+ // See isstring() function * - * - * \param out_str Output string with parsed token (string) - * \param str_size Size of str buffer we can use - * - * \return Return #Token enum value used by parser to check for key-value occurrences - * - */ -static int gettok(char *out_str, const int str_size) { - static int LastChar = '!'; - static int str_idx = 0; - - // whitespace ::= - while (isspace(LastChar)) { - LastChar = greentea_getc(); - } - - // string ::= [a-zA-Z0-9_-!@#$%^&*()]+ - if (isstring(LastChar)) { - str_idx = 0; - if (out_str && str_idx < str_size - 1) { - out_str[str_idx++] = LastChar; - } - - while (isstring((LastChar = greentea_getc()))) - if (out_str && str_idx < str_size - 1) { - out_str[str_idx++] = LastChar; - } - if (out_str && str_idx < str_size) { - out_str[str_idx] = '\0'; - } - - return tok_string; - } - - // semicolon ::= ';' - if (LastChar == ';') { - LastChar = greentea_getc(); - return tok_semicolon; - } - - // open ::= '{{' - if (LastChar == '{') { - LastChar = greentea_getc(); - if (LastChar == '{') { - LastChar = greentea_getc(); - return tok_open; - } - } - - // close ::= '}' - if (LastChar == '}') { - LastChar = greentea_getc(); - if (LastChar == '}') { - greentea_getc(); //offset the extra '\n' send by Greentea python tool - LastChar = '!'; - return tok_close; - } - } - - if (LastChar == EOF) - return tok_eof; - - // Otherwise, just return the character as its ascii value. - int ThisChar = LastChar; - LastChar = greentea_getc(); - return ThisChar; -} - -/** - * \brief Key-value parser - * - * Key-value message grammar - * - * : - * - * Examples: - * message: "{{__timeout; 1000}}" - * "{{__sync; 12345678-1234-5678-1234-567812345678}}" - * - * \param out_key Output buffer to store key string value - * \param out_value Output buffer to store value string value - * \param out_key_size Buffer 'out_key' buffer size - * \param out_value_size Buffer 'out_value_size' buffer size - * \return Returns 1 if key-value message was parsed successfully in stream of tokens from tokenizer - * - */ -static int HandleKV(char *out_key, - char *out_value, - const int out_key_size, - const int out_value_size) { - // We already started with - if (getNextToken(out_key, out_key_size) == tok_string) { - if (getNextToken(0, 0) == tok_semicolon) { - if (getNextToken(out_value, out_value_size) == tok_string) { - if (getNextToken(0, 0) == tok_close) { - // - // Found "{{KEY;VALUE}}" expression - return 1; - } - } - } - } - getNextToken(0, 0); - return 0; -} diff --git a/features/frameworks/utest/CMakeLists.txt b/features/frameworks/utest/CMakeLists.txt index f9f27f2c2d9..839b8931774 100644 --- a/features/frameworks/utest/CMakeLists.txt +++ b/features/frameworks/utest/CMakeLists.txt @@ -22,4 +22,4 @@ target_sources(mbed-utest source/utest_types.cpp ) -target_link_libraries(mbed-utest PUBLIC mbed-core-flags mbed-unity) +target_link_libraries(mbed-utest PUBLIC mbed-core-flags mbed-unity greentea::client) diff --git a/hal/include/hal/lp_ticker_api.h b/hal/include/hal/lp_ticker_api.h index 574fd3ffa21..3a967f5db26 100644 --- a/hal/include/hal/lp_ticker_api.h +++ b/hal/include/hal/lp_ticker_api.h @@ -176,16 +176,25 @@ uint32_t lp_ticker_read(void); /** Set interrupt for specified timestamp * - * @param timestamp The time in ticks to be set + * @param timestamp The time in ticks to be set. Guaranteed to be between 0 and 2^bits-1, where bits is + * the number of bits returned by ::lp_ticker_get_info * - * @note no special handling needs to be done for times in the past - * as the common timer code will detect this and call - * lp_ticker_fire_interrupt() if this is the case + * @note If \c timestamp is less than the current time read by the ticker, then the intention is to set an + * interrupt for once the ticker rolls over and reaches this time. * - * @note calling this function with timestamp of more than the supported + * @note Upper level Mbed OS code is responsible for ensuring that if we try to set a wake-up for a time + * in the past, ::lp_ticker_fire_interrupt is called instead. It will also ensure that if + * we want to wake up far in the future, we will instead set a wakeup for about (rollover period/2) ticks + * in the future, then reschedule the timer for the correct time. + * + * Calling this function with timestamp of more than the supported * number of bits returned by ::lp_ticker_get_info results in undefined * behavior. * + * If the timer interrupt is pending when this function is called (e.g. due to the ticker being set, + * but the interrupt being disabled before it could fire), this function shall clear the pending interrupt + * before reenabling and setting it to prevent a spurious execution of the interrupt. + * * Pseudo Code: * @code * void lp_ticker_set_interrupt(timestamp_t timestamp) @@ -210,7 +219,12 @@ void lp_ticker_set_interrupt(timestamp_t timestamp); */ void lp_ticker_disable_interrupt(void); -/** Clear the low power ticker interrupt +/** + * @brief Clear the low power ticker interrupt. + * + * This is required to be called from the interrupt handler to stop the interrupt handler + * from being executed again after it returns. This does not do anything if called before the interrupt + * fires (e.g. it doesn't cancel the interrupt if it's set in the future). * * Pseudo Code: * @code diff --git a/hal/include/hal/us_ticker_api.h b/hal/include/hal/us_ticker_api.h index 618a65f747a..a083e9dba69 100644 --- a/hal/include/hal/us_ticker_api.h +++ b/hal/include/hal/us_ticker_api.h @@ -235,16 +235,25 @@ uint32_t (us_ticker_read)(void); /** Set interrupt for specified timestamp * - * @param timestamp The time in ticks to be set + * @param timestamp The time in ticks to be set. Guaranteed to be between 0 and 2^bits-1, where bits is + * the number of bits returned by us_ticker_get_info() * - * @note no special handling needs to be done for times in the past - * as the common timer code will detect this and call - * us_ticker_fire_interrupt() if this is the case + * @note If \c timestamp is less than the current time read by the ticker, then the intention is to set an + * interrupt for once the ticker rolls over and reaches this time. * - * @note calling this function with timestamp of more than the supported - * number of bits returned by ::us_ticker_get_info results in undefined + * @note Upper level Mbed OS code is responsible for ensuring that if we try to set a wake-up for a time + * in the past, \c us_ticker_fire_interrupt() is called instead. It will also ensure that if + * we want to wake up far in the future, we will instead set a wakeup for about (rollover period/2) ticks + * in the future, then reschedule the timer for the correct time. + * + * Calling this function with timestamp of more than the supported + * number of bits returned by ::lp_ticker_get_info results in undefined * behavior. * + * If the timer interrupt is pending when this function is called (e.g. due to the ticker being set, + * but the interrupt being disabled before it could fire), this function shall clear the pending interrupt + * before reenabling and setting it to prevent a spurious execution of the interrupt. + * * Pseudo Code: * @code * void us_ticker_set_interrupt(timestamp_t timestamp) diff --git a/hal/tests/TESTS/mbed_hal/common_tickers/main.cpp b/hal/tests/TESTS/mbed_hal/common_tickers/main.cpp index 96f940a5bbe..6c0b0183405 100644 --- a/hal/tests/TESTS/mbed_hal/common_tickers/main.cpp +++ b/hal/tests/TESTS/mbed_hal/common_tickers/main.cpp @@ -19,6 +19,7 @@ #include "greentea-client/test_env.h" #include "unity.h" #include "utest.h" +#include #include "ticker_api_tests.h" #include "hal/us_ticker_api.h" #include "hal/lp_ticker_api.h" @@ -266,6 +267,37 @@ void ticker_interrupt_test(void) TEST_ASSERT_MESSAGE(run_count >= 3, "At least 3 sub test cases must be executed"); } +/* Test that we can disable the ticker interrupt and it will not fire. */ +void ticker_disable_test() +{ + intFlag = 0; + + const uint32_t ticksFor100us = lroundf(intf->get_info()->frequency * .0001f); + + // Set an interrupt for 100us in the future, then disable it immediately + intf->set_interrupt(intf->read() + ticksFor100us); + intf->disable_interrupt(); + + // Verify that it does not fire + wait_us(200); + TEST_ASSERT_EQUAL_INT(0, intFlag); + + // Now reset the interrupt again. + intf->set_interrupt(intf->read() + ticksFor100us); + + // Should not have fired yet + TEST_ASSERT_EQUAL_INT_MESSAGE(0, intFlag, "Ticker fired during set_interrupt() while disabled! Check that set_interrupt() function clears pending timer compare."); + + // Still not yet + wait_us(20); + TEST_ASSERT_EQUAL_INT(0, intFlag); + + // NOW it should have fired + wait_us(170); + TEST_ASSERT_EQUAL_INT(1, intFlag); +} + + /* Test that ticker interrupt is not triggered when ticker_set_interrupt */ void ticker_past_test(void) { @@ -339,6 +371,9 @@ void ticker_overflow_test(void) */ const uint32_t max_count = (1 << p_ticker_info->bits) - 1; const uint32_t required_time_sec = (max_count / p_ticker_info->frequency); + printf("This test is estimated to take about %" PRIu32 " seconds.\n", required_time_sec); + + intFlag = 0; if (required_time_sec > 30 && !FORCE_OVERFLOW_TEST) { TEST_ASSERT_TRUE(true); @@ -346,7 +381,11 @@ void ticker_overflow_test(void) return; } - intFlag = 0; + // Set an interrupt for slightly after the counter rolls over. We will make sure later that this + // fires at the appropriate time. + const float isrTimeAfterOverflow = 0.001f; // sec + const uint32_t isrTicksAfterOverflow = lroundf(p_ticker_info->frequency * isrTimeAfterOverflow); + intf->set_interrupt(isrTicksAfterOverflow); /* Wait for max count. */ while (intf->read() >= (max_count - ticker_overflow_delta2) && @@ -359,17 +398,22 @@ void ticker_overflow_test(void) const uint32_t after_overflow = intf->read(); + // Interrupt should NOT have fired yet + TEST_ASSERT_EQUAL_INT(0, intFlag); + /* Now we are just after overflow. Wait a while assuming that ticker still counts. */ - while (intf->read() < TICKER_100_TICKS) { + while (intf->read() < isrTicksAfterOverflow + TICKER_DELTA) { /* Just wait. */ } const uint32_t next_after_overflow = intf->read(); - /* Check that after the overflow ticker continue count. */ + // Interrupt should now have fired + TEST_ASSERT_EQUAL_INT(1, intFlag); + + /* Check that after the overflow ticker continues to count. */ TEST_ASSERT(after_overflow <= ticker_overflow_delta1); - TEST_ASSERT(next_after_overflow >= TICKER_100_TICKS); - TEST_ASSERT_EQUAL(0, intFlag); + TEST_ASSERT(next_after_overflow >= (isrTicksAfterOverflow + TICKER_DELTA)); const uint32_t tick_count = intf->read(); @@ -381,7 +425,7 @@ void ticker_overflow_test(void) /* Just wait. */ } - TEST_ASSERT_EQUAL(1, intFlag); + TEST_ASSERT_EQUAL(2, intFlag); } /* Test that the ticker increments by one on each tick. */ @@ -598,7 +642,7 @@ utest::v1::status_t lp_ticker_teardown(const Case *const source, const size_t pa utest::v1::status_t test_setup(const size_t number_of_cases) { - GREENTEA_SETUP(80, "default_auto"); + GREENTEA_SETUP(120, "default_auto"); return verbose_test_setup_handler(number_of_cases); } @@ -606,6 +650,7 @@ Case cases[] = { Case("Microsecond ticker init is safe to call repeatedly", us_ticker_setup, ticker_init_test, us_ticker_teardown), Case("Microsecond ticker info test", us_ticker_setup, ticker_info_test, us_ticker_teardown), Case("Microsecond ticker interrupt test", us_ticker_setup, ticker_interrupt_test, us_ticker_teardown), + Case("Microsecond ticker disable test", us_ticker_setup, ticker_disable_test, us_ticker_teardown), Case("Microsecond ticker past interrupt test", us_ticker_setup, ticker_past_test, us_ticker_teardown), Case("Microsecond ticker reschedule test", us_ticker_setup, ticker_repeat_reschedule_test, us_ticker_teardown), Case("Microsecond ticker fire interrupt", us_ticker_setup, ticker_fire_now_test, us_ticker_teardown), @@ -616,6 +661,7 @@ Case cases[] = { Case("lp ticker init is safe to call repeatedly", lp_ticker_setup, ticker_init_test, lp_ticker_teardown), Case("lp ticker info test", lp_ticker_setup, ticker_info_test, lp_ticker_teardown), Case("lp ticker interrupt test", lp_ticker_setup, ticker_interrupt_test, lp_ticker_teardown), + Case("lp ticker disable test", lp_ticker_setup, ticker_disable_test, lp_ticker_teardown), Case("lp ticker past interrupt test", lp_ticker_setup, ticker_past_test, lp_ticker_teardown), Case("lp ticker reschedule test", lp_ticker_setup, ticker_repeat_reschedule_test, lp_ticker_teardown), Case("lp ticker fire interrupt", lp_ticker_setup, ticker_fire_now_test, lp_ticker_teardown), diff --git a/platform/tests/TESTS/mbed_platform/stats_sys/main.cpp b/platform/tests/TESTS/mbed_platform/stats_sys/main.cpp index 23429b8b523..0a58668535f 100644 --- a/platform/tests/TESTS/mbed_platform/stats_sys/main.cpp +++ b/platform/tests/TESTS/mbed_platform/stats_sys/main.cpp @@ -59,45 +59,45 @@ void test_sys_info() TEST_ASSERT_NOT_EQUAL(0, stats.compiler_version); // RAM / ROM sizes should not be zero and should match the define -#if defined(MBED_ROM_START) && defined(MBED_ROM_SIZE) +#if defined(MBED_CONFIGURED_ROM_START) && defined(MBED_CONFIGURED_ROM_SIZE) TEST_ASSERT_NOT_EQUAL(0, stats.rom_size[0]); - TEST_ASSERT_EQUAL(MBED_ROM_SIZE, stats.rom_size[0]); - TEST_ASSERT_EQUAL(MBED_ROM_START, stats.rom_start[0]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_ROM_SIZE, stats.rom_size[0]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_ROM_START, stats.rom_start[0]); #endif -#if defined(MBED_RAM_START) && defined(MBED_RAM_SIZE) +#if defined(MBED_CONFIGURED_RAM_START) && defined(MBED_CONFIGURED_RAM_SIZE) TEST_ASSERT_NOT_EQUAL(0, stats.ram_size[0]); - TEST_ASSERT_EQUAL(MBED_RAM_START, stats.ram_start[0]); - TEST_ASSERT_EQUAL(MBED_RAM_SIZE, stats.ram_size[0]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_RAM_START, stats.ram_start[0]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_RAM_SIZE, stats.ram_size[0]); #endif -#if defined(MBED_RAM1_START) && defined(MBED_RAM1_SIZE) +#if defined(MBED_CONFIGURED_RAM1_START) && defined(MBED_CONFIGURED_RAM1_SIZE) TEST_ASSERT_NOT_EQUAL(0, stats.ram_size[1]); - TEST_ASSERT_EQUAL(MBED_RAM1_SIZE, stats.ram_size[1]); - TEST_ASSERT_EQUAL(MBED_RAM1_START, stats.ram_start[1]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_RAM1_SIZE, stats.ram_size[1]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_RAM1_START, stats.ram_start[1]); #endif -#if defined(MBED_RAM2_START) && defined(MBED_RAM2_SIZE) +#if defined(MBED_CONFIGURED_RAM2_START) && defined(MBED_CONFIGURED_RAM2_SIZE) TEST_ASSERT_NOT_EQUAL(0, stats.ram_size[2]); - TEST_ASSERT_EQUAL(MBED_RAM2_SIZE, stats.ram_size[2]); - TEST_ASSERT_EQUAL(MBED_RAM2_START, stats.ram_start[2]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_RAM2_SIZE, stats.ram_size[2]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_RAM2_START, stats.ram_start[2]); #endif -#if defined(MBED_RAM3_START) && defined(MBED_RAM3_SIZE) +#if defined(MBED_CONFIGURED_RAM3_START) && defined(MBED_CONFIGURED_RAM3_SIZE) TEST_ASSERT_NOT_EQUAL(0, stats.ram_size[3]); - TEST_ASSERT_EQUAL(MBED_RAM3_SIZE, stats.ram_size[3]); - TEST_ASSERT_EQUAL(MBED_RAM3_START, stats.ram_start[3]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_RAM3_SIZE, stats.ram_size[3]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_RAM3_START, stats.ram_start[3]); #endif -#if defined(MBED_ROM1_START) && defined(MBED_ROM1_SIZE) +#if defined(MBED_CONFIGURED_ROM1_START) && defined(MBED_CONFIGURED_ROM1_SIZE) TEST_ASSERT_NOT_EQUAL(0, stats.rom_size[1]); - TEST_ASSERT_EQUAL(MBED_ROM1_SIZE, stats.rom_size[1]); - TEST_ASSERT_EQUAL(MBED_ROM1_START, stats.rom_start[1]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_ROM1_SIZE, stats.rom_size[1]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_ROM1_START, stats.rom_start[1]); #endif -#if defined(MBED_ROM2_START) && defined(MBED_ROM2_SIZE) +#if defined(MBED_CONFIGURED_ROM2_START) && defined(MBED_CONFIGURED_ROM2_SIZE) TEST_ASSERT_NOT_EQUAL(0, stats.rom_size[2]); - TEST_ASSERT_EQUAL(MBED_ROM2_SIZE, stats.rom_size[2]); - TEST_ASSERT_EQUAL(MBED_ROM2_START, stats.rom_start[2]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_ROM2_SIZE, stats.rom_size[2]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_ROM2_START, stats.rom_start[2]); #endif -#if defined(MBED_ROM3_START) && defined(MBED_ROM3_SIZE) +#if defined(MBED_CONFIGURED_ROM3_START) && defined(MBED_CONFIGURED_ROM3_SIZE) TEST_ASSERT_NOT_EQUAL(0, stats.rom_size[3]); - TEST_ASSERT_EQUAL(MBED_ROM3_SIZE, stats.rom_size[3]); - TEST_ASSERT_EQUAL(MBED_ROM3_START, stats.rom_start[3]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_ROM3_SIZE, stats.rom_size[3]); + TEST_ASSERT_EQUAL(MBED_CONFIGURED_ROM3_START, stats.rom_start[3]); #endif } diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/isr.c b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/isr.c index 0558ab24ff9..4e34d1bdea3 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/isr.c +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/isr.c @@ -23,7 +23,6 @@ #include "am_mcu_apollo.h" #include "lp_ticker_defines.h" -volatile bool someFlagThatGetSetinISR = false; void am_ctimer_isr(void) { diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/lp_ticker.c b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/lp_ticker.c index a285de718d3..32541b0a316 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/lp_ticker.c +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/lp_ticker.c @@ -45,6 +45,12 @@ void lp_ticker_init(void) lp_ticker_disable_interrupt(); return; } + + // Configure two timers: + // - The "time keeper" timer, which maintains the 16-bit lp ticker counter and counts continuously + // - The "int counter" timer, which is only activated when an interrupt is set and counts up to the + // desired compare value for the interrupt + am_hal_ctimer_int_register(LP_TICKER_AM_HAL_CTIMER_CMPR_INT, lp_ticker_irq_handler); am_hal_ctimer_config_single(LP_TICKER_AM_HAL_CTIMER_NUMBER, LP_TICKER_AM_HAL_CTIMER_SEGMENT_TIME_KEEPER, @@ -76,17 +82,24 @@ uint32_t lp_ticker_read() void lp_ticker_set_interrupt(timestamp_t timestamp) { - am_hal_ctimer_int_enable(LP_TICKER_AM_HAL_CTIMER_CMPR_INT); + // Reset timer count back to 0 and hold it there am_hal_ctimer_clear(LP_TICKER_AM_HAL_CTIMER_NUMBER, LP_TICKER_AM_HAL_CTIMER_SEGMENT_INT_COUNTER); - // am_hal_ctimer_config_single(LP_TICKER_AM_HAL_CTIMER_NUMBER, - // LP_TICKER_AM_HAL_CTIMER_SEGMENT_INT_COUNTER, - // (LP_TICKER_AM_HAL_CTIMER_INT_COUNTER_FN | LP_TICKER_AM_HAL_CTIMER_SRC | AM_HAL_CTIMER_INT_ENABLE | CTIMER_CTRL0_TMRA0IE1_Msk)); - am_hal_ctimer_start(LP_TICKER_AM_HAL_CTIMER_NUMBER, LP_TICKER_AM_HAL_CTIMER_SEGMENT_INT_COUNTER); - uint32_t delta = (uint32_t)timestamp - lp_ticker_read(); + + // Clear compare if it fired previously + am_hal_ctimer_int_clear(LP_TICKER_AM_HAL_CTIMER_CMPR_INT); + + // Figure out how long to sleep, accounting for rollover. + // Example: if current count is 65536 and timestamp is 1, then we should sleep for 2 ticks + const uint16_t delta = (uint16_t)timestamp - (uint16_t)lp_ticker_read(); + + am_hal_ctimer_compare_set(LP_TICKER_AM_HAL_CTIMER_NUMBER, LP_TICKER_AM_HAL_CTIMER_SEGMENT_INT_COUNTER, LP_TICKER_AM_HAL_CTIMER_CMPR_REG, (uint32_t)delta); + + am_hal_ctimer_start(LP_TICKER_AM_HAL_CTIMER_NUMBER, LP_TICKER_AM_HAL_CTIMER_SEGMENT_INT_COUNTER); + am_hal_ctimer_int_enable(LP_TICKER_AM_HAL_CTIMER_CMPR_INT); } void lp_ticker_fire_interrupt(void) diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/sleep.c b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/sleep.c index 60113499797..e3431b2d53b 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/sleep.c +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/sleep.c @@ -24,5 +24,15 @@ void hal_sleep(void) void hal_deepsleep(void) { + // To pass Mbed unit tests, the us ticker is required to be off when in deep sleep. + // Ideally all of the high speed clocks should be off, but the datasheet is not very helpful + // about how to accomplish this. I *think* the HFRC oscillator can only be turned off by + // finding every peripheral using it and disabling the peripheral or changing it to a different + // clock source. Implementing this, though, might be a bit tough. For now we at least turn off + // the STIMER clock and freeze the value. + am_hal_stimer_config(AM_HAL_STIMER_CFG_FREEZE); + am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP); + + am_hal_stimer_config(US_TICKER_FREQ); } diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/us_ticker.c b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/us_ticker.c index 9c962b2d632..30eafe80aaf 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/us_ticker.c +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/us_ticker.c @@ -159,6 +159,7 @@ void us_ticker_set_interrupt(timestamp_t timestamp) break; } + us_ticker_clear_interrupt(); am_hal_stimer_int_enable(US_TICKER_STIMER_INT_COMPARE); timestamp_t now = (timestamp_t)am_hal_stimer_counter_get(); am_hal_stimer_compare_delta_set(instance, (timestamp - now)); diff --git a/targets/upload_method_cfg/SFE_ARTEMIS.cmake b/targets/upload_method_cfg/SFE_ARTEMIS.cmake index ea2fa6da90f..2fee1799777 100644 --- a/targets/upload_method_cfg/SFE_ARTEMIS.cmake +++ b/targets/upload_method_cfg/SFE_ARTEMIS.cmake @@ -3,7 +3,9 @@ # include mbed_toolchain_setup and where you add mbed-os as a subdirectory. # Notes: -# 1. Support for this device exists in PyOCD main branch but has not been released yet (as of Jun 2025). +# 1. This board does not have an onboard debugger. You must use an external debugger, e.g. a PicoProbe +# or J-Link, if you wish to debug code. +# 2. Support for this device exists in PyOCD main branch but has not been released yet (as of Jun 2025). # To use PyOCD, you need to manually install it from the git repository by running (inside the Mbed OS venv): # pip install git+https://github.com/pyocd/pyOCD.git diff --git a/tools/cmake/mbed_greentea.cmake b/tools/cmake/mbed_greentea.cmake index 5140157d9f7..bccba7e72e5 100644 --- a/tools/cmake/mbed_greentea.cmake +++ b/tools/cmake/mbed_greentea.cmake @@ -119,6 +119,11 @@ function(mbed_greentea_add_test) list(APPEND MBED_HTRUN_ARGUMENTS --skip-reset) endif() + # Forward sync predelay argument to htrun + if("${MBED_CONFIG_DEFINITIONS}" MATCHES "MBED_CONF_GREENTEA_CLIENT_SYNC_PREDELAY=([^;]+)") + list(APPEND MBED_HTRUN_ARGUMENTS --sync-predelay ${CMAKE_MATCH_1}) + endif() + if(DEFINED MBED_GREENTEA_EXTRA_HTRUN_ARGUMENTS) list(APPEND MBED_HTRUN_ARGUMENTS ${MBED_GREENTEA_EXTRA_HTRUN_ARGUMENTS}) endif() diff --git a/tools/python/mbed_os_tools/test/host_tests_conn_proxy/conn_proxy.py b/tools/python/mbed_os_tools/test/host_tests_conn_proxy/conn_proxy.py index 334a211e66a..6725079db4f 100644 --- a/tools/python/mbed_os_tools/test/host_tests_conn_proxy/conn_proxy.py +++ b/tools/python/mbed_os_tools/test/host_tests_conn_proxy/conn_proxy.py @@ -275,7 +275,6 @@ def __send_sync(timeout=None) -> str | None: if sync_uuid_discovered: event_queue.put((key, value, timestamp)) - logger.prn_inf("found KV pair in stream: {{%s;%s}}, queued..."% (key, value)) else: if key == '__sync': if value in sync_uuid_list: @@ -289,7 +288,7 @@ def __send_sync(timeout=None) -> str | None: connector.reset() loop_timer = time() else: - logger.prn_wrn("found KV pair in stream: {{%s;%s}}, ignoring..."% (key, value)) + logger.prn_wrn("found KV pair in stream before sync: {{%s;%s}}, ignoring..."% (key, value)) if not sync_uuid_discovered: # Resending __sync after 'sync_timeout' secs (default 1 sec) From 69b23ad2580f54ae78a8b6c7eb400b24b9d98504 Mon Sep 17 00:00:00 2001 From: Jamie Smith Date: Fri, 20 Jun 2025 16:48:01 -0700 Subject: [PATCH 6/8] Add J-Link --- targets/upload_method_cfg/SFE_ARTEMIS.cmake | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/targets/upload_method_cfg/SFE_ARTEMIS.cmake b/targets/upload_method_cfg/SFE_ARTEMIS.cmake index 2fee1799777..afabe62d267 100644 --- a/targets/upload_method_cfg/SFE_ARTEMIS.cmake +++ b/targets/upload_method_cfg/SFE_ARTEMIS.cmake @@ -16,3 +16,10 @@ set(UPLOAD_METHOD_DEFAULT NONE) set(PYOCD_UPLOAD_ENABLED TRUE) set(PYOCD_TARGET_NAME ama3b1kk_kbr) set(PYOCD_CLOCK_SPEED 4000k) + +# Config options for JLINK +# ------------------------------------------------------------- +set(JLINK_UPLOAD_ENABLED TRUE) +set(JLINK_CPU_NAME AMA3B1KK-KBR) +set(JLINK_CLOCK_SPEED 4000) +set(JLINK_UPLOAD_INTERFACE SWD) From bc5a23ad81a4f6032d99c29e64c26621c029e53e Mon Sep 17 00:00:00 2001 From: Jamie Smith Date: Fri, 20 Jun 2025 16:50:52 -0700 Subject: [PATCH 7/8] Typo --- targets/upload_method_cfg/SFE_ARTEMIS.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/upload_method_cfg/SFE_ARTEMIS.cmake b/targets/upload_method_cfg/SFE_ARTEMIS.cmake index afabe62d267..2f8ff55ee17 100644 --- a/targets/upload_method_cfg/SFE_ARTEMIS.cmake +++ b/targets/upload_method_cfg/SFE_ARTEMIS.cmake @@ -1,4 +1,4 @@ -# Mbed OS upload method configuration file for target NUMAKER_PFM_M487. +# Mbed OS upload method configuration file for target SFE_ARTEMIS. # To change any of these parameters from their default values, set them in your build script between where you # include mbed_toolchain_setup and where you add mbed-os as a subdirectory. From b0e45dd7c208df551d116233ff25ede2c916c30d Mon Sep 17 00:00:00 2001 From: Jamie Smith Date: Fri, 20 Jun 2025 17:28:44 -0700 Subject: [PATCH 8/8] Fix some CI issues --- features/CMakeLists.txt | 13 ++++++---- hal/include/hal/us_ticker_api.h | 7 +++++- .../TESTS/mbed_hal/common_tickers/main.cpp | 2 +- .../TARGET_SFE_ARTEMIS/PinNames.h | 24 +++++++++---------- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/features/CMakeLists.txt b/features/CMakeLists.txt index a81de65536b..eebc9509e49 100644 --- a/features/CMakeLists.txt +++ b/features/CMakeLists.txt @@ -4,12 +4,15 @@ # List of all features libraries available. add_library(mbed-fpga-ci-test-shield INTERFACE) add_library(mbed-client-cli INTERFACE) -add_library(mbed-unity STATIC EXCLUDE_FROM_ALL) -add_library(mbed-utest STATIC EXCLUDE_FROM_ALL) add_subdirectory(frameworks/COMPONENT_FPGA_CI_TEST_SHIELD) add_subdirectory(frameworks/mbed-client-cli) -add_subdirectory(frameworks/unity) -add_subdirectory(frameworks/utest) -add_subdirectory(frameworks/mbed-greentea-io) add_subdirectory(frameworks/cy_rtos_rtx_adapter) + +if(MBED_ENABLE_TESTING) + add_library(mbed-unity STATIC EXCLUDE_FROM_ALL) + add_library(mbed-utest STATIC EXCLUDE_FROM_ALL) + add_subdirectory(frameworks/unity) + add_subdirectory(frameworks/utest) + add_subdirectory(frameworks/mbed-greentea-io) +endif() \ No newline at end of file diff --git a/hal/include/hal/us_ticker_api.h b/hal/include/hal/us_ticker_api.h index a083e9dba69..508c7cff279 100644 --- a/hal/include/hal/us_ticker_api.h +++ b/hal/include/hal/us_ticker_api.h @@ -278,7 +278,12 @@ void us_ticker_set_interrupt(timestamp_t timestamp); */ void us_ticker_disable_interrupt(void); -/** Clear us ticker interrupt +/** + * @brief Clear the us ticker interrupt. + * + * This is required to be called from the interrupt handler to stop the interrupt handler + * from being executed again after it returns. This does not do anything if called before the interrupt + * fires (e.g. it doesn't cancel the interrupt if it's set in the future). * * Pseudo Code: * @code diff --git a/hal/tests/TESTS/mbed_hal/common_tickers/main.cpp b/hal/tests/TESTS/mbed_hal/common_tickers/main.cpp index 6c0b0183405..dd39c773a28 100644 --- a/hal/tests/TESTS/mbed_hal/common_tickers/main.cpp +++ b/hal/tests/TESTS/mbed_hal/common_tickers/main.cpp @@ -642,7 +642,7 @@ utest::v1::status_t lp_ticker_teardown(const Case *const source, const size_t pa utest::v1::status_t test_setup(const size_t number_of_cases) { - GREENTEA_SETUP(120, "default_auto"); + GREENTEA_SETUP(80, "default_auto"); return verbose_test_setup_handler(number_of_cases); } diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS/PinNames.h b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS/PinNames.h index ea48f9afc17..55269393883 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS/PinNames.h +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS/PinNames.h @@ -75,19 +75,6 @@ typedef enum A9 = D9, A10 = D10, - // I2C - I2C_SCL = AM_BSP_QWIIC_I2C_SCL_PIN, - I2C_SDA = AM_BSP_QWIIC_I2C_SDA_PIN, - - // Qwiic - QWIIC_SCL = I2C_SCL, - QWIIC_SDA = I2C_SDA, - - // SPI - SPI_CLK = AM_BSP_PRIM_SPI_CLK_PIN, - SPI_SDO = AM_BSP_PRIM_SPI_SDO_PIN, - SPI_SDI = AM_BSP_PRIM_SPI_SDI_PIN, - // UART SERIAL_TX = AM_BSP_PRIM_UART_TX_PIN, SERIAL_RX = AM_BSP_PRIM_UART_RX_PIN, @@ -104,6 +91,17 @@ typedef enum // LEDs #define LED1 D13 // Blue LED +// I2C bus +#define I2C_SCL D15 +#define I2C_SDA D14 +#define QWIIC_SCL I2C_SCL +#define QWIIC_SDA I2C_SDA + +// SPI bus +#define SPI_CLK D13 +#define SPI_SDO D11 +#define SPI_SDI D12 + #if defined(MBED_CONF_TARGET_STDIO_UART_TX) #define STDIO_UART_TX MBED_CONF_TARGET_STDIO_UART_TX #else