diff --git a/drivers/can/can_bee.c b/drivers/can/can_bee.c index dbf30d7cfb98a..487a2399496a1 100644 --- a/drivers/can/can_bee.c +++ b/drivers/can/can_bee.c @@ -1,27 +1,28 @@ /* - * Copyright(c) 2025, Realtek Semiconductor Corporation. + * Copyright (c) 2026, Realtek Semiconductor Corporation * * SPDX-License-Identifier: Apache-2.0 */ + #define DT_DRV_COMPAT realtek_bee_can +#include +#include +#include +#include + #include #include #include #include #include -#include #include -#include -#include -#include #include -#include #include -#ifdef CONFIG_PM_DEVICE +#include + #include #include -#endif #if defined(CONFIG_SOC_SERIES_RTL87X2G) #include @@ -62,22 +63,30 @@ struct can_bee_data { struct can_bee_config { const struct can_driver_config common; - CAN_TypeDef *can; /*!< CAN Registers*/ - uint8_t sjw; - uint8_t prop_ts1; - uint8_t ts2; - uint16_t clkid; - void (*config_irq)(); + CAN_TypeDef *can; const struct pinctrl_dev_config *pcfg; + uint16_t clkid; + void (*irq_config_func)(); }; -static struct k_mutex filter_mutex; - #ifdef CONFIG_PM_DEVICE const struct device *devs[DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT)]; #endif -#define CAN_BUS_ON_TIMEOUT (10 * (sys_clock_hw_cycles_per_sec() / MSEC_PER_SEC)) +static int can_bee_wait_ram_state(k_timeout_t timeout) +{ + int64_t start_time; + + start_time = k_uptime_ticks(); + while (CAN_GetRamState() != CAN_RAM_STATE_IDLE) { + if (!K_TIMEOUT_EQ(timeout, K_FOREVER) && + k_uptime_ticks() - start_time >= timeout.ticks) { + return -EAGAIN; + } + } + + return 0; +} static int can_bee_check_bus_on(k_timeout_t timeout) { @@ -98,8 +107,6 @@ static void can_bee_tx_complete(const struct device *dev, int mb_list_idx) struct can_bee_data *data = dev->data; can_tx_callback_t callback = data->tx_mb_list[mb_list_idx].tx_callback; - LOG_DBG("[%s]", __func__); - if (data->tx_mb_list[mb_list_idx].is_busy) { data->tx_mb_list[mb_list_idx].is_busy = false; k_sem_give(&data->tx_int_sem); @@ -120,21 +127,11 @@ static void can_bee_rx_complete(const struct device *dev, int mb_list_idx) CANDataFrameSel_TypeDef frame_type; struct can_frame frame; - LOG_DBG("[%s]", __func__); - CAN_GetMsgBufInfo(data->rx_mb_list[mb_list_idx].idx, &mb_info); memset(frame.data, 0, 8); CAN_GetRamData(mb_info.data_length, frame.data); frame_type = CAN_CheckFrameType(mb_info.rtr_bit, mb_info.ide_bit); - LOG_DBG("[CAN HANDLER] rx_mb_list[mb_list_idx].idx%d frame_type %d, frame_id = 0x%03x, " - "ext_frame_id = 0x%05x", - data->rx_mb_list[mb_list_idx].idx, frame_type, mb_info.standard_frame_id, - mb_info.extend_frame_id); - for (uint8_t index = 0; index < mb_info.data_length; index++) { - LOG_DBG("[CAN HANDLER] frame.data [%d] 0x%02x", index, frame.data[index]); - } - frame.dlc = mb_info.data_length; frame.flags = (mb_info.rtr_bit ? CAN_FRAME_RTR : 0) | (mb_info.ide_bit ? CAN_FRAME_IDE : 0); frame.id = mb_info.ide_bit ? ((mb_info.standard_frame_id << CAN_STD_FRAME_ID_POS) | @@ -149,11 +146,13 @@ static void can_bee_rx_complete(const struct device *dev, int mb_list_idx) static int can_bee_get_capabilities(const struct device *dev, can_mode_t *cap) { ARG_UNUSED(dev); - ARG_UNUSED(cap); - LOG_DBG("[%s]", __func__); + *cap = CAN_MODE_NORMAL | CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY | CAN_MODE_ONE_SHOT; + + if (IS_ENABLED(CONFIG_CAN_MANUAL_RECOVERY_MODE)) { + *cap |= CAN_MODE_MANUAL_RECOVERY; + } - *cap = CAN_MODE_NORMAL | CAN_MODE_LISTENONLY | CAN_MODE_MANUAL_RECOVERY; return 0; } @@ -162,9 +161,6 @@ static int can_bee_start(const struct device *dev) const struct can_bee_config *cfg = dev->config; struct can_bee_data *data = dev->data; int ret = 0; - CAN_InitTypeDef *init_struct = &(data->init_struct); - - LOG_DBG("[%s] dev %s", dev->name, __func__); k_mutex_lock(&data->inst_mutex, K_FOREVER); @@ -181,12 +177,9 @@ static int can_bee_start(const struct device *dev) } } - (void)clock_control_on(BEE_CLOCK_CONTROLLER, (clock_control_subsys_t)&cfg->clkid); - - CAN_Init(init_struct); CAN_Cmd(ENABLE); - ret = can_bee_check_bus_on(K_MSEC(10)); + ret = can_bee_check_bus_on(K_MSEC(10)); if (ret < 0) { LOG_ERR("CAN bus off"); CAN_Cmd(DISABLE); @@ -200,8 +193,10 @@ static int can_bee_start(const struct device *dev) CAN_INTConfig((CAN_BUS_OFF_INT | CAN_ERROR_INT | CAN_RX_INT | CAN_TX_INT), ENABLE); data->common.started = true; + unlock: k_mutex_unlock(&data->inst_mutex); + return ret; } @@ -211,8 +206,6 @@ static int can_bee_stop(const struct device *dev) struct can_bee_data *data = dev->data; int ret = 0; - LOG_DBG("[%s] dev %s", dev->name, __func__); - k_mutex_lock(&data->inst_mutex, K_FOREVER); if (!data->common.started) { @@ -220,7 +213,6 @@ static int can_bee_stop(const struct device *dev) goto unlock; } - (void)clock_control_off(BEE_CLOCK_CONTROLLER, (clock_control_subsys_t)&cfg->clkid); for (uint8_t i = 0; i < CONFIG_CAN_BEE_RX_MSG_BUF_NUM; i++) { data->rx_mb_list[i].is_busy = false; } @@ -237,28 +229,40 @@ static int can_bee_stop(const struct device *dev) } data->common.started = false; + unlock: k_mutex_unlock(&data->inst_mutex); + return ret; } static int can_bee_set_mode(const struct device *dev, can_mode_t mode) { struct can_bee_data *data = dev->data; + can_mode_t supported = CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY | CAN_MODE_ONE_SHOT; CAN_InitTypeDef *init_struct = &(data->init_struct); LOG_DBG("[%s] dev %s mode 0x%x", __func__, dev->name, mode); - if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY | CAN_MODE_ONE_SHOT)) != 0) { + if (IS_ENABLED(CONFIG_CAN_MANUAL_RECOVERY_MODE)) { + supported |= CAN_MODE_MANUAL_RECOVERY; + } + + if ((mode & ~(supported)) != 0) { LOG_ERR("unsupported mode: 0x%08x", mode); return -ENOTSUP; } + if (data->common.started) { return -EBUSY; } k_mutex_lock(&data->inst_mutex, K_FOREVER); + if ((mode & CAN_MODE_MANUAL_RECOVERY) != 0) { + data->common.mode |= CAN_MODE_MANUAL_RECOVERY; + } + if ((mode & CAN_MODE_LOOPBACK) != 0) { init_struct->CAN_TestModeSel = CAN_TEST_MODE_INT_LOOPBACK; } else if ((mode & CAN_MODE_LISTENONLY) != 0) { @@ -270,14 +274,17 @@ static int can_bee_set_mode(const struct device *dev, can_mode_t mode) CAN_SetTestMode(init_struct->CAN_TestModeSel); if ((mode & CAN_MODE_ONE_SHOT) != 0) { - /* No automatic retransmission */ init_struct->CAN_AutoReTxEn = false; } else { init_struct->CAN_AutoReTxEn = true; } CAN_AutoReTxCmd(init_struct->CAN_AutoReTxEn); + + data->common.mode = mode; + k_mutex_unlock(&data->inst_mutex); + return 0; } @@ -286,19 +293,21 @@ static int can_bee_set_timing(const struct device *dev, const struct can_timing struct can_bee_data *data = dev->data; CAN_InitTypeDef *init_struct = &(data->init_struct); - LOG_DBG("[%s] dev %s", __func__, dev->name); - if (data->common.started) { return -EBUSY; } k_mutex_lock(&data->inst_mutex, K_FOREVER); + init_struct->CAN_BitTiming.b.can_brp = timing->prescaler - 1; init_struct->CAN_BitTiming.b.can_sjw = timing->sjw; init_struct->CAN_BitTiming.b.can_tseg1 = timing->phase_seg1 - 1; init_struct->CAN_BitTiming.b.can_tseg2 = timing->phase_seg2 - 1; + CAN_SetTiming(&(init_struct->CAN_BitTiming)); + k_mutex_unlock(&data->inst_mutex); + return 0; } @@ -316,6 +325,7 @@ static int can_bee_request_message_buffer(const struct device *dev, bool is_tx) return i; } } + return -EAGAIN; } @@ -331,23 +341,22 @@ static int can_bee_send(const struct device *dev, const struct can_frame *frame, int mb_idx; int ret; - LOG_DBG("Sending %d bytes on %s. " - "Id: 0x%x, " - "ID type: %s, " - "Remote Frame: %s", - frame->dlc, dev->name, frame->id, - (frame->flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard", - (frame->flags & CAN_FRAME_RTR) != 0 ? "yes" : "no"); - __ASSERT_NO_MSG(callback != NULL); - __ASSERT(frame->dlc == 0U || frame->data != NULL, "Dataptr is null"); + LOG_DBG("Sending %d bytes %s frame on %s: %s id: 0x%x", frame->dlc, + (frame->flags & CAN_FRAME_RTR) != 0 ? "remote" : "data", dev->name, + (frame->flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard", frame->id); + + if (!callback) { + LOG_ERR("No valid callback"); + return -EINVAL; + } if (frame->dlc > CAN_MAX_DLC) { - LOG_ERR("DLC of %d exceeds maximum (%d)", frame->dlc, CAN_MAX_DLC); + LOG_ERR("DLC (%d) exceeds maximum (%d)", frame->dlc, CAN_MAX_DLC); return -EINVAL; } if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_RTR)) != 0) { - LOG_ERR("Unsupported CAN frame flags 0x%02x", frame->flags); + LOG_ERR("Unsupported CAN frame flags (0x%x)", frame->flags); return -ENOTSUP; } @@ -401,12 +410,16 @@ static int can_bee_send(const struct device *dev, const struct can_frame *frame, tx_frame_type.msg_buf_id = mb_idx; tx_frame_type.auto_reply_bit = DISABLE; tx_error = CAN_SetMsgBufTxMode(&tx_frame_type, frame->data, frame->dlc); - while (CAN_GetRamState(can) != CAN_RAM_STATE_IDLE) { - ; + + ret = can_bee_wait_ram_state(K_MSEC(10)); + if (ret < 0) { + LOG_ERR("Wait CAN RAM state timeout"); + ret = -EIO; + goto fail; } if (tx_error != CAN_NO_ERR) { - ret = -EINVAL; + ret = -EIO; goto fail; } @@ -421,35 +434,29 @@ static int can_bee_send(const struct device *dev, const struct can_frame *frame, } k_mutex_unlock(&data->inst_mutex); + return ret; } static int can_bee_add_rx_filter(const struct device *dev, can_rx_callback_t callback, void *user_data, const struct can_filter *filter) { - const struct can_bee_config *cfg = dev->config; struct can_bee_data *data = dev->data; - CAN_TypeDef *can = cfg->can; CANRxFrame_TypeDef rx_frame_type; CANError_TypeDef rx_error; int mb_list_idx; + int ret; - LOG_DBG("[%s] filter->id=0x%x, filter->flags=0x%x, filter->mask=0x%x", __func__, - filter->id, filter->flags, filter->mask); + LOG_DBG("[%s] filter->id=0x%x, filter->flags=0x%x, filter->mask=0x%x", __func__, filter->id, + filter->flags, filter->mask); if ((filter->flags & ~(CAN_FILTER_IDE)) != 0) { LOG_ERR("Unsupported CAN filter flags 0x%02x", filter->flags); return -ENOTSUP; } - k_mutex_lock(&filter_mutex, K_FOREVER); k_mutex_lock(&data->inst_mutex, K_FOREVER); - if (!data->common.started) { - LOG_ERR("CAN not start"); - return -ENETDOWN; - } - mb_list_idx = can_bee_request_message_buffer(dev, false); if (mb_list_idx < 0) { mb_list_idx = -ENOSPC; @@ -483,8 +490,12 @@ static int can_bee_add_rx_filter(const struct device *dev, can_rx_callback_t cal #endif rx_error = CAN_SetMsgBufRxMode(&rx_frame_type); - while (CAN_GetRamState(can) != CAN_RAM_STATE_IDLE) { - ; + + ret = can_bee_wait_ram_state(K_MSEC(10)); + if (ret < 0) { + LOG_ERR("Wait CAN RAM state timeout"); + mb_list_idx = -EIO; + goto unlock; } if (rx_error != CAN_NO_ERR) { @@ -496,36 +507,38 @@ static int can_bee_add_rx_filter(const struct device *dev, can_rx_callback_t cal data->rx_mb_list[mb_list_idx].user_data = user_data; data->rx_mb_list[mb_list_idx].is_busy = true; CAN_MBRxINTConfig(rx_frame_type.msg_buf_id, ENABLE); + unlock: k_mutex_unlock(&data->inst_mutex); - k_mutex_unlock(&filter_mutex); return mb_list_idx; } static void can_bee_remove_rx_filter(const struct device *dev, int mb_list_idx) { - const struct can_bee_config *cfg = dev->config; struct can_bee_data *data = dev->data; - CAN_TypeDef *can = cfg->can; CANRxFrame_TypeDef rx_frame_type; + int ret; LOG_DBG("[%s]", __func__); - k_mutex_lock(&filter_mutex, K_FOREVER); k_mutex_lock(&data->inst_mutex, K_FOREVER); rx_frame_type.msg_buf_id = data->rx_mb_list[mb_list_idx].idx; rx_frame_type.rx_msg_buf_enable = false; CAN_SetMsgBufRxMode(&rx_frame_type); CAN_MBRxINTConfig(data->rx_mb_list[mb_list_idx].idx, DISABLE); - while (CAN_GetRamState(can) != CAN_RAM_STATE_IDLE) { - ; + + ret = can_bee_wait_ram_state(K_MSEC(10)); + if (ret < 0) { + LOG_ERR("Wait CAN RAM state timeout"); + goto unlock; } data->rx_mb_list[mb_list_idx].rx_callback = NULL; data->rx_mb_list[mb_list_idx].user_data = NULL; data->rx_mb_list[mb_list_idx].is_busy = false; + +unlock: k_mutex_unlock(&data->inst_mutex); - k_mutex_unlock(&filter_mutex); } static int can_bee_get_state(const struct device *dev, enum can_state *state, @@ -535,8 +548,6 @@ static int can_bee_get_state(const struct device *dev, enum can_state *state, struct can_bee_data *data = dev->data; CAN_TypeDef *can = cfg->can; - LOG_DBG("[%s]", __func__); - if (state != NULL) { if (!data->common.started) { *state = CAN_STATE_STOPPED; @@ -555,6 +566,7 @@ static int can_bee_get_state(const struct device *dev, enum can_state *state, err_cnt->tx_err_cnt = CAN_GetTxErrorCnt(can); err_cnt->rx_err_cnt = CAN_GetRxErrorCnt(can); } + return 0; } @@ -564,14 +576,16 @@ static int can_bee_recover(const struct device *dev, k_timeout_t timeout) const struct can_bee_config *cfg = dev->config; struct can_bee_data *data = dev->data; CAN_TypeDef *can = cfg->can; - int ret = -EAGAIN; - - LOG_DBG("[%s]", __func__); + int ret = 0; if (!data->common.started) { return -ENETDOWN; } + if ((data->common.mode & CAN_MODE_MANUAL_RECOVERY) == 0U) { + return -ENOTSUP; + } + if (CAN_GetBusState(can) == CAN_BUS_STATE_ON) { return 0; } @@ -581,8 +595,15 @@ static int can_bee_recover(const struct device *dev, k_timeout_t timeout) } CAN_Cmd(ENABLE); + ret = can_bee_check_bus_on(timeout); + if (ret < 0) { + LOG_ERR("CAN bus off"); + ret = -EIO; + } + k_mutex_unlock(&data->inst_mutex); + return ret; } #endif /* CONFIG_CAN_MANUAL_RECOVERY_MODE */ @@ -592,8 +613,6 @@ static void can_bee_set_state_change_callback(const struct device *dev, { struct can_bee_data *data = dev->data; - LOG_DBG("[%s]", __func__); - data->common.state_change_cb = cb; data->common.state_change_cb_user_data = user_data; @@ -608,9 +627,8 @@ static int can_bee_get_core_clock(const struct device *dev, uint32_t *rate) { ARG_UNUSED(dev); - LOG_DBG("[%s]", __func__); - *rate = 40000000; + return 0; } @@ -619,13 +637,7 @@ static int can_bee_get_max_filters(const struct device *dev, bool ide) ARG_UNUSED(dev); ARG_UNUSED(ide); - LOG_DBG("[%s]", __func__); - - if (ide) { - return CONFIG_CAN_BEE_MAX_EXT_ID_FILTER; - } else { - return CONFIG_CAN_BEE_MAX_STD_ID_FILTER; - } + return CONFIG_CAN_BEE_RX_MSG_BUF_NUM; } static inline void can_bee_isr(const struct device *dev) @@ -636,8 +648,6 @@ static inline void can_bee_isr(const struct device *dev) const can_state_change_callback_t cb = data->common.state_change_cb; void *state_change_cb_data = data->common.state_change_cb_user_data; - LOG_DBG("[%s]", __func__); - if (SET == CAN_GetINTStatus(CAN_BUS_OFF_INT_FLAG)) { CAN_ClearINTPendingBit(CAN_BUS_OFF_INT_FLAG); for (uint8_t mb_list_idx = 0; mb_list_idx < CONFIG_CAN_BEE_TX_MSG_BUF_NUM; @@ -757,7 +767,6 @@ static void pm_restore_work(struct k_work *work) CAN_TypeDef *can = cfg->can; int ret; - k_mutex_lock(&filter_mutex, K_FOREVER); k_mutex_lock(&data->inst_mutex, K_FOREVER); ret = can_bee_check_bus_on(K_MSEC(10)); @@ -779,7 +788,6 @@ static void pm_restore_work(struct k_work *work) } } k_mutex_unlock(&data->inst_mutex); - k_mutex_unlock(&filter_mutex); } static int can_bee_pm_action(const struct device *dev, enum pm_device_action action) @@ -856,9 +864,6 @@ static int can_bee_init(const struct device *dev) CAN_InitTypeDef *init_struct = &(data->init_struct); int ret; - LOG_DBG("[%s]", __func__); - - k_mutex_init(&filter_mutex); k_mutex_init(&data->inst_mutex); k_sem_init(&data->tx_int_sem, CONFIG_CAN_BEE_TX_MSG_BUF_NUM, CONFIG_CAN_BEE_TX_MSG_BUF_NUM); @@ -899,7 +904,6 @@ static int can_bee_init(const struct device *dev) } } - /* Configure pinmux */ ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); if (ret < 0) { return ret; @@ -907,7 +911,6 @@ static int can_bee_init(const struct device *dev) (void)clock_control_on(BEE_CLOCK_CONTROLLER, (clock_control_subsys_t)&cfg->clkid); - /* Configure peripheral */ ret = can_calc_timing(dev, &timing, cfg->common.bitrate, cfg->common.sample_point); if (ret == -EINVAL) { LOG_ERR("Can't find timing for given param"); @@ -915,9 +918,7 @@ static int can_bee_init(const struct device *dev) } LOG_DBG("Presc: %d, SJW: %d, TS1: %d, TS2: %d", timing.prescaler, timing.sjw, timing.phase_seg1, timing.phase_seg2); - LOG_DBG("Sample-point err : %d", ret); - /* Initialize CAN. */ CAN_StructInit(init_struct); init_struct->CAN_AutoReTxEn = ENABLE; init_struct->CAN_ErrorWarnThd = 128; @@ -939,9 +940,10 @@ static int can_bee_init(const struct device *dev) return ret; } - cfg->config_irq(); + cfg->irq_config_func(); return 0; } + #define CAN_BEE_IRQ_INST(index) \ static void config_can_##index##_irq(void) \ { \ @@ -955,13 +957,9 @@ static int can_bee_init(const struct device *dev) .common = CAN_DT_DRIVER_CONFIG_INST_GET( \ index, 0, DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(index, 1000000)), \ .can = (CAN_TypeDef *)DT_INST_REG_ADDR(index), \ - .sjw = DT_INST_PROP_OR(index, sjw, 1), \ - .prop_ts1 = DT_INST_PROP_OR(index, prop_seg, 0) + \ - DT_INST_PROP_OR(index, phase_seg1, 0), \ - .ts2 = DT_INST_PROP_OR(index, phase_seg2, 0), \ .clkid = DT_INST_CLOCKS_CELL(index, id), \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \ - .config_irq = config_can_##index##_irq, \ + .irq_config_func = config_can_##index##_irq, \ }; #define CAN_BEE_DATA_INST(index) static struct can_bee_data can_bee_dev_data_##index; #define CAN_BEE_DEFINE_INST(index) \ diff --git a/samples/bee_pm_device/dts/bindings/bee-pm-device-spi.yaml b/samples/bee_pm_device/dts/bindings/bee-pm-device-spi.yaml deleted file mode 100644 index d91b400b07b12..0000000000000 --- a/samples/bee_pm_device/dts/bindings/bee-pm-device-spi.yaml +++ /dev/null @@ -1,7 +0,0 @@ -description: | - This binding provides resources required to build and run the - bee_pm_device. - -compatible: "bee-pm-device-spi" - -include: [spi-device.yaml] diff --git a/samples/bee_pm_device/sample.yaml b/samples/bee_pm_device/sample.yaml deleted file mode 100644 index 55869ff2ac01a..0000000000000 --- a/samples/bee_pm_device/sample.yaml +++ /dev/null @@ -1,6 +0,0 @@ -sample: - description: Bee pm device sample - name: bee pm device -common: - tags: introduction - harness: console diff --git a/samples/bee_pm_device/src/main.c b/samples/bee_pm_device/src/main.c deleted file mode 100644 index 55d5339464dd4..0000000000000 --- a/samples/bee_pm_device/src/main.c +++ /dev/null @@ -1,1395 +0,0 @@ -/* - * Copyright (c) 2025 Realtek Semiconductor Corp. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#ifdef CONFIG_GPIO -#include -#if defined(CONFIG_GPIO_BEE) -#include -#endif -#endif -#ifdef CONFIG_SERIAL -#include -#endif -#ifdef CONFIG_PWM -#include -#endif -#ifdef CONFIG_COUNTER -#include -#endif -#ifdef CONFIG_SPI -#include -#endif -#ifdef CONFIG_RTC -#include -#endif -#ifdef CONFIG_I2C -#include -#endif -#ifdef CONFIG_ADC -#include -#endif -#ifdef CONFIG_SENSOR -#include -#if defined(CONFIG_QDEC_BEE) -#include -#endif -#endif -#ifdef CONFIG_SDMMC_STACK -#include -#endif -#ifdef CONFIG_CAN -#include -#endif -#if defined(CONFIG_SOC_SERIES_RTL87X2G) -#include "trace.h" -#include -#include "power_manager_unit_platform.h" - -#define PM_TEST_CHECK_PASS PM_CHECK_PASS -#define PM_TEST_CHECK_FAIL PM_CHECK_FAIL -#define PM_TEST_CHECK_RET PMCheckResult - -#define pm_test_register_check_cb(app_check) \ - platform_pm_register_callback_func_with_priority((void *)app_check, PLATFORM_PM_CHECK, 1) -#define pm_test_register_store_cb(app_store) \ - platform_pm_register_callback_func_with_priority((void *)app_store, PLATFORM_PM_STORE, 1) -#define pm_test_register_restore_cb(app_restore) \ - platform_pm_register_callback_func_with_priority((void *)app_restore, PLATFORM_PM_RESTORE, \ - 1) - -#elif defined(CONFIG_SOC_SERIES_RTL8752H) -#include "trace.h" -#include - -extern void (*platform_pm_register_callback_func_with_priority)(void *cb_func, - PlatformPMStage pf_pm_stage, - int8_t priority); - -#define PM_TEST_CHECK_PASS PM_CHECK_PASS -#define PM_TEST_CHECK_FAIL PM_CHECK_FAIL -#define PM_TEST_CHECK_RET PMCheckResult - -#define pm_test_register_check_cb(app_check) \ - platform_pm_register_callback_func_with_priority((void *)app_check, PLATFORM_PM_CHECK, 1) -#define pm_test_register_store_cb(app_store) \ - platform_pm_register_callback_func_with_priority((void *)app_store, PLATFORM_PM_STORE, 1) -#define pm_test_register_restore_cb(app_restore) \ - platform_pm_register_callback_func_with_priority((void *)app_restore, PLATFORM_PM_RESTORE, \ - 1) - -#else -#include "log_core.h" -#endif - -#if defined(CONFIG_PM_DEVICE) -struct k_sem app_sem; - -static PM_TEST_CHECK_RET dlps_check_flag = PM_TEST_CHECK_FAIL; - -static PM_TEST_CHECK_RET app_check(void) -{ - return dlps_check_flag; -} - -uint32_t pm_cnt; - -static void app_store(void) -{ - DBG_DIRECT("[%s] %d line%d", __func__, ++pm_cnt, __LINE__); -} - -static void app_restore(void) -{ - DBG_DIRECT("[%s] %d line%d", __func__, pm_cnt, __LINE__); - k_sem_give(&app_sem); -} - -#endif - -int main(void) -{ - printf("[%lld] Bee pm device test for %s\n", k_uptime_get(), CONFIG_BOARD_TARGET); - -#if defined(CONFIG_PM_DEVICE) - k_sem_init(&app_sem, 0, 1); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - pm_test_register_check_cb(app_check); - pm_test_register_store_cb(app_store); - pm_test_register_restore_cb(app_restore); -#endif - - return 0; -} - -static int shell_pm_test_uart(const struct shell *sh, size_t argc, char **argv) -{ -#ifdef CONFIG_SERIAL -#if defined(CONFIG_PM_DEVICE) - /* ==================================================================================== */ - /* enter dlps */ - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] type on shell to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rx 1 byte to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); - /* ==================================================================================== */ -#endif -#endif - - return 0; -} - -#ifdef CONFIG_UART_ASYNC_API -const struct device *test_uart_dma_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_uart_dma)); -struct k_sem uart_dma_tx_sem; -struct k_sem uart_dma_rx_sem; -uint8_t uart_dma_rx_buf[1024]; -uint32_t uart_dma_rx_len; -bool uart_dma_rx_enabled; - -static void uart_async_console_callback(const struct device *dev, struct uart_event *evt, - void *user_data) -{ - printf("[%s] evt->type=%d", __func__, evt->type); - switch (evt->type) { - case UART_TX_DONE: - printf("uart dma tx done\n"); - k_sem_give(&uart_dma_tx_sem); - break; - case UART_RX_RDY: - printf("uart dma rx ready\n"); - memcpy(uart_dma_rx_buf, &evt->data.rx.buf[evt->data.rx.offset], evt->data.rx.len); - uart_dma_rx_len = evt->data.rx.len; - k_sem_give(&uart_dma_rx_sem); - break; - default: - break; - } -} -static void uart_dma_enter_cb(void) -{ - DBG_DIRECT("[%s] line%d", __func__, __LINE__); -} - -static void uart_dma_exit_cb(void) -{ - DBG_DIRECT("[%s] line%d", __func__, __LINE__); - if (uart_dma_rx_enabled) { - } -} - -static int shell_pm_test_uart_dma(const struct shell *sh, size_t argc, char **argv) -{ - static bool pm_uart_dma_register_cb_flag; - - DBG_DIRECT("[%s] pm_uart_dma_register_cb_flag=%d line%d", __func__, - pm_uart_dma_register_cb_flag, __LINE__); - if (pm_uart_dma_register_cb_flag == false) { - pm_test_register_store_cb(uart_dma_enter_cb); - pm_test_register_restore_cb(uart_dma_exit_cb); - pm_uart_dma_register_cb_flag = true; - } - - /* ==================================================================================== */ - k_sem_init(&uart_dma_tx_sem, 0, 1); - k_sem_init(&uart_dma_rx_sem, 0, 1); - memset(uart_dma_rx_buf, 0, sizeof(uart_dma_rx_buf)); - uart_dma_rx_len = 0; - - uart_callback_set(test_uart_dma_dev, uart_async_console_callback, NULL); - - uart_dma_rx_enabled = true; - uart_rx_enable(test_uart_dma_dev, uart_dma_rx_buf, sizeof(uart_dma_rx_buf), - 50 * USEC_PER_MSEC); - printf("send some data from dma uart\n"); - k_sem_take(&uart_dma_rx_sem, K_FOREVER); - - printf("uart dma rx data(%d bytes):\n", uart_dma_rx_len); - for (size_t i = 0; i < uart_dma_rx_len; i++) { - if (i % 16 == 0) { - printf("%d: ", i); - } - - printf("%c ", uart_dma_rx_buf[i]); - - if (i % 16 == 15 || i == uart_dma_rx_len - 1) { - printf("\n"); - } - } - - uart_tx(test_uart_dma_dev, uart_dma_rx_buf, uart_dma_rx_len, 100 * USEC_PER_MSEC); - k_sem_take(&uart_dma_tx_sem, K_FOREVER); - - /* ==================================================================================== */ - - /* enter dlps */ - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] type on shell to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rx 1 byte to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); - - /* ==================================================================================== */ - - k_sem_init(&uart_dma_tx_sem, 0, 1); - k_sem_init(&uart_dma_rx_sem, 0, 1); - memset(uart_dma_rx_buf, 0, sizeof(uart_dma_rx_buf)); - uart_dma_rx_len = 0; - - uart_rx_disable(test_uart_dma_dev); - uart_rx_enable(test_uart_dma_dev, uart_dma_rx_buf, sizeof(uart_dma_rx_buf), - 50 * USEC_PER_MSEC); - printf("send some data from dma uart\n"); - k_sem_take(&uart_dma_rx_sem, K_FOREVER); - - printf("uart dma rx data(%d bytes):\n", uart_dma_rx_len); - for (size_t i = 0; i < uart_dma_rx_len; i++) { - if (i % 16 == 0) { - printf("%d: ", i); - } - - printf("%c ", uart_dma_rx_buf[i]); - - if (i % 16 == 15 || i == uart_dma_rx_len - 1) { - printf("\n"); - } - } - - uart_tx(test_uart_dma_dev, uart_dma_rx_buf, uart_dma_rx_len, 100 * USEC_PER_MSEC); - k_sem_take(&uart_dma_tx_sem, K_FOREVER); - - uart_rx_disable(test_uart_dma_dev); - uart_dma_rx_enabled = false; - - /* ==================================================================================== */ - return 0; -} -#endif - -#ifdef CONFIG_COUNTER -const struct device *counter_timer_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_counter_timer)); - -static void top_handler(const struct device *dev, void *user_data) -{ - printf("[%s]\n", __func__); - - k_sem_give(&app_sem); -} - -static int shell_pm_test_counter(const struct shell *sh, size_t argc, char **argv) -{ - struct counter_top_cfg top_cfg; - uint64_t current_sys_time_ms; - uint64_t pre_sys_time_ms; - uint64_t timeout_ms = atoi(argv[1]); - - /* ==================================================================================== */ - counter_start(counter_timer_dev); - - top_cfg.callback = top_handler; - top_cfg.flags = 0; - top_cfg.ticks = counter_us_to_ticks(counter_timer_dev, timeout_ms * 1000); - pre_sys_time_ms = k_uptime_get(); - top_cfg.user_data = NULL; - printf("[%lld] wait %lldms to trigger handler\n", pre_sys_time_ms, timeout_ms); - counter_set_top_value(counter_timer_dev, &top_cfg); - /* ==================================================================================== */ - - /* enter dlps */ - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - current_sys_time_ms = k_uptime_get(); - printf("[%lld] trigger handler after %lldms\n", current_sys_time_ms, - current_sys_time_ms - pre_sys_time_ms); - - counter_stop(counter_timer_dev); - /* ==================================================================================== */ - - return 0; -} -#endif - -#ifdef CONFIG_GPIO -#define DEV_OUT DT_GPIO_CTLR(DT_INST(0, bee_pm_device_gpio), out_gpios) -#define DEV_IN DT_GPIO_CTLR(DT_INST(0, bee_pm_device_gpio), in_gpios) -#define PIN_OUT DT_GPIO_PIN(DT_INST(0, bee_pm_device_gpio), out_gpios) -#define PIN_OUT_FLAGS DT_GPIO_FLAGS(DT_INST(0, bee_pm_device_gpio), out_gpios) -#define PIN_IN DT_GPIO_PIN(DT_INST(0, bee_pm_device_gpio), in_gpios) -#define PIN_IN_FLAGS DT_GPIO_FLAGS(DT_INST(0, bee_pm_device_gpio), in_gpios) - -const struct device *const gpio_dev_in = DEVICE_DT_GET_OR_NULL(DEV_IN); -const struct device *const gpio_dev_out = DEVICE_DT_GET_OR_NULL(DEV_OUT); - -struct gpio_callback gpio_cb; -struct k_sem gpio_sem; - -static void gpio_callback(const struct device *dev_in, struct gpio_callback *gpio_cb, uint32_t pins) -{ - static uint8_t cnt; -#if defined(CONFIG_PM_DEVICE) - dlps_check_flag = PM_TEST_CHECK_FAIL; -#endif - k_sem_give(&gpio_sem); - printf("[%lld] enter gpio callback cnt%d\n", k_uptime_get(), cnt); - ++cnt; -} - -static int shell_pm_test_gpio(const struct shell *sh, size_t argc, char **argv) -{ - - k_sem_init(&gpio_sem, 0, 1); - - /* ==================================================================================== */ - /* 1. set PIN_OUT to logical initial state inactive */ - gpio_pin_configure(gpio_dev_out, PIN_OUT, GPIO_OUTPUT_LOW | PIN_OUT_FLAGS); - - /* 2. configure PIN_IN callback and trigger condition */ - gpio_pin_configure(gpio_dev_in, PIN_IN, - (GPIO_INPUT | GPIO_PULL_UP | PIN_IN_FLAGS | BEE_GPIO_INPUT_PM_WAKEUP)); - - gpio_init_callback(&gpio_cb, gpio_callback, BIT(PIN_IN)); - gpio_add_callback(gpio_dev_in, &gpio_cb); - gpio_pin_interrupt_configure(gpio_dev_in, PIN_IN, GPIO_INT_EDGE_FALLING); - -#if defined(CONFIG_PM_DEVICE) - /* enter dlps */ - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] connect input pin to output pin to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rising edge to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#else - printf("[%lld] connect input pin to output pin to wakeup\n", k_uptime_get()); - k_sem_init(&gpio_sem, 0, 1); - k_sem_take(&gpio_sem, K_FOREVER); -#endif - k_busy_wait(100000); - gpio_pin_interrupt_configure(gpio_dev_in, PIN_IN, GPIO_INT_EDGE_RISING); - - /* ==================================================================================== */ -#if defined(CONFIG_PM_DEVICE) - /* enter dlps */ - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] disconnect input pin to output pin to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* falling edge to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#else - printf("[%lld] disconnect input pin to output pin to wakeup\n", k_uptime_get()); - k_sem_init(&gpio_sem, 0, 1); - k_sem_take(&gpio_sem, K_FOREVER); -#endif - k_busy_wait(100000); - /* ==================================================================================== */ -#if defined(CONFIG_BEE_GPIO_SUPPORT_BOTH_EDGE) - /* both edge */ - gpio_pin_interrupt_configure(gpio_dev_in, PIN_IN, GPIO_INT_EDGE_BOTH); - -#if defined(CONFIG_PM_DEVICE) - /* enter dlps */ - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] connect input pin to output pin to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rising edge to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#else - printf("[%lld] connect input pin to output pin to wakeup\n", k_uptime_get()); - k_sem_init(&gpio_sem, 0, 1); - k_sem_take(&gpio_sem, K_FOREVER); -#endif - k_busy_wait(100000); - - /* ==================================================================================== */ -#if defined(CONFIG_PM_DEVICE) - /* enter dlps */ - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] disconnect input pin to output pin to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* falling edge to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#else - printf("[%lld] disconnect input pin to output pin to wakeup\n", k_uptime_get()); - k_sem_init(&gpio_sem, 0, 1); - k_sem_take(&gpio_sem, K_FOREVER); -#endif - - k_busy_wait(100000); - -#endif - - gpio_remove_callback(gpio_dev_in, &gpio_cb); - - gpio_pin_interrupt_configure(gpio_dev_in, PIN_IN, GPIO_INT_DISABLE); - gpio_pin_configure(gpio_dev_in, PIN_IN, - ((GPIO_INPUT) | GPIO_PULL_UP | PIN_IN_FLAGS) & - (~BEE_GPIO_INPUT_PM_WAKEUP)); - - /* ==================================================================================== */ - - return 0; -} -#endif - -#ifdef CONFIG_PWM -const struct device *pwm_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_pwm)); - -static int shell_pm_test_pwm(const struct shell *sh, size_t argc, char **argv) -{ - uint32_t period, pulse; - - /* ==================================================================================== */ - printf("[%lld] connect pwm pin to LA to watch the waveform\n", k_uptime_get()); - - period = 50000; - pulse = 10000; - printf("[%lld] [PWM]: %s, [period]: %d, [pulse]: %d\n", k_uptime_get(), pwm_dev->name, - period, pulse); - pwm_set_cycles(pwm_dev, 0, period, pulse, 0); - k_busy_wait(500000); - - /* ==================================================================================== */ -#if defined(CONFIG_PM_DEVICE) - /* enter dlps */ - printf("[%lld] before enter dlps\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - /* delay 500 ms to wakeup */ - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_MSEC(500)); - dlps_check_flag = PM_TEST_CHECK_FAIL; - - printf("[%lld] after exit dlps\n", k_uptime_get()); - k_busy_wait(500000); -#endif - /* ==================================================================================== */ - - period = 0; - pulse = 0; - printf("[%lld] [PWM]: %s, [period]: %d, [pulse]: %d\n", k_uptime_get(), pwm_dev->name, - period, pulse); - pwm_set_cycles(pwm_dev, 0, period, pulse, 0); - k_busy_wait(500000); - -#if defined(CONFIG_PM_DEVICE) - k_sleep(K_MSEC(10)); -#endif - - period = 50000; - pulse = 40000; - printf("[%lld] [PWM]: %s, [period]: %d, [pulse]: %d\n", k_uptime_get(), pwm_dev->name, - period, pulse); - pwm_set_cycles(pwm_dev, 0, period, pulse, 0); - k_busy_wait(500000); - - /* ==================================================================================== */ -#if defined(CONFIG_PM_DEVICE) - /* enter dlps */ - printf("[%lld] before enter dlps\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - /* delay 500 ms to wakeup */ - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_MSEC(500)); - dlps_check_flag = PM_TEST_CHECK_FAIL; - - printf("[%lld] after exit dlps\n", k_uptime_get()); - k_busy_wait(500000); -#endif - /* ==================================================================================== */ - - period = 0; - pulse = 0; - printf("[%lld] [PWM]: %s, [period]: %d, [pulse]: %d\n", k_uptime_get(), pwm_dev->name, - period, pulse); - pwm_set_cycles(pwm_dev, 0, period, pulse, 0); - /* ==================================================================================== */ - - return 0; -} -#endif - -#ifdef CONFIG_SPI -#define MODE_LOOP 0 -#define FRAME_SIZE (8) -#define SPI_OP(frame_size) \ - SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(frame_size) | \ - SPI_LINES_SINGLE - -#define SPI_DEV DT_COMPAT_GET_ANY_STATUS_OKAY(bee_pm_device_spi) -static struct spi_dt_spec spi_spec = SPI_DT_SPEC_GET(SPI_DEV, SPI_OP(FRAME_SIZE), 0); - -#define BUF_SIZE 18 - -static const char tx_data[BUF_SIZE] = "0123456789abcdef-\0"; -static __aligned(32) char buffer_tx[BUF_SIZE]; -static __aligned(32) char buffer_rx[BUF_SIZE]; - -static int spi_complete_loop(struct spi_dt_spec *spec) -{ - memcpy(buffer_tx, tx_data, sizeof(tx_data)); - memset(buffer_rx, 0, sizeof(buffer_rx)); - - const struct spi_buf tx_bufs[] = { - { - .buf = buffer_tx, - .len = BUF_SIZE, - }, - }; - const struct spi_buf rx_bufs[] = { - { - .buf = buffer_rx, - .len = BUF_SIZE, - }, - }; - const struct spi_buf_set tx = {.buffers = tx_bufs, .count = ARRAY_SIZE(tx_bufs)}; - const struct spi_buf_set rx = {.buffers = rx_bufs, .count = ARRAY_SIZE(rx_bufs)}; - - int ret; - - printf("[%lld] Start complete loop\n", k_uptime_get()); - - ret = spi_transceive_dt(spec, &tx, &rx); - - if (memcmp(buffer_tx, buffer_rx, BUF_SIZE)) { - printf("[%lld] Buffer contents are different\n", k_uptime_get()); - return -1; - } - - printf("[%lld] Buffer contents are same\n", k_uptime_get()); - return 0; -} - -static int shell_pm_test_spi(const struct shell *sh, size_t argc, char **argv) -{ - - /* ==================================================================================== */ - printf("[%lld] connect MOSI pin to the MISO of the SPI\n", k_uptime_get()); - - if (spi_complete_loop(&spi_spec) < 0) { - printf("[%lld] loopback test fali\n", k_uptime_get()); - return 0; - } - - /* ==================================================================================== */ -#if defined(CONFIG_PM_DEVICE) - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] type on shell to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rx 1 byte to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#endif - - /* ==================================================================================== */ - if (spi_complete_loop(&spi_spec) < 0) { - printf("[%lld] loopback test fali\n", k_uptime_get()); - return 0; - } - /* ==================================================================================== */ - - return 0; -} -#endif - -#ifdef CONFIG_RTC -static const struct device *rtc_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_rtc)); - -static const struct rtc_time rtc_time_set = { - .tm_sec = 50, - .tm_min = 29, - .tm_hour = 13, - .tm_mday = 1, - .tm_mon = 0, - .tm_year = 121, - .tm_wday = 5, - .tm_yday = 1, - .tm_isdst = -1, - .tm_nsec = 0, -}; - -static const struct rtc_time alarm_time_set = { - .tm_sec = 52, - .tm_min = 29, - .tm_hour = 13, - .tm_mday = 1, - .tm_mon = 0, - .tm_year = 121, - .tm_wday = 5, - .tm_yday = 1, - .tm_isdst = -1, - .tm_nsec = 0, -}; - -static void rtc_alarm_callback_handler(const struct device *dev, uint16_t id, void *user_data) -{ -#if defined(CONFIG_PM_DEVICE) - k_sem_give(&app_sem); -#endif -} - -static int shell_pm_test_rtc(const struct shell *sh, size_t argc, char **argv) -{ - uint64_t current_sys_time_ms; - uint64_t pre_sys_time_ms; - - /* ==================================================================================== */ - rtc_alarm_set_callback(rtc_dev, 0, NULL, NULL); - rtc_set_time(rtc_dev, &rtc_time_set); - - rtc_alarm_set_callback(rtc_dev, 0, rtc_alarm_callback_handler, NULL); - - pre_sys_time_ms = k_uptime_get(); - rtc_alarm_set_time(rtc_dev, 0, 0x1ff, &alarm_time_set); - - printf("[%lld] wait %dms to trigger handler\n", pre_sys_time_ms, 2000); - - /* ==================================================================================== */ -#if defined(CONFIG_PM_DEVICE) - /* enter dlps */ - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - printf("[%s] wakeup\n", __func__); -#endif - - current_sys_time_ms = k_uptime_get(); - printf("[%lld] trigger handler after %lldms\n", current_sys_time_ms, - current_sys_time_ms - pre_sys_time_ms); - /* ==================================================================================== */ - return 0; -} -#endif - -#if defined(CONFIG_SENSOR) && defined(CONFIG_QDEC_BEE) -static const struct gpio_dt_spec qdec_phase_a = GPIO_DT_SPEC_GET(DT_ALIAS(test_qenca), gpios); -static const struct gpio_dt_spec qdec_phase_b = GPIO_DT_SPEC_GET(DT_ALIAS(test_qencb), gpios); -const struct device *const qdec_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_qdec)); - -static int shell_pm_test_qdec(const struct shell *sh, size_t argc, char **argv) -{ - static bool toggle_a; - struct sensor_value val; - - /* ==================================================================================== */ - gpio_pin_configure_dt(&qdec_phase_a, GPIO_OUTPUT); - gpio_pin_configure_dt(&qdec_phase_b, GPIO_OUTPUT); - - k_busy_wait(100000); - - for (int i = 0; i < 12; i++) { - toggle_a = !toggle_a; - if (toggle_a) { - gpio_pin_toggle_dt(&qdec_phase_a); - } else { - gpio_pin_toggle_dt(&qdec_phase_b); - } - k_busy_wait(100000); - sensor_sample_fetch(qdec_dev); - sensor_channel_get(qdec_dev, SENSOR_ATTR_QDEC_X_ROTATION, &val); - printf("Position[%d] = %d degrees\n", i, val.val1); - } - - /* ==================================================================================== */ -#if defined(CONFIG_PM_DEVICE) - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] type on shell to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rx 1 byte to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#endif - - for (int i = 0; i < 12; i++) { - toggle_a = !toggle_a; - if (!toggle_a) { - gpio_pin_toggle_dt(&qdec_phase_a); - } else { - gpio_pin_toggle_dt(&qdec_phase_b); - } - k_busy_wait(100000); - sensor_sample_fetch(qdec_dev); - sensor_channel_get(qdec_dev, SENSOR_ATTR_QDEC_X_ROTATION, &val); - printf("Position[%d] = %d degrees\n", i, val.val1); - } - - /* ==================================================================================== */ -#if defined(CONFIG_PM_DEVICE) - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] type on shell to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rx 1 byte to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#endif - - for (int i = 0; i < 12; i++) { - toggle_a = !toggle_a; - if (!toggle_a) { - gpio_pin_toggle_dt(&qdec_phase_a); - } else { - gpio_pin_toggle_dt(&qdec_phase_b); - } - k_busy_wait(100000); - sensor_sample_fetch(qdec_dev); - sensor_channel_get(qdec_dev, SENSOR_ATTR_QDEC_X_ROTATION, &val); - printf("Position[%d] = %d degrees\n", i, val.val1); - } - - /* ==================================================================================== */ -#if defined(CONFIG_PM_DEVICE) - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] type on shell to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rx 1 byte to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#endif - - for (int i = 0; i < 12; i++) { - toggle_a = !toggle_a; - if (toggle_a) { - gpio_pin_toggle_dt(&qdec_phase_a); - } else { - gpio_pin_toggle_dt(&qdec_phase_b); - } - k_busy_wait(100000); - sensor_sample_fetch(qdec_dev); - sensor_channel_get(qdec_dev, SENSOR_ATTR_QDEC_X_ROTATION, &val); - printf("Position[%d] = %d degrees\n", i, val.val1); - } - return 0; -} -#endif - -#if defined(CONFIG_SENSOR) && (defined(CONFIG_AON_QDEC_BEE)) -static const struct gpio_dt_spec aon_qdec_phase_a = GPIO_DT_SPEC_GET(DT_ALIAS(test_qenca), gpios); -static const struct gpio_dt_spec aon_qdec_phase_b = GPIO_DT_SPEC_GET(DT_ALIAS(test_qencb), gpios); -const struct device *const aon_qdec_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_aon_qdec)); - -static int shell_pm_test_aon_qdec(const struct shell *sh, size_t argc, char **argv) -{ - static bool toggle_a; - struct sensor_value val; - - gpio_pin_configure_dt(&aon_qdec_phase_a, GPIO_OUTPUT); - gpio_pin_configure_dt(&aon_qdec_phase_b, GPIO_OUTPUT); - - k_busy_wait(100000); - - for (int i = 0; i < 10; i++) { - toggle_a = !toggle_a; - if (toggle_a) { - gpio_pin_toggle_dt(&aon_qdec_phase_a); - } else { - gpio_pin_toggle_dt(&aon_qdec_phase_b); - } - k_busy_wait(100000); - sensor_sample_fetch(aon_qdec_dev); - sensor_channel_get(aon_qdec_dev, SENSOR_CHAN_ROTATION, &val); - printf("Position[%d] = %d degrees\n", i, val.val1); - } - -#if defined(CONFIG_PM_DEVICE) - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] type on shell to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rx 1 byte to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#endif - - for (int i = 0; i < 10; i++) { - toggle_a = !toggle_a; - if (!toggle_a) { - gpio_pin_toggle_dt(&aon_qdec_phase_a); - } else { - gpio_pin_toggle_dt(&aon_qdec_phase_b); - } - k_busy_wait(100000); - sensor_sample_fetch(aon_qdec_dev); - sensor_channel_get(aon_qdec_dev, SENSOR_CHAN_ROTATION, &val); - printf("Position[%d] = %d degrees\n", i, val.val1); - } - -#if defined(CONFIG_PM_DEVICE) - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] type on shell to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rx 1 byte to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#endif - - for (int i = 0; i < 10; i++) { - toggle_a = !toggle_a; - if (!toggle_a) { - gpio_pin_toggle_dt(&aon_qdec_phase_a); - } else { - gpio_pin_toggle_dt(&aon_qdec_phase_b); - } - k_busy_wait(100000); - sensor_sample_fetch(aon_qdec_dev); - sensor_channel_get(aon_qdec_dev, SENSOR_CHAN_ROTATION, &val); - printf("Position[%d] = %d degrees\n", i, val.val1); - } - -#if defined(CONFIG_PM_DEVICE) - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] type on shell to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rx 1 byte to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#endif - - for (int i = 0; i < 10; i++) { - toggle_a = !toggle_a; - if (toggle_a) { - gpio_pin_toggle_dt(&aon_qdec_phase_a); - } else { - gpio_pin_toggle_dt(&aon_qdec_phase_b); - } - k_busy_wait(100000); - sensor_sample_fetch(aon_qdec_dev); - sensor_channel_get(aon_qdec_dev, SENSOR_CHAN_ROTATION, &val); - printf("Position[%d] = %d degrees\n", i, val.val1); - } - return 0; -} -#endif - -#ifdef CONFIG_I2C -const struct device *const i2c_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_i2c)); - -static int shell_pm_test_i2c(const struct shell *sh, size_t argc, char **argv) -{ - unsigned char icm20618_addr = 0x68; - unsigned char write_buf[6], read_buf[12]; - int write_len, read_len; - /* ==================================================================================== */ - (void)memset(write_buf, 0, sizeof(write_buf)); - (void)memset(read_buf, 0, sizeof(read_buf)); - /* read id */ - write_buf[0] = 0x00; - write_len = 1; - read_len = 1; - i2c_write_read(i2c_dev, icm20618_addr, write_buf, write_len, read_buf, read_len); - printf("icm20618 addr:0x%x reg: 0x%x = 0x%x\n", icm20618_addr, write_buf[0], read_buf[0]); - - /* ==================================================================================== */ -#if defined(CONFIG_PM_DEVICE) - /* enter dlps */ - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] type on shell to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rx 1 byte to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#endif - - /* ==================================================================================== */ - (void)memset(write_buf, 0, sizeof(write_buf)); - (void)memset(read_buf, 0, sizeof(read_buf)); - /* read id */ - write_buf[0] = 0x00; - write_len = 1; - read_len = 1; - i2c_write_read(i2c_dev, icm20618_addr, write_buf, write_len, read_buf, read_len); - printf("icm20618 addr:0x%x reg: 0x%x = 0x%x\n", icm20618_addr, write_buf[0], read_buf[0]); - /* ==================================================================================== */ - - return 0; -} -#endif - -#ifdef CONFIG_ADC -#define DT_SPEC_AND_COMMA(node_id, prop, idx) ADC_DT_SPEC_GET_BY_IDX(node_id, idx), -static const struct adc_dt_spec adc_channels[] = { - DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, DT_SPEC_AND_COMMA)}; - -#define ADC_BUFFER_SIZE 2 -#define INVALID_ADC_VALUE SHRT_MIN - -static const int adc_channels_count = ARRAY_SIZE(adc_channels); - -static int32_t m_sample_buffer[ADC_BUFFER_SIZE]; -static uint8_t m_samplings_done; - -static void check_samples(int expected_count) -{ - printf("Samples read: "); - for (int i = 0; i < ADC_BUFFER_SIZE; i++) { - int32_t sample_value = m_sample_buffer[i]; - - printf("[%u]:%04hd ", i, sample_value); - if (i < expected_count) { - if (INVALID_ADC_VALUE == sample_value) { - printf("[%u]:%4d should be filled ", i, sample_value); - } - } else { - if (INVALID_ADC_VALUE != sample_value) { - printf("[%u]:%4d should be %d ", i, sample_value, - INVALID_ADC_VALUE); - } - } - } - printf("\n"); -} - -static enum adc_action repeated_samplings_callback(const struct device *dev, - const struct adc_sequence *sequence, - uint16_t sampling_index) -{ - ++m_samplings_done; - printf("%s: done %d\n", __func__, m_samplings_done); - if (m_samplings_done == 1U) { - check_samples(MIN(adc_channels_count, 2)); - - /* After first sampling continue normally. */ - return ADC_ACTION_CONTINUE; - } - - check_samples(2 * MIN(adc_channels_count, 2)); - - /* - * The second sampling is repeated 9 times (the samples are - * written in the same place), then the sequence is finished - * prematurely. - */ - if (m_samplings_done < 10) { - return ADC_ACTION_REPEAT; - } - - return ADC_ACTION_FINISH; -} - -static int shell_pm_test_adc(const struct shell *sh, size_t argc, char **argv) -{ - /* ==================================================================================== */ - const struct adc_sequence_options options = { - .callback = repeated_samplings_callback, - .extra_samplings = 2, - .interval_us = 0, - }; - struct adc_sequence sequence = { - .options = &options, - .buffer = m_sample_buffer, - .buffer_size = sizeof(m_sample_buffer), - .resolution = 12, - }; - - for (uint8_t i = 0; i < adc_channels_count; i++) { - adc_channel_setup_dt(&adc_channels[i]); - } - - (void)adc_sequence_init_dt(&adc_channels[0], &sequence); - printf("adc_channels_count=%d, adc_channels[0].channel_id=%d\n", adc_channels_count, - adc_channels[0].channel_id); - if (adc_channels_count > 1) { - sequence.channels |= BIT(adc_channels[1].channel_id); - } - - for (uint8_t i = 0; i < ADC_BUFFER_SIZE; ++i) { - m_sample_buffer[i] = INVALID_ADC_VALUE; - } - - m_samplings_done = 0; - - adc_read_dt(&adc_channels[0], &sequence); - - /* ==================================================================================== */ -#if defined(CONFIG_PM_DEVICE) - /* enter dlps */ - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] type on shell to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rx 1 byte to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#endif - - /* ==================================================================================== */ - for (uint8_t i = 0; i < ADC_BUFFER_SIZE; ++i) { - m_sample_buffer[i] = INVALID_ADC_VALUE; - } - - m_samplings_done = 0; - - adc_read_dt(&adc_channels[0], &sequence); - /* ==================================================================================== */ - - return 0; -} -#endif - -#if defined(CONFIG_SDMMC_STACK) || defined(CONFIG_SDIO_STACK) -static const struct device *const sdhc_dev_sdmmc = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_sdmmc)); -static const struct device *const sdhc_dev_sdio = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_sdio)); -uint8_t sdmmc_wbuf[512]; -uint8_t sdmmc_rbuf[512]; - -static int shell_pm_test_sdhc(const struct shell *sh, size_t argc, char **argv) -{ - static struct sd_card sdmmc_card = {0}, sdio_card = {0}; - int ret; - /* ==================================================================================== */ - - if (sdhc_dev_sdmmc) { - memset(sdmmc_rbuf, 0, sizeof(sdmmc_rbuf)); - - for (uint32_t i = 0; i < sizeof(sdmmc_wbuf); i++) { - sdmmc_wbuf[i] = i; - } - - printf("before dlps sdmmc card %s initializing...\n", sdhc_dev_sdmmc->name); - ret = sd_init(sdhc_dev_sdmmc, &sdmmc_card); - - if (ret != 0) { - printf("before dlps sdmmc card initialization failed\n"); - return 0; - } - - printf("before dlps sdmmc card %s initialization success\n", sdhc_dev_sdmmc->name); - - sdmmc_write_blocks(&sdmmc_card, sdmmc_wbuf, 0, 1); - sdmmc_read_blocks(&sdmmc_card, sdmmc_rbuf, 0, 1); - if (memcmp(sdmmc_rbuf, sdmmc_wbuf, sizeof(sdmmc_rbuf))) { - printf("before dlps sdmmc card read fail\n"); - } else { - printf("before dlps sdmmc card read success\n"); - } - } - - if (sdhc_dev_sdio) { - printf("before dlps sdio card %s initializing...\n", sdhc_dev_sdio->name); - ret = sd_init(sdhc_dev_sdio, &sdio_card); - - if (ret != 0) { - printf("before dlps sdio card initialization failed\n"); - return 0; - } - - printf("before dlps sdio card %s initialization success\n", sdhc_dev_sdio->name); - } - - /* ==================================================================================== */ -#if defined(CONFIG_PM_DEVICE) - /* enter dlps */ - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] type on shell to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rx 1 byte to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#endif - /* ==================================================================================== */ - - if (sdhc_dev_sdmmc) { - memset(sdmmc_rbuf, 0, sizeof(sdmmc_rbuf)); - - for (uint32_t i = 0; i < sizeof(sdmmc_wbuf); i++) { - sdmmc_wbuf[i] = i * 3; - } - - sdmmc_write_blocks(&sdmmc_card, sdmmc_wbuf, 0, 1); - sdmmc_read_blocks(&sdmmc_card, sdmmc_rbuf, 0, 1); - if (memcmp(sdmmc_rbuf, sdmmc_wbuf, sizeof(sdmmc_rbuf))) { - printf("after dlps sdmmc card read fail\n"); - } else { - printf("after dlps sdmmc card read success\n"); - } - } - - if (sdhc_dev_sdio) { - printf("after dlps sdio card %s initializing...\n", sdhc_dev_sdio->name); - ret = sd_init(sdhc_dev_sdio, &sdio_card); - - if (ret != 0) { - printf("after dlps sdio card initialization failed\n"); - return 0; - } - - printf("after dlps sdio card %s initialization success\n", sdhc_dev_sdio->name); - } - /* ==================================================================================== */ - return 0; -} -#endif - -#ifdef CONFIG_CAN -static const struct device *const can_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_can)); -static volatile bool can_rx_received; - -static void can_tx_callback(const struct device *dev, int error, void *user_data) -{ - printf("dev %s tx cb\n", dev->name); -} - -static void can_rx_callback(const struct device *dev, struct can_frame *frame, void *user_data) -{ - printf("dev %s rx cb reecive id:0x%x, %ddata: ", dev->name, frame->id, frame->dlc); - - for (uint8_t i = 0; i < frame->dlc; i++) { - printf("0x%02x ", frame->data[i]); - } - - printf("\n"); - - can_rx_received = true; -} - -static int shell_pm_test_can(const struct shell *sh, size_t argc, char **argv) -{ - int ret; - struct can_frame frame = {0}; - struct can_filter filter; - - /* ==================================================================================== */ - frame.flags = 0; - frame.dlc = 0; - frame.id = 0x123; - frame.dlc = 8; - - filter.flags = 0U; - filter.id = 0x456; - filter.mask = 0x3ff; - - for (uint8_t i = 0; i < frame.dlc; i++) { - frame.data[i] = i; - } - - ret = can_start(can_dev); - if (ret != 0) { - printf("failed to start CAN controller (ret %d)\n", ret); - return ret; - } - - can_send(can_dev, &frame, K_NO_WAIT, can_tx_callback, NULL); - - k_busy_wait(10000); - - can_rx_received = false; - can_add_rx_filter(can_dev, can_rx_callback, NULL, &filter); - - printf("waiting for frame with id 0x456 from tool\n"); - while (can_rx_received == false) - ; - - /* ==================================================================================== */ -#if defined(CONFIG_PM_DEVICE) - /* enter dlps */ - printf("[%lld] before enter dlps\n", k_uptime_get()); - printf("[%lld] type on shell to wakeup\n", k_uptime_get()); - dlps_check_flag = PM_TEST_CHECK_PASS; - k_sem_init(&app_sem, 0, 1); - k_sem_take(&app_sem, K_FOREVER); - - dlps_check_flag = PM_TEST_CHECK_FAIL; - - /* rx 1 byte to wakeup */ - printf("[%lld] after exit dlps\n", k_uptime_get()); -#endif - - /* ==================================================================================== */ - can_send(can_dev, &frame, K_NO_WAIT, can_tx_callback, NULL); - - k_busy_wait(10000); - - can_rx_received = false; - can_add_rx_filter(can_dev, can_rx_callback, NULL, &filter); - - printf("waiting for frame with id 0x456 from tool\n"); - while (can_rx_received == false) - ; - - ret = can_stop(can_dev); - if (ret != 0) { - printf("failed to stop CAN controller (ret %d)\n", ret); - return ret; - } - /* ==================================================================================== */ - return 0; -} -#endif - -#if defined(CONFIG_SERIAL) -#define SHELL_CMD_UART_PM_TEST SHELL_CMD_ARG(uart, NULL, "uart pm test", shell_pm_test_uart, 0, 0), -#else -#define SHELL_CMD_UART_PM_TEST -#endif - -#if defined(CONFIG_UART_ASYNC_API) -#define SHELL_CMD_UART_DMA_PM_TEST \ - SHELL_CMD_ARG(uartdma, NULL, "Uart dma pm test", shell_pm_test_uart_dma, 0, 0), -#else -#define SHELL_CMD_UART_DMA_PM_TEST -#endif - -#if defined(CONFIG_GPIO) -#define SHELL_CMD_GPIO_PM_TEST SHELL_CMD_ARG(gpio, NULL, "gpio pm test", shell_pm_test_gpio, 0, 0), -#else -#define SHELL_CMD_GPIO_PM_TEST -#endif - -#if defined(CONFIG_PWM) -#define SHELL_CMD_PWM_PM_TEST SHELL_CMD_ARG(pwm, NULL, "pwm pm test", shell_pm_test_pwm, 0, 0), -#else -#define SHELL_CMD_PWM_PM_TEST -#endif - -#if defined(CONFIG_COUNTER) -#define SHELL_CMD_COUNTER_PM_TEST \ - SHELL_CMD_ARG(counter, NULL, "counter pm test(input a time in ms)", shell_pm_test_counter, \ - 2, 0), -#else -#define SHELL_CMD_COUNTER_PM_TEST -#endif - -#if defined(CONFIG_SPI) -#define SHELL_CMD_SPI_PM_TEST SHELL_CMD_ARG(spi, NULL, "spi pm test", shell_pm_test_spi, 0, 0), -#else -#define SHELL_CMD_SPI_PM_TEST -#endif - -#if defined(CONFIG_RTC) -#define SHELL_CMD_RTC_PM_TEST SHELL_CMD_ARG(rtc, NULL, "rtc pm test", shell_pm_test_rtc, 0, 0), -#else -#define SHELL_CMD_RTC_PM_TEST -#endif - -#if defined(CONFIG_I2C) -#define SHELL_CMD_I2C_PM_TEST SHELL_CMD_ARG(i2c, NULL, "i2c pm test", shell_pm_test_i2c, 0, 0), -#else -#define SHELL_CMD_I2C_PM_TEST -#endif - -#if defined(CONFIG_ADC) -#define SHELL_CMD_ADC_PM_TEST SHELL_CMD_ARG(adc, NULL, "adc pm test", shell_pm_test_adc, 0, 0), -#else -#define SHELL_CMD_ADC_PM_TEST -#endif - -#if defined(CONFIG_QDEC_BEE) -#define SHELL_CMD_QDEC_PM_TEST SHELL_CMD_ARG(qdec, NULL, "qdec pm test", shell_pm_test_qdec, 0, 0), -#else -#define SHELL_CMD_QDEC_PM_TEST -#endif - -#if defined(CONFIG_AON_QDEC_BEE) -#define SHELL_CMD_AONQDEC_PM_TEST \ - SHELL_CMD_ARG(aon_qdec, NULL, "aon_qdec pm test", shell_pm_test_aon_qdec, 0, 0), -#else -#define SHELL_CMD_AONQDEC_PM_TEST -#endif - -#if defined(CONFIG_SDMMC_STACK) || defined(CONFIG_SDIO_STACK) -#define SHELL_CMD_SHDC_PM_TEST SHELL_CMD_ARG(sdhc, NULL, "sdhc pm test", shell_pm_test_sdhc, 0, 0), -#else -#define SHELL_CMD_SHDC_PM_TEST -#endif - -#if defined(CONFIG_CAN) -#define SHELL_CMD_CAN_PM_TEST SHELL_CMD_ARG(can, NULL, "can pm test", shell_pm_test_can, 0, 0), -#else -#define SHELL_CMD_CAN_PM_TEST -#endif - -#define SHELL_CMD_ARG_CREATE \ - SHELL_CMD_UART_PM_TEST \ - SHELL_CMD_UART_DMA_PM_TEST \ - SHELL_CMD_GPIO_PM_TEST \ - SHELL_CMD_PWM_PM_TEST \ - SHELL_CMD_COUNTER_PM_TEST \ - SHELL_CMD_SPI_PM_TEST \ - SHELL_CMD_RTC_PM_TEST \ - SHELL_CMD_QDEC_PM_TEST \ - SHELL_CMD_AONQDEC_PM_TEST \ - SHELL_CMD_I2C_PM_TEST \ - SHELL_CMD_ADC_PM_TEST \ - SHELL_CMD_SHDC_PM_TEST \ - SHELL_CMD_CAN_PM_TEST \ - SHELL_SUBCMD_SET_END /* Array terminated. */ -SHELL_STATIC_SUBCMD_SET_CREATE(sub_pm_test, SHELL_CMD_ARG_CREATE); - -SHELL_CMD_REGISTER(pm_test, &sub_pm_test, "Pm test", NULL); diff --git a/tests/drivers/can/api/boards/rtl87x2g_evb.conf b/tests/drivers/can/api/boards/rtl87x2g_evb.conf new file mode 100644 index 0000000000000..33b9f199e1b4e --- /dev/null +++ b/tests/drivers/can/api/boards/rtl87x2g_evb.conf @@ -0,0 +1,4 @@ +# Copyright (c) 2026, Realtek Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_CAN_FD_MODE=n diff --git a/tests/drivers/can/api/boards/rtl87x2g_evb.overlay b/tests/drivers/can/api/boards/rtl87x2g_evb.overlay new file mode 100644 index 0000000000000..5a0ca7b17a499 --- /dev/null +++ b/tests/drivers/can/api/boards/rtl87x2g_evb.overlay @@ -0,0 +1,26 @@ +/* + * Copyright(c) 2026, Realtek Semiconductor Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,canbus = &can; + }; +}; + +&can { + pinctrl-0 = <&can_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&pinctrl { + can_default: can_default { + group1 { + psels = , + ; + }; + }; +}; diff --git a/samples/bee_pm_device/CMakeLists.txt b/tests/pm_device_test/CMakeLists.txt similarity index 87% rename from samples/bee_pm_device/CMakeLists.txt rename to tests/pm_device_test/CMakeLists.txt index 2d8a4c4dcd70c..b99b946cf9bc9 100644 --- a/samples/bee_pm_device/CMakeLists.txt +++ b/tests/pm_device_test/CMakeLists.txt @@ -3,6 +3,6 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(bee_pm_device) +project(pm_device_test) target_sources(app PRIVATE src/main.c) diff --git a/samples/bee_pm_device/boards/rtl8752h_evb_rtl8752htv.conf b/tests/pm_device_test/boards/rtl8752h_evb_rtl8752htv.conf similarity index 86% rename from samples/bee_pm_device/boards/rtl8752h_evb_rtl8752htv.conf rename to tests/pm_device_test/boards/rtl8752h_evb_rtl8752htv.conf index 882413e2a8df2..e72b9f32e915e 100644 --- a/samples/bee_pm_device/boards/rtl8752h_evb_rtl8752htv.conf +++ b/tests/pm_device_test/boards/rtl8752h_evb_rtl8752htv.conf @@ -1,3 +1,6 @@ +# Copyright (c) 2026, Realtek Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + CONFIG_HEAP_MEM_POOL_SIZE=512 CONFIG_SHELL=y CONFIG_PM=y @@ -13,7 +16,6 @@ CONFIG_UART_BEE_KEEP_ACTIVE_TIMEOUT_MSEC=0 CONFIG_GPIO=y CONFIG_GPIO_LOG_LEVEL_ERR=y CONFIG_DMA=y -CONFIG_COUNTER=y CONFIG_PWM=y CONFIG_SPI=y CONFIG_RTC=y diff --git a/samples/bee_pm_device/boards/rtl8752h_evb_rtl8752htv.overlay b/tests/pm_device_test/boards/rtl8752h_evb_rtl8752htv.overlay similarity index 78% rename from samples/bee_pm_device/boards/rtl8752h_evb_rtl8752htv.overlay rename to tests/pm_device_test/boards/rtl8752h_evb_rtl8752htv.overlay index 6bc1a823712e0..a640e1a2b30ac 100644 --- a/samples/bee_pm_device/boards/rtl8752h_evb_rtl8752htv.overlay +++ b/tests/pm_device_test/boards/rtl8752h_evb_rtl8752htv.overlay @@ -1,8 +1,9 @@ /* - * Copyright(c) 2025, Realtek Semiconductor Corporation. + * Copyright (c) 2026, Realtek Semiconductor Corporation * * SPDX-License-Identifier: Apache-2.0 */ + #include #include #include @@ -10,42 +11,40 @@ #include /* - * P0_0 GPIO(TEST OUT) - * P0_1 GPIO(TEST IN) - * P0_2 PWM6 - * P0_4 I2C0_CLK - * P0_5 I2C0_DAT - * P0_6 UART0_TX - * P1_0 SWD - * P1_1 SWD - * P2_2 ADC - * P2_3 UART0_RX - * P2_4 KSCAN_R0 - * P2_5 KSCAN_R1 - * P2_6 KSCAN_C0 - * P2_7 KSCAN_C1 - * P3_0 UART2_TX - * P3_1 UART2_RX - * P3_2 QDECX_A - * P3_3 QDECX_B - * P3_4 - * P4_0 SPI0_CLK - * P4_1 SPI0_MO - * P4_2 SPI0_MI - * P4_3 GPIO(SPI0_CS) - * P5_1 GPIO(TEST QDECX) - * P5_2 GPIO(TEST QDECX) - */ +P0_0 GPIO(TEST OUT) +P0_1 GPIO(TEST IN) +P0_2 PWM6 +P0_4 I2C0_CLK +P0_5 I2C0_DAT +P0_6 UART0_TX +P1_0 SWD +P1_1 SWD +P2_2 ADC +P2_3 UART0_RX +P2_4 KSCAN_R0 +P2_5 KSCAN_R1 +P2_6 KSCAN_C0 +P2_7 KSCAN_C1 +P3_0 UART2_TX +P3_1 UART2_RX +P3_2 QDECX_A +P3_3 QDECX_B +P3_4 +P4_0 SPI0_CLK +P4_1 SPI0_MO +P4_2 SPI0_MI +P4_3 GPIO(SPI0_CS) +P5_1 GPIO(TEST QDECX) +P5_2 GPIO(TEST QDECX) +*/ / { resources { - compatible = "bee-pm-device-gpio"; + compatible = "test-gpio-basic-api"; // P0_0 out-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; // P0_1 - in-gpios = <&gpio 1 (GPIO_ACTIVE_HIGH - | BEE_GPIO_INPUT_DEBOUNCE_MS(8) - | BEE_GPIO_INPUT_PM_WAKEUP)>; + in-gpios = <&gpio 1 (GPIO_ACTIVE_HIGH | BEE_GPIO_INPUT_DEBOUNCE_MS(8) | BEE_GPIO_INPUT_PM_WAKEUP)>; }; chosen { @@ -84,11 +83,11 @@ pinctrl-0 = <&uart2_default>; pinctrl-1 = <&uart2_sleep>; pinctrl-names = "default", "sleep"; - status = "okay"; - current-speed = <2000000>; - parity = "none"; - stop-bits = "1"; - data-bits = <8>; + status = "okay"; + current-speed = <2000000>; + parity = "none"; + stop-bits = "1"; + data-bits = <8>; }; &uart0 { @@ -134,7 +133,7 @@ // P4_3 cs-gpios = <&gpio 31 GPIO_ACTIVE_LOW>; test-spi@0 { - compatible = "bee-pm-device-spi"; + compatible = "test-spi-loopback"; reg = <0>; spi-max-frequency = <500000>; }; @@ -149,8 +148,8 @@ }; &rtc { - status = "okay"; - prescaler = <3200>; + status = "okay"; + prescaler = <3200>; }; &qdec { @@ -189,18 +188,18 @@ }; &adc { - pinctrl-0 = <&adc_default>; - pinctrl-names = "default"; - #address-cells = <1>; - #size-cells = <0>; - status = "okay"; - channel@2 { - reg = <2>; - zephyr,gain = "ADC_GAIN_1"; - zephyr,reference = "ADC_REF_INTERNAL"; - zephyr,acquisition-time = ; - zephyr,resolution = <12>; - }; + pinctrl-0 = <&adc_default>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + channel@2 { + reg = <2>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; }; &pinctrl { @@ -239,11 +238,11 @@ }; spi0_default: spi0_default { - group1 { - psels = , - , - ; - }; + group1 { + psels = , + , + ; + }; }; pwm6_default: pwm6_default { diff --git a/samples/bee_pm_device/boards/rtl87x2g_evb.conf b/tests/pm_device_test/boards/rtl87x2g_evb.conf similarity index 88% rename from samples/bee_pm_device/boards/rtl87x2g_evb.conf rename to tests/pm_device_test/boards/rtl87x2g_evb.conf index e5c777fe1339e..b803316dbbd34 100644 --- a/samples/bee_pm_device/boards/rtl87x2g_evb.conf +++ b/tests/pm_device_test/boards/rtl87x2g_evb.conf @@ -1,3 +1,6 @@ +# Copyright (c) 2026, Realtek Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + CONFIG_HEAP_MEM_POOL_SIZE=1024 CONFIG_SHELL=y CONFIG_PM=y @@ -13,7 +16,6 @@ CONFIG_UART_BEE_KEEP_ACTIVE_TIMEOUT_MSEC=0 CONFIG_GPIO=y CONFIG_GPIO_LOG_LEVEL_ERR=y CONFIG_DMA=y -CONFIG_COUNTER=y CONFIG_PWM=y CONFIG_SPI=y CONFIG_I2C=y diff --git a/samples/bee_pm_device/boards/rtl87x2g_evb.overlay b/tests/pm_device_test/boards/rtl87x2g_evb.overlay similarity index 72% rename from samples/bee_pm_device/boards/rtl87x2g_evb.overlay rename to tests/pm_device_test/boards/rtl87x2g_evb.overlay index 6a73501d4145e..848a092700dd4 100644 --- a/samples/bee_pm_device/boards/rtl87x2g_evb.overlay +++ b/tests/pm_device_test/boards/rtl87x2g_evb.overlay @@ -1,8 +1,9 @@ /* - * Copyright(c) 2025, Realtek Semiconductor Corporation. + * Copyright (c) 2026, Realtek Semiconductor Corporation * * SPDX-License-Identifier: Apache-2.0 */ + #include #include #include @@ -10,66 +11,63 @@ #include /* - * P0_0 GPIO(TEST OUT) - * P0_1 GPIO(TEST IN) - * P0_2 PWM6 - * P0_4 GPIO(TEST AON_QDECX) - * P0_5 GPIO(TEST AON_QDECX) - * P0_6 KSCAN_R0 - * P0_7 KSCAN_R1 - * P1_0 SWD - * P1_1 SWD - * P1_2 - * P1_3 AON_QDECX_A - * P1_4 AON_QDECX_B - * P1_5 - * P1_6 - * P1_7 - * P2_2 I2C0_CLK - * P2_3 I2C0_DAT - * P2_4 ADC - * P2_6 KSCAN_C0 - * P2_7 KSCAN_C1 - * P3_0 - * P3_1 - * P3_2 UART2_TX - * P3_3 UART2_RX - * P3_4 CAN_TX - * P3_5 CAN_RX - * P3_6 - * P3_7 - * P4_0 SPI0_CLK - * P4_1 SPI0_MO - * P4_2 SPI0_MI - * P4_3 GPIO(SPI0_CS) - * P4_4 UART3_TX(DMA) - * P4_5 UART3_RX(DMA) - * P4_6 - * P4_7 - * P5_0 - * P5_1 - * P5_2 - * P5_3 - * P5_4 - * P5_5 - * P9_3 SDHC - * P9_4 SDHC - * P9_5 SDHC - * P9_6 SDHC - * P9_7 SDHC - * P10_0 SDHC - */ +P0_0 GPIO(TEST OUT) +P0_1 GPIO(TEST IN) +P0_2 PWM6 +P0_4 GPIO(TEST AON_QDECX) +P0_5 GPIO(TEST AON_QDECX) +P0_6 KSCAN_R0 +P0_7 KSCAN_R1 +P1_0 SWD +P1_1 SWD +P1_2 +P1_3 AON_QDECX_A +P1_4 AON_QDECX_B +P1_5 +P1_6 +P1_7 +P2_2 I2C0_CLK +P2_3 I2C0_DAT +P2_4 ADC +P2_6 KSCAN_C0 +P2_7 KSCAN_C1 +P3_0 +P3_1 +P3_2 UART2_TX +P3_3 UART2_RX +P3_4 CAN_TX +P3_5 CAN_RX +P3_6 +P3_7 +P4_0 SPI0_CLK +P4_1 SPI0_MO +P4_2 SPI0_MI +P4_3 GPIO(SPI0_CS) +P4_4 UART3_TX(DMA) +P4_5 UART3_RX(DMA) +P4_6 +P4_7 +P5_0 +P5_1 +P5_2 +P5_3 +P5_4 +P5_5 +P9_3 SDHC +P9_4 SDHC +P9_5 SDHC +P9_6 SDHC +P9_7 SDHC +P10_0 SDHC +*/ / { resources { - compatible = "bee-pm-device-gpio"; + compatible = "test-gpio-basic-api"; // P0_0 out-gpios = <&gpioa 0 GPIO_ACTIVE_HIGH>; // P0_1 - in-gpios = - <&gpioa 1 (GPIO_ACTIVE_HIGH - | BEE_GPIO_INPUT_DEBOUNCE_MS(8) - | BEE_GPIO_INPUT_PM_WAKEUP)>; + in-gpios = <&gpioa 1 (GPIO_ACTIVE_HIGH | BEE_GPIO_INPUT_DEBOUNCE_MS(8) | BEE_GPIO_INPUT_PM_WAKEUP)>; }; chosen { @@ -110,11 +108,11 @@ pinctrl-0 = <&uart2_default>; pinctrl-1 = <&uart2_sleep>; pinctrl-names = "default", "sleep"; - status = "okay"; - current-speed = <2000000>; - parity = "none"; - stop-bits = "1"; - data-bits = <8>; + status = "okay"; + current-speed = <2000000>; + parity = "none"; + stop-bits = "1"; + data-bits = <8>; }; &uart3 { @@ -164,7 +162,7 @@ // P4_3 cs-gpios = <&gpiob 8 GPIO_ACTIVE_LOW>; test-spi@0 { - compatible = "bee-pm-device-spi"; + compatible = "test-spi-loopback"; reg = <0>; spi-max-frequency = <500000>; }; @@ -179,8 +177,8 @@ }; &rtc { - status = "okay"; - prescaler = <3200>; + status = "okay"; + prescaler = <3200>; }; &aon_qdec { @@ -219,24 +217,24 @@ }; &adc { - pinctrl-0 = <&adc_default>; - pinctrl-names = "default"; - #address-cells = <1>; - #size-cells = <0>; - status = "okay"; - channel@4 { - reg = <4>; - zephyr,gain = "ADC_GAIN_1"; - zephyr,reference = "ADC_REF_INTERNAL"; - zephyr,acquisition-time = ; - zephyr,resolution = <12>; - }; + pinctrl-0 = <&adc_default>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + channel@4 { + reg = <4>; + zephyr,gain = "ADC_GAIN_1"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,resolution = <12>; + }; }; &can { - pinctrl-0 = <&can_default>; + pinctrl-0 = <&can_default>; pinctrl-1 = <&can_sleep>; - pinctrl-names = "default", "sleep"; + pinctrl-names = "default", "sleep"; status = "okay"; }; @@ -286,16 +284,16 @@ }; spi0_default: spi0_default { - group1 { - psels = , - , - ; - }; + group1 { + psels = , + , + ; + }; }; pwm6_default: pwm6_default { group1 { - psels = ; + psels = ; }; }; @@ -370,13 +368,13 @@ sdhc0_default: sdhc0_default { group1 { - psels = , - , - , - , - , - ; - current-level = <1>; + psels = , + , + , + , + , + ; + current-level = <1>; }; }; }; diff --git a/samples/bee_pm_device/dts/bindings/bee-pm-device-gpio.yaml b/tests/pm_device_test/dts/bindings/test-gpio-basic-api.yaml similarity index 75% rename from samples/bee_pm_device/dts/bindings/bee-pm-device-gpio.yaml rename to tests/pm_device_test/dts/bindings/test-gpio-basic-api.yaml index f61fba603ada1..7652c25577e54 100644 --- a/samples/bee_pm_device/dts/bindings/bee-pm-device-gpio.yaml +++ b/tests/pm_device_test/dts/bindings/test-gpio-basic-api.yaml @@ -1,8 +1,11 @@ +# Copyright (c) 2026, Realtek Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + description: | This binding provides resources required to build and run the - bee_pm_device. + tests/drivers/gpio/gpio_basic_api test in Zephyr. -compatible: "bee-pm-device-gpio" +compatible: "test-gpio-basic-api" properties: out-gpios: diff --git a/tests/pm_device_test/dts/bindings/test-spi-loopback.yaml b/tests/pm_device_test/dts/bindings/test-spi-loopback.yaml new file mode 100644 index 0000000000000..306cc1a05c97e --- /dev/null +++ b/tests/pm_device_test/dts/bindings/test-spi-loopback.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2026, Realtek Semiconductor Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: | + This binding provides resources required to build and run the test. + +compatible: "test-spi-loopback" + +include: [spi-device.yaml] diff --git a/tests/pm_device_test/pm_device_pytest/__init__.py b/tests/pm_device_test/pm_device_pytest/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/tests/pm_device_test/pm_device_pytest/conftest.py b/tests/pm_device_test/pm_device_pytest/conftest.py new file mode 100644 index 0000000000000..c182a0a6623e9 --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/conftest.py @@ -0,0 +1,289 @@ +import re +import time +from pathlib import Path +from typing import List, Optional, TextIO + +import pytest +import serial +import serial.tools.list_ports + +from pm_device_pytest.pm_device_board_config import ( + get_dma_uart_baudrate, + get_dma_uart_port, + get_shell_uart_baudrate, + get_shell_uart_port, +) + + +def pytest_addoption(parser): + """Add custom command line options.""" + parser.addoption( + "--shell-port", + action="store", + default=None, + help="Shell UART port (e.g., COM10)", + ) + parser.addoption( + "--shell-baudrate", + action="store", + type=int, + default=None, + help="Shell UART baudrate (e.g., 2000000)", + ) + parser.addoption( + "--dma-port", + action="store", + default=None, + help="DMA UART port (e.g., COM21)", + ) + parser.addoption( + "--dma-baudrate", + action="store", + type=int, + default=None, + help="DMA UART baudrate (e.g., 2000000)", + ) + + +@pytest.fixture(scope="session", autouse=True) +def _parse_cmdline_options(request): + """Parse command line options and store in module for board_config to use.""" + from pm_device_pytest import pm_device_board_config + + if request.config.getoption("--shell-port"): + pm_device_board_config._cmdline_shell_port = request.config.getoption("--shell-port") + if request.config.getoption("--shell-baudrate"): + pm_device_board_config._cmdline_shell_baudrate = request.config.getoption("--shell-baudrate") + if request.config.getoption("--dma-port"): + pm_device_board_config._cmdline_dma_port = request.config.getoption("--dma-port") + if request.config.getoption("--dma-baudrate"): + pm_device_board_config._cmdline_dma_baudrate = request.config.getoption("--dma-baudrate") + + +class SerialShellDUT: + ANSI_RE = re.compile(r"\x1B\[[0-9;]*[mK]") + + def __init__( + self, + port: str, + baudrate: int = 2000000, + timeout: float = 0.1, + prompt_regex: str = r".*~\$ *$", + log_file: Optional[str] = None, + encoding: str = "utf-8", + errors: str = "ignore", + ): + self.port = port + self.baudrate = baudrate + self.timeout = timeout + self.prompt_regex = re.compile(prompt_regex) + self.encoding = encoding + self.errors = errors + + self.ser = serial.Serial( + port=self.port, + baudrate=self.baudrate, + timeout=self.timeout, + ) + + self.all_logs: List[str] = [] + + self._log_fp: Optional[TextIO] = None + if log_file is not None: + path = Path(log_file) + path.parent.mkdir(parents=True, exist_ok=True) + self._log_fp = path.open("a", encoding="utf-8") + self._log_fp.write("\n===== NEW SESSION =====\n") + self._log_fp.flush() + + def _log_line(self, text: str): + if not text: + return + + if self._log_fp is not None: + self._log_fp.write(text + "\n") + self._log_fp.flush() + + self.all_logs.append(text) + + def close(self): + if self.ser and self.ser.is_open: + self.ser.close() + if self._log_fp is not None: + self._log_fp.close() + self._log_fp = None + + def write(self, data: bytes): + self.ser.write(data) + self.ser.flush() + + def readline(self) -> str: + raw = self.ser.readline() + + if not raw: + return "" + + try: + text = raw.decode(self.encoding, errors=self.errors).rstrip("\r\n") + except Exception: + text = "" + + if text: + clean = self.ANSI_RE.sub("", text) + self._log_line(clean) + return clean + + return "" + + def readlines_until(self, regex, timeout: float = 5.0) -> List[str]: + if isinstance(regex, re.Pattern): + pattern = regex + else: + pattern = re.compile(regex) + + end_time = time.time() + timeout + lines: List[str] = [] + + while time.time() < end_time: + text = self.readline() + if not text: + continue + + lines.append(text) + + if pattern.search(text): + break + + return lines + + def read_until_prompt(self, timeout: float = 5.0) -> List[str]: + return self.readlines_until(self.prompt_regex, timeout=timeout) + + def flush_input(self, timeout: float = 0.5): + end = time.time() + timeout + while time.time() < end: + text = self.readline() + if not text: + break + + def ensure_prompt(self, timeout: float = 5.0) -> List[str]: + self.write(b"\r") + logs = self.read_until_prompt(timeout=timeout) + return logs + + def send_cmd( + self, + cmd: str, + wait_prompt: bool = True, + timeout: float = 10.0, + ) -> List[str]: + if not cmd.endswith("\n"): + cmd_to_send = cmd + "\r\n" + else: + cmd_to_send = cmd + + self.write(cmd_to_send.encode(self.encoding)) + + if not wait_prompt: + return [] + + logs = self.read_until_prompt(timeout=timeout) + return logs + + def relay_on(self, channel: int): + pass + + def relay_off(self, channel: int): + pass + + +class SerialDMADUT: + def __init__(self, port, baudrate, timeout=0.1): + self.ser = serial.Serial(port=port, baudrate=baudrate, timeout=timeout) + + def close(self): + if self.ser and self.ser.is_open: + self.ser.close() + + def write(self, data): + self.ser.write(data) + self.ser.flush() + + def read(self, size, timeout=5.0): + self.ser.timeout = timeout + data = self.ser.read(size) + self.ser.timeout = 0.1 + return data + + def flush_input(self, timeout=0.5): + end = time.time() + timeout + while time.time() < end: + if self.ser.in_waiting > 0: + self.ser.read(self.ser.in_waiting) + else: + break + + +@pytest.fixture(scope="session") +def dut(): + """Shell UART DUT fixture.""" + target_port = get_shell_uart_port() + target_baudrate = get_shell_uart_baudrate() + + print(f"\n[DUT] Connecting to {target_port} at {target_baudrate} baud...") + + available = [p.device for p in serial.tools.list_ports.comports()] + + if target_port not in available: + raise RuntimeError( + f"[DUT] {target_port} unavailable. Available serial ports: {available}" + ) + + log_dir = Path(__file__).parent / "logs" + log_file = log_dir / "session_shell.log" + + d = SerialShellDUT( + port=target_port, + baudrate=target_baudrate, + timeout=0.1, + prompt_regex=r".*~\$ *$", + log_file=str(log_file), + ) + + try: + print(f"[DUT] Waiting for shell prompt...") + logs = d.ensure_prompt(timeout=10.0) + print(f"[DUT] Got {len(logs)} lines, first few:") + for i, line in enumerate(logs[:5]): + print(f" [{i}] {line!r}") + + if not logs: + print("[DUT] WARNING: No prompt received!") + + yield d + + finally: + end = time.time() + 1.0 + while time.time() < end: + text = d.readline() + if not text: + break + + d.close() + + +@pytest.fixture(scope="session") +def dma_dut(): + """DMA UART DUT fixture for uart_dma test.""" + dma_port = get_dma_uart_port() + dma_baudrate = get_dma_uart_baudrate() + + available = [p.device for p in serial.tools.list_ports.comports()] + if dma_port not in available: + raise RuntimeError(f"[DMA DUT] {dma_port} unavailable. Available: {available}") + + dma = SerialDMADUT(port=dma_port, baudrate=dma_baudrate, timeout=0.1) + try: + yield dma + finally: + dma.close() \ No newline at end of file diff --git a/tests/pm_device_test/pm_device_pytest/pm_device_board_config.py b/tests/pm_device_test/pm_device_pytest/pm_device_board_config.py new file mode 100644 index 0000000000000..46e15fb9f528a --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/pm_device_board_config.py @@ -0,0 +1,105 @@ +"""Serial port configuration for PM device tests. + +Configuration is read from serial_ports.ini file in the same directory. +Priority: command line > environment variables > config file > defaults. +""" + +import configparser +import os +from pathlib import Path + +# Command line options (set by conftest.py) +_cmdline_shell_port = None +_cmdline_shell_baudrate = None +_cmdline_dma_port = None +_cmdline_dma_baudrate = None + + +def _load_config(): + """Load configuration from serial_ports.ini.""" + config_file = Path(__file__).parent / "serial_ports.ini" + config = configparser.ConfigParser() + + if config_file.exists(): + config.read(config_file) + else: + # Fallback to defaults if file doesn't exist + config["shell_uart"] = {"port": "COM10", "baudrate": "2000000"} + config["dma_uart"] = {"port": "COM11", "baudrate": "2000000"} + + return config + + +# Cache the config +_config = None + + +def _get_config(): + global _config + if _config is None: + _config = _load_config() + return _config + + +def get_shell_uart_port() -> str: + """Get shell UART port. + + Priority: command line > env var > config file > default (COM10) + """ + global _cmdline_shell_port + if _cmdline_shell_port: + return _cmdline_shell_port + + if "SHELL_UART_PORT" in os.environ: + return os.environ["SHELL_UART_PORT"] + + config = _get_config() + return config.get("shell_uart", "port", fallback="COM10") + + +def get_shell_uart_baudrate() -> int: + """Get shell UART baudrate. + + Priority: command line > env var > config file > default (2000000) + """ + global _cmdline_shell_baudrate + if _cmdline_shell_baudrate: + return _cmdline_shell_baudrate + + if "SHELL_UART_BAUDRATE" in os.environ: + return int(os.environ["SHELL_UART_BAUDRATE"]) + + config = _get_config() + return config.getint("shell_uart", "baudrate", fallback=2000000) + + +def get_dma_uart_port() -> str: + """Get DMA UART port. + + Priority: command line > env var > config file > default (COM11) + """ + global _cmdline_dma_port + if _cmdline_dma_port: + return _cmdline_dma_port + + if "DMA_UART_PORT" in os.environ: + return os.environ["DMA_UART_PORT"] + + config = _get_config() + return config.get("dma_uart", "port", fallback="COM11") + + +def get_dma_uart_baudrate() -> int: + """Get DMA UART baudrate. + + Priority: command line > env var > config file > default (2000000) + """ + global _cmdline_dma_baudrate + if _cmdline_dma_baudrate: + return _cmdline_dma_baudrate + + if "DMA_UART_BAUDRATE" in os.environ: + return int(os.environ["DMA_UART_BAUDRATE"]) + + config = _get_config() + return config.getint("dma_uart", "baudrate", fallback=2000000) \ No newline at end of file diff --git a/tests/pm_device_test/pm_device_pytest/pm_device_common.py b/tests/pm_device_test/pm_device_pytest/pm_device_common.py new file mode 100644 index 0000000000000..291f6cad766c7 --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/pm_device_common.py @@ -0,0 +1,360 @@ +# pm_device_pytest/pm_device_common.py + +import random +import re +import time +from dataclasses import dataclass +from typing import Callable, List, Optional, Tuple + +from .conftest import SerialShellDUT + +# Timestamps in logs look like: [451730] +TIMESTAMP_REGEX = re.compile(r"\[(\d+)\]") + + +def extract_timestamp(line: str) -> Optional[int]: + """Extract a timestamp in the form [123456] from a log line (unit: ms).""" + m = TIMESTAMP_REGEX.search(line) + if not m: + return None + return int(m.group(1)) + + +@dataclass +class DLPSSession: + """One DLPS round-trip (enter -> exit).""" + before_ts: int + after_ts: int + before_idx: int + after_idx: int + + @property + def delta_ms(self) -> int: + return self.after_ts - self.before_ts + + +def parse_all_dlps_sessions(lines: List[str]) -> List[DLPSSession]: + """Parse all DLPS sessions from the given log lines. + + Matching rules: + - A line containing "before enter dlps" is treated as the enter point. + - A line containing "after exit dlps" is treated as the exit point. + - The most recent "before" is paired with the next "after". + """ + sessions: List[DLPSSession] = [] + current_before_idx: Optional[int] = None + current_before_ts: Optional[int] = None + + for idx, line in enumerate(lines): + if "before enter dlps" in line: + ts = extract_timestamp(line) + assert ts is not None, f"Failed to parse timestamp from line: {line!r}" + current_before_idx = idx + current_before_ts = ts + + elif "after exit dlps" in line: + ts = extract_timestamp(line) + assert ts is not None, f"Failed to parse timestamp from line: {line!r}" + if current_before_ts is not None: + assert ts >= current_before_ts, ( + f"after_exit_ts < before_enter_ts: {ts} < {current_before_ts}" + ) + sessions.append( + DLPSSession( + before_ts=current_before_ts, + after_ts=ts, + before_idx=current_before_idx, + after_idx=idx, + ) + ) + current_before_idx = None + current_before_ts = None + + return sessions + + +def assert_single_dlps_present(lines: List[str]) -> DLPSSession: + """Assert that there is exactly one DLPS session in the log and return it.""" + sessions = parse_all_dlps_sessions(lines) + assert len(sessions) == 1, f"Expected 1 DLPS session, got {len(sessions)}" + return sessions[0] + + +def assert_delta_close_to( + session: DLPSSession, + *, + target_ms: int, + tolerance_ms: int, + reason: str = "", +) -> None: + """Assert that session.delta_ms is close to target_ms within the given tolerance.""" + delta = session.delta_ms + diff = abs(delta - target_ms) + msg = ( + f"DLPS delta_ms diff too large: |{delta} - {target_ms}| = {diff} > {tolerance_ms}" + + (f" ({reason})" if reason else "") + ) + assert diff <= tolerance_ms, msg + + +# ======================================================= +# 1. Generic helper: random delay + shell-enter wakeup + timestamp check +# ======================================================= + +def run_pm_shell_random_wakeup_single( + dut: SerialShellDUT, + *, + subcmd: str, + timeout: float = 10.0, + # Random delay range in milliseconds + rand_min_ms: int = 1000, + rand_max_ms: int = 5000, + # Allowed difference between timestamp delta and random delay (ms) + delta_tolerance_ms: int = 300, + check_before_dlps: Optional[Callable[[List[str]], None]] = None, + check_after_dlps: Optional[Callable[[List[str]], None]] = None, + rand_seed: Optional[int] = None, +) -> Tuple[List[str], DLPSSession, int]: + """Helper for single DLPS test cases where: + + - Firmware prints a prompt 'type on shell to wakeup'. + - pytest waits for a random delay and then sends ENTER on the shell to wake up. + - The timestamp delta between 'before enter dlps' and 'after exit dlps' is checked + against the random delay. + + Typical usage: + - For uart / i2c or other tests that use shell ENTER to wake up and need to + validate random wake-up delays. + - The random delay is controlled by pytest. + - Verifies that 'after_ts - before_ts' ≈ random_delay_ms. + + Returns: + (all_logs, dlps_session, rand_delay_ms) + + This helper assumes that the command finishes and returns to the shell prompt + after the DLPS session. + """ + if rand_seed is not None: + random.seed(rand_seed) + + # 1. Generate a random delay + rand_delay_ms = random.randint(rand_min_ms, rand_max_ms) + + # 2. Send command + dut.write(f"pm_test {subcmd}\r".encode("ascii")) + + # 3. Read until "type on shell to wakeup" + logs_pre = dut.readlines_until( + regex=r"type on shell to wakeup", + timeout=timeout, + ) + text_pre = "\n".join(logs_pre) + + # Ensure that DLPS enter messages are present + assert "before enter dlps" in text_pre, "Missing 'before enter dlps' log" + assert "type on shell to wakeup" in text_pre, "Missing 'type on shell to wakeup' log" + + if check_before_dlps is not None: + check_before_dlps(logs_pre) + + # 4. Wait for the random delay, then wake up via UART ENTER + time.sleep(rand_delay_ms / 1000.0) + dut.write(b"\r") + + # 5. Read until "after exit dlps" + logs_mid = dut.readlines_until( + regex=r"after exit dlps", + timeout=timeout, + ) + + # 6. Then read until shell prompt to mark the end of this interaction + logs_post = dut.readlines_until( + regex=r"uart:~\$ *$", + timeout=timeout, + ) + + all_logs: List[str] = logs_pre + logs_mid + logs_post + + # 7. Parse the DLPS session and check the random delay + session = assert_single_dlps_present(all_logs) + assert_delta_close_to( + session, + target_ms=rand_delay_ms, + tolerance_ms=delta_tolerance_ms, + reason=f"{subcmd} shell random wakeup", + ) + + if check_after_dlps is not None: + check_after_dlps(all_logs) + + return all_logs, session, rand_delay_ms + +def run_pm_shell_random_wakeup_multi( + dut: SerialShellDUT, + *, + subcmd: str, + count: int, + timeout: float = 10.0, + rand_min_ms: int = 1000, + rand_max_ms: int = 5000, + delta_tolerance_ms: int = 300, + rand_seed: Optional[int] = None, +) -> Tuple[List[str], List[DLPSSession], List[int]]: + """Run a command that performs multiple DLPS sessions in sequence. + + The firmware is expected to behave as: + - For each session i in [0, count): + * print "before enter dlps [ts]" + * print "type on shell to wakeup" + * enter DLPS and wait for shell ENTER + * print "after exit dlps [ts]" + - After all sessions are done, return to the shell prompt "uart:~$". + + This helper: + - Sends "pm_test ". + - For each session: + * waits for "before enter dlps" + "type on shell to wakeup". + * waits for a random delay, sends ENTER. + * waits for "after exit dlps". + - After the last session, waits for "uart:~$". + - Parses all DLPS sessions and checks each delta against its random delay. + + Returns: + (all_logs, sessions, rand_delays_ms) + """ + if rand_seed is not None: + random.seed(rand_seed) + + # Generate random delays for all sessions in advance, for reproducibility + rand_delays: List[int] = [ + random.randint(rand_min_ms, rand_max_ms) for _ in range(count) + ] + + all_logs: List[str] = [] + + # Send command once + dut.write(f"pm_test {subcmd}\r".encode("ascii")) + + for i in range(count): + # Wait for "before enter dlps" + "type on shell to wakeup" for this session + logs_pre = dut.readlines_until( + regex=r"type on shell to wakeup", + timeout=timeout, + ) + text_pre = "\n".join(logs_pre) + assert "before enter dlps" in text_pre, ( + f"Session {i + 1} missing 'before enter dlps'" + ) + assert "type on shell to wakeup" in text_pre, ( + f"Session {i + 1} missing 'type on shell to wakeup'" + ) + + all_logs.extend(logs_pre) + + # Wait random delay and wakeup + time.sleep(rand_delays[i] / 1000.0) + dut.write(b"\r") + + # Wait for "after exit dlps" of this session + logs_mid = dut.readlines_until( + regex=r"after exit dlps", + timeout=timeout, + ) + all_logs.extend(logs_mid) + + # After all sessions are done, read until shell prompt + logs_post = dut.readlines_until( + regex=r"uart:~\$ *$", + timeout=timeout, + ) + all_logs.extend(logs_post) + + # Parse sessions + sessions = parse_all_dlps_sessions(all_logs) + assert len(sessions) == count, ( + f"Expected {count} DLPS sessions, got {len(sessions)}" + ) + + # Check each session delta against its random delay + for i, (sess, delay) in enumerate(zip(sessions, rand_delays), start=1): + assert_delta_close_to( + sess, + target_ms=delay, + tolerance_ms=delta_tolerance_ms, + reason=f"{subcmd} session {i}", + ) + + return all_logs, sessions, rand_delays + +def run_pm_shell_single_auto_wakeup( + dut: SerialShellDUT, + *, + subcmd: str, + timeout: float = 10.0, + done_regex: Optional[str] = None, + check_before_dlps: Optional[Callable[[List[str]], None]] = None, + check_after_dlps: Optional[Callable[[List[str]], None]] = None, +) -> Tuple[List[str], DLPSSession]: + """Helper for single DLPS test cases where: + + - Firmware enters DLPS and is woken up automatically (e.g. by a hardware + interrupt such as RTC alarm, counter, GPIO, etc.). + - No shell ENTER or other host-side action is used to wake up the device. + - The function waits until: + * a complete DLPS session is observed in logs + ('before enter dlps' + 'after exit dlps'), and + * an optional done_regex is matched (e.g. 'trigger handler after ...ms'). + + Typical usage: + - For tests where wakeup is driven solely by on-board peripherals and + firmware, not by the test host (e.g. RTC auto wakeup). + + Returns: + (all_logs, dlps_session) + """ + # 1. Send command + dut.write(f"pm_test {subcmd}\r".encode("ascii")) + + # 2. Collect logs until: + # - we see a complete DLPS session, and + # - (optionally) done_regex is matched. + all_logs: List[str] = [] + start_time = time.time() + done_re = re.compile(done_regex) if done_regex else None + + saw_before = False + saw_after = False + done_matched = False + + while time.time() - start_time < timeout: + # readlines_until with a generic pattern that always returns on timeout + chunk_lines = dut.readlines_until(regex=r".*", timeout=1.0) + if not chunk_lines: + continue + + all_logs.extend(chunk_lines) + + text = "\n".join(chunk_lines) + + if "before enter dlps" in text: + saw_before = True + if "after exit dlps" in text: + saw_after = True + if done_re is not None and done_re.search(text): + done_matched = True + + # Break if we already have a complete DLPS session and (if required) + # the done condition is satisfied. + if saw_before and saw_after and (done_re is None or done_matched): + break + + # 3. Basic assertions on DLPS session existence + session = assert_single_dlps_present(all_logs) + + if check_before_dlps is not None: + check_before_dlps(all_logs) + + if check_after_dlps is not None: + check_after_dlps(all_logs) + + return all_logs, session diff --git a/tests/pm_device_test/pm_device_pytest/serial_ports.ini b/tests/pm_device_test/pm_device_pytest/serial_ports.ini new file mode 100644 index 0000000000000..7f2f73506e161 --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/serial_ports.ini @@ -0,0 +1,10 @@ +# Serial port configuration for PM device tests +# Edit this file to change COM ports for your test setup + +[shell_uart] +port = COM10 +baudrate = 2000000 + +[dma_uart] +port = COM21 +baudrate = 2000000 \ No newline at end of file diff --git a/tests/pm_device_test/pm_device_pytest/test_pm_adc.py b/tests/pm_device_test/pm_device_pytest/test_pm_adc.py new file mode 100644 index 0000000000000..eddcf13288702 --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/test_pm_adc.py @@ -0,0 +1,47 @@ +import re +from typing import List, Tuple + +from pm_device_pytest.pm_device_common import run_pm_shell_random_wakeup_single + +ADC_BEFORE_RE = re.compile(r"ADC sample before dlps:\s*(?P-?\d+)") +ADC_AFTER_RE = re.compile(r"ADC sample after dlps:\s*(?P-?\d+)") + +EXPECT_MIN_VAL = 3000 +EXPECT_MAX_VAL = 3600 +MAX_DELTA_ABS = 300 + + +def _find_adc_values(lines: List[str]) -> Tuple[List[int], List[int]]: + before_vals = [int(m.group("val")) for line in lines if (m := ADC_BEFORE_RE.search(line))] + after_vals = [int(m.group("val")) for line in lines if (m := ADC_AFTER_RE.search(line))] + return before_vals, after_vals + + +def test_pm_adc(dut): + def check_before(lines: List[str]) -> None: + before_vals, _ = _find_adc_values(lines) + assert before_vals, "No 'ADC sample before dlps' found" + val = before_vals[-1] + assert EXPECT_MIN_VAL <= val <= EXPECT_MAX_VAL, f"ADC before dlps out of range: {val}" + + def check_after(lines: List[str]) -> None: + before_vals, after_vals = _find_adc_values(lines) + assert before_vals, "Expected 'ADC sample before dlps' in session" + assert after_vals, "Expected 'ADC sample after dlps' in session" + before_val, after_val = before_vals[-1], after_vals[-1] + assert EXPECT_MIN_VAL <= before_val <= EXPECT_MAX_VAL, f"ADC before dlps out of range: {before_val}" + assert EXPECT_MIN_VAL <= after_val <= EXPECT_MAX_VAL, f"ADC after dlps out of range: {after_val}" + delta = abs(after_val - before_val) + assert delta <= MAX_DELTA_ABS, f"ADC delta too large: before={before_val}, after={after_val}, delta={delta}" + + run_pm_shell_random_wakeup_single( + dut, + subcmd="adc", + timeout=10.0, + rand_min_ms=1000, + rand_max_ms=5000, + delta_tolerance_ms=300, + check_before_dlps=check_before, + check_after_dlps=check_after, + rand_seed=None, + ) \ No newline at end of file diff --git a/tests/pm_device_test/pm_device_pytest/test_pm_all.py b/tests/pm_device_test/pm_device_pytest/test_pm_all.py new file mode 100644 index 0000000000000..8b16358779cfb --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/test_pm_all.py @@ -0,0 +1,161 @@ +"""Run all PM tests in sequence with single build and flash. + +Tests are selected based on Kconfig options in the firmware. +Each test uses its own pass/fail logic from the individual test_pm_xxx.py files. +""" + +import importlib +from pathlib import Path +import sys + + +def _load_kconfig(): + """Load Kconfig options from build directory.""" + possible_paths = [ + Path(__file__).parent.parent / "build" / "zephyr" / "include" / "generated" / "zephyr" / "autoconf.h", + Path(__file__).parent.parent / "twister-out" / "rtl87x2g_evb" / "tests" / "boards" / "pm_device_test" / "driver.pm.bee_evb_all_test" / "zephyr" / "include" / "generated" / "zephyr" / "autoconf.h", + ] + + config = {} + for autoconf_path in possible_paths: + if autoconf_path.exists(): + with open(autoconf_path, "r") as f: + for line in f: + if line.startswith("#define CONFIG_"): + parts = line.strip().split() + if len(parts) >= 3: + config[parts[1]] = parts[2] + break + + return config + + +# Test configurations - maps Kconfig option to test file and function +# Format: (config_opts, module_name, func_name) +# - config_opts: single config or tuple of configs (any one enables the test) +# - module_name: the test file name (without .py) +# - func_name: the test function name in that file +TEST_CONFIGS = [ + (("CONFIG_ADC",), "test_pm_adc", "test_pm_adc"), + (("CONFIG_AON_QDEC_BEE",), "test_pm_aon_qdec", "test_pm_aon_qdec_multi_session"), + (("CONFIG_CAN",), "test_pm_can", "test_pm_can"), + (("CONFIG_COUNTER",), "test_pm_counter", "test_pm_counter"), + (("CONFIG_GPIO",), "test_pm_gpio", "test_pm_gpio"), + (("CONFIG_I2C",), "test_pm_i2c", "test_pm_i2c"), + (("CONFIG_PWM",), "test_pm_pwm", "test_pm_pwm"), + (("CONFIG_QDEC_BEE", "CONFIG_QDEC_RTL87X3G"), "test_pm_qdec", "test_pm_qdec_multi_session"), + (("CONFIG_RTC",), "test_pm_rtc", "test_pm_rtc"), + (("CONFIG_SDMMC_STACK",), "test_pm_sdhc", "test_pm_sdhc"), + (("CONFIG_SPI",), "test_pm_spi", "test_pm_spi"), + (("CONFIG_SERIAL",), "test_pm_uart", "test_pm_uart"), + (("CONFIG_UART_ASYNC_API",), "test_pm_uart_dma", "test_pm_uart_dma"), +] + + +def _get_enabled_tests(kconfig): + """Get list of enabled tests based on Kconfig.""" + enabled = [] + + for config_opts, module_name, func_name in TEST_CONFIGS: + # Handle both single config and tuple of configs + if isinstance(config_opts, tuple): + config_list = config_opts + else: + config_list = (config_opts,) + + enabled_now = False + enabled_config = None + + for config_opt in config_list: + if config_opt in kconfig and kconfig[config_opt] == "1": + enabled_now = True + enabled_config = config_opt + break + + if enabled_now: + # Check if module exists + try: + importlib.import_module(f"pm_device_pytest.{module_name}") + enabled.append((module_name, func_name)) + print(f"[CONFIG] {enabled_config} enabled - will run {module_name} test") + except ModuleNotFoundError: + print(f"[CONFIG] {enabled_config} enabled but {module_name}.py not found - skipping") + else: + config_str = " or ".join(config_list) + print(f"[CONFIG] {config_str} disabled - skipping {module_name} test") + + return enabled + + +def test_pm_all(dut, dma_dut): + """Run all PM tests based on Kconfig selection. + + Single build + flash, runs all enabled tests. + Each test uses its own pass/fail logic from the individual test_pm_xxx.py files. + """ + # Load Kconfig + kconfig = _load_kconfig() + if not kconfig: + print("WARNING: Could not load Kconfig, running all tests") + + enabled_tests = _get_enabled_tests(kconfig) + + # Sort tests by module name (alphabetical order) + enabled_tests = sorted(enabled_tests, key=lambda x: x[0]) + + print("\n" + "=" * 50) + print("Starting PM Test Suite") + print(f"Found {len(enabled_tests)} tests to run") + print("=" * 50) + + passed = 0 + failed = 0 + errors = 0 + results = {} + + for module_name, func_name in enabled_tests: + print(f"\n--- Running: {module_name}.{func_name} ---") + + try: + # Import the module and get the test function + module = importlib.import_module(f"pm_device_pytest.{module_name}") + test_func = getattr(module, func_name) + + # Run the test - some tests may need special fixtures + if module_name == "test_pm_uart_dma": + # uart_dma needs dma_dut fixture + try: + test_func(dut, dma_dut) + except TypeError: + # If function signature changed, try without dma_dut + test_func(dut) + else: + test_func(dut) + + # If we get here, test passed + results[module_name] = "PASSED" + passed += 1 + print(f"[{module_name}] PASSED") + + except AssertionError as e: + results[module_name] = "FAILED" + failed += 1 + print(f"[{module_name}] FAILED: {e}") + + except Exception as e: + results[module_name] = "ERROR" + errors += 1 + print(f"[{module_name}] ERROR: {e}") + + # Summary (sorted alphabetically) + print("\n" + "=" * 50) + print("Test Summary") + print("=" * 50) + for name in sorted(results.keys()): + print(f" {name}: {results[name]}") + print(f"\nTotal: {passed} passed, {failed} failed, {errors} errors") + print("=" * 50) + + # Assert if any test failed + assert failed == 0, f"{failed} test(s) failed!" + assert errors == 0, f"{errors} test(s) had errors!" \ No newline at end of file diff --git a/tests/pm_device_test/pm_device_pytest/test_pm_aon_qdec.py b/tests/pm_device_test/pm_device_pytest/test_pm_aon_qdec.py new file mode 100644 index 0000000000000..b958d69d875e2 --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/test_pm_aon_qdec.py @@ -0,0 +1,39 @@ +import re + +from pm_device_pytest.pm_device_common import run_pm_shell_random_wakeup_multi + +_POS_RE = re.compile(r"Position\[(\d+)\]\s*=\s*(-?\d+)\s+degrees") + + +def _parse_positions(lines) -> list: + return [(int(m.group(1)), int(m.group(2))) for line in lines if (m := _POS_RE.search(line))] + + +def test_pm_aon_qdec_multi_session(dut): + count = 3 + + all_logs, sessions, rand_delays = run_pm_shell_random_wakeup_multi( + dut, + subcmd="aon_qdec", + count=count, + timeout=10.0, + rand_min_ms=1000, + rand_max_ms=5000, + delta_tolerance_ms=300, + rand_seed=1, + ) + + assert len(sessions) == count, f"Expected {count} DLPS sessions" + assert len(rand_delays) == count, f"Expected {count} random delays" + assert all_logs, "No logs captured" + + positions = _parse_positions(all_logs) + expected_total = 40 + assert len(positions) == expected_total, f"Expected {expected_total} Position lines" + + degrees = [deg for (_, deg) in positions] + + assert degrees[0:10] == list(range(1, 11)), "Segment 1 pattern mismatch" + assert degrees[10:20] == list(range(9, -1, -1)), "Segment 2 pattern mismatch" + assert degrees[20:30] == list(range(-1, -11, -1)), "Segment 3 pattern mismatch" + assert degrees[30:40] == list(range(-9, 1)), "Segment 4 pattern mismatch" \ No newline at end of file diff --git a/tests/pm_device_test/pm_device_pytest/test_pm_can.py b/tests/pm_device_test/pm_device_pytest/test_pm_can.py new file mode 100644 index 0000000000000..7798ad00161b0 --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/test_pm_can.py @@ -0,0 +1,63 @@ +import re +from typing import List + +from pm_device_pytest.pm_device_common import run_pm_shell_random_wakeup_single + +# CAN RX frame log pattern +CAN_RX_RE = re.compile(r"can rx: id=(0x[0-9a-fA-F]+), dlc=(\d+), data:") + +# TX/RX match pattern +CAN_MATCH_RE = re.compile(r"tx/rx match") + +# DLPS enter/exit patterns +BEFORE_DLPS_RE = re.compile(r"before enter dlps") +AFTER_DLPS_RE = re.compile(r"after exit dlps") + + +def test_pm_can(dut): + """Run CAN PM test and verify results.""" + + def check_before(lines: List[str]) -> None: + """Check CAN RX before DLPS.""" + rx_count = sum(1 for line in lines if CAN_RX_RE.search(line)) + match_count = sum(1 for line in lines if CAN_MATCH_RE.search(line)) + + assert rx_count >= 1, "Before dlps: expected at least 1 CAN RX" + assert match_count >= 1, "Before dlps: expected 'tx/rx match'" + + def check_after(lines: List[str]) -> None: + """Check CAN RX after DLPS.""" + # Check for DLPS entry/exit + has_before = any(BEFORE_DLPS_RE.search(line) for line in lines) + has_after = any(AFTER_DLPS_RE.search(line) for line in lines) + + assert has_before, "After dlps: expected 'before enter dlps'" + assert has_after, "After dlps: expected 'after exit dlps'" + + # Check CAN RX after wakeup + # Find lines after "after exit dlps" + dlps_idx = -1 + for i, line in enumerate(lines): + if AFTER_DLPS_RE.search(line): + dlps_idx = i + break + + if dlps_idx >= 0: + after_dlps_lines = lines[dlps_idx:] + rx_count = sum(1 for line in after_dlps_lines if CAN_RX_RE.search(line)) + match_count = sum(1 for line in after_dlps_lines if CAN_MATCH_RE.search(line)) + + assert rx_count >= 1, "After dlps: expected at least 1 CAN RX" + assert match_count >= 1, "After dlps: expected 'tx/rx match'" + + run_pm_shell_random_wakeup_single( + dut, + subcmd="can", + timeout=30.0, + rand_min_ms=1000, + rand_max_ms=5000, + delta_tolerance_ms=300, + check_before_dlps=check_before, + check_after_dlps=check_after, + rand_seed=None, + ) \ No newline at end of file diff --git a/tests/pm_device_test/pm_device_pytest/test_pm_i2c.py b/tests/pm_device_test/pm_device_pytest/test_pm_i2c.py new file mode 100644 index 0000000000000..57d97d88e4252 --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/test_pm_i2c.py @@ -0,0 +1,36 @@ +import re +from typing import List + +from pm_device_pytest.pm_device_common import run_pm_shell_random_wakeup_single + +I2C_REG_RE = re.compile(r"icm20618 addr:0x68 reg:\s*0x0\s*=\s*0x(?P[0-9a-fA-F]+)") +EXPECT_REG0_VAL = 0xA0 + + +def _find_i2c_values(lines: List[str]) -> List[int]: + return [int(m.group("val"), 16) for line in lines if (m := I2C_REG_RE.search(line))] + + +def test_pm_i2c(dut): + def check_before(lines: List[str]) -> None: + vals = _find_i2c_values(lines) + assert vals, "No icm20618 read before dlps" + assert vals[-1] == EXPECT_REG0_VAL, f"Before dlps: expected 0x{EXPECT_REG0_VAL:02x}, got 0x{vals[-1]:02x}" + + def check_after(lines: List[str]) -> None: + vals = _find_i2c_values(lines) + assert len(vals) >= 2, f"Expected at least 2 i2c reads, got {len(vals)}" + assert vals[0] == EXPECT_REG0_VAL, f"Before dlps: expected 0x{EXPECT_REG0_VAL:02x}, got 0x{vals[0]:02x}" + assert vals[-1] == EXPECT_REG0_VAL, f"After dlps: expected 0x{EXPECT_REG0_VAL:02x}, got 0x{vals[-1]:02x}" + + run_pm_shell_random_wakeup_single( + dut, + subcmd="i2c", + timeout=10.0, + rand_min_ms=1000, + rand_max_ms=5000, + delta_tolerance_ms=300, + check_before_dlps=check_before, + check_after_dlps=check_after, + rand_seed=None, + ) \ No newline at end of file diff --git a/tests/pm_device_test/pm_device_pytest/test_pm_pwm.py b/tests/pm_device_test/pm_device_pytest/test_pm_pwm.py new file mode 100644 index 0000000000000..4aa16679908b4 --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/test_pm_pwm.py @@ -0,0 +1,39 @@ +from typing import List + +from pm_device_pytest.pm_device_common import ( + parse_all_dlps_sessions, + assert_delta_close_to, +) + + +def _find_lines(lines: List[str], keyword: str) -> List[int]: + return [idx for idx, line in enumerate(lines) if keyword in line] + + +def test_pm_pwm(dut): + dut.write(b"pm_test pwm\r") + + lines = dut.readlines_until(regex=r"uart:~\$ *$", timeout=10.0) + + sessions = parse_all_dlps_sessions(lines) + assert len(sessions) == 2, f"Expected 2 DLPS sessions, got {len(sessions)}" + + assert_delta_close_to(sessions[0], target_ms=500, tolerance_ms=200, reason="pwm first dlps") + assert_delta_close_to(sessions[1], target_ms=500, tolerance_ms=200, reason="pwm second dlps") + + text = "\n".join(lines) + assert "connect pwm pin to LA to watch the waveform" in text + + idx_p10000 = _find_lines(lines, "[PWM]: pwm6, [period]: 50000, [pulse]: 10000") + idx_p0 = _find_lines(lines, "[PWM]: pwm6, [period]: 0, [pulse]: 0") + idx_p40000 = _find_lines(lines, "[PWM]: pwm6, [period]: 50000, [pulse]: 40000") + + assert idx_p10000, "Missing PWM config: period 50000, pulse 10000" + assert idx_p40000, "Missing PWM config: period 50000, pulse 40000" + assert len(idx_p0) >= 2, "Expected at least two PWM stop logs" + + i_10000, i_0_first, i_40000, i_0_second = idx_p10000[0], idx_p0[0], idx_p40000[0], idx_p0[1] + + assert i_10000 < sessions[0].before_idx, "PWM 50000/10000 should appear before first DLPS" + assert sessions[0].after_idx < i_0_first < i_40000 < sessions[1].before_idx, "PWM logs order incorrect" + assert sessions[1].after_idx < i_0_second, "Final PWM 0/0 should appear after second DLPS" \ No newline at end of file diff --git a/tests/pm_device_test/pm_device_pytest/test_pm_qdec.py b/tests/pm_device_test/pm_device_pytest/test_pm_qdec.py new file mode 100644 index 0000000000000..6a9da56555569 --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/test_pm_qdec.py @@ -0,0 +1,39 @@ +import re + +from pm_device_pytest.pm_device_common import run_pm_shell_random_wakeup_multi + +_POS_RE = re.compile(r"Position\[(\d+)\]\s*=\s*(-?\d+)\s+degrees") + + +def _parse_positions(lines) -> list: + return [(int(m.group(1)), int(m.group(2))) for line in lines if (m := _POS_RE.search(line))] + + +def test_pm_qdec_multi_session(dut): + count = 3 + + all_logs, sessions, rand_delays = run_pm_shell_random_wakeup_multi( + dut, + subcmd="qdec", + count=count, + timeout=10.0, + rand_min_ms=1000, + rand_max_ms=5000, + delta_tolerance_ms=300, + rand_seed=1, + ) + + assert len(sessions) == count, f"Expected {count} DLPS sessions" + assert len(rand_delays) == count, f"Expected {count} random delays" + assert all_logs, "No logs captured" + + positions = _parse_positions(all_logs) + expected_total = 48 + assert len(positions) == expected_total, f"Expected {expected_total} Position lines, got {len(positions)}" + + degrees = [deg for (_, deg) in positions] + + assert degrees[0:12] == list(range(1, 13)), f"Segment 1 pattern mismatch" + assert degrees[12:24] == list(range(11, -1, -1)), f"Segment 2 pattern mismatch" + assert degrees[24:36] == list(range(-1, -13, -1)), f"Segment 3 pattern mismatch" + assert degrees[36:48] == list(range(-11, 1)), f"Segment 4 pattern mismatch" \ No newline at end of file diff --git a/tests/pm_device_test/pm_device_pytest/test_pm_rtc.py b/tests/pm_device_test/pm_device_pytest/test_pm_rtc.py new file mode 100644 index 0000000000000..96744e87a8d05 --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/test_pm_rtc.py @@ -0,0 +1,51 @@ +import random +from typing import List + +from pm_device_pytest.pm_device_common import ( + run_pm_shell_single_auto_wakeup, + assert_delta_close_to, +) + +RTC_WAIT_RE = r"wait\s+(?P\d+)ms\s+to trigger handler" +RTC_TRIGGER_RE = r"trigger handler after\s+(?P\d+)ms" + +TIMEOUT_MIN_MS = 1000 +TIMEOUT_MAX_MS = 5000 +RTC_DELTA_TOLERANCE_MS = 300 + + +def _find_rtc_values(lines: List[str], regex: str) -> tuple: + import re + for line in lines: + m = re.search(regex, line) + if m: + return int(m.group("timeout_ms")), int(m.group("after_ms")) + raise AssertionError(f"No match for {regex} in logs") + + +def test_pm_rtc(dut): + timeout_ms = random.randint(TIMEOUT_MIN_MS, TIMEOUT_MAX_MS) + + def check_before(lines: List[str]) -> None: + import re + for line in lines: + m = re.search(RTC_WAIT_RE, line) + if m and int(m.group("timeout_ms")) != timeout_ms: + raise AssertionError(f"RTC timeout mismatch: expected {timeout_ms}") + + def check_after(lines: List[str]) -> None: + import re + _, after_ms = _find_rtc_values(lines, f"{RTC_WAIT_RE}|{RTC_TRIGGER_RE}") + diff = abs(after_ms - timeout_ms) + assert diff <= RTC_DELTA_TOLERANCE_MS, f"RTC trigger diff too large: {diff}ms" + + logs, session = run_pm_shell_single_auto_wakeup( + dut, + subcmd=f"rtc {timeout_ms}", + timeout=15.0, + done_regex=RTC_TRIGGER_RE, + check_before_dlps=check_before, + check_after_dlps=check_after, + ) + + assert_delta_close_to(session, target_ms=timeout_ms, tolerance_ms=RTC_DELTA_TOLERANCE_MS, reason="RTC auto wakeup") \ No newline at end of file diff --git a/tests/pm_device_test/pm_device_pytest/test_pm_sdhc.py b/tests/pm_device_test/pm_device_pytest/test_pm_sdhc.py new file mode 100644 index 0000000000000..d849cb12c89c9 --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/test_pm_sdhc.py @@ -0,0 +1,51 @@ +import re +from typing import List + +from pm_device_pytest.pm_device_common import run_pm_shell_random_wakeup_single + +SDMMC_INIT_RE = re.compile(r"before dlps sdmmc card .* initialization success") +SDMMC_READ_OK_RE = re.compile(r"before dlps sdmmc card read success") +SDMMC_READ_FAIL_RE = re.compile(r"before dlps sdmmc card read fail") +SDIO_INIT_RE = re.compile(r"before dlps sdio card .* initialization success") +SDMMC_AFTER_INIT_RE = re.compile(r"after dlps sdmmc card .* initialization success") +SDMMC_AFTER_READ_OK_RE = re.compile(r"after dlps sdmmc card read success") +SDMMC_AFTER_READ_FAIL_RE = re.compile(r"after dlps sdmmc card read fail") +SDIO_AFTER_INIT_RE = re.compile(r"after dlps sdio card .* initialization success") + + +def _check_sdmmc_before_dlps(lines: List[str]) -> None: + text = "\n".join(lines) + if SDMMC_INIT_RE.search(text): + assert SDMMC_INIT_RE.search(text), "SDMMC init before DLPS failed" + if SDMMC_READ_OK_RE.search(text): + assert SDMMC_READ_OK_RE.search(text), "SDMMC read before DLPS failed" + elif SDMMC_READ_FAIL_RE.search(text): + assert False, "SDMMC read before DLPS failed" + if SDIO_INIT_RE.search(text): + assert SDIO_INIT_RE.search(text), "SDIO init before DLPS failed" + + +def _check_sdmmc_after_dlps(lines: List[str]) -> None: + text = "\n".join(lines) + if SDMMC_AFTER_INIT_RE.search(text): + assert SDMMC_AFTER_INIT_RE.search(text), "SDMMC init after DLPS failed" + if SDMMC_AFTER_READ_OK_RE.search(text): + assert SDMMC_AFTER_READ_OK_RE.search(text), "SDMMC read after DLPS failed" + elif SDMMC_AFTER_READ_FAIL_RE.search(text): + assert False, "SDMMC read after DLPS failed" + if SDIO_AFTER_INIT_RE.search(text): + assert SDIO_AFTER_INIT_RE.search(text), "SDIO init after DLPS failed" + + +def test_pm_sdhc(dut): + run_pm_shell_random_wakeup_single( + dut, + subcmd="sdhc", + timeout=30.0, + rand_min_ms=1000, + rand_max_ms=5000, + delta_tolerance_ms=300, + check_before_dlps=_check_sdmmc_before_dlps, + check_after_dlps=_check_sdmmc_after_dlps, + rand_seed=None, + ) \ No newline at end of file diff --git a/tests/pm_device_test/pm_device_pytest/test_pm_spi.py b/tests/pm_device_test/pm_device_pytest/test_pm_spi.py new file mode 100644 index 0000000000000..1fde75ebc6c39 --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/test_pm_spi.py @@ -0,0 +1,41 @@ +import re +from typing import List + +from pm_device_pytest.pm_device_common import run_pm_shell_random_wakeup_single + +START_LOOP_RE = re.compile(r"Start complete loop") +BUF_SAME_RE = re.compile(r"Buffer contents are same") +BUF_DIFF_RE = re.compile(r"Buffer contents are different") + + +def _count_spi_loops(lines: List[str]) -> tuple: + start_cnt = sum(1 for line in lines if START_LOOP_RE.search(line)) + same_cnt = sum(1 for line in lines if BUF_SAME_RE.search(line)) + diff_cnt = sum(1 for line in lines if BUF_DIFF_RE.search(line)) + return start_cnt, same_cnt, diff_cnt + + +def test_pm_spi(dut): + def check_before(lines: List[str]) -> None: + start_cnt, same_cnt, diff_cnt = _count_spi_loops(lines) + assert start_cnt >= 1, "Before dlps: expected at least 1 'Start complete loop'" + assert same_cnt >= 1, "Before dlps: expected at least 1 'Buffer contents are same'" + assert diff_cnt == 0, "Before dlps: found 'Buffer contents are different'" + + def check_after(lines: List[str]) -> None: + start_cnt, same_cnt, diff_cnt = _count_spi_loops(lines) + assert start_cnt >= 2, f"Expected at least 2 'Start complete loop', got {start_cnt}" + assert same_cnt >= 2, f"Expected at least 2 'Buffer contents are same', got {same_cnt}" + assert diff_cnt == 0, f"Found 'Buffer contents are different' in logs" + + run_pm_shell_random_wakeup_single( + dut, + subcmd="spi", + timeout=10.0, + rand_min_ms=1000, + rand_max_ms=5000, + delta_tolerance_ms=300, + check_before_dlps=check_before, + check_after_dlps=check_after, + rand_seed=None, + ) \ No newline at end of file diff --git a/tests/pm_device_test/pm_device_pytest/test_pm_uart.py b/tests/pm_device_test/pm_device_pytest/test_pm_uart.py new file mode 100644 index 0000000000000..506bf0eeee4bf --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/test_pm_uart.py @@ -0,0 +1,15 @@ +from pm_device_pytest.pm_device_common import run_pm_shell_random_wakeup_single + + +def test_pm_uart(dut): + run_pm_shell_random_wakeup_single( + dut, + subcmd="uart", + timeout=10.0, + rand_min_ms=1000, + rand_max_ms=5000, + delta_tolerance_ms=300, + check_before_dlps=None, + check_after_dlps=None, + rand_seed=None, + ) \ No newline at end of file diff --git a/tests/pm_device_test/pm_device_pytest/test_pm_uart_dma.py b/tests/pm_device_test/pm_device_pytest/test_pm_uart_dma.py new file mode 100644 index 0000000000000..ea7e4fd8c5e29 --- /dev/null +++ b/tests/pm_device_test/pm_device_pytest/test_pm_uart_dma.py @@ -0,0 +1,103 @@ +import random +import time + +import serial +import serial.tools.list_ports + +from pm_device_pytest.pm_device_board_config import ( + get_dma_uart_baudrate, + get_dma_uart_port, +) +from pm_device_pytest.pm_device_common import ( + assert_delta_close_to, + assert_single_dlps_present, +) + +DMA_PORT = get_dma_uart_port() +DMA_BAUDRATE = get_dma_uart_baudrate() +TEST_DATA = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + + +class SerialDMADUT: + def __init__(self, port, baudrate, timeout=0.1): + self.ser = serial.Serial(port=port, baudrate=baudrate, timeout=timeout) + + def close(self): + if self.ser and self.ser.is_open: + self.ser.close() + + def write(self, data): + self.ser.write(data) + self.ser.flush() + + def read(self, size, timeout=5.0): + self.ser.timeout = timeout + data = self.ser.read(size) + self.ser.timeout = 0.1 + return data + + def flush_input(self, timeout=0.5): + end = time.time() + timeout + while time.time() < end: + if self.ser.in_waiting > 0: + self.ser.read(self.ser.in_waiting) + else: + break + + +def dma_dut(): + available = [p.device for p in serial.tools.list_ports.comports()] + if DMA_PORT not in available: + raise RuntimeError(f"[DMA DUT] {DMA_PORT} unavailable. Available: {available}") + + dma = SerialDMADUT(port=DMA_PORT, baudrate=DMA_BAUDRATE, timeout=0.1) + try: + yield dma + finally: + dma.close() + + +def _send_receive_dma(dut, data): + dma = dut.dma + dma.flush_input(timeout=0.5) + dma.write(data) + time.sleep(0.1) + received = dma.read(len(data), timeout=5.0) + return received, (received == data) + + +def test_pm_uart_dma(dut, dma_dut): + dut.dma = dma_dut + rand_delay_ms = random.randint(1000, 5000) + + dut.write(b"pm_test uartdma\r") + logs_pre = dut.readlines_until(regex=r"send some data from dma uart", timeout=10.0) + assert "send some data from dma uart" in "\n".join(logs_pre) + + received, ok = _send_receive_dma(dut, TEST_DATA) + logs_rx = dut.readlines_until(regex=r"uart dma rx \d+ bytes", timeout=5.0) + assert "uart dma rx" in "\n".join(logs_rx) and "bytes" in "\n".join(logs_rx) + assert ok, f"Data mismatch before DLPS" + + logs_dlps = dut.readlines_until(regex=r"type on shell to wakeup", timeout=10.0) + assert "before enter dlps" in "\n".join(logs_dlps) + + time.sleep(rand_delay_ms / 1000.0) + dut.write(b"\r") + + logs_end = dut.readlines_until(regex=r"after exit dlps", timeout=10.0) + assert "after exit dlps" in "\n".join(logs_end) + + logs_ready = dut.readlines_until(regex=r"send some data from dma uart", timeout=10.0) + assert "send some data from dma uart" in "\n".join(logs_ready) + + received2, ok2 = _send_receive_dma(dut, TEST_DATA) + logs_rx2 = dut.readlines_until(regex=r"uart dma rx \d+ bytes", timeout=5.0) + assert "uart dma rx" in "\n".join(logs_rx2) and "bytes" in "\n".join(logs_rx2) + assert ok2, f"Data mismatch after DLPS" + + logs_post = dut.readlines_until(regex=r".*~\$ *$", timeout=10.0) + + all_logs = logs_pre + logs_dlps + logs_end + logs_ready + logs_post + session = assert_single_dlps_present(all_logs) + assert_delta_close_to(session, target_ms=rand_delay_ms, tolerance_ms=300, reason="uartdma") \ No newline at end of file diff --git a/samples/bee_pm_device/prj.conf b/tests/pm_device_test/prj.conf similarity index 100% rename from samples/bee_pm_device/prj.conf rename to tests/pm_device_test/prj.conf diff --git a/tests/pm_device_test/src/main.c b/tests/pm_device_test/src/main.c new file mode 100644 index 0000000000000..1fd02a8ca8b4a --- /dev/null +++ b/tests/pm_device_test/src/main.c @@ -0,0 +1,1305 @@ +/* + * Copyright (c) 2026, Realtek Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#ifdef CONFIG_GPIO +#include +#if defined(CONFIG_GPIO_BEE) +#include +#elif defined(CONFIG_GPIO_RTL87X3G) +#include +#endif +#endif + +#ifdef CONFIG_SERIAL +#include +#endif + +#ifdef CONFIG_PWM +#include +#endif + +#ifdef CONFIG_COUNTER +#include +#endif + +#ifdef CONFIG_SPI +#include +#endif + +#ifdef CONFIG_RTC +#include +#endif + +#ifdef CONFIG_I2C +#include +#endif + +#ifdef CONFIG_ADC +#include +#endif + +#ifdef CONFIG_SENSOR +#include +#if defined(CONFIG_QDEC_BEE) +#include +#elif defined(CONFIG_QDEC_RTL87X3G) +#include +#endif +#endif + +#ifdef CONFIG_SDMMC_STACK +#include +#endif + +#ifdef CONFIG_CAN +#include +#endif + +#if defined(CONFIG_SOC_SERIES_RTL87X2G) + +#include "trace.h" +#include +#include "power_manager_unit_platform.h" + +#define PM_TEST_CHECK_PASS PM_CHECK_PASS +#define PM_TEST_CHECK_FAIL PM_CHECK_FAIL +#define PM_TEST_CHECK_RET PMCheckResult + +#define pm_test_register_check_cb(app_check) \ + platform_pm_register_callback_func_with_priority((void *)app_check, PLATFORM_PM_CHECK, 1) + +#define pm_test_register_store_cb(app_store) \ + platform_pm_register_callback_func_with_priority((void *)app_store, PLATFORM_PM_STORE, 1) + +#define pm_test_register_restore_cb(app_restore) \ + platform_pm_register_callback_func_with_priority((void *)app_restore, PLATFORM_PM_RESTORE, \ + 1) + +#elif defined(CONFIG_SOC_SERIES_RTL8752H) + +#include "trace.h" +#include + +extern void (*platform_pm_register_callback_func_with_priority)(void *cb_func, + PlatformPMStage pf_pm_stage, + int8_t priority); + +#define PM_TEST_CHECK_PASS PM_CHECK_PASS +#define PM_TEST_CHECK_FAIL PM_CHECK_FAIL +#define PM_TEST_CHECK_RET PMCheckResult + +#define pm_test_register_check_cb(app_check) \ + platform_pm_register_callback_func_with_priority((void *)app_check, PLATFORM_PM_CHECK, 1) + +#define pm_test_register_store_cb(app_store) \ + platform_pm_register_callback_func_with_priority((void *)app_store, PLATFORM_PM_STORE, 1) + +#define pm_test_register_restore_cb(app_restore) \ + platform_pm_register_callback_func_with_priority((void *)app_restore, PLATFORM_PM_RESTORE, \ + 1) + +#elif defined(CONFIG_SOC_SERIES_RTL87X3G) + +#include "trace.h" +#include +#include + +#define PM_TEST_CHECK_PASS true +#define PM_TEST_CHECK_FAIL false +#define PM_TEST_CHECK_RET bool + +typedef bool (*POWERCheckFunc)(void); +extern int32_t power_check_cb_register(POWERCheckFunc func); + +#define pm_test_register_check_cb(app_check) power_check_cb_register(app_check) + +#define pm_test_register_store_cb(app_store) power_stage_cb_register(app_store, POWER_STAGE_STORE) + +#define pm_test_register_restore_cb(app_restore) \ + power_stage_cb_register(app_restore, POWER_STAGE_RESTORE) + +#elif defined(CONFIG_SOC_SERIES_RTL8762J) + +#include "log_core.h" + +#endif /* SoC select */ + +#if defined(CONFIG_PM_DEVICE) + +struct k_sem pm_app_sem; + +static PM_TEST_CHECK_RET pm_dlps_check_flag = PM_TEST_CHECK_FAIL; +static uint32_t pm_counter; + +static PM_TEST_CHECK_RET app_check(void) +{ + return pm_dlps_check_flag; +} + +static void app_store(void) +{ + DBG_DIRECT("[%s] %d line %d", __func__, ++pm_counter, __LINE__); +} + +static void app_restore(void) +{ + DBG_DIRECT("[%s] %d line %d", __func__, pm_counter, __LINE__); + k_sem_give(&pm_app_sem); +} + +static void pm_test_enter_dlps_forever(void) +{ + printf("[%lld] before enter dlps\n", k_uptime_get()); + printf("[%lld] type on shell to wakeup\n", k_uptime_get()); + + pm_dlps_check_flag = PM_TEST_CHECK_PASS; + k_sem_init(&pm_app_sem, 0, 1); + k_sem_take(&pm_app_sem, K_FOREVER); + pm_dlps_check_flag = PM_TEST_CHECK_FAIL; + + printf("[%lld] after exit dlps\n", k_uptime_get()); +} + +static void pm_test_enter_dlps_timeout(k_timeout_t timeout) +{ + printf("[%lld] before enter dlps\n", k_uptime_get()); + + pm_dlps_check_flag = PM_TEST_CHECK_PASS; + k_sem_init(&pm_app_sem, 0, 1); + k_sem_take(&pm_app_sem, timeout); + pm_dlps_check_flag = PM_TEST_CHECK_FAIL; + + printf("[%lld] after exit dlps\n", k_uptime_get()); +} + +#endif /* CONFIG_PM_DEVICE */ + +int main(void) +{ + printf("[%lld] Hello World! %s\n", k_uptime_get(), CONFIG_BOARD_TARGET); + +#if defined(CONFIG_PM_DEVICE) + k_sem_init(&pm_app_sem, 0, 1); + + pm_dlps_check_flag = PM_TEST_CHECK_FAIL; + + pm_test_register_check_cb(app_check); + pm_test_register_store_cb(app_store); + pm_test_register_restore_cb(app_restore); +#endif + + return 0; +} + +/* UART PM test */ + +static int shell_pm_test_uart(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + +#ifdef CONFIG_SERIAL +#if defined(CONFIG_PM_DEVICE) + pm_test_enter_dlps_forever(); +#endif +#endif + + return 0; +} + +/* UART DMA PM test */ + +#ifdef CONFIG_UART_ASYNC_API + +static const struct device *uart_dma_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_uart_dma)); + +static struct k_sem uart_dma_tx_sem; +static struct k_sem uart_dma_rx_sem; + +static uint8_t uart_dma_rx_buf[1024]; +static uint32_t uart_dma_rx_len; +static bool uart_dma_rx_enabled; + +static void uart_async_console_cb(const struct device *dev, struct uart_event *evt, void *user_data) +{ + ARG_UNUSED(dev); + ARG_UNUSED(user_data); + + switch (evt->type) { + case UART_TX_DONE: + k_sem_give(&uart_dma_tx_sem); + break; + + case UART_RX_RDY: + memcpy(uart_dma_rx_buf, &evt->data.rx.buf[evt->data.rx.offset], evt->data.rx.len); + uart_dma_rx_len = evt->data.rx.len; + k_sem_give(&uart_dma_rx_sem); + break; + + default: + break; + } +} + +static void uart_dma_enter_cb(void) +{ +} + +static void uart_dma_exit_cb(void) +{ + if (uart_dma_rx_enabled) { + /* Re-enable DMA RX after wakeup if needed (left intentionally empty) */ + } +} + +static void pm_uart_dma_do_rx_tx_cycle(const struct device *dev) +{ + k_sem_init(&uart_dma_tx_sem, 0, 1); + k_sem_init(&uart_dma_rx_sem, 0, 1); + memset(uart_dma_rx_buf, 0, sizeof(uart_dma_rx_buf)); + uart_dma_rx_len = 0; + + uart_rx_enable(dev, uart_dma_rx_buf, sizeof(uart_dma_rx_buf), 50 * USEC_PER_MSEC); + + printf("send some data from dma uart\n"); + k_sem_take(&uart_dma_rx_sem, K_FOREVER); + + printf("uart dma rx %d bytes\n", uart_dma_rx_len); + + uart_tx(dev, uart_dma_rx_buf, uart_dma_rx_len, 100 * USEC_PER_MSEC); + k_sem_take(&uart_dma_tx_sem, K_FOREVER); +} + +#endif /* CONFIG_UART_ASYNC_API */ + +static int shell_pm_test_uart_dma(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + +#ifdef CONFIG_UART_ASYNC_API + static bool pm_uart_dma_cb_registered; + + if (!pm_uart_dma_cb_registered) { + pm_test_register_store_cb(uart_dma_enter_cb); + pm_test_register_restore_cb(uart_dma_exit_cb); + pm_uart_dma_cb_registered = true; + } + + uart_callback_set(uart_dma_dev, uart_async_console_cb, NULL); + + uart_dma_rx_enabled = true; + + /* First DMA RX/TX cycle before entering DLPS */ + pm_uart_dma_do_rx_tx_cycle(uart_dma_dev); + + /* Enter DLPS */ +#if defined(CONFIG_PM_DEVICE) + pm_test_enter_dlps_forever(); +#endif + + /* Second DMA RX/TX cycle after exiting DLPS */ + k_sem_init(&uart_dma_tx_sem, 0, 1); + k_sem_init(&uart_dma_rx_sem, 0, 1); + memset(uart_dma_rx_buf, 0, sizeof(uart_dma_rx_buf)); + uart_dma_rx_len = 0; + + uart_rx_disable(uart_dma_dev); + pm_uart_dma_do_rx_tx_cycle(uart_dma_dev); + + uart_rx_disable(uart_dma_dev); + uart_dma_rx_enabled = false; + +#endif /* CONFIG_UART_ASYNC_API */ + + return 0; +} + +/* COUNTER PM test */ + +#ifdef CONFIG_COUNTER + +static void counter_top_cb(const struct device *dev, void *user_data) +{ + ARG_UNUSED(dev); + + uint64_t *pre_sys_time_ms = (uint64_t *)user_data; + uint64_t current_sys_time_ms = k_uptime_get(); + + printf("top_handler\n"); + printf("[%lld] trigger handler after %lldms\n", current_sys_time_ms, + current_sys_time_ms - *pre_sys_time_ms); + +#if defined(CONFIG_PM_DEVICE) + k_sem_give(&pm_app_sem); +#endif +} + +#endif /* CONFIG_COUNTER */ + +static int shell_pm_test_counter(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + +#ifdef CONFIG_COUNTER + const struct device *counter_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_counter_timer)); + struct counter_top_cfg top_cfg; + uint64_t current_sys_time_ms; + uint64_t timeout_ms; + + if (argc < 2) { + printf("Usage: pm_test counter \n"); + return 0; + } + + timeout_ms = strtoul(argv[1], NULL, 10); + + counter_start(counter_dev); + + top_cfg.callback = counter_top_cb; + top_cfg.flags = 0; + top_cfg.ticks = counter_us_to_ticks(counter_dev, timeout_ms * 1000); + current_sys_time_ms = k_uptime_get(); + top_cfg.user_data = ¤t_sys_time_ms; + + printf("[%lld] wait %lldms to trigger handler\n", current_sys_time_ms, timeout_ms); + + counter_set_top_value(counter_dev, &top_cfg); + +#if defined(CONFIG_PM_DEVICE) + pm_test_enter_dlps_forever(); +#endif + + counter_stop(counter_dev); +#endif /* CONFIG_COUNTER */ + + return 0; +} + +/* GPIO PM test */ + +#ifdef CONFIG_GPIO + +#define DEV_OUT DT_GPIO_CTLR(DT_INST(0, test_gpio_basic_api), out_gpios) +#define DEV_IN DT_GPIO_CTLR(DT_INST(0, test_gpio_basic_api), in_gpios) +#define DEV DEV_OUT + +#define PIN_OUT DT_GPIO_PIN(DT_INST(0, test_gpio_basic_api), out_gpios) +#define PIN_OUT_FLAGS DT_GPIO_FLAGS(DT_INST(0, test_gpio_basic_api), out_gpios) +#define PIN_IN DT_GPIO_PIN(DT_INST(0, test_gpio_basic_api), in_gpios) +#define PIN_IN_FLAGS DT_GPIO_FLAGS(DT_INST(0, test_gpio_basic_api), in_gpios) + +static struct gpio_callback pm_gpio_cb; +static struct k_sem pm_gpio_sem; + +static void pm_gpio_irq_cb(const struct device *dev_in, struct gpio_callback *cb, uint32_t pins) +{ + ARG_UNUSED(dev_in); + ARG_UNUSED(cb); + ARG_UNUSED(pins); + + static uint8_t irq_count; + +#if defined(CONFIG_PM_DEVICE) + pm_dlps_check_flag = PM_TEST_CHECK_FAIL; +#endif + + k_sem_give(&pm_gpio_sem); + printf("[%lld] enter gpio callback cnt %d\n", k_uptime_get(), irq_count); + irq_count++; +} + +static void pm_gpio_do_one_round(const char *hint) +{ +#if defined(CONFIG_PM_DEVICE) + printf("[%lld] before enter dlps\n", k_uptime_get()); + printf("[%lld] %s\n", k_uptime_get(), hint); + + pm_dlps_check_flag = PM_TEST_CHECK_PASS; + k_sem_init(&pm_app_sem, 0, 1); + k_sem_take(&pm_app_sem, K_FOREVER); + pm_dlps_check_flag = PM_TEST_CHECK_FAIL; + + printf("[%lld] after exit dlps\n", k_uptime_get()); +#else + printf("[%lld] %s\n", k_uptime_get(), hint); + k_sem_take(&pm_gpio_sem, K_FOREVER); +#endif + + k_busy_wait(100000); +} + +#endif /* CONFIG_GPIO */ + +static int shell_pm_test_gpio(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + +#ifdef CONFIG_GPIO + const struct device *const dev_in = DEVICE_DT_GET_OR_NULL(DEV_IN); + const struct device *const dev_out = DEVICE_DT_GET_OR_NULL(DEV_OUT); + + k_sem_init(&pm_gpio_sem, 0, 1); + + gpio_pin_configure(dev_out, PIN_OUT, GPIO_OUTPUT_LOW | PIN_OUT_FLAGS); + +#if defined(CONFIG_GPIO_BEE) + gpio_pin_configure(dev_in, PIN_IN, + GPIO_INPUT | GPIO_PULL_UP | PIN_IN_FLAGS | BEE_GPIO_INPUT_PM_WAKEUP); +#elif defined(CONFIG_GPIO_RTL87X3G) + gpio_pin_configure(dev_in, PIN_IN, + GPIO_INPUT | GPIO_PULL_UP | PIN_IN_FLAGS | + RTL87X3G_GPIO_INPUT_PM_WAKEUP); +#endif + + gpio_init_callback(&pm_gpio_cb, pm_gpio_irq_cb, BIT(PIN_IN)); + gpio_add_callback(dev_in, &pm_gpio_cb); + + /* Falling edge */ + gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_EDGE_FALLING); + pm_gpio_do_one_round("connect input pin to output pin to wakeup"); + + /* Rising edge */ + gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_EDGE_RISING); + pm_gpio_do_one_round("disconnect input pin to output pin to wakeup"); + +#if defined(CONFIG_BEE_GPIO_SUPPORT_BOTH_EDGE) + /* Both edges */ + gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_EDGE_BOTH); + pm_gpio_do_one_round("connect input pin to output pin to wakeup"); + pm_gpio_do_one_round("disconnect input pin to output pin to wakeup"); +#endif /* CONFIG_BEE_GPIO_SUPPORT_BOTH_EDGE */ + + gpio_remove_callback(dev_in, &pm_gpio_cb); + gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_DISABLE); + +#if defined(CONFIG_GPIO_BEE) + gpio_pin_configure(dev_in, PIN_IN, + (GPIO_INPUT | GPIO_PULL_UP | PIN_IN_FLAGS) & + (~BEE_GPIO_INPUT_PM_WAKEUP)); +#elif defined(CONFIG_GPIO_RTL87X3G) + gpio_pin_configure(dev_in, PIN_IN, + (GPIO_INPUT | GPIO_PULL_UP | PIN_IN_FLAGS) & + (~RTL87X3G_GPIO_INPUT_PM_WAKEUP)); +#endif + +#endif /* CONFIG_GPIO */ + + return 0; +} + +/* PWM PM test */ + +static int shell_pm_test_pwm(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + +#ifdef CONFIG_PWM + const struct device *pwm_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_pwm)); + uint32_t period; + uint32_t pulse; + + printf("[%lld] connect pwm pin to LA to watch the waveform\n", k_uptime_get()); + + /* First waveform */ + period = 50000; + pulse = 10000; + printf("[%lld] [PWM]: %s, [period]: %u, [pulse]: %u\n", k_uptime_get(), pwm_dev->name, + period, pulse); + pwm_set_cycles(pwm_dev, 0, period, pulse, 0); + k_busy_wait(500000); + +#if defined(CONFIG_PM_DEVICE) + /* Enter DLPS in the middle of PWM test */ + pm_test_enter_dlps_timeout(K_MSEC(500)); + k_busy_wait(500000); +#endif + + /* Stop PWM */ + period = 0; + pulse = 0; + printf("[%lld] [PWM]: %s, [period]: %u, [pulse]: %u\n", k_uptime_get(), pwm_dev->name, + period, pulse); + pwm_set_cycles(pwm_dev, 0, period, pulse, 0); + k_busy_wait(500000); + +#if defined(CONFIG_PM_DEVICE) + k_sleep(K_MSEC(10)); +#endif + + /* Second waveform */ + period = 50000; + pulse = 40000; + printf("[%lld] [PWM]: %s, [period]: %u, [pulse]: %u\n", k_uptime_get(), pwm_dev->name, + period, pulse); + pwm_set_cycles(pwm_dev, 0, period, pulse, 0); + k_busy_wait(500000); + +#if defined(CONFIG_PM_DEVICE) + pm_test_enter_dlps_timeout(K_MSEC(500)); + k_busy_wait(500000); +#endif + + /* Stop again */ + period = 0; + pulse = 0; + printf("[%lld] [PWM]: %s, [period]: %u, [pulse]: %u\n", k_uptime_get(), pwm_dev->name, + period, pulse); + pwm_set_cycles(pwm_dev, 0, period, pulse, 0); + +#endif /* CONFIG_PWM */ + + return 0; +} + +/* SPI PM test */ + +#ifdef CONFIG_SPI + +#define MODE_LOOP 0 +#define FRAME_SIZE 8 +#define SPI_OP_CFG(fs) \ + (SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(fs) | SPI_LINES_SINGLE) + +#define SPI_DEV DT_COMPAT_GET_ANY_STATUS_OKAY(test_spi_loopback) +#define BUF_SIZE 18 + +static const char tx_data[BUF_SIZE] = "0123456789abcdef-\0"; +static __aligned(32) char spi_tx_buf[BUF_SIZE]; +static __aligned(32) char spi_rx_buf[BUF_SIZE]; + +static int spi_complete_loop(struct spi_dt_spec *spec) +{ + int ret; + + memcpy(spi_tx_buf, tx_data, sizeof(tx_data)); + memset(spi_rx_buf, 0, sizeof(spi_rx_buf)); + + const struct spi_buf tx_bufs[] = { + { + .buf = spi_tx_buf, + .len = BUF_SIZE, + }, + }; + const struct spi_buf rx_bufs[] = { + { + .buf = spi_rx_buf, + .len = BUF_SIZE, + }, + }; + + const struct spi_buf_set tx = { + .buffers = tx_bufs, + .count = ARRAY_SIZE(tx_bufs), + }; + const struct spi_buf_set rx = { + .buffers = rx_bufs, + .count = ARRAY_SIZE(rx_bufs), + }; + + printf("[%lld] Start complete loop\n", k_uptime_get()); + + ret = spi_transceive_dt(spec, &tx, &rx); + if (ret) { + printf("[%lld] spi_transceive_dt error: %d\n", k_uptime_get(), ret); + return ret; + } + + if (memcmp(spi_tx_buf, spi_rx_buf, BUF_SIZE)) { + printf("[%lld] Buffer contents are different\n", k_uptime_get()); + return -1; + } + + printf("[%lld] Buffer contents are same\n", k_uptime_get()); + return 0; +} + +#endif /* CONFIG_SPI */ + +static int shell_pm_test_spi(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + +#ifdef CONFIG_SPI + static struct spi_dt_spec spi_spec = SPI_DT_SPEC_GET(SPI_DEV, SPI_OP_CFG(FRAME_SIZE), 0); + + printf("[%lld] connect MOSI pin to the MISO of the SPI\n", k_uptime_get()); + + if (spi_complete_loop(&spi_spec) < 0) { + printf("[%lld] loopback test fail\n", k_uptime_get()); + return 0; + } + +#if defined(CONFIG_PM_DEVICE) + pm_test_enter_dlps_forever(); +#endif + + if (spi_complete_loop(&spi_spec) < 0) { + printf("[%lld] loopback test fail\n", k_uptime_get()); + return 0; + } + +#endif /* CONFIG_SPI */ + + return 0; +} + +/* RTC PM test */ + +#ifdef CONFIG_RTC + +static const struct rtc_time test_rtc_time_set = { + .tm_sec = 50, + .tm_min = 29, + .tm_hour = 13, + .tm_mday = 1, + .tm_mon = 0, + .tm_year = 121, + .tm_wday = 5, + .tm_yday = 1, + .tm_isdst = -1, + .tm_nsec = 0, +}; + +static const struct rtc_time test_alarm_time_set = { + .tm_sec = 52, + .tm_min = 29, + .tm_hour = 13, + .tm_mday = 1, + .tm_mon = 0, + .tm_year = 121, + .tm_wday = 5, + .tm_yday = 1, + .tm_isdst = -1, + .tm_nsec = 0, +}; + +static void test_rtc_alarm_cb(const struct device *dev, uint16_t id, void *user_data) +{ + ARG_UNUSED(dev); + ARG_UNUSED(id); + + uint64_t *pre_sys_time_ms = (uint64_t *)user_data; + uint64_t current_sys_time_ms = k_uptime_get(); + + printf("[%lld] trigger handler after %lldms\n", current_sys_time_ms, + current_sys_time_ms - *pre_sys_time_ms); + +#if defined(CONFIG_PM_DEVICE) + k_sem_give(&pm_app_sem); +#endif +} + +#endif /* CONFIG_RTC */ + +static int shell_pm_test_rtc(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + +#ifdef CONFIG_RTC + static const struct device *rtc_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_rtc)); + uint64_t current_sys_time_ms; + uint32_t timeout_ms = 2000; /* default 2000 ms */ + + /* Usage: pm_test rtc [timeout_ms] */ + if (argc > 2) { + printf("Usage: pm_test rtc [timeout_ms]\n"); + return 0; + } + + if (argc == 2) { + timeout_ms = strtoul(argv[1], NULL, 10); + } + + rtc_alarm_set_callback(rtc_dev, 0, NULL, NULL); + rtc_set_time(rtc_dev, &test_rtc_time_set); + + current_sys_time_ms = k_uptime_get(); + rtc_alarm_set_callback(rtc_dev, 0, test_rtc_alarm_cb, ¤t_sys_time_ms); + + rtc_alarm_set_time(rtc_dev, 0, 0x1ff, &test_alarm_time_set); + + printf("[%lld] wait %ums to trigger handler\n", current_sys_time_ms, timeout_ms); + +#if defined(CONFIG_PM_DEVICE) + pm_test_enter_dlps_forever(); +#endif + +#endif /* CONFIG_RTC */ + + return 0; +} + +/* QDEC PM test */ + +static int shell_pm_test_qdec(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + +#if defined(CONFIG_SENSOR) && defined(CONFIG_QDEC_BEE) + static const struct gpio_dt_spec phase_a = GPIO_DT_SPEC_GET(DT_ALIAS(test_qenca), gpios); + static const struct gpio_dt_spec phase_b = GPIO_DT_SPEC_GET(DT_ALIAS(test_qencb), gpios); + + static bool toggle_a; + + struct sensor_value val; + const struct device *const qdec_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_qdec)); + + gpio_pin_configure_dt(&phase_a, GPIO_OUTPUT); + gpio_pin_configure_dt(&phase_b, GPIO_OUTPUT); + + k_busy_wait(100000); + + /* First rotation */ + for (int i = 0; i < 12; i++) { + toggle_a = !toggle_a; + if (toggle_a) { + gpio_pin_toggle_dt(&phase_a); + } else { + gpio_pin_toggle_dt(&phase_b); + } + + k_busy_wait(100000); + sensor_sample_fetch(qdec_dev); + sensor_channel_get(qdec_dev, SENSOR_ATTR_QDEC_X_ROTATION, &val); + + printf("Position[%d] = %d degrees\n", i, val.val1); + } + +#if defined(CONFIG_PM_DEVICE) + pm_test_enter_dlps_forever(); +#endif + + /* Additional rotations (logic kept identical to original) */ + for (int round = 0; round < 3; round++) { + for (int i = 0; i < 12; i++) { + toggle_a = !toggle_a; + if ((round == 0 || round == 1) ? !toggle_a : toggle_a) { + gpio_pin_toggle_dt(&phase_a); + } else { + gpio_pin_toggle_dt(&phase_b); + } + + k_busy_wait(100000); + sensor_sample_fetch(qdec_dev); + sensor_channel_get(qdec_dev, SENSOR_ATTR_QDEC_X_ROTATION, &val); + printf("Position[%d] = %d degrees\n", i, val.val1); + } + +#if defined(CONFIG_PM_DEVICE) + pm_test_enter_dlps_forever(); +#endif + } + +#endif /* CONFIG_SENSOR && CONFIG_QDEC_BEE */ + + return 0; +} + +/* AON QDEC PM test */ + +static int shell_pm_test_aon_qdec(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + +#if defined(CONFIG_SENSOR) && (defined(CONFIG_AON_QDEC_BEE) || defined(CONFIG_LPQDEC_BEE) || \ + defined(CONFIG_AON_QDEC_RTL87X3G)) + + static const struct gpio_dt_spec phase_a = GPIO_DT_SPEC_GET(DT_ALIAS(test_qenca), gpios); + static const struct gpio_dt_spec phase_b = GPIO_DT_SPEC_GET(DT_ALIAS(test_qencb), gpios); + + static bool toggle_a; + + struct sensor_value val; + const struct device *const aon_qdec_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_aon_qdec)); + + gpio_pin_configure_dt(&phase_a, GPIO_OUTPUT); + gpio_pin_configure_dt(&phase_b, GPIO_OUTPUT); + + k_busy_wait(100000); + + for (int i = 0; i < 10; i++) { + toggle_a = !toggle_a; + if (toggle_a) { + gpio_pin_toggle_dt(&phase_a); + } else { + gpio_pin_toggle_dt(&phase_b); + } + + k_busy_wait(100000); + sensor_sample_fetch(aon_qdec_dev); + sensor_channel_get(aon_qdec_dev, SENSOR_CHAN_ROTATION, &val); + + printf("Position[%d] = %d degrees\n", i, val.val1 / 90); + } + +#if defined(CONFIG_PM_DEVICE) + for (int round = 0; round < 3; round++) { + pm_test_enter_dlps_forever(); + + for (int i = 0; i < 10; i++) { + toggle_a = !toggle_a; + if ((round == 2) ? toggle_a : !toggle_a) { + gpio_pin_toggle_dt(&phase_a); + } else { + gpio_pin_toggle_dt(&phase_b); + } + + k_busy_wait(100000); + sensor_sample_fetch(aon_qdec_dev); + sensor_channel_get(aon_qdec_dev, SENSOR_CHAN_ROTATION, &val); + printf("Position[%d] = %d degrees\n", i, val.val1 / 90); + } + } +#endif /* CONFIG_PM_DEVICE */ + +#endif /* CONFIG_SENSOR && AON_QDEC */ + + return 0; +} + +/* I2C PM test */ + +static int shell_pm_test_i2c(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + +#ifdef CONFIG_I2C + const struct device *const i2c_dev = DEVICE_DT_GET_OR_NULL(DT_NODELABEL(i2c0)); + + uint8_t icm20618_addr = 0x68; + uint8_t write_buf[6]; + uint8_t read_buf[12]; + int write_len; + int read_len; + + memset(write_buf, 0, sizeof(write_buf)); + memset(read_buf, 0, sizeof(read_buf)); + + /* Read ID before DLPS */ + write_buf[0] = 0x00; + write_len = 1; + read_len = 1; + + i2c_write_read(i2c_dev, icm20618_addr, write_buf, write_len, read_buf, read_len); + + printf("icm20618 addr:0x%x reg:0x%x = 0x%x\n", icm20618_addr, write_buf[0], read_buf[0]); + +#if defined(CONFIG_PM_DEVICE) + pm_test_enter_dlps_forever(); +#endif + + /* Read ID after DLPS */ + memset(write_buf, 0, sizeof(write_buf)); + memset(read_buf, 0, sizeof(read_buf)); + + write_buf[0] = 0x00; + write_len = 1; + read_len = 1; + + i2c_write_read(i2c_dev, icm20618_addr, write_buf, write_len, read_buf, read_len); + + printf("icm20618 addr:0x%x reg:0x%x = 0x%x\n", icm20618_addr, write_buf[0], read_buf[0]); + +#endif /* CONFIG_I2C */ + + return 0; +} + +/* ADC PM test */ + +#ifdef CONFIG_ADC + +#define ADC_BUFFER_SIZE 1 +#define INVALID_ADC_VALUE SHRT_MIN + +#define DT_SPEC_AND_COMMA(node_id, prop, idx) ADC_DT_SPEC_GET_BY_IDX(node_id, idx), + +static const struct adc_dt_spec adc_channels[] = { + DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, DT_SPEC_AND_COMMA)}; + +static const int adc_channels_count = ARRAY_SIZE(adc_channels); + +static int16_t adc_sample_buf[ADC_BUFFER_SIZE]; + +static int do_single_adc_read(const struct adc_dt_spec *adc, int16_t *out_val) +{ + int ret; + + if (!device_is_ready(adc->dev)) { + printf("ADC device not ready\n"); + return -ENODEV; + } + + struct adc_sequence sequence = { + .buffer = adc_sample_buf, + .buffer_size = sizeof(adc_sample_buf), + .resolution = 12, + }; + + ret = adc_sequence_init_dt(adc, &sequence); + if (ret < 0) { + printf("adc_sequence_init_dt failed: %d\n", ret); + return ret; + } + + for (int i = 0; i < ADC_BUFFER_SIZE; i++) { + adc_sample_buf[i] = INVALID_ADC_VALUE; + } + + ret = adc_read_dt(adc, &sequence); + if (ret < 0) { + printf("adc_read_dt failed: %d\n", ret); + return ret; + } + + *out_val = adc_sample_buf[0]; + return 0; +} + +#endif /* CONFIG_ADC */ + +static int shell_pm_test_adc(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + +#ifdef CONFIG_ADC + if (adc_channels_count < 1) { + printf("No ADC channel configured in zephyr_user node\n"); + return 0; + } + + int ret; + int16_t val_before = INVALID_ADC_VALUE; + int16_t val_after = INVALID_ADC_VALUE; + + for (uint8_t i = 0; i < adc_channels_count; i++) { + ret = adc_channel_setup_dt(&adc_channels[i]); + if (ret < 0) { + printf("adc_channel_setup_dt[%d] failed: %d\n", i, ret); + return 0; + } + } + + ret = do_single_adc_read(&adc_channels[0], &val_before); + if (ret == 0) { + printf("ADC sample before dlps: %d\n", val_before); + } else { + printf("ADC sample before dlps failed: %d\n", ret); + } + +#if defined(CONFIG_PM_DEVICE) + pm_test_enter_dlps_forever(); +#endif + + ret = do_single_adc_read(&adc_channels[0], &val_after); + if (ret == 0) { + printf("ADC sample after dlps: %d\n", val_after); + } else { + printf("ADC sample after dlps failed: %d\n", ret); + } + +#endif /* CONFIG_ADC */ + + return 0; +} + +/* SDHC / SDIO PM test */ + +#ifdef CONFIG_SDMMC_STACK +static uint8_t sdmmc_wbuf[512]; +static uint8_t sdmmc_rbuf[512]; +#endif + +static int shell_pm_test_sdhc(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + +#if defined(CONFIG_SDMMC_STACK) || defined(CONFIG_SDIO_STACK) + static const struct device *const sdhc_dev_sdmmc = + DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_sdmmc)); + static const struct device *const sdhc_dev_sdio = + DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_sdio)); + + static struct sd_card sdmmc_card; + static struct sd_card sdio_card; + + int ret; + + if (sdhc_dev_sdmmc) { + memset(sdmmc_rbuf, 0, sizeof(sdmmc_rbuf)); + + for (uint32_t i = 0; i < sizeof(sdmmc_wbuf); i++) { + sdmmc_wbuf[i] = (uint8_t)i; + } + + printf("before dlps sdmmc card %s initializing...\n", sdhc_dev_sdmmc->name); + + ret = sd_init(sdhc_dev_sdmmc, &sdmmc_card); + if (ret != 0) { + printf("before dlps sdmmc card initialization failed\n"); + return 0; + } + + printf("before dlps sdmmc card %s initialization success\n", sdhc_dev_sdmmc->name); + + sdmmc_write_blocks(&sdmmc_card, sdmmc_wbuf, 0, 1); + sdmmc_read_blocks(&sdmmc_card, sdmmc_rbuf, 0, 1); + + if (memcmp(sdmmc_rbuf, sdmmc_wbuf, sizeof(sdmmc_rbuf))) { + printf("before dlps sdmmc card read fail\n"); + } else { + printf("before dlps sdmmc card read success\n"); + } + } + + if (sdhc_dev_sdio) { + printf("before dlps sdio card %s initializing...\n", sdhc_dev_sdio->name); + + ret = sd_init(sdhc_dev_sdio, &sdio_card); + if (ret != 0) { + printf("before dlps sdio card initialization failed\n"); + return 0; + } + + printf("before dlps sdio card %s initialization success\n", sdhc_dev_sdio->name); + } + +#if defined(CONFIG_PM_DEVICE) + pm_test_enter_dlps_forever(); +#endif + + if (sdhc_dev_sdmmc) { + memset(sdmmc_rbuf, 0, sizeof(sdmmc_rbuf)); + + for (uint32_t i = 0; i < sizeof(sdmmc_wbuf); i++) { + sdmmc_wbuf[i] = (uint8_t)(i * 3U); + } + + sdmmc_write_blocks(&sdmmc_card, sdmmc_wbuf, 0, 1); + sdmmc_read_blocks(&sdmmc_card, sdmmc_rbuf, 0, 1); + + if (memcmp(sdmmc_rbuf, sdmmc_wbuf, sizeof(sdmmc_rbuf))) { + printf("after dlps sdmmc card read fail\n"); + } else { + printf("after dlps sdmmc card read success\n"); + } + } + + if (sdhc_dev_sdio) { + printf("after dlps sdio card %s initializing...\n", sdhc_dev_sdio->name); + + ret = sd_init(sdhc_dev_sdio, &sdio_card); + if (ret != 0) { + printf("after dlps sdio card initialization failed\n"); + return 0; + } + + printf("after dlps sdio card %s initialization success\n", sdhc_dev_sdio->name); + } + +#endif /* SDMMC/SDIO */ + + return 0; +} + +/* CAN PM test */ + +#ifdef CONFIG_CAN + +static struct k_sem can_tx_sem; +static struct k_sem can_rx_sem; +static uint8_t can_tx_data[8]; +static uint8_t can_rx_data[8]; +static int rx_count; + +static void can_tx_cb(const struct device *dev, int error, void *user_data) +{ + ARG_UNUSED(dev); + ARG_UNUSED(user_data); + ARG_UNUSED(error); + k_sem_give(&can_tx_sem); +} + +static void can_rx_cb(const struct device *dev, struct can_frame *frame, void *user_data) +{ + ARG_UNUSED(user_data); + + printf("[%lld] can rx: id=0x%x, dlc=%d, data: ", k_uptime_get(), frame->id, frame->dlc); + for (uint8_t i = 0; i < frame->dlc; i++) { + can_rx_data[i] = frame->data[i]; + printf("0x%02x ", can_rx_data[i]); + } + printf("\n"); + rx_count++; + k_sem_give(&can_rx_sem); +} + +#endif /* CONFIG_CAN */ + +static int shell_pm_test_can(const struct shell *sh, size_t argc, char **argv) +{ + ARG_UNUSED(sh); + ARG_UNUSED(argc); + ARG_UNUSED(argv); + +#ifdef CONFIG_CAN + const struct device *const can_dev = DEVICE_DT_GET_OR_NULL(DT_ALIAS(test_can)); + struct can_frame frame = {0}; + struct can_filter filter = {0}; + int filter_id; + int ret; + + if (!can_dev) { + printf("CAN device not found\n"); + return 0; + } + + /* Set loopback mode */ + ret = can_set_mode(can_dev, CAN_MODE_LOOPBACK); + if (ret != 0) { + printf("CAN set mode failed: %d\n", ret); + return ret; + } + + ret = can_start(can_dev); + if (ret != 0) { + printf("CAN start failed: %d\n", ret); + return ret; + } + + /* Prepare test frame */ + frame.id = 0x123; + frame.dlc = 8; + frame.flags = 0; + for (uint8_t i = 0; i < frame.dlc; i++) { + frame.data[i] = i + 1; + can_tx_data[i] = frame.data[i]; + } + + /* Test 1: Add filter, TX, check RX */ + k_sem_init(&can_tx_sem, 0, 1); + k_sem_init(&can_rx_sem, 0, 1); + rx_count = 0; + + filter.id = 0x123; + filter.mask = 0x7FF; + filter.flags = 0; + filter_id = can_add_rx_filter(can_dev, can_rx_cb, NULL, &filter); + + ret = can_send(can_dev, &frame, K_MSEC(100), can_tx_cb, NULL); + if (ret != 0) { + printf("CAN send failed: %d\n", ret); + return ret; + } + k_sem_take(&can_tx_sem, K_MSEC(200)); + k_sem_take(&can_rx_sem, K_MSEC(200)); + + /* Verify RX data matches TX */ + if (rx_count == 1 && memcmp(can_tx_data, can_rx_data, 8) == 0) { + printf("tx/rx match\n"); + } else { + printf("tx/rx mismatch\n"); + } + + /* Test 2: Remove filter, TX, check no RX */ + can_remove_rx_filter(can_dev, filter_id); + rx_count = 0; + + frame.data[0] = 0xAA; + can_tx_data[0] = frame.data[0]; + ret = can_send(can_dev, &frame, K_MSEC(100), can_tx_cb, NULL); + k_sem_take(&can_tx_sem, K_MSEC(200)); + k_busy_wait(50000); + + if (rx_count != 0) { + printf("unexpected rx\n"); + } + + /* Test 3: Add filter, enter DLPS, TX, check RX */ + filter_id = can_add_rx_filter(can_dev, can_rx_cb, NULL, &filter); + rx_count = 0; + +#if defined(CONFIG_PM_DEVICE) + pm_test_enter_dlps_forever(); +#endif + + frame.data[0] = 0x55; + can_tx_data[0] = frame.data[0]; + ret = can_send(can_dev, &frame, K_MSEC(100), can_tx_cb, NULL); + k_sem_take(&can_tx_sem, K_MSEC(200)); + k_sem_take(&can_rx_sem, K_MSEC(200)); + + if (rx_count == 1 && memcmp(can_tx_data, can_rx_data, 8) == 0) { + printf("tx/rx match\n"); + } else { + printf("tx/rx mismatch\n"); + } + + /* Test 4: Remove filter, TX, check no RX */ + can_remove_rx_filter(can_dev, filter_id); + rx_count = 0; + + frame.data[0] = 0xCC; + can_tx_data[0] = frame.data[0]; + ret = can_send(can_dev, &frame, K_MSEC(100), can_tx_cb, NULL); + k_sem_take(&can_tx_sem, K_MSEC(200)); + k_busy_wait(50000); + + if (rx_count != 0) { + printf("unexpected rx\n"); + } + + can_stop(can_dev); + +#endif /* CONFIG_CAN */ + + return 0; +} + +/* Shell commands */ + +#define SHELL_CMD_ARG_CREATE \ + SHELL_CMD_ARG(uart, NULL, "uart pm test", shell_pm_test_uart, 0, 0), \ + SHELL_CMD_ARG(uartdma, NULL, "uart dma pm test", shell_pm_test_uart_dma, 0, 0), \ + SHELL_CMD_ARG(gpio, NULL, "gpio pm test", shell_pm_test_gpio, 0, 0), \ + SHELL_CMD_ARG(pwm, NULL, "pwm pm test", shell_pm_test_pwm, 0, 0), \ + SHELL_CMD_ARG(counter, NULL, "counter pm test (input time in ms)", \ + shell_pm_test_counter, 2, 0), \ + SHELL_CMD_ARG(spi, NULL, "spi pm test", shell_pm_test_spi, 0, 0), \ + SHELL_CMD_ARG(rtc, NULL, "rtc pm test", shell_pm_test_rtc, 0, 0), \ + SHELL_CMD_ARG(qdec, NULL, "qdec pm test", shell_pm_test_qdec, 0, 0), \ + SHELL_CMD_ARG(aon_qdec, NULL, "aon qdec pm test", shell_pm_test_aon_qdec, 0, 0), \ + SHELL_CMD_ARG(i2c, NULL, "i2c pm test", shell_pm_test_i2c, 0, 0), \ + SHELL_CMD_ARG(adc, NULL, "adc pm test", shell_pm_test_adc, 0, 0), \ + SHELL_CMD_ARG(sdhc, NULL, "sdhc/sdio pm test", shell_pm_test_sdhc, 0, 0), \ + SHELL_CMD_ARG(can, NULL, "can pm test", shell_pm_test_can, 0, 0), \ + SHELL_SUBCMD_SET_END + +SHELL_STATIC_SUBCMD_SET_CREATE(sub_pm_test, SHELL_CMD_ARG_CREATE); + +SHELL_CMD_REGISTER(pm_test, &sub_pm_test, "PM tests", NULL); diff --git a/tests/pm_device_test/testcase.yaml b/tests/pm_device_test/testcase.yaml new file mode 100644 index 0000000000000..14c58b45ad7b7 --- /dev/null +++ b/tests/pm_device_test/testcase.yaml @@ -0,0 +1,18 @@ +common: + tags: + - driver + harness: pytest + harness_config: + pytest_dut_scope: session + pytest_args: + - "--shell-port=COM10" + - "--dma-port=COM21" + platform_allow: + - rtl87x2g_evb + - rtl8752h_evb_rtl8752htv + +tests: + driver.pm.bee_evb_all_test: + harness_config: + pytest_root: + - "pm_device_pytest/test_pm_all.py"