mirror of https://github.com/ARMmbed/mbed-os.git
168 lines
6.4 KiB
Python
168 lines
6.4 KiB
Python
"""
|
|
Copyright (c) 2018-2019 Arm Limited and affiliates.
|
|
SPDX-License-Identifier: Apache-2.0
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
"""
|
|
import time
|
|
from mbed_host_tests import BaseHostTest
|
|
|
|
DEFAULT_SYNC_DELAY = 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'
|
|
MSG_KEY_RESET_COMPLETE = 'reset_complete'
|
|
|
|
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()
|
|
self.sync_delay = DEFAULT_SYNC_DELAY
|
|
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):
|
|
sync_delay = self.get_config_item('forced_reset_timeout')
|
|
self.sync_delay = sync_delay if sync_delay is not None else DEFAULT_SYNC_DELAY
|
|
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)
|
|
self.register_callback(MSG_KEY_RESET_COMPLETE, 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.sync_delay)
|
|
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()
|
|
__ignored_reset_ack = yield # 'reset_complete'
|
|
time.sleep(self.sync_delay)
|
|
self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY)
|
|
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.sync_delay)
|
|
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
|