Tests: HAL API: Reset_reason: Add tests

pull/11023/head
Filip Jagodzinski 2017-11-29 13:18:27 +01:00 committed by Martin Kojtal
parent 685efbde97
commit 9ed1209657
3 changed files with 346 additions and 0 deletions

View File

@ -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

View File

@ -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.
}

View File

@ -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
/** @}*/