mirror of https://github.com/ARMmbed/mbed-os.git
Tests: HAL API: Reset_reason: Add tests
parent
685efbde97
commit
9ed1209657
|
@ -0,0 +1,162 @@
|
||||||
|
"""
|
||||||
|
mbed SDK
|
||||||
|
Copyright (c) 2017-2017 ARM Limited
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
"""
|
||||||
|
import time
|
||||||
|
from mbed_host_tests import BaseHostTest
|
||||||
|
from mbed_host_tests.host_tests_runner.host_test_default import DefaultTestSelector
|
||||||
|
|
||||||
|
DEFAULT_CYCLE_PERIOD = 4.0
|
||||||
|
|
||||||
|
MSG_VALUE_WATCHDOG_PRESENT = 'wdg_present'
|
||||||
|
MSG_VALUE_DUMMY = '0'
|
||||||
|
MSG_VALUE_RESET_REASON_GET = 'get'
|
||||||
|
MSG_VALUE_RESET_REASON_CLEAR = 'clear'
|
||||||
|
MSG_VALUE_DEVICE_RESET_NVIC = 'nvic'
|
||||||
|
MSG_VALUE_DEVICE_RESET_WATCHDOG = 'watchdog'
|
||||||
|
|
||||||
|
MSG_KEY_DEVICE_READY = 'ready'
|
||||||
|
MSG_KEY_RESET_REASON_RAW = 'reason_raw'
|
||||||
|
MSG_KEY_RESET_REASON = 'reason'
|
||||||
|
MSG_KEY_DEVICE_RESET = 'reset'
|
||||||
|
MSG_KEY_SYNC = '__sync'
|
||||||
|
|
||||||
|
RESET_REASONS = {
|
||||||
|
'POWER_ON': '0',
|
||||||
|
'PIN_RESET': '1',
|
||||||
|
'BROWN_OUT': '2',
|
||||||
|
'SOFTWARE': '3',
|
||||||
|
'WATCHDOG': '4',
|
||||||
|
'LOCKUP': '5',
|
||||||
|
'WAKE_LOW_POWER': '6',
|
||||||
|
'ACCESS_ERROR': '7',
|
||||||
|
'BOOT_ERROR': '8',
|
||||||
|
'MULTIPLE': '9',
|
||||||
|
'PLATFORM': '10',
|
||||||
|
'UNKNOWN': '11'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def raise_if_different(expected, actual, text=''):
|
||||||
|
"""Raise a RuntimeError if actual is different than expected."""
|
||||||
|
if expected != actual:
|
||||||
|
raise RuntimeError('{}Got {!r}, expected {!r}'
|
||||||
|
.format(text, actual, expected))
|
||||||
|
|
||||||
|
|
||||||
|
class ResetReasonTest(BaseHostTest):
|
||||||
|
"""Test for the Reset Reason HAL API.
|
||||||
|
|
||||||
|
Given a device supporting a Reset Reason API.
|
||||||
|
When the device is restarted using various methods.
|
||||||
|
Then the device returns a correct reset reason for every restart.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(ResetReasonTest, self).__init__()
|
||||||
|
self.device_has_watchdog = None
|
||||||
|
self.raw_reset_reasons = set()
|
||||||
|
cycle_s = self.get_config_item('program_cycle_s')
|
||||||
|
self.program_cycle_s = cycle_s if cycle_s is not None else DEFAULT_CYCLE_PERIOD
|
||||||
|
self.test_steps_sequence = self.test_steps()
|
||||||
|
# Advance the coroutine to it's first yield statement.
|
||||||
|
self.test_steps_sequence.send(None)
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready)
|
||||||
|
self.register_callback(MSG_KEY_RESET_REASON_RAW, self.cb_reset_reason_raw)
|
||||||
|
self.register_callback(MSG_KEY_RESET_REASON, self.cb_reset_reason)
|
||||||
|
self.register_callback(MSG_KEY_DEVICE_RESET, self.cb_reset_reason)
|
||||||
|
|
||||||
|
def cb_device_ready(self, key, value, timestamp):
|
||||||
|
"""Request a raw value of the reset_reason register.
|
||||||
|
|
||||||
|
Additionally, save the device's watchdog status on the first call.
|
||||||
|
"""
|
||||||
|
if self.device_has_watchdog is None:
|
||||||
|
self.device_has_watchdog = (value == MSG_VALUE_WATCHDOG_PRESENT)
|
||||||
|
self.send_kv(MSG_KEY_RESET_REASON_RAW, MSG_VALUE_RESET_REASON_GET)
|
||||||
|
|
||||||
|
def cb_reset_reason_raw(self, key, value, timestamp):
|
||||||
|
"""Verify that the raw reset_reason register value is unique.
|
||||||
|
|
||||||
|
Fail the test suite if the raw reset_reason value is not unique.
|
||||||
|
Request a platform independent reset_reason otherwise.
|
||||||
|
"""
|
||||||
|
if value in self.raw_reset_reasons:
|
||||||
|
self.log('TEST FAILED: The raw reset reason is not unique. '
|
||||||
|
'{!r} is already present in {!r}.'
|
||||||
|
.format(value, self.raw_reset_reasons))
|
||||||
|
self.notify_complete(False)
|
||||||
|
else:
|
||||||
|
self.raw_reset_reasons.add(value)
|
||||||
|
self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_GET)
|
||||||
|
|
||||||
|
def cb_reset_reason(self, key, value, timestamp):
|
||||||
|
"""Feed the test_steps coroutine with reset_reason value.
|
||||||
|
|
||||||
|
Pass the test suite if the coroutine yields True.
|
||||||
|
Fail the test suite if the iterator stops or raises a RuntimeError.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if self.test_steps_sequence.send(value):
|
||||||
|
self.notify_complete(True)
|
||||||
|
except (StopIteration, RuntimeError) as exc:
|
||||||
|
self.log('TEST FAILED: {}'.format(exc))
|
||||||
|
self.notify_complete(False)
|
||||||
|
|
||||||
|
def test_steps(self):
|
||||||
|
"""Generate a sequence of test steps.
|
||||||
|
|
||||||
|
This coroutine calls yield to wait for the input from the device
|
||||||
|
(the reset_reason). If the device gives the wrong response, the
|
||||||
|
generator raises a RuntimeError exception and fails the test.
|
||||||
|
"""
|
||||||
|
# Ignore the first reason.
|
||||||
|
__ignored_reset_reason = yield
|
||||||
|
self.raw_reset_reasons.clear()
|
||||||
|
self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR)
|
||||||
|
__ignored_clear_ack = yield
|
||||||
|
|
||||||
|
# Request a NVIC_SystemReset() call.
|
||||||
|
self.send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_NVIC)
|
||||||
|
__ignored_reset_ack = yield
|
||||||
|
time.sleep(self.program_cycle_s)
|
||||||
|
self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY)
|
||||||
|
reset_reason = yield
|
||||||
|
raise_if_different(RESET_REASONS['SOFTWARE'], reset_reason, 'Wrong reset reason. ')
|
||||||
|
self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR)
|
||||||
|
__ignored_clear_ack = yield
|
||||||
|
|
||||||
|
# Reset the device using DAP.
|
||||||
|
self.reset_dut(DefaultTestSelector.RESET_TYPE_SW_RST)
|
||||||
|
reset_reason = yield
|
||||||
|
raise_if_different(RESET_REASONS['PIN_RESET'], reset_reason, 'Wrong reset reason. ')
|
||||||
|
self.send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR)
|
||||||
|
__ignored_clear_ack = yield
|
||||||
|
|
||||||
|
# Start a watchdog timer and wait for it to reset the device.
|
||||||
|
if not self.device_has_watchdog:
|
||||||
|
self.log('DUT does not have a watchdog. Skipping this reset reason.')
|
||||||
|
else:
|
||||||
|
self.send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_WATCHDOG)
|
||||||
|
__ignored_reset_ack = yield
|
||||||
|
time.sleep(self.program_cycle_s)
|
||||||
|
self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY)
|
||||||
|
reset_reason = yield
|
||||||
|
raise_if_different(RESET_REASONS['WATCHDOG'], reset_reason, 'Wrong reset reason. ')
|
||||||
|
|
||||||
|
# The sequence is correct -- test passed.
|
||||||
|
yield True
|
|
@ -0,0 +1,136 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017 ARM Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#if !DEVICE_RESET_REASON
|
||||||
|
#error [NOT_SUPPORTED] Reset reason API not supported for this target
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "hal/reset_reason_api.h"
|
||||||
|
#include "reset_reason_api_tests.h"
|
||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
#include "hal/watchdog_api.h"
|
||||||
|
|
||||||
|
#define MSG_VALUE_WATCHDOG_STATUS "wdg_present"
|
||||||
|
#define WDG_TIMEOUT_MS 50UL
|
||||||
|
#define WDG_TIMEOUT_DELTA_MS 50UL
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define MSG_VALUE_WATCHDOG_STATUS "no_wdg"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MSG_VALUE_DUMMY "0"
|
||||||
|
#define MSG_VALUE_RESET_REASON_GET "get"
|
||||||
|
#define MSG_VALUE_RESET_REASON_CLEAR "clear"
|
||||||
|
#define MSG_VALUE_RESET_REASON_CLEAR_ACK "cleared"
|
||||||
|
#define MSG_VALUE_DEVICE_RESET_ACK "ack"
|
||||||
|
#define MSG_VALUE_DEVICE_RESET_NVIC "nvic"
|
||||||
|
#define MSG_VALUE_DEVICE_RESET_WATCHDOG "watchdog"
|
||||||
|
#define MSG_VALUE_LEN 16
|
||||||
|
#define MSG_KEY_LEN 16
|
||||||
|
|
||||||
|
#define MSG_KEY_DEVICE_READY "ready"
|
||||||
|
#define MSG_KEY_RESET_REASON_RAW "reason_raw"
|
||||||
|
#define MSG_KEY_RESET_REASON "reason"
|
||||||
|
#define MSG_KEY_DEVICE_RESET "reset"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CMD_STATUS_CONTINUE,
|
||||||
|
CMD_STATUS_ERROR
|
||||||
|
} cmd_status_t;
|
||||||
|
|
||||||
|
static cmd_status_t handle_command(const char *key, const char *value)
|
||||||
|
{
|
||||||
|
if (strcmp(key, MSG_KEY_RESET_REASON_RAW) == 0) {
|
||||||
|
uint32_t raw_reason = hal_reset_reason_get_raw();
|
||||||
|
char raw_reason_hex_str[9] = { };
|
||||||
|
int raw_reason_hex_str_len = snprintf(raw_reason_hex_str,
|
||||||
|
sizeof raw_reason_hex_str, "%08lx", raw_reason);
|
||||||
|
|
||||||
|
if (raw_reason_hex_str_len != (sizeof raw_reason_hex_str) - 1) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Failed to compose raw reset reason hex string.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
greentea_send_kv(MSG_KEY_RESET_REASON_RAW, raw_reason_hex_str);
|
||||||
|
return CMD_STATUS_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_RESET_REASON) == 0 && strcmp(value, MSG_VALUE_RESET_REASON_GET) == 0) {
|
||||||
|
int reason = (int) hal_reset_reason_get();
|
||||||
|
greentea_send_kv(MSG_KEY_RESET_REASON, reason);
|
||||||
|
return CMD_STATUS_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_RESET_REASON) == 0 && strcmp(value, MSG_VALUE_RESET_REASON_CLEAR) == 0) {
|
||||||
|
hal_reset_reason_clear();
|
||||||
|
greentea_send_kv(MSG_KEY_RESET_REASON, MSG_VALUE_RESET_REASON_CLEAR_ACK);
|
||||||
|
return CMD_STATUS_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_NVIC) == 0) {
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK);
|
||||||
|
wait_ms(10); // Wait for the serial buffers to flush.
|
||||||
|
NVIC_SystemReset();
|
||||||
|
TEST_ASSERT_MESSAGE(0, "NVIC_SystemReset did not reset the device as expected.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEVICE_WATCHDOG
|
||||||
|
if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_WATCHDOG) == 0) {
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK);
|
||||||
|
wait_ms(10); // Wait for the serial buffers to flush.
|
||||||
|
watchdog_config_t config = { .timeout_ms = WDG_TIMEOUT_MS };
|
||||||
|
if (hal_watchdog_init(&config) != WATCHDOG_STATUS_OK) {
|
||||||
|
TEST_ASSERT_MESSAGE(0, "hal_watchdog_init() error.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
wait_ms(WDG_TIMEOUT_MS + WDG_TIMEOUT_DELTA_MS);
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST_ASSERT_MESSAGE(0, "Invalid message key.");
|
||||||
|
return CMD_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_reset_reason()
|
||||||
|
{
|
||||||
|
// Report readiness and watchdog status.
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_WATCHDOG_STATUS);
|
||||||
|
|
||||||
|
cmd_status_t cmd_status = CMD_STATUS_CONTINUE;
|
||||||
|
static char _key[MSG_KEY_LEN + 1] = { };
|
||||||
|
static char _value[MSG_VALUE_LEN + 1] = { };
|
||||||
|
|
||||||
|
// Let the host side decide what to do and just handle the commands.
|
||||||
|
while (CMD_STATUS_CONTINUE == cmd_status) {
|
||||||
|
memset(_key, 0, sizeof _key);
|
||||||
|
memset(_value, 0, sizeof _value);
|
||||||
|
greentea_parse_kv(_key, _value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||||
|
cmd_status = handle_command(_key, _value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(60, "reset_reason");
|
||||||
|
test_reset_reason(); // The result of this test suite is reported by the host side.
|
||||||
|
GREENTEA_TESTSUITE_RESULT(0); // Fail on any error.
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017 ARM Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup hal_reset_reason_tests
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MBED_HAL_RESET_REASON_API_TESTS_H
|
||||||
|
#define MBED_HAL_RESET_REASON_API_TESTS_H
|
||||||
|
|
||||||
|
#if DEVICE_RESET_REASON
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Test the Reset Reason HAL API
|
||||||
|
*
|
||||||
|
* Given a device supporting a Reset Reason API
|
||||||
|
* When the device is restarted using various methods
|
||||||
|
* Then the device returns a correct reset reason for every restart
|
||||||
|
*/
|
||||||
|
void test_reset_reason();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @}*/
|
||||||
|
|
Loading…
Reference in New Issue