Merge pull request #11023 from ARMmbed/release-candidate

Release candidate for mbed-os-5.13.1
pull/11094/head mbed-os-5.13.1
Evelyne Donnaes 2019-07-15 09:47:53 +01:00 committed by GitHub
commit 5941d17183
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1375 changed files with 262291 additions and 95744 deletions

View File

@ -127,7 +127,17 @@ class PyusbMSDTest(BaseHostTest):
else:
self.report_error("unmount")
def _callback_os_type(self, key, value, timestamp):
system_name = platform.system()
if system_name == "Windows":
self.send_kv("os_type", 1)
elif system_name == "Linux":
self.send_kv("os_type", 2)
elif system_name == "Darwin":
self.send_kv("os_type", 3)
def setup(self):
self.register_callback("get_os_type", self._callback_os_type)
self.register_callback("get_serial_number", self._callback_device_ready)
self.register_callback('check_if_mounted', self._callback_check_if_mounted)
self.register_callback('check_if_not_mounted', self._callback_check_if_not_mounted)
@ -204,25 +214,16 @@ class MSDUtils(object):
@staticmethod
def _unmount_windows(serial):
disk_path = MSDUtils._disk_path_windows(serial)
tmp_file = tempfile.NamedTemporaryFile(suffix='.ps1', delete=False)
try:
# create unmount script
tmp_file.write('$disk_leter=$args[0]\n')
tmp_file.write('$driveEject = New-Object -comObject Shell.Application\n')
tmp_file.write('$driveEject.Namespace(17).ParseName($disk_leter).InvokeVerb("Eject")\n')
# close to allow open by other process
tmp_file.close()
cmd_string = r'(New-Object -comObject Shell.Application).Namespace(17).ParseName("{}").InvokeVerb("Eject")'.format(disk_path)
try_count = 10
while try_count:
p = subprocess.Popen(["powershell.exe", tmp_file.name + " " + disk_path], stdout=sys.stdout)
p = subprocess.Popen(["powershell.exe", cmd_string], stdout=sys.stdout)
p.communicate()
try_count -= 1
if MSDUtils._disk_path_windows(serial) is None:
return True
time.sleep(1)
finally:
os.remove(tmp_file.name)
return False

View File

@ -0,0 +1,163 @@
"""
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
from mbed_host_tests.host_tests_runner.host_test_default import DefaultTestSelector
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'
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)
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_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.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

View File

@ -0,0 +1,74 @@
"""
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_DUMMY = '0'
MSG_KEY_DEVICE_READY = 'ready'
MSG_KEY_START_CASE = 'start_case'
MSG_KEY_DEVICE_RESET = 'reset_on_case_teardown'
MSG_KEY_SYNC = '__sync'
class SyncOnReset(BaseHostTest):
"""Host side test that handles device reset during case teardown.
Given a device that performs a reset during a test case teardown.
When the device notifies the host about the reset.
Then the host:
* keeps track of the test case index of the current test suite,
* performs a dev-host handshake,
* advances the test suite to next test case.
Note:
Developed for a watchdog test, so that it can be run on devices that
do not support watchdog timeout updates after the initial setup.
As a solution, after testing watchdog with one set of settings, the
device performs a reset and notifies the host with the test case number,
so that the test suite may be advanced once the device boots again.
"""
def __init__(self):
super(SyncOnReset, self).__init__()
self.test_case_num = 0
self.sync_delay = DEFAULT_SYNC_DELAY
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_DEVICE_RESET, self.cb_device_reset)
def cb_device_ready(self, key, value, timestamp):
"""Advance the device test suite to the next test case."""
self.send_kv(MSG_KEY_START_CASE, self.test_case_num)
def cb_device_reset(self, key, value, timestamp):
"""Wait for the device to boot and perform a handshake.
Additionally, keep track of the last test case number.
"""
try:
self.test_case_num = int(value)
except ValueError:
pass
self.test_case_num += 1
time.sleep(self.sync_delay)
self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY)

View File

@ -0,0 +1,145 @@
"""
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 collections
import threading
from mbed_host_tests import BaseHostTest
TestCaseData = collections.namedtuple('TestCaseData', ['index', 'data_to_send'])
DEFAULT_SYNC_DELAY = 4.0
MAX_HB_PERIOD = 2.5 # [s] Max expected heartbeat period.
MSG_VALUE_DUMMY = '0'
CASE_DATA_INVALID = 0xffffffff
CASE_DATA_PHASE2_OK = 0xfffffffe
CASE_DATA_INSUFF_HB = 0x0
MSG_KEY_SYNC = '__sync'
MSG_KEY_DEVICE_READY = 'ready'
MSG_KEY_START_CASE = 'start_case'
MSG_KEY_DEVICE_RESET = 'dev_reset'
MSG_KEY_HEARTBEAT = 'hb'
class WatchdogReset(BaseHostTest):
"""Host side test that handles device reset.
Given a device with a watchdog timer started.
When the device notifies the host about an incoming reset.
Then the host:
* keeps track of the test case index of the current test suite,
* performs a dev-host handshake.
"""
def __init__(self):
super(WatchdogReset, self).__init__()
self.current_case = TestCaseData(0, CASE_DATA_INVALID)
self.__handshake_timer = None
self.sync_delay = DEFAULT_SYNC_DELAY
self.drop_heartbeat_messages = True
self.hb_timestamps_us = []
def handshake_timer_start(self, seconds=1.0, pre_sync_fun=None):
"""Start a new handshake timer."""
def timer_handler():
"""Perform a dev-host handshake by sending a sync message."""
if pre_sync_fun is not None:
pre_sync_fun()
self.send_kv(MSG_KEY_SYNC, MSG_VALUE_DUMMY)
self.__handshake_timer = threading.Timer(seconds, timer_handler)
self.__handshake_timer.start()
def handshake_timer_cancel(self):
"""Cancel the current handshake timer."""
try:
self.__handshake_timer.cancel()
except AttributeError:
pass
finally:
self.__handshake_timer = None
def heartbeat_timeout_handler(self):
"""Handler for the heartbeat timeout.
Compute the time span of the last heartbeat sequence.
Set self.current_case.data_to_send to CASE_DATA_INVALID if no heartbeat was received.
Set self.current_case.data_to_send to CASE_DATA_INSUFF_HB if only one heartbeat was
received.
"""
self.drop_heartbeat_messages = True
dev_data = CASE_DATA_INVALID
if len(self.hb_timestamps_us) == 1:
dev_data = CASE_DATA_INSUFF_HB
self.log('Not enough heartbeats received.')
elif len(self.hb_timestamps_us) >= 2:
dev_data = int(round(0.001 * (self.hb_timestamps_us[-1] - self.hb_timestamps_us[0])))
self.log('Heartbeat time span was {} ms.'.format(dev_data))
self.current_case = TestCaseData(self.current_case.index, dev_data)
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_DEVICE_RESET, self.cb_device_reset)
self.register_callback(MSG_KEY_HEARTBEAT, self.cb_heartbeat)
def teardown(self):
self.handshake_timer_cancel()
def cb_device_ready(self, key, value, timestamp):
"""Advance the device test suite to a proper test case.
Additionally, send test case data to the device.
"""
self.handshake_timer_cancel()
msg_value = '{0.index:02x},{0.data_to_send:08x}'.format(self.current_case)
self.send_kv(MSG_KEY_START_CASE, msg_value)
self.drop_heartbeat_messages = False
self.hb_timestamps_us = []
def cb_device_reset(self, key, value, timestamp):
"""Keep track of the test case number.
Also set a new handshake timeout, so when the device gets
restarted by the watchdog, the communication will be restored
by the __handshake_timer.
"""
self.handshake_timer_cancel()
case_num, dev_reset_delay_ms = (int(i, base=16) for i in value.split(','))
self.current_case = TestCaseData(case_num, CASE_DATA_PHASE2_OK)
self.handshake_timer_start(self.sync_delay + dev_reset_delay_ms / 1000.0)
def cb_heartbeat(self, key, value, timestamp):
"""Save the timestamp of a heartbeat message.
Additionally, keep track of the test case number.
Also each heartbeat sets a new timeout, so when the device gets
restarted by the watchdog, the communication will be restored
by the __handshake_timer.
"""
if self.drop_heartbeat_messages:
return
self.handshake_timer_cancel()
case_num, timestamp_us = (int(i, base=16) for i in value.split(','))
self.current_case = TestCaseData(case_num, CASE_DATA_INVALID)
self.hb_timestamps_us.append(timestamp_us)
self.handshake_timer_start(
seconds=(MAX_HB_PERIOD + self.sync_delay),
pre_sync_fun=self.heartbeat_timeout_handler)

View File

@ -144,7 +144,7 @@ void test_thread_safety()
TEST_ASSERT_EQUAL(0, ct.compute_partial_start(&crc));
TEST_ASSERT_EQUAL(0, ct.compute_partial((void *)&test, 4, &crc));
Thread t1(osPriorityNormal1, 320);
Thread t1(osPriorityNormal1, 380);
t1.start(callback(test_thread));
TEST_ASSERT_EQUAL(0, ct.compute_partial((void *)&test[4], 5, &crc));
TEST_ASSERT_EQUAL(0, ct.compute_partial_stop(&crc));

View File

@ -218,7 +218,7 @@ Case cases[] = {
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(test_timeout, "timing_drift_auto");
GREENTEA_SETUP(test_timeout, "default_auto");
return utest::v1::greentea_test_setup_handler(number_of_cases);
}

View File

@ -74,7 +74,8 @@ Case cases[] = {
Case("1 s delay during deepsleep (attach_us)", test_deepsleep<AttachUSTester<LowPowerTimeout>, 1000000, LONG_DELTA_US>,
greentea_failure_handler),
#endif
#if !defined(__ARM_FM) //FastModels not support time drifting test
#if !defined(SKIP_TIME_DRIFT_TESTS)
Case("Timing drift (attach)", test_drift<AttachTester<LowPowerTimeout> >),
Case("Timing drift (attach_us)", test_drift<AttachUSTester<LowPowerTimeout> >),
#endif

View File

@ -0,0 +1,33 @@
/*
* 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.
*/
#ifndef MBED_DRIVERS_RESET_REASON_TESTS_H
#define MBED_DRIVERS_RESET_REASON_TESTS_H
#if DEVICE_RESET_REASON
/** Test the ResetReason driver API
*
* Given a device supporting a ResetReason API,
* when the device is restarted,
* then the device returns a correct reset reason for every restart.
*/
void test_reset_reason();
#endif
#endif

View File

@ -0,0 +1,143 @@
/*
* 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.
*/
#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 "drivers/ResetReason.h"
#include "ResetReason_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
#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"
#define SERIAL_FLUSH_TIME_MS 20
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 = ResetReason::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) ResetReason::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) {
/* In order to keep this code compatible with a host script common for
* both HAL API tests and driver API tests, ignore the 'clear' command
* received from host.
*
* The driver API does not provide clear() function directly.
*/
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(SERIAL_FLUSH_TIME_MS); // 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(SERIAL_FLUSH_TIME_MS); // 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(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value.
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

@ -71,8 +71,10 @@ void ticker_callback_1(void)
void ticker_callback_2(void)
{
++callback_trigger_count;
if (LED2 != NC) {
switch_led2_state();
}
}
void sem_release(Semaphore *sem)
@ -110,7 +112,9 @@ void test_case_1x_ticker()
Ticker ticker;
led1 = 1;
if (LED2 != NC) {
led2 = 1;
}
callback_trigger_count = 0;
greentea_send_kv("timing_drift_check_start", 0);
@ -151,7 +155,9 @@ void test_case_2x_ticker()
Ticker ticker1, ticker2;
led1 = 0;
if (LED2 != NC) {
led2 = 1;
}
callback_trigger_count = 0;
ticker1.attach_us(ticker_callback_1, 2 * ONE_MILLI_SEC);
@ -329,7 +335,8 @@ Case cases[] = {
Case("Test detach", test_detach),
Case("Test multi call and time measure", test_multi_call_time),
Case("Test multi ticker", test_multi_ticker),
#if !defined(__ARM_FM) //FastModels not support time drifting test
#if !defined(SKIP_TIME_DRIFT_TESTS)
Case("Test timers: 1x ticker", test_case_1x_ticker),
Case("Test timers: 2x ticker", test_case_2x_ticker)
#endif

View File

@ -68,7 +68,8 @@ Case cases[] = {
Case("1 s delay during sleep (attach_us)", test_sleep<AttachUSTester<Timeout>, 1000000, LONG_DELTA_US>,
greentea_failure_handler),
#endif
#if !defined(__ARM_FM) //FastModels not support time drifting test
#if !defined(SKIP_TIME_DRIFT_TESTS)
Case("Timing drift (attach)", test_drift<AttachTester<Timeout> >),
Case("Timing drift (attach_us)", test_drift<AttachUSTester<Timeout> >),
#endif

View File

@ -196,14 +196,15 @@ void test_multiple(void)
template<typename T>
void test_no_wait(void)
{
for (int i = 0; i < 100; i++) {
Semaphore sem(0, 1);
T timeout;
timeout.attach_callback(mbed::callback(sem_callback, &sem), 0ULL);
bool acquired = sem.try_acquire();
TEST_ASSERT_TRUE(acquired);
int32_t sem_slots = sem.wait(0);
TEST_ASSERT_EQUAL(1, sem_slots);
timeout.detach();
}
}
/** Template for tests: accuracy of timeout delay
*
@ -264,9 +265,7 @@ void test_sleep(void)
bool deep_sleep_allowed = sleep_manager_can_deep_sleep_test_check();
TEST_ASSERT_FALSE_MESSAGE(deep_sleep_allowed, "Deep sleep should be disallowed");
while (!sem.try_acquire()) {
sleep();
}
sem.acquire();
timer.stop();
sleep_manager_unlock_deep_sleep();
@ -323,9 +322,7 @@ void test_deepsleep(void)
bool deep_sleep_allowed = sleep_manager_can_deep_sleep_test_check();
TEST_ASSERT_TRUE_MESSAGE(deep_sleep_allowed, "Deep sleep should be allowed");
while (!sem.try_acquire()) {
sleep();
}
sem.acquire();
timer.stop();
TEST_ASSERT_UINT64_WITHIN(delta_us, delay_us, timer.read_high_resolution_us());

View File

@ -0,0 +1,85 @@
/*
* 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.
*/
#ifndef MBED_DRIVERS_WATCHDOG_TESTS_H
#define MBED_DRIVERS_WATCHDOG_TESTS_H
#if DEVICE_WATCHDOG
/** Test Watchdog max_timeout validity
*
* Given a device supporting Watchdog driver API,
* when @a Watchdog::get_max_timeout() is called,
* then the returned value is greater than 1.
*/
void test_max_timeout_is_valid();
/** Test Watchdog stop
*
* Given a device without a support for the @a disable_watchdog feature,
* when @a Watchdog::stop() is called,
* then false is returned.
*
* Otherwise, given the device with @a disable_watchdog feature support:
*
* Given the Watchdog is *NOT* running,
* when @a Watchdog::stop() is called,
* then false is returned.
*
* Given the Watchdog is running,
* when @a Watchdog::stop() is called before the timeout expires,
* then true is returned and the device is not restarted.
*
* Given the Watchdog is *NOT* running (it has already been stopped),
* when @a Watchdog::stop() is called,
* then false is returned.
*/
void test_stop();
/** Test Watchdog start multiple times
*
* Given a set of unique timeout values,
* when Watchdog::start(T) is called for each value T,
* then, for every T, Watchdog::start() returns true
* and Watchdog::get_timeout() returns an actual timeout value R
* and T <= R < 2 * T.
*/
void test_restart();
/** Test Watchdog start with a valid config
*
* Given a value of T ms which is within supported Watchdog timeout range,
* when Watchdog::start(T) is called,
* then true is returned
* and Watchdog::get_timeout() returns an actual timeout value R
* and T <= R < 2 * T.
*/
template<uint32_t timeout_ms>
void test_start();
/** Test Watchdog start with max_timeout
*
* Given max_timeout value returned by @a Watchdog::get_max_timeout(),
* when @a Watchdog::start(max_timeout) is called,
* then true is returned
* and @a Watchdog::get_timeout() returns max_timeout.
*/
void test_start_max_timeout();
#endif
#endif

View File

@ -0,0 +1,284 @@
/*
* 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.
*/
#if !DEVICE_WATCHDOG
#error [NOT_SUPPORTED] Watchdog not supported for this target
#endif
#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest/utest.h"
#include "mbed.h"
#include "drivers/Watchdog.h"
#include "hal/watchdog_api.h"
#include "Watchdog_tests.h"
#include <stdlib.h>
/* The shortest timeout value, this test suite is able to handle correctly. */
#define WDG_MIN_TIMEOUT_MS 50UL
// Do not set watchdog timeout shorter than WDG_MIN_TIMEOUT_MS, as it may
// cause the host-test-runner return 'TIMEOUT' instead of 'FAIL' / 'PASS'
// if watchdog performs reset during test suite teardown.
#define WDG_TIMEOUT_MS 100UL
#define MSG_VALUE_DUMMY "0"
#define MSG_VALUE_LEN 24
#define MSG_KEY_LEN 24
#define MSG_KEY_DEVICE_READY "ready"
#define MSG_KEY_START_CASE "start_case"
#define MSG_KEY_DEVICE_RESET "reset_on_case_teardown"
/* To prevent a loss of Greentea data, the serial buffers have to be flushed
* before the UART peripheral shutdown. The UART shutdown happens when the
* device is entering the deepsleep mode or performing a reset.
*
* With the current API, it is not possible to check if the hardware buffers
* are empty. However, it is possible to determine the time required for the
* buffers to flush.
*
* Take NUMAKER_PFM_NUC472 as an example:
* The UART peripheral has 16-byte Tx FIFO. With a baud rate set to 9600,
* flushing the Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 ms.
* To be on the safe side, set the wait time to 20 ms.
*/
#define SERIAL_FLUSH_TIME_MS 20
int CASE_INDEX_START;
int CASE_INDEX_CURRENT;
bool CASE_IGNORED = false;
using utest::v1::Case;
using utest::v1::Specification;
using utest::v1::Harness;
using namespace mbed;
Thread wdg_kicking_thread;
Semaphore kick_wdg_during_test_teardown(0, 1);
void wdg_kicking_thread_fun()
{
kick_wdg_during_test_teardown.wait();
while (true) {
hal_watchdog_kick();
wait_ms(20);
}
}
void test_max_timeout_is_valid()
{
Watchdog &watchdog = Watchdog::get_instance();
TEST_ASSERT(watchdog.get_max_timeout() > 1UL);
}
void test_stop()
{
watchdog_features_t features = hal_watchdog_get_platform_features();
Watchdog &watchdog = Watchdog::get_instance();
if (!features.disable_watchdog) {
TEST_ASSERT_FALSE(watchdog.stop());
CASE_IGNORED = true;
TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform");
return;
}
TEST_ASSERT_FALSE(watchdog.is_running());
TEST_ASSERT_FALSE(watchdog.stop());
TEST_ASSERT_FALSE(watchdog.is_running());
TEST_ASSERT_TRUE(watchdog.start(WDG_TIMEOUT_MS));
TEST_ASSERT_TRUE(watchdog.is_running());
TEST_ASSERT_TRUE(watchdog.stop());
TEST_ASSERT_FALSE(watchdog.is_running());
// Make sure that a disabled watchdog does not reset the core.
wait_ms(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value.
TEST_ASSERT_FALSE(watchdog.stop());
}
void test_restart()
{
watchdog_features_t features = hal_watchdog_get_platform_features();
if (!features.update_config) {
CASE_IGNORED = true;
TEST_IGNORE_MESSAGE("Updating watchdog config not supported for this platform");
return;
}
if (!features.disable_watchdog) {
CASE_IGNORED = true;
TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform");
return;
}
Watchdog &watchdog = Watchdog::get_instance();
uint32_t max_timeout = watchdog.get_max_timeout();
uint32_t timeouts[] = {
max_timeout / 4,
max_timeout / 8,
max_timeout / 16
};
int num_timeouts = sizeof timeouts / sizeof timeouts[0];
for (size_t i = 0; i < num_timeouts; i++) {
if (timeouts[i] < WDG_MIN_TIMEOUT_MS) {
CASE_IGNORED = true;
TEST_IGNORE_MESSAGE("Requested timeout value is too short -- ignoring test case.");
return;
}
TEST_ASSERT_TRUE(watchdog.start(timeouts[i]));
TEST_ASSERT_TRUE(watchdog.is_running());
uint32_t actual_timeout = watchdog.get_timeout();
TEST_ASSERT_TRUE(watchdog.stop());
TEST_ASSERT_FALSE(watchdog.is_running());
// The watchdog should trigger at, or after the timeout value.
TEST_ASSERT(actual_timeout >= timeouts[i]);
// The watchdog should trigger before twice the timeout value.
TEST_ASSERT(actual_timeout < 2 * timeouts[i]);
}
}
utest::v1::status_t case_setup_sync_on_reset(const Case *const source, const size_t index_of_case)
{
CASE_INDEX_CURRENT = index_of_case;
CASE_IGNORED = false;
return utest::v1::greentea_case_setup_handler(source, index_of_case);
}
utest::v1::status_t case_teardown_sync_on_reset(const Case *const source, const size_t passed, const size_t failed,
const utest::v1::failure_t failure)
{
if (CASE_IGNORED) {
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
}
// Unlock kicking the watchdog during teardown.
kick_wdg_during_test_teardown.release();
utest::v1::status_t status = utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
if (failed) {
/* Return immediately and skip the device reset, if the test case failed.
* Provided that the device won't be restarted by other means (i.e. watchdog timer),
* this should allow the test suite to finish in a defined manner
* and report failure to host.
* In case of watchdog reset during test suite teardown, the loss of serial
* connection is possible, so the host-test-runner may return 'TIMEOUT'
* instead of 'FAIL'.
*/
return status;
}
greentea_send_kv(MSG_KEY_DEVICE_RESET, CASE_INDEX_START + CASE_INDEX_CURRENT);
utest_printf("The device will now restart.\n");
wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush.
NVIC_SystemReset();
return status; // Reset is instant so this line won't be reached.
}
utest::v1::status_t case_teardown_wdg_stop_or_reset(const Case *const source, const size_t passed, const size_t failed,
const utest::v1::failure_t failure)
{
if (CASE_IGNORED) {
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
}
watchdog_features_t features = hal_watchdog_get_platform_features();
if (features.disable_watchdog) {
hal_watchdog_stop();
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
}
return case_teardown_sync_on_reset(source, passed, failed, failure);
}
template<uint32_t timeout_ms>
void test_start()
{
if (timeout_ms < WDG_MIN_TIMEOUT_MS) {
CASE_IGNORED = true;
TEST_IGNORE_MESSAGE("Requested timeout value is too short -- ignoring test case.");
return;
}
Watchdog &watchdog = Watchdog::get_instance();
TEST_ASSERT_TRUE(watchdog.start(timeout_ms));
uint32_t actual_timeout = watchdog.get_timeout();
// The watchdog should trigger at, or after the timeout value.
TEST_ASSERT(actual_timeout >= timeout_ms);
// The watchdog should trigger before twice the timeout value.
TEST_ASSERT(actual_timeout < 2 * timeout_ms);
}
void test_start_max_timeout()
{
Watchdog &watchdog = Watchdog::get_instance();
uint32_t max_timeout = watchdog.get_max_timeout();
TEST_ASSERT_TRUE(watchdog.start(max_timeout));
// The watchdog should trigger at, or after the timeout value.
TEST_ASSERT(watchdog.get_timeout() >= max_timeout);
}
int testsuite_setup_sync_on_reset(const size_t number_of_cases)
{
GREENTEA_SETUP(45, "sync_on_reset");
utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases);
if (status != utest::v1::STATUS_CONTINUE) {
return status;
}
char key[MSG_KEY_LEN + 1] = { };
char value[MSG_VALUE_LEN + 1] = { };
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY);
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
if (strcmp(key, MSG_KEY_START_CASE) != 0) {
utest_printf("Invalid message key.\n");
return utest::v1::STATUS_ABORT;
}
char *tailptr = NULL;
CASE_INDEX_START = (int) strtol(value, &tailptr, 10);
if (*tailptr != '\0' || CASE_INDEX_START < 0) {
utest_printf("Invalid start case index received from host\n");
return utest::v1::STATUS_ABORT;
}
// The thread is started here, but feeding the watchdog will start
// when the semaphore is released during a test case teardown.
wdg_kicking_thread.start(mbed::callback(wdg_kicking_thread_fun));
utest_printf("Starting with test case index %i of all %i defined test cases.\n", CASE_INDEX_START, number_of_cases);
return CASE_INDEX_START;
}
Case cases[] = {
Case("max_timeout is valid", test_max_timeout_is_valid),
Case("Stop", test_stop),
Case("Restart multiple times",
(utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
test_restart, (utest::v1::case_teardown_handler_t) case_teardown_wdg_stop_or_reset),
Case("Start, 100 ms", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
test_start<100UL>, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset),
Case("Start, max_timeout", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
test_start_max_timeout, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset),
};
Specification specification((utest::v1::test_setup_handler_t) testsuite_setup_sync_on_reset, cases);
int main()
{
// Harness will start with a test case index provided by host script.
return !Harness::run(specification);
}

View File

@ -0,0 +1,69 @@
/*
* 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.
*/
#ifndef MBED_DRIVERS_WATCHDOG_RESET_TESTS_H
#define MBED_DRIVERS_WATCHDOG_RESET_TESTS_H
#if DEVICE_WATCHDOG
/** Test Watchdog reset
*
* Given a device with a Watchdog started,
* when a Watchdog timeout expires,
* then the device is restarted.
*/
void test_simple_reset();
/** Test Watchdog reset in sleep mode
*
* Given a device with a Watchdog started,
* when the Watchdog timeout expires while the device is in sleep mode,
* then the device is restarted.
*/
void test_sleep_reset();
/** Test Watchdog reset in deepsleep mode
*
* Given a device with a Watchdog started,
* when the Watchdog timeout expires while the device is in deepsleep mode,
* then the device is restarted.
*/
void test_deepsleep_reset();
/** Test Watchdog reset after Watchdog restart
*
* Given a device with a Watchdog started,
* when the Watchdog is stopped before its timeout expires,
* then the device is not restarted.
* When the Watchdog is started again and its timeout expires,
* then the device is restarted.
*/
void test_restart_reset();
/** Test Watchdog kick
*
* Given a device with a Watchdog started,
* when the Watchdog is kicked before its timeout expires,
* then the device restart is prevented.
* When the Watchdog is *NOT* kicked again before next timeout expires,
* then the device is restarted.
*/
void test_kick_reset();
#endif
#endif

View File

@ -0,0 +1,321 @@
/*
* 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.
*/
#if !DEVICE_WATCHDOG
#error [NOT_SUPPORTED] Watchdog not supported for this target
#endif
#include "greentea-client/test_env.h"
#include "utest/utest.h"
#include "unity/unity.h"
#include "drivers/Watchdog.h"
#include "Watchdog_reset_tests.h"
#include "mbed.h"
#define TIMEOUT_MS 100UL
#define KICK_ADVANCE_MS 10UL
#define MSG_VALUE_DUMMY "0"
#define CASE_DATA_INVALID 0xffffffffUL
#define CASE_DATA_PHASE2_OK 0xfffffffeUL
#define MSG_VALUE_LEN 24
#define MSG_KEY_LEN 24
#define MSG_KEY_DEVICE_READY "ready"
#define MSG_KEY_START_CASE "start_case"
#define MSG_KEY_DEVICE_RESET "dev_reset"
/* To prevent a loss of Greentea data, the serial buffers have to be flushed
* before the UART peripheral shutdown. The UART shutdown happens when the
* device is entering the deepsleep mode or performing a reset.
*
* With the current API, it is not possible to check if the hardware buffers
* are empty. However, it is possible to determine the time required for the
* buffers to flush.
*
* Take NUMAKER_PFM_NUC472 as an example:
* The UART peripheral has 16-byte Tx FIFO. With a baud rate set to 9600,
* flushing the Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 ms.
* To be on the safe side, set the wait time to 20 ms.
*/
#define SERIAL_FLUSH_TIME_MS 20
using utest::v1::Case;
using utest::v1::Specification;
using utest::v1::Harness;
using namespace mbed;
struct testcase_data {
int index;
int start_index;
uint32_t received_data;
};
void release_sem(Semaphore *sem)
{
sem->release();
}
testcase_data current_case;
bool send_reset_notification(testcase_data *tcdata, uint32_t delay_ms)
{
char msg_value[12];
int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms);
if (str_len != (sizeof msg_value) - 1) {
utest_printf("Failed to compose a value string to be sent to host.");
return false;
}
greentea_send_kv(MSG_KEY_DEVICE_RESET, msg_value);
return true;
}
void test_simple_reset()
{
// Phase 2. -- verify the test results.
// Verify if this test case passed based on data received from host.
if (current_case.received_data != CASE_DATA_INVALID) {
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
current_case.received_data = CASE_DATA_INVALID;
return;
}
// Phase 1. -- run the test code.
// Init the watchdog and wait for a device reset.
if (send_reset_notification(&current_case, 2 * TIMEOUT_MS) == false) {
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
return;
}
Watchdog &watchdog = Watchdog::get_instance();
TEST_ASSERT_FALSE(watchdog.is_running());
TEST_ASSERT_TRUE(watchdog.start(TIMEOUT_MS));
TEST_ASSERT_TRUE(watchdog.is_running());
// Watchdog should fire before twice the timeout value.
wait_ms(2 * TIMEOUT_MS); // Device reset expected.
// Watchdog reset should have occurred during wait_ms() above;
watchdog.kick(); // Just to buy some time for testsuite failure handling.
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
}
#if DEVICE_SLEEP
void test_sleep_reset()
{
// Phase 2. -- verify the test results.
if (current_case.received_data != CASE_DATA_INVALID) {
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
current_case.received_data = CASE_DATA_INVALID;
return;
}
// Phase 1. -- run the test code.
Semaphore sem(0, 1);
Timeout timeout;
if (send_reset_notification(&current_case, 2 * TIMEOUT_MS) == false) {
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
return;
}
Watchdog &watchdog = Watchdog::get_instance();
TEST_ASSERT_FALSE(watchdog.is_running());
TEST_ASSERT_TRUE(watchdog.start(TIMEOUT_MS));
TEST_ASSERT_TRUE(watchdog.is_running());
sleep_manager_lock_deep_sleep();
// Watchdog should fire before twice the timeout value.
timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (2 * TIMEOUT_MS));
if (sleep_manager_can_deep_sleep()) {
TEST_ASSERT_MESSAGE(0, "Deepsleep should be disallowed.");
return;
}
sem.wait(); // Device reset expected.
sleep_manager_unlock_deep_sleep();
// Watchdog reset should have occurred during sem.wait() (sleep) above;
watchdog.kick(); // Just to buy some time for testsuite failure handling.
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
}
#if DEVICE_LOWPOWERTIMER
void test_deepsleep_reset()
{
// Phase 2. -- verify the test results.
if (current_case.received_data != CASE_DATA_INVALID) {
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
current_case.received_data = CASE_DATA_INVALID;
return;
}
// Phase 1. -- run the test code.
Semaphore sem(0, 1);
LowPowerTimeout lp_timeout;
if (send_reset_notification(&current_case, 2 * TIMEOUT_MS) == false) {
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
return;
}
Watchdog &watchdog = Watchdog::get_instance();
TEST_ASSERT_FALSE(watchdog.is_running());
TEST_ASSERT_TRUE(watchdog.start(TIMEOUT_MS));
TEST_ASSERT_TRUE(watchdog.is_running());
// Watchdog should fire before twice the timeout value.
lp_timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (2 * TIMEOUT_MS));
wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush.
if (!sleep_manager_can_deep_sleep()) {
TEST_ASSERT_MESSAGE(0, "Deepsleep should be allowed.");
}
sem.wait(); // Device reset expected.
// Watchdog reset should have occurred during sem.wait() (deepsleep) above;
watchdog.kick(); // Just to buy some time for testsuite failure handling.
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
}
#endif
#endif
void test_restart_reset()
{
watchdog_features_t features = hal_watchdog_get_platform_features();
if (!features.disable_watchdog) {
TEST_IGNORE_MESSAGE("Disabling Watchdog not supported for this platform");
return;
}
// Phase 2. -- verify the test results.
if (current_case.received_data != CASE_DATA_INVALID) {
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
current_case.received_data = CASE_DATA_INVALID;
return;
}
// Phase 1. -- run the test code.
Watchdog &watchdog = Watchdog::get_instance();
TEST_ASSERT_FALSE(watchdog.is_running());
TEST_ASSERT_TRUE(watchdog.start(TIMEOUT_MS));
TEST_ASSERT_TRUE(watchdog.is_running());
wait_ms(TIMEOUT_MS / 2UL);
TEST_ASSERT_TRUE(watchdog.stop());
TEST_ASSERT_FALSE(watchdog.is_running());
// Check that stopping the Watchdog prevents a device reset.
// The watchdog should trigger at, or after the timeout value.
// The watchdog should trigger before twice the timeout value.
wait_ms(TIMEOUT_MS / 2UL + TIMEOUT_MS);
if (send_reset_notification(&current_case, 2 * TIMEOUT_MS) == false) {
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
return;
}
TEST_ASSERT_TRUE(watchdog.start(TIMEOUT_MS));
TEST_ASSERT_TRUE(watchdog.is_running());
// Watchdog should fire before twice the timeout value.
wait_ms(2 * TIMEOUT_MS); // Device reset expected.
// Watchdog reset should have occurred during that wait() above;
watchdog.kick(); // Just to buy some time for testsuite failure handling.
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
}
void test_kick_reset()
{
// Phase 2. -- verify the test results.
if (current_case.received_data != CASE_DATA_INVALID) {
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
current_case.received_data = CASE_DATA_INVALID;
return;
}
// Phase 1. -- run the test code.
Watchdog &watchdog = Watchdog::get_instance();
TEST_ASSERT_FALSE(watchdog.is_running());
TEST_ASSERT_TRUE(watchdog.start(TIMEOUT_MS));
TEST_ASSERT_TRUE(watchdog.is_running());
for (int i = 3; i; i--) {
// The reset is prevented as long as the watchdog is kicked
// anytime before the timeout.
wait_ms(TIMEOUT_MS - KICK_ADVANCE_MS);
watchdog.kick();
}
if (send_reset_notification(&current_case, 2 * TIMEOUT_MS) == false) {
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
return;
}
// Watchdog should fire before twice the timeout value.
wait_ms(2 * TIMEOUT_MS); // Device reset expected.
// Watchdog reset should have occurred during that wait() above;
watchdog.kick(); // Just to buy some time for testsuite failure handling.
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
}
utest::v1::status_t case_setup(const Case *const source, const size_t index_of_case)
{
current_case.index = index_of_case;
return utest::v1::greentea_case_setup_handler(source, index_of_case);
}
int testsuite_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(90, "watchdog_reset");
utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases);
if (status != utest::v1::STATUS_CONTINUE) {
return status;
}
char key[MSG_KEY_LEN + 1] = { };
char value[MSG_VALUE_LEN + 1] = { };
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY);
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
if (strcmp(key, MSG_KEY_START_CASE) != 0) {
utest_printf("Invalid message key.\n");
return utest::v1::STATUS_ABORT;
}
int num_args = sscanf(value, "%02x,%08lx", &(current_case.start_index), &(current_case.received_data));
if (num_args == 0 || num_args == EOF) {
utest_printf("Invalid data received from host\n");
return utest::v1::STATUS_ABORT;
}
utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases,
current_case.start_index);
return current_case.start_index;
}
Case cases[] = {
Case("Watchdog reset", case_setup, test_simple_reset),
#if DEVICE_SLEEP
Case("Watchdog reset in sleep mode", case_setup, test_sleep_reset),
#if DEVICE_LOWPOWERTIMER
Case("Watchdog reset in deepsleep mode", case_setup, test_deepsleep_reset),
#endif
#endif
Case("Watchdog started again", case_setup, test_restart_reset),
Case("Kicking the Watchdog prevents reset", case_setup, test_kick_reset),
};
Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases);
int main()
{
// Harness will start with a test case index provided by host script.
return !Harness::run(specification);
}

View File

@ -30,12 +30,11 @@
#include "hal/lp_ticker_api.h"
#include "hal/mbed_lp_ticker_wrapper.h"
#if !DEVICE_USTICKER
#if defined(SKIP_TIME_DRIFT_TESTS)
#error [NOT_SUPPORTED] test not supported
#endif
//FastModels not support time drifting test
#if defined(__ARM_FM)
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] test not supported
#endif

View File

@ -69,7 +69,7 @@ Case cases[] = {
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(10, "timing_drift_auto");
GREENTEA_SETUP(10, "default_auto");
return utest::v1::greentea_test_setup_handler(number_of_cases);
}

View File

@ -113,7 +113,7 @@
#define QUAD_IO_ENABLE() \
#define EXTENDED_SPI_ENABLE() \
\
const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \
uint8_t reg_data[reg_size] = { 0 }; \
@ -150,7 +150,7 @@
#define QUAD_IO_DISABLE() \
#define EXTENDED_SPI_DISABLE() \
\
const int32_t reg_size = QSPI_STATUS_REG_SIZE + QSPI_CONFIG_REG_0_SIZE; \
uint8_t reg_data[reg_size] = { 0 }; \

View File

@ -26,8 +26,6 @@
#include "flash_configs/flash_configs.h"
#include "mbed.h"
static qspi_status_t quad_io_enable(Qspi &qspi);
static qspi_status_t quad_io_disable(Qspi &qspi);
static qspi_status_t extended_enable(Qspi &qspi);
static qspi_status_t extended_disable(Qspi &qspi);
static qspi_status_t dual_enable(Qspi &qspi);
@ -203,9 +201,7 @@ qspi_status_t erase(uint32_t erase_cmd, uint32_t flash_addr, Qspi &qspi)
qspi_status_t mode_enable(Qspi &qspi, qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width)
{
if (is_quad_io_mode(inst_width, addr_width, data_width)) {
return quad_io_enable(qspi);
} else if (is_extended_mode(inst_width, addr_width, data_width)) {
if (is_extended_mode(inst_width, addr_width, data_width)) {
return extended_enable(qspi);
} else if (is_dual_mode(inst_width, addr_width, data_width)) {
return dual_enable(qspi);
@ -218,9 +214,7 @@ qspi_status_t mode_enable(Qspi &qspi, qspi_bus_width_t inst_width, qspi_bus_widt
qspi_status_t mode_disable(Qspi &qspi, qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width)
{
if (is_quad_io_mode(inst_width, addr_width, data_width)) {
return quad_io_disable(qspi);
} else if (is_extended_mode(inst_width, addr_width, data_width)) {
if (is_extended_mode(inst_width, addr_width, data_width)) {
return extended_disable(qspi);
} else if (is_dual_mode(inst_width, addr_width, data_width)) {
return dual_disable(qspi);
@ -231,24 +225,6 @@ qspi_status_t mode_disable(Qspi &qspi, qspi_bus_width_t inst_width, qspi_bus_wid
}
}
static qspi_status_t quad_io_enable(Qspi &qspi)
{
#ifdef QUAD_IO_ENABLE
QUAD_IO_ENABLE();
#else
return QSPI_STATUS_OK;
#endif
}
static qspi_status_t quad_io_disable(Qspi &qspi)
{
#ifdef QUAD_IO_DISABLE
QUAD_IO_DISABLE();
#else
return QSPI_STATUS_OK;
#endif
}
static qspi_status_t extended_enable(Qspi &qspi)
{
#ifdef EXTENDED_SPI_ENABLE
@ -322,11 +298,6 @@ qspi_status_t fast_mode_disable(Qspi &qspi)
#endif
}
bool is_quad_io_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width)
{
return (inst_width == QSPI_CFG_BUS_SINGLE) && ((addr_width == QSPI_CFG_BUS_QUAD) || (data_width == QSPI_CFG_BUS_QUAD));
}
bool is_extended_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width)
{
return (inst_width == QSPI_CFG_BUS_SINGLE) && ((addr_width != QSPI_CFG_BUS_SINGLE) || (data_width != QSPI_CFG_BUS_SINGLE));

View File

@ -150,7 +150,6 @@ qspi_status_t fast_mode_disable(Qspi &qspi);
qspi_status_t erase(uint32_t erase_cmd, uint32_t flash_addr, Qspi &qspi);
bool is_quad_io_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width);
bool is_extended_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width);
bool is_dual_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width);
bool is_quad_mode(qspi_bus_width_t inst_width, qspi_bus_width_t addr_width, qspi_bus_width_t data_width);

View File

@ -0,0 +1,150 @@
/*
* 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.
*/
#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
#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"
/* To prevent loss of Greentea data, flush serial buffers before the UART peripheral shutdown. The UART shutdown happens when the
* device is entering the deepsleep mode or performing a reset.
*
* With the current API, it is not possible to check if the hardware buffers
* are empty. However, you can determine the amount of time required for the
* buffers to flush.
*
* For example, NUMAKER_PFM_NUC472:
* The UART peripheral has 16-byte Tx FIFO. With a baud rate of 9600,
* flushing the Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 ms.
* To be on the safe side, set the wait time to 20 ms.
*/
#define SERIAL_FLUSH_TIME_MS 20
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(SERIAL_FLUSH_TIME_MS); // 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(SERIAL_FLUSH_TIME_MS); // 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(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value.
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,49 @@
/*
* 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.
*/
/**
* @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,
* then the device returns a correct reset reason for every restart.
*/
void test_reset_reason();
#ifdef __cplusplus
}
#endif
#endif
#endif
/** @}*/

View File

@ -122,8 +122,27 @@ void deepsleep_lpticker_test()
lp_ticker_set_interrupt(next_match_timestamp);
/* On some targets like STM family boards with LPTIM enabled there is a required delay (~100 us) before we are able to
reprogram LPTIM_COMPARE register back to back. This is handled by the low level lp ticker wrapper which uses LPTIM_CMPOK interrupt.
CMPOK fires when LPTIM_COMPARE register can be safely reprogrammed again. During this period deep-sleep is locked.
This means that on these platforms we have additional interrupt (CMPOK) fired always ~100 us after programming lp ticker.
Since this interrupt wakes-up the board from the sleep we need to go to sleep after CMPOK is handled. */
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check());
sleep();
/* On some targets like STM family boards with LPTIM enabled an interrupt is triggered on counter rollover.
We need special handling for cases when next_match_timestamp < start_timestamp (interrupt is to be fired after rollover).
In such case after first wake-up we need to reset interrupt and go back to sleep waiting for the valid one.
NOTE: Above comment (CMPOK) applies also here.*/
#if MBED_CONF_TARGET_LPTICKER_LPTIM
if ((next_match_timestamp < start_timestamp) && lp_ticker_read() < next_match_timestamp) {
lp_ticker_set_interrupt(next_match_timestamp);
wait_ns(200000);
sleep();
}
#endif
const timestamp_t wakeup_timestamp = lp_ticker_read();
sprintf(info, "Delta ticks: %u, Ticker width: %u, Expected wake up tick: %d, Actual wake up tick: %d, delay ticks: %d, wake up after ticks: %d",
@ -154,11 +173,14 @@ void deepsleep_high_speed_clocks_turned_off_test()
TEST_ASSERT_TRUE_MESSAGE(sleep_manager_can_deep_sleep(), "deep sleep should not be locked");
const unsigned int us_ticks_before_sleep = us_ticker_read();
const timestamp_t wakeup_time = lp_ticker_read() + us_to_ticks(20000, lp_ticker_freq);
lp_ticker_set_interrupt(wakeup_time);
/* Wait for CMPOK */
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check());
const unsigned int us_ticks_before_sleep = us_ticker_read();
sleep();
const unsigned int us_ticks_after_sleep = us_ticker_read();

View File

@ -28,12 +28,34 @@
#define SLEEP_DURATION_US 20000ULL
#define DEEP_SLEEP_TEST_CHECK_WAIT_US 2000
#define DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US 500
// As sleep_manager_can_deep_sleep_test_check() is based on wait_ns
// and wait_ns can be up to 40% slower, use a 50% delta here.
#define DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US 1000
using utest::v1::Case;
using utest::v1::Specification;
using utest::v1::Harness;
#if DEVICE_LPTICKER
/* Make sure there are enough ticks to cope with more than SLEEP_DURATION_US sleep
* without hitting the wrap-around.
*/
void wraparound_lp_protect(void)
{
const uint32_t ticks_now = get_lp_ticker_data()->interface->read();
const ticker_info_t *p_ticker_info = get_lp_ticker_data()->interface->get_info();
const uint32_t max_count = ((1 << p_ticker_info->bits) - 1);
const uint32_t delta_ticks = us_to_ticks(SLEEP_DURATION_US * 1.5, p_ticker_info->frequency);
if (ticks_now < (max_count - delta_ticks)) {
return;
}
while (get_lp_ticker_data()->interface->read() > (max_count - delta_ticks));
}
#endif
void test_lock_unlock()
{
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
@ -62,8 +84,6 @@ void test_lock_eq_ushrt_max()
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
}
#if DEVICE_LPTICKER
#if DEVICE_USTICKER
utest::v1::status_t testcase_setup(const Case *const source, const size_t index_of_case)
{
// Suspend the RTOS kernel scheduler to prevent interference with duration of sleep.
@ -98,6 +118,8 @@ utest::v1::status_t testcase_teardown(const Case *const source, const size_t pas
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
}
#if DEVICE_LPTICKER
#if DEVICE_USTICKER
/* This test is based on the fact that the high-speed clocks are turned off
* in deep sleep mode but remain on in the ordinary sleep mode. Low-speed
* clocks stay on for both sleep and deep sleep modes.
@ -115,10 +137,18 @@ void test_sleep_auto()
const ticker_irq_handler_type lp_ticker_irq_handler_org = set_lp_ticker_irq_handler(lp_ticker_isr);
us_timestamp_t us_ts1, us_ts2, lp_ts1, lp_ts2, us_diff1, us_diff2, lp_diff1, lp_diff2;
sleep_manager_lock_deep_sleep();
/* Let's avoid the Lp ticker wrap-around case */
wraparound_lp_protect();
uint32_t lp_wakeup_ts_raw = lp_ticker_read() + us_to_ticks(SLEEP_DURATION_US, lp_ticker_info->frequency);
timestamp_t lp_wakeup_ts = overflow_protect(lp_wakeup_ts_raw, lp_ticker_info->bits);
lp_ticker_set_interrupt(lp_wakeup_ts);
/* Some targets may need an interrupt short time after LPTIM interrupt is
* set and forbid deep_sleep during that period. Let this period pass */
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check());
sleep_manager_lock_deep_sleep();
us_ts1 = ticks_to_us(us_ticker_read(), us_ticker_info->frequency);
lp_ts1 = ticks_to_us(lp_ticker_read(), lp_ticker_info->frequency);
@ -144,13 +174,21 @@ void test_sleep_auto()
// Wait for hardware serial buffers to flush.
busy_wait_ms(SERIAL_FLUSH_TIME_MS);
/* Let's avoid the Lp ticker wrap-around case */
wraparound_lp_protect();
lp_wakeup_ts_raw = lp_ticker_read() + us_to_ticks(SLEEP_DURATION_US, lp_ticker_info->frequency);
lp_wakeup_ts = overflow_protect(lp_wakeup_ts_raw, lp_ticker_info->bits);
lp_ticker_set_interrupt(lp_wakeup_ts);
/* Some targets may need an interrupt short time after LPTIM interrupt is
* set and forbid deep_sleep during that period. Let this period pass */
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check());
us_ts1 = ticks_to_us(us_ticker_read(), us_ticker_info->frequency);
lp_ts1 = ticks_to_us(lp_ticker_read(), lp_ticker_info->frequency);
sleep_manager_sleep_auto();
us_ts2 = ticks_to_us(us_ticker_read(), us_ticker_info->frequency);
us_diff2 = (us_ts1 <= us_ts2) ? (us_ts2 - us_ts1) : (us_ticker_mask - us_ts1 + us_ts2 + 1);
lp_ts2 = ticks_to_us(lp_ticker_read(), lp_ticker_info->frequency);
@ -175,36 +213,62 @@ void test_sleep_auto()
}
#endif
#define US_PER_S 1000000
uint32_t diff_us(uint32_t start_ticks, uint32_t stop_ticks, const ticker_info_t *info)
{
uint32_t counter_mask = ((1 << info->bits) - 1);
uint32_t diff_ticks = ((stop_ticks - start_ticks) & counter_mask);
return (uint32_t)((uint64_t) diff_ticks * US_PER_S / info->frequency);
}
volatile bool unlock_deep_sleep = false;
void ticker_event_handler_stub(const ticker_data_t *const ticker)
{
lp_ticker_clear_interrupt();
if (unlock_deep_sleep) {
sleep_manager_unlock_deep_sleep_internal();
unlock_deep_sleep = false;
}
}
ticker_irq_handler_type prev_irq_handler;
void test_lock_unlock_test_check()
{
// Make sure HAL tickers are initialized.
ticker_read(get_us_ticker_data());
ticker_read(get_lp_ticker_data());
prev_irq_handler = set_lp_ticker_irq_handler(ticker_event_handler_stub);
for (int i = 0; i < 1000; i++) {
wraparound_lp_protect();
const ticker_info_t *p_ticker_info = get_lp_ticker_data()->interface->get_info();
// Use LowPowerTimer instead of Timer to prevent deep sleep lock.
LowPowerTimer lp_timer;
us_timestamp_t exec_time_unlocked, exec_time_locked;
LowPowerTimeout lp_timeout;
uint32_t start, stop;
// Deep sleep unlocked:
// * sleep_manager_can_deep_sleep() returns true,
// * sleep_manager_can_deep_sleep_test_check() returns true instantly.
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
lp_timer.start();
start = lp_ticker_read();
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check());
lp_timer.stop();
exec_time_unlocked = lp_timer.read_high_resolution_us();
stop = lp_ticker_read();
exec_time_unlocked = diff_us(start, stop, p_ticker_info);
// Deep sleep locked:
// * sleep_manager_can_deep_sleep() returns false,
// * sleep_manager_can_deep_sleep_test_check() returns false with 2 ms delay.
sleep_manager_lock_deep_sleep();
TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep());
lp_timer.reset();
lp_timer.start();
start = lp_ticker_read();
TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep_test_check());
lp_timer.stop();
exec_time_locked = lp_timer.read_high_resolution_us();
stop = lp_ticker_read();
exec_time_locked = diff_us(start, stop, p_ticker_info);
TEST_ASSERT_UINT64_WITHIN(DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US, DEEP_SLEEP_TEST_CHECK_WAIT_US,
exec_time_locked - exec_time_unlocked);
@ -212,28 +276,43 @@ void test_lock_unlock_test_check()
// * sleep_manager_can_deep_sleep() returns false,
// * sleep_manager_can_deep_sleep_test_check() returns true with a 1 ms delay,
// * sleep_manager_can_deep_sleep() returns true when checked again.
lp_timer.reset();
lp_timeout.attach_us(mbed::callback(sleep_manager_unlock_deep_sleep_internal),
DEEP_SLEEP_TEST_CHECK_WAIT_US / 2);
lp_timer.start();
unlock_deep_sleep = true;
/* Let's avoid the Lp ticker wrap-around case */
wraparound_lp_protect();
start = lp_ticker_read();
uint32_t lp_wakeup_ts_raw = start + us_to_ticks(DEEP_SLEEP_TEST_CHECK_WAIT_US / 2, p_ticker_info->frequency);
timestamp_t lp_wakeup_ts = overflow_protect(lp_wakeup_ts_raw, p_ticker_info->bits);
lp_ticker_set_interrupt(lp_wakeup_ts);
// Extra wait after setting interrupt to handle CMPOK
wait_ns(100000);
TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep());
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check());
lp_timer.stop();
TEST_ASSERT_UINT64_WITHIN(DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US, DEEP_SLEEP_TEST_CHECK_WAIT_US / 2,
lp_timer.read_high_resolution_us());
stop = lp_ticker_read();
TEST_ASSERT(diff_us(start, stop, p_ticker_info) > 0UL);
TEST_ASSERT(diff_us(start, stop, p_ticker_info) < DEEP_SLEEP_TEST_CHECK_WAIT_US);
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
}
set_lp_ticker_irq_handler(prev_irq_handler);
}
#endif
utest::v1::status_t testsuite_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(10, "default_auto");
GREENTEA_SETUP(15, "default_auto");
return utest::v1::greentea_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("deep sleep lock/unlock", test_lock_unlock),
Case("deep sleep locked USHRT_MAX times", test_lock_eq_ushrt_max),
Case("deep sleep lock/unlock",
(utest::v1::case_setup_handler_t) testcase_setup,
test_lock_unlock,
(utest::v1::case_teardown_handler_t) testcase_teardown),
Case("deep sleep locked USHRT_MAX times",
(utest::v1::case_setup_handler_t) testcase_setup,
test_lock_eq_ushrt_max,
(utest::v1::case_teardown_handler_t) testcase_teardown),
#if DEVICE_LPTICKER
#if DEVICE_USTICKER
Case("sleep_auto calls sleep/deep sleep based on lock",
@ -241,7 +320,10 @@ Case cases[] = {
test_sleep_auto,
(utest::v1::case_teardown_handler_t) testcase_teardown),
#endif
Case("deep sleep lock/unlock test_check", test_lock_unlock_test_check),
Case("deep sleep lock/unlock test_check",
(utest::v1::case_setup_handler_t) testcase_setup,
test_lock_unlock_test_check,
(utest::v1::case_teardown_handler_t) testcase_teardown)
#endif
};

View File

@ -23,8 +23,8 @@
#error [NOT_SUPPORTED] this test is supported on GCC only
#endif
#if defined(__CORTEX_M33)
#error [NOT_SUPPORTED] Cannot run on M33 core as SecureFault is implemented in secure-side and cant be remapped
#if DOMAIN_NS == 1
#error [NOT_SUPPORTED] Cannot run on M23/M33 core as SecureFault is implemented in secure-side and cant be remapped
#endif
#include "utest/utest.h"

View File

@ -34,6 +34,11 @@ void us_ticker_info_test()
TEST_ASSERT(p_ticker_info->frequency >= 250000);
TEST_ASSERT(p_ticker_info->frequency <= 8000000);
TEST_ASSERT(p_ticker_info->bits >= 16);
#ifdef US_TICKER_PERIOD_NUM
TEST_ASSERT_UINT32_WITHIN(1, 1000000 * US_TICKER_PERIOD_DEN / US_TICKER_PERIOD_NUM, p_ticker_info->frequency);
TEST_ASSERT_EQUAL_UINT32(US_TICKER_MASK, ((uint64_t)1 << p_ticker_info->bits) - 1);
#endif
}
utest::v1::status_t test_setup(const size_t number_of_cases)

View File

@ -0,0 +1,285 @@
/*
* 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.
*/
#if !DEVICE_WATCHDOG
#error [NOT_SUPPORTED] Watchdog not supported for this target
#endif
#include "greentea-client/test_env.h"
#include "hal/watchdog_api.h"
#include "mbed_wait_api.h"
#include "unity/unity.h"
#include "utest/utest.h"
#include "watchdog_api_tests.h"
#include "mbed.h"
#include <stdlib.h>
/* The shortest timeout value, this test suite is able to handle correctly. */
#define WDG_MIN_TIMEOUT_MS 50UL
// Do not set watchdog timeout shorter than WDG_MIN_TIMEOUT_MS, as it may
// cause the host-test-runner return 'TIMEOUT' instead of 'FAIL' / 'PASS'
// if watchdog performs reset during test suite teardown.
#define WDG_TIMEOUT_MS 100UL
#define MSG_VALUE_DUMMY "0"
#define MSG_VALUE_LEN 24
#define MSG_KEY_LEN 24
#define MSG_KEY_DEVICE_READY "ready"
#define MSG_KEY_START_CASE "start_case"
#define MSG_KEY_DEVICE_RESET "reset_on_case_teardown"
/* To prevent a loss of Greentea data, the serial buffers have to be flushed
* before the UART peripheral shutdown. The UART shutdown happens when the
* device is entering the deepsleep mode or performing a reset.
*
* With the current API, it is not possible to check if the hardware buffers
* are empty. However, it is possible to determine the time required for the
* buffers to flush.
*
* Take NUMAKER_PFM_NUC472 as an example:
* The UART peripheral has 16-byte Tx FIFO. With a baud rate set to 9600,
* flushing the Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 ms.
* To be on the safe side, set the wait time to 20 ms.
*/
#define SERIAL_FLUSH_TIME_MS 20
int CASE_INDEX_START;
int CASE_INDEX_CURRENT;
bool CASE_IGNORED = false;
using utest::v1::Case;
using utest::v1::Specification;
using utest::v1::Harness;
const watchdog_config_t WDG_CONFIG_DEFAULT = { .timeout_ms = WDG_TIMEOUT_MS };
Thread wdg_kicking_thread;
Semaphore kick_wdg_during_test_teardown(0, 1);
void wdg_kicking_thread_fun()
{
kick_wdg_during_test_teardown.wait();
while (true) {
hal_watchdog_kick();
wait_ms(20);
}
}
void test_max_timeout_is_valid()
{
TEST_ASSERT(hal_watchdog_get_platform_features().max_timeout > 1UL);
}
void test_restart_is_possible()
{
watchdog_features_t features = hal_watchdog_get_platform_features();
if (!features.disable_watchdog) {
CASE_IGNORED = true;
TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform");
return;
}
TEST_ASSERT(features.update_config);
}
void test_stop()
{
watchdog_features_t features = hal_watchdog_get_platform_features();
if (!features.disable_watchdog) {
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_NOT_SUPPORTED, hal_watchdog_stop());
CASE_IGNORED = true;
TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform");
return;
}
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop());
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&WDG_CONFIG_DEFAULT));
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop());
// Make sure that a disabled watchdog does not reset the core.
wait_ms(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value.
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop());
}
void test_update_config()
{
watchdog_features_t features = hal_watchdog_get_platform_features();
if (!features.update_config) {
CASE_IGNORED = true;
TEST_IGNORE_MESSAGE("Updating watchdog config not supported for this platform");
return;
}
watchdog_config_t config = WDG_CONFIG_DEFAULT;
uint32_t timeouts[] = {
features.max_timeout / 4,
features.max_timeout / 8,
features.max_timeout / 16
};
int num_timeouts = sizeof timeouts / sizeof timeouts[0];
for (size_t i = 0; i < num_timeouts; i++) {
if (timeouts[i] < WDG_MIN_TIMEOUT_MS) {
CASE_IGNORED = true;
TEST_IGNORE_MESSAGE("Requested timeout value is too short -- ignoring test case.");
return;
}
config.timeout_ms = timeouts[i];
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
uint32_t reload_value = hal_watchdog_get_reload_value();
// The watchdog should trigger at, or after the timeout value.
TEST_ASSERT(reload_value >= timeouts[i]);
// The watchdog should trigger before twice the timeout value.
TEST_ASSERT(reload_value < 2 * timeouts[i]);
}
}
utest::v1::status_t case_setup_sync_on_reset(const Case *const source, const size_t index_of_case)
{
CASE_INDEX_CURRENT = index_of_case;
CASE_IGNORED = false;
return utest::v1::greentea_case_setup_handler(source, index_of_case);
}
utest::v1::status_t case_teardown_sync_on_reset(const Case *const source, const size_t passed, const size_t failed,
const utest::v1::failure_t failure)
{
if (CASE_IGNORED) {
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
}
// Unlock kicking the watchdog during teardown.
kick_wdg_during_test_teardown.release();
utest::v1::status_t status = utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
if (failed) {
/* Return immediately and skip the device reset, if the test case failed.
* Provided that the device won't be restarted by other means (i.e. watchdog timer),
* this should allow the test suite to finish in a defined manner
* and report failure to host.
* In case of watchdog reset during test suite teardown, the loss of serial
* connection is possible, so the host-test-runner may return 'TIMEOUT'
* instead of 'FAIL'.
*/
return status;
}
greentea_send_kv(MSG_KEY_DEVICE_RESET, CASE_INDEX_START + CASE_INDEX_CURRENT);
utest_printf("The device will now restart.\n");
wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush.
NVIC_SystemReset();
return status; // Reset is instant so this line won't be reached.
}
utest::v1::status_t case_teardown_wdg_stop_or_reset(const Case *const source, const size_t passed, const size_t failed,
const utest::v1::failure_t failure)
{
if (CASE_IGNORED) {
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
}
watchdog_features_t features = hal_watchdog_get_platform_features();
if (features.disable_watchdog) {
hal_watchdog_stop();
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
}
return case_teardown_sync_on_reset(source, passed, failed, failure);
}
template<uint32_t timeout_ms>
void test_init()
{
if (timeout_ms < WDG_MIN_TIMEOUT_MS) {
CASE_IGNORED = true;
TEST_IGNORE_MESSAGE("Requested timeout value is too short -- ignoring test case.");
return;
}
watchdog_config_t config = { .timeout_ms = timeout_ms };
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
uint32_t reload_value = hal_watchdog_get_reload_value();
// The watchdog should trigger at, or after the timeout value.
TEST_ASSERT(reload_value >= timeout_ms);
// The watchdog should trigger before twice the timeout value.
TEST_ASSERT(reload_value < 2 * timeout_ms);
}
void test_init_max_timeout()
{
watchdog_features_t features = hal_watchdog_get_platform_features();
watchdog_config_t config = { .timeout_ms = features.max_timeout };
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
// The watchdog should trigger at, or after the timeout value.
TEST_ASSERT(hal_watchdog_get_reload_value() >= features.max_timeout);
}
int testsuite_setup_sync_on_reset(const size_t number_of_cases)
{
GREENTEA_SETUP(45, "sync_on_reset");
utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases);
if (status != utest::v1::STATUS_CONTINUE) {
return status;
}
char key[MSG_KEY_LEN + 1] = { };
char value[MSG_VALUE_LEN + 1] = { };
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY);
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
if (strcmp(key, MSG_KEY_START_CASE) != 0) {
utest_printf("Invalid message key.\n");
return utest::v1::STATUS_ABORT;
}
char *tailptr = NULL;
CASE_INDEX_START = (int) strtol(value, &tailptr, 10);
if (*tailptr != '\0' || CASE_INDEX_START < 0) {
utest_printf("Invalid start case index received from host\n");
return utest::v1::STATUS_ABORT;
}
// The thread is started here, but feeding the watchdog will start
// when the semaphore is released during a test case teardown.
wdg_kicking_thread.start(mbed::callback(wdg_kicking_thread_fun));
utest_printf("Starting with test case index %i of all %i defined test cases.\n", CASE_INDEX_START, number_of_cases);
return CASE_INDEX_START;
}
Case cases[] = {
Case("Platform feature max_timeout is valid", test_max_timeout_is_valid),
Case("Stopped watchdog can be started again", test_restart_is_possible),
Case("Watchdog can be stopped", test_stop),
Case("Update config with multiple init calls",
(utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
test_update_config,
(utest::v1::case_teardown_handler_t) case_teardown_wdg_stop_or_reset),
Case("Init, 100 ms", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
test_init<100UL>, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset),
Case("Init, max_timeout", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset,
test_init_max_timeout, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset),
};
Specification specification((utest::v1::test_setup_handler_t) testsuite_setup_sync_on_reset, cases);
int main()
{
// Harness will start with a test case index provided by host script.
return !Harness::run(specification);
}

View File

@ -0,0 +1,103 @@
/*
* 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.
*/
/**
* @addtogroup hal_watchdog_tests
* @{
*/
#ifndef MBED_HAL_WATCHDOG_API_TESTS_H
#define MBED_HAL_WATCHDOG_API_TESTS_H
#if DEVICE_WATCHDOG
/** Test max_timeout validity
*
* Given a device supporting Watchdog HAL API,
* when @a hal_watchdog_get_platform_features() is called,
* then max_timeout member of returned watchdog_features_t struct is greater than 1.
*/
void test_max_timeout_is_valid();
/** Test Watchdog features if a stopped Watchdog can be started again
*
* Given a device supporting Watchdog HAL API,
* when the device supports the @a disable_watchdog feature,
* then the device also supports @a update_config feature.
*/
void test_restart_is_possible();
/** Test Watchdog stop
*
* Given a device without a support for the @a disable_watchdog feature,
* when @a hal_watchdog_stop() is called,
* then WATCHDOG_STATUS_NOT_SUPPORTED is returned.
*
* Otherwise, given the device with @a disable_watchdog feature support:
*
* Given the Watchdog is *NOT* running,
* when @a hal_watchdog_stop() is called,
* then WATCHDOG_STATUS_OK is returned.
*
* Given the Watchdog is running,
* when @a hal_watchdog_stop() is called before the timeout expires,
* then WATCHDOG_STATUS_OK is returned and the device is not restarted.
*
* Given the Watchdog is *NOT* running (it has already been stopped),
* when @a hal_watchdog_stop() is called,
* then WATCHDOG_STATUS_OK is returned.
*/
void test_stop();
/** Test Watchdog init multiple times
*
* Given a set of unique timeout values,
* when @a config.timeout_ms is set to each of these values (T),
* then, for every value T, @a hal_watchdog_init() returns @a WATCHDOG_STATUS_OK
* and @a hal_watchdog_get_reload_value() returns a reload value R
* and T <= R < 2 * T.
*/
void test_update_config();
/** Test Watchdog init with a valid config
*
* Given @a config.timeout_ms is set to T ms,
* which is within supported Watchdog timeout range,
* when @a hal_watchdog_init() is called,
* then @a WATCHDOG_STATUS_OK is returned
* and @a hal_watchdog_get_reload_value() returns a reload value R
* and T <= R < 2 * T.
*/
template<uint32_t timeout_ms>
void test_init();
/** Test Watchdog init with a max_timeout
*
* Given @a config.timeout_ms is set to max_timeout,
* which is a value returned by @a hal_watchdog_get_platform_features(),
* when @a hal_watchdog_init() is called,
* then @a WATCHDOG_STATUS_OK is returned
* and @a hal_watchdog_get_reload_value() returns max_timeout.
*/
void test_init_max_timeout();
#endif
#endif
/** @}*/

View File

@ -0,0 +1,307 @@
/*
* 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.
*/
#if !DEVICE_WATCHDOG
#error [NOT_SUPPORTED] Watchdog not supported for this target
#endif
#include "greentea-client/test_env.h"
#include "utest/utest.h"
#include "unity/unity.h"
#include "hal/watchdog_api.h"
#include "watchdog_reset_tests.h"
#include "mbed.h"
#define TIMEOUT_MS 100UL
#define KICK_ADVANCE_MS 10UL
#define MSG_VALUE_DUMMY "0"
#define CASE_DATA_INVALID 0xffffffffUL
#define CASE_DATA_PHASE2_OK 0xfffffffeUL
#define MSG_VALUE_LEN 24
#define MSG_KEY_LEN 24
#define MSG_KEY_DEVICE_READY "ready"
#define MSG_KEY_START_CASE "start_case"
#define MSG_KEY_DEVICE_RESET "dev_reset"
/* To prevent a loss of Greentea data, the serial buffers have to be flushed
* before the UART peripheral shutdown. The UART shutdown happens when the
* device is entering the deepsleep mode or performing a reset.
*
* With the current API, it is not possible to check if the hardware buffers
* are empty. However, it is possible to determine the time required for the
* buffers to flush.
*
* Take NUMAKER_PFM_NUC472 as an example:
* The UART peripheral has 16-byte Tx FIFO. With a baud rate set to 9600,
* flushing the Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 ms.
* To be on the safe side, set the wait time to 20 ms.
*/
#define SERIAL_FLUSH_TIME_MS 20
using utest::v1::Case;
using utest::v1::Specification;
using utest::v1::Harness;
struct testcase_data {
int index;
int start_index;
uint32_t received_data;
};
void release_sem(Semaphore *sem)
{
sem->release();
}
testcase_data current_case;
bool send_reset_notification(testcase_data *tcdata, uint32_t delay_ms)
{
char msg_value[12];
int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms);
if (str_len != (sizeof msg_value) - 1) {
utest_printf("Failed to compose a value string to be sent to host.");
return false;
}
greentea_send_kv(MSG_KEY_DEVICE_RESET, msg_value);
return true;
}
void test_simple_reset()
{
// Phase 2. -- verify the test results.
// Verify if this test case passed based on data received from host.
if (current_case.received_data != CASE_DATA_INVALID) {
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
current_case.received_data = CASE_DATA_INVALID;
return;
}
// Phase 1. -- run the test code.
// Init the watchdog and wait for a device reset.
watchdog_config_t config = { TIMEOUT_MS };
if (send_reset_notification(&current_case, 2 * TIMEOUT_MS) == false) {
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
return;
}
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
// Watchdog should fire before twice the timeout value.
wait_ms(2 * TIMEOUT_MS); // Device reset expected.
// Watchdog reset should have occurred during wait_ms() above;
hal_watchdog_kick(); // Just to buy some time for testsuite failure handling.
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
}
#if DEVICE_SLEEP
void test_sleep_reset()
{
// Phase 2. -- verify the test results.
if (current_case.received_data != CASE_DATA_INVALID) {
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
current_case.received_data = CASE_DATA_INVALID;
return;
}
// Phase 1. -- run the test code.
watchdog_config_t config = { TIMEOUT_MS };
Semaphore sem(0, 1);
Timeout timeout;
if (send_reset_notification(&current_case, 2 * TIMEOUT_MS) == false) {
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
return;
}
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
sleep_manager_lock_deep_sleep();
// Watchdog should fire before twice the timeout value.
timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (2 * TIMEOUT_MS));
if (sleep_manager_can_deep_sleep()) {
TEST_ASSERT_MESSAGE(0, "Deepsleep should be disallowed.");
return;
}
sem.wait(); // Device reset expected.
sleep_manager_unlock_deep_sleep();
// Watchdog reset should have occurred during sem.wait() (sleep) above;
hal_watchdog_kick(); // Just to buy some time for testsuite failure handling.
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
}
#if DEVICE_LOWPOWERTIMER
void test_deepsleep_reset()
{
// Phase 2. -- verify the test results.
if (current_case.received_data != CASE_DATA_INVALID) {
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
current_case.received_data = CASE_DATA_INVALID;
return;
}
// Phase 1. -- run the test code.
watchdog_config_t config = { TIMEOUT_MS };
Semaphore sem(0, 1);
LowPowerTimeout lp_timeout;
if (send_reset_notification(&current_case, 2 * TIMEOUT_MS) == false) {
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
return;
}
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
// Watchdog should fire before twice the timeout value.
lp_timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (2 * TIMEOUT_MS));
wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush.
if (!sleep_manager_can_deep_sleep()) {
TEST_ASSERT_MESSAGE(0, "Deepsleep should be allowed.");
}
sem.wait(); // Device reset expected.
// Watchdog reset should have occurred during sem.wait() (deepsleep) above;
hal_watchdog_kick(); // Just to buy some time for testsuite failure handling.
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
}
#endif
#endif
void test_restart_reset()
{
watchdog_features_t features = hal_watchdog_get_platform_features();
if (!features.disable_watchdog) {
TEST_IGNORE_MESSAGE("Disabling Watchdog not supported for this platform");
return;
}
// Phase 2. -- verify the test results.
if (current_case.received_data != CASE_DATA_INVALID) {
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
current_case.received_data = CASE_DATA_INVALID;
return;
}
// Phase 1. -- run the test code.
watchdog_config_t config = { TIMEOUT_MS };
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
wait_ms(TIMEOUT_MS / 2UL);
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop());
// Check that stopping the Watchdog prevents a device reset.
// The watchdog should trigger at, or after the timeout value.
// The watchdog should trigger before twice the timeout value.
wait_ms(TIMEOUT_MS / 2UL + TIMEOUT_MS);
if (send_reset_notification(&current_case, 2 * TIMEOUT_MS) == false) {
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
return;
}
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
// Watchdog should fire before twice the timeout value.
wait_ms(2 * TIMEOUT_MS); // Device reset expected.
// Watchdog reset should have occurred during that wait() above;
hal_watchdog_kick(); // Just to buy some time for testsuite failure handling.
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
}
void test_kick_reset()
{
// Phase 2. -- verify the test results.
if (current_case.received_data != CASE_DATA_INVALID) {
TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data);
current_case.received_data = CASE_DATA_INVALID;
return;
}
// Phase 1. -- run the test code.
watchdog_config_t config = { TIMEOUT_MS };
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
for (int i = 3; i; i--) {
// The reset is prevented as long as the watchdog is kicked
// anytime before the timeout.
wait_ms(TIMEOUT_MS - KICK_ADVANCE_MS);
hal_watchdog_kick();
}
if (send_reset_notification(&current_case, 2 * TIMEOUT_MS) == false) {
TEST_ASSERT_MESSAGE(0, "Dev-host communication error.");
return;
}
// Watchdog should fire before twice the timeout value.
wait_ms(2 * TIMEOUT_MS); // Device reset expected.
// Watchdog reset should have occurred during that wait() above;
hal_watchdog_kick(); // Just to buy some time for testsuite failure handling.
TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected.");
}
utest::v1::status_t case_setup(const Case *const source, const size_t index_of_case)
{
current_case.index = index_of_case;
return utest::v1::greentea_case_setup_handler(source, index_of_case);
}
int testsuite_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(90, "watchdog_reset");
utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases);
if (status != utest::v1::STATUS_CONTINUE) {
return status;
}
char key[MSG_KEY_LEN + 1] = { };
char value[MSG_VALUE_LEN + 1] = { };
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY);
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
if (strcmp(key, MSG_KEY_START_CASE) != 0) {
utest_printf("Invalid message key.\n");
return utest::v1::STATUS_ABORT;
}
int num_args = sscanf(value, "%02x,%08lx", &(current_case.start_index), &(current_case.received_data));
if (num_args == 0 || num_args == EOF) {
utest_printf("Invalid data received from host\n");
return utest::v1::STATUS_ABORT;
}
utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases,
current_case.start_index);
return current_case.start_index;
}
Case cases[] = {
Case("Watchdog reset", case_setup, test_simple_reset),
#if DEVICE_SLEEP
Case("Watchdog reset in sleep mode", case_setup, test_sleep_reset),
#if DEVICE_LOWPOWERTIMER
Case("Watchdog reset in deepsleep mode", case_setup, test_deepsleep_reset),
#endif
#endif
Case("Watchdog started again", case_setup, test_restart_reset),
Case("Kicking the Watchdog prevents reset", case_setup, test_kick_reset),
};
Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases);
int main()
{
// Harness will start with a test case index provided by host script.
return !Harness::run(specification);
}

View File

@ -0,0 +1,77 @@
/*
* 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.
*/
/**
* @addtogroup hal_watchdog_tests
* @{
*/
#ifndef MBED_HAL_WATCHDOG_RESET_TESTS_H
#define MBED_HAL_WATCHDOG_RESET_TESTS_H
#if DEVICE_WATCHDOG
/** Test watchdog reset
*
* Given a device with a watchdog started,
* when a watchdog timeout expires,
* then the device is restarted.
*/
void test_simple_reset();
/** Test watchdog reset in sleep mode
*
* Given a device with a watchdog started,
* when the watchdog timeout expires while the device is in sleep mode,
* then the device is restarted.
*/
void test_sleep_reset();
/** Test watchdog reset in deepsleep mode
*
* Given a device with a watchdog started,
* when the watchdog timeout expires while the device is in deepsleep mode,
* then the device is restarted.
*/
void test_deepsleep_reset();
/** Test watchdog reset after watchdog restart
*
* Given a device with a watchdog started,
* when the watchdog is stopped before its timeout expires,
* then the device is not restarted.
* When the watchdog is started again and its timeout expires,
* then the device is restarted.
*/
void test_restart_reset();
/** Test watchdog kick
*
* Given a device with a watchdog started,
* when the watchdog is kicked before its timeout expires,
* then the device restart is prevented.
* When the watchdog is *NOT* kicked again before next timeout expires,
* then the device is restarted.
*/
void test_kick_reset();
#endif
#endif
/** @}*/

View File

@ -0,0 +1,162 @@
/*
* 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.
*/
#if !DEVICE_WATCHDOG
#error [NOT_SUPPORTED] Watchdog not supported for this target
#endif
#include "greentea-client/test_env.h"
#include "hal/watchdog_api.h"
#include "unity/unity.h"
#include "us_ticker_api.h"
#include "utest/utest.h"
#include "watchdog_timing_tests.h"
#define MSG_VALUE_DUMMY "0"
#define CASE_DATA_INVALID 0xffffffffUL
#define MSG_VALUE_LEN 24
#define MSG_KEY_LEN 24
#define MSG_KEY_DEVICE_READY "ready"
#define MSG_KEY_START_CASE "start_case"
#define MSG_KEY_HEARTBEAT "hb"
using utest::v1::Case;
using utest::v1::Specification;
using utest::v1::Harness;
struct testcase_data {
int index;
int start_index;
uint32_t received_data;
};
testcase_data current_case;
template<uint32_t timeout_ms>
void test_timing()
{
watchdog_features_t features = hal_watchdog_get_platform_features();
if (timeout_ms > features.max_timeout) {
TEST_IGNORE_MESSAGE("Requested timeout value not supported for this target -- ignoring test case.");
return;
}
// Phase 2. -- verify the test results.
// Verify the heartbeat time span sent by host is within given range:
// 1. The watchdog should trigger at, or after the timeout value.
// 2. The watchdog should trigger before twice the timeout value.
if (current_case.received_data != CASE_DATA_INVALID) {
// Provided the watchdog works as expected, the last timestamp received
// by the host will always be before the expected reset time. Because
// of that, the constraint no 1. is not verified.
TEST_ASSERT(current_case.received_data > 0);
TEST_ASSERT(current_case.received_data < 2 * timeout_ms);
current_case.received_data = CASE_DATA_INVALID;
return;
}
// Phase 1. -- run the test code.
// Send heartbeat messages to host until the watchdeg resets the device.
const ticker_data_t *const us_ticker = get_us_ticker_data();
us_timestamp_t current_ts, next_ts, expected_reset_ts, divider, ts_increment;
char msg_value[12];
watchdog_config_t config = { timeout_ms };
TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config));
next_ts = ticker_read_us(us_ticker);
expected_reset_ts = next_ts + 1000ULL * timeout_ms;
divider = 0x2ULL;
while (1) {
current_ts = ticker_read_us(us_ticker);
if (current_ts < next_ts) {
continue;
}
int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", current_case.start_index + current_case.index,
(uint32_t) current_ts);
if (str_len != (sizeof msg_value) - 1) {
utest_printf("Failed to compose a value string to be sent to host.");
return;
}
greentea_send_kv(MSG_KEY_HEARTBEAT, msg_value);
// The closer to expected reset, the smaller heartbeat time difference.
// This should reduce measurement error present for heartbeat with
// equal periods.
ts_increment = (1000ULL * timeout_ms / divider);
next_ts += ts_increment;
if (current_ts <= expected_reset_ts) {
divider <<= 1;
} else if (divider > 0x2ULL) {
divider >>= 1;
}
}
}
utest::v1::status_t case_setup(const Case *const source, const size_t index_of_case)
{
current_case.index = index_of_case;
return utest::v1::greentea_case_setup_handler(source, index_of_case);
}
int testsuite_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(90, "watchdog_reset");
utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases);
if (status != utest::v1::STATUS_CONTINUE) {
return status;
}
char key[MSG_KEY_LEN + 1] = { };
char value[MSG_VALUE_LEN + 1] = { };
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY);
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
if (strcmp(key, MSG_KEY_START_CASE) != 0) {
utest_printf("Invalid message key.\n");
return utest::v1::STATUS_ABORT;
}
int num_args = sscanf(value, "%02x,%08lx", &(current_case.start_index), &(current_case.received_data));
if (num_args == 0 || num_args == EOF) {
utest_printf("Invalid data received from host\n");
return utest::v1::STATUS_ABORT;
}
utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases,
current_case.start_index);
return current_case.start_index;
}
Case cases[] = {
Case("Timing, 200 ms", case_setup, test_timing<200UL>),
Case("Timing, 500 ms", case_setup, test_timing<500UL>),
Case("Timing, 1000 ms", case_setup, test_timing<1000UL>),
Case("Timing, 3000 ms", case_setup, test_timing<3000UL>),
};
Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases);
int main()
{
// Harness will start with a test case index provided by host script.
return !Harness::run(specification);
}

View File

@ -0,0 +1,48 @@
/*
* 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.
*/
/**
* @addtogroup hal_watchdog_tests
* @{
*/
#ifndef MBED_HAL_WATCHDOG_TIMING_TESTS_H
#define MBED_HAL_WATCHDOG_TIMING_TESTS_H
#if DEVICE_WATCHDOG
/** Test watchdog timing accuracy
*
* Phase 1.
* Given a watchdog timer started with a timeout value of X ms,
* when the time of X ms elapses,
* then the device is restarted by the watchdog.
*
* Phase 2.
* Given a device restarted by the watchdog timer,
* when the device receives time measurement T from the host,
* then X <= T < 2 * X.
*/
template<uint32_t timeout_ms, uint32_t delta_ms>
void test_timing();
#endif
#endif
/** @}*/

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 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.
*/
#if !DEVICE_ANALOGIN
#error [NOT_SUPPORTED] Analog in not supported for this target
#elif !COMPONENT_FPGA_CI_TEST_SHIELD
#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test
#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR)
#error [NOT_SUPPORTED] Test not supported for this form factor
#else
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "mbed.h"
#include "pinmap.h"
#include "test_utils.h"
#include "MbedTester.h"
using namespace utest::v1;
#define analogin_debug_printf(...)
#define DELTA_FLOAT 0.03f // 3%
#define DELTA_U16 1965 // 3%
const PinList *form_factor = pinmap_ff_default_pins();
const PinList *restricted = pinmap_restricted_pins();
MbedTester tester(form_factor, restricted);
void analogin_init(PinName pin)
{
analogin_t analogin;
analogin_init(&analogin, pin);
}
void analogin_test(PinName pin)
{
tester.reset();
tester.pin_map_set(pin, MbedTester::LogicalPinGPIO0);
tester.select_peripheral(MbedTester::PeripheralGPIO);
/* Test analog input */
analogin_t analogin;
analogin_init(&analogin, pin);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
TEST_ASSERT_FLOAT_WITHIN(DELTA_FLOAT, 1.0f, analogin_read(&analogin));
TEST_ASSERT_UINT16_WITHIN(DELTA_U16, 65535, analogin_read_u16(&analogin));
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
TEST_ASSERT_FLOAT_WITHIN(DELTA_FLOAT, 0.0f, analogin_read(&analogin));
TEST_ASSERT_UINT16_WITHIN(DELTA_U16, 0, analogin_read_u16(&analogin));
/* Set gpio back to Hi-Z */
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false);
}
Case cases[] = {
// This will be run for all pins
Case("AnalogIn - init test", all_ports<AnaloginPort, DefaultFormFactor, analogin_init>),
// This will be run for single pin
Case("AnalogIn - read test", all_ports<AnaloginPort, DefaultFormFactor, analogin_test>),
};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(120, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
int main()
{
Harness::run(specification);
}
#endif /* !DEVICE_ANALOGIN */

View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 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.
*/
#if !COMPONENT_FPGA_CI_TEST_SHIELD
#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test
#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR)
#error [NOT_SUPPORTED] Test not supported for this form factor
#else
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "mbed.h"
using namespace utest::v1;
#include "MbedTester.h"
#include "pinmap.h"
const PinList *form_factor = pinmap_ff_default_pins();
const PinList *restricted = pinmap_restricted_pins();
MbedTester tester(form_factor, restricted);
void gpio_inout_test(PinName pin)
{
gpio_t gpio;
gpio_init_inout(&gpio, pin, PIN_OUTPUT, PullNone, 0);
TEST_ASSERT_EQUAL(0, tester.gpio_read(MbedTester::LogicalPinGPIO0));
/* Test GPIO output */
gpio_write(&gpio, 1);
TEST_ASSERT_EQUAL(1, tester.gpio_read(MbedTester::LogicalPinGPIO0));
gpio_write(&gpio, 0);
TEST_ASSERT_EQUAL(0, tester.gpio_read(MbedTester::LogicalPinGPIO0));
gpio_dir(&gpio, PIN_INPUT);
/* Test GPIO input */
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
TEST_ASSERT_EQUAL(0, gpio_read(&gpio));
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
TEST_ASSERT_EQUAL(1, gpio_read(&gpio));
/* Set gpio back to Hi-Z */
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, false);
}
void gpio_inout_test()
{
for (int i = 0; i < form_factor->count; i++) {
const PinName test_pin = form_factor->pins[i];
if (test_pin == NC) {
continue;
}
if (pinmap_list_has_pin(restricted, test_pin)) {
printf("Skipping gpio pin %s (%i)\r\n", pinmap_ff_default_pin_to_string(test_pin), test_pin);
continue;
}
tester.pin_map_reset();
tester.pin_map_set(test_pin, MbedTester::LogicalPinGPIO0);
printf("GPIO test on pin %s (%i)\r\n", pinmap_ff_default_pin_to_string(test_pin), test_pin);
gpio_inout_test(test_pin);
}
}
utest::v1::status_t setup(const Case *const source, const size_t index_of_case)
{
tester.reset();
tester.select_peripheral(MbedTester::PeripheralGPIO);
return greentea_case_setup_handler(source, index_of_case);
}
utest::v1::status_t teardown(const Case *const source, const size_t passed, const size_t failed,
const failure_t reason)
{
return greentea_case_teardown_handler(source, passed, failed, reason);
}
Case cases[] = {
Case("GPIO - inout", setup, gpio_inout_test, teardown),
};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(60, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
int main()
{
Harness::run(specification);
}
#endif /* !COMPONENT_FPGA_CI_TEST_SHIELD */

View File

@ -0,0 +1,299 @@
/*
* Copyright (c) 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.
*/
#if !DEVICE_INTERRUPTIN
#error [NOT_SUPPORTED] test not supported
#elif !COMPONENT_FPGA_CI_TEST_SHIELD
#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test
#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR)
#error [NOT_SUPPORTED] Test not supported for this form factor
#else
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "mbed.h"
using namespace utest::v1;
#include "mbed.h"
#include "MbedTester.h"
#include "pinmap.h"
static uint32_t call_counter;
void test_gpio_irq_handler(uint32_t id, gpio_irq_event event)
{
call_counter++;
}
const PinList *form_factor = pinmap_ff_default_pins();
const PinList *restricted = pinmap_restricted_pins();
MbedTester tester(form_factor, restricted);
#define WAIT() wait_us(10)
void gpio_irq_test(PinName pin)
{
gpio_t gpio;
// configure pin as input
gpio_init_in(&gpio, pin);
gpio_irq_t gpio_irq;
uint32_t id = 123;
gpio_irq_init(&gpio_irq, pin, test_gpio_irq_handler, id);
gpio_irq_set(&gpio_irq, IRQ_RISE, true);
gpio_irq_enable(&gpio_irq);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
// test irq on rising edge
call_counter = 0;
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(1, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(1, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(2, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(2, call_counter);
gpio_irq_disable(&gpio_irq);
call_counter = 0;
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(0, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(0, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(0, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(0, call_counter);
gpio_irq_enable(&gpio_irq);
call_counter = 0;
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(1, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(1, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(2, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(2, call_counter);
// test irq on both rising and falling edge
gpio_irq_set(&gpio_irq, IRQ_FALL, true);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
call_counter = 0;
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(1, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(2, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(3, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(4, call_counter);
gpio_irq_disable(&gpio_irq);
call_counter = 0;
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(0, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(0, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(0, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(0, call_counter);
gpio_irq_enable(&gpio_irq);
call_counter = 0;
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(1, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(2, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(3, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(4, call_counter);
// test irq on falling edge
gpio_irq_set(&gpio_irq, IRQ_RISE, false);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
call_counter = 0;
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(1, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(1, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(2, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(2, call_counter);
gpio_irq_disable(&gpio_irq);
call_counter = 0;
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(0, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(0, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(0, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(0, call_counter);
gpio_irq_enable(&gpio_irq);
call_counter = 0;
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(1, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(1, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 0, true);
WAIT();
TEST_ASSERT_EQUAL(2, call_counter);
tester.gpio_write(MbedTester::LogicalPinGPIO0, 1, true);
WAIT();
TEST_ASSERT_EQUAL(2, call_counter);
gpio_irq_free(&gpio_irq);
}
void gpio_irq_test()
{
for (uint32_t i = 0; i < form_factor->count; i++) {
const PinName test_pin = form_factor->pins[i];
if (test_pin == NC) {
continue;
}
if (pinmap_list_has_pin(restricted, test_pin)) {
printf("Skipping gpio pin %s (%i)\r\n", pinmap_ff_default_pin_to_string(test_pin), test_pin);
continue;
}
tester.pin_map_reset();
tester.pin_map_set(test_pin, MbedTester::LogicalPinGPIO0);
printf("GPIO irq test on pin %3s (%3i)\r\n", pinmap_ff_default_pin_to_string(test_pin), test_pin);
gpio_irq_test(test_pin);
}
}
utest::v1::status_t setup(const Case *const source, const size_t index_of_case)
{
tester.reset();
tester.select_peripheral(MbedTester::PeripheralGPIO);
return greentea_case_setup_handler(source, index_of_case);
}
utest::v1::status_t teardown(const Case *const source, const size_t passed, const size_t failed,
const failure_t reason)
{
return greentea_case_teardown_handler(source, passed, failed, reason);
}
Case cases[] = {
Case("GPIO - irq test", setup, gpio_irq_test, teardown)
};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(10, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
int main()
{
Harness::run(specification);
}
#endif /* !DEVICE_INTERRUPTIN */

View File

@ -0,0 +1,446 @@
/*
* Copyright (c) 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.
*/
#if !DEVICE_I2C
#error [NOT_SUPPORTED] I2C not supported for this target
#elif !COMPONENT_FPGA_CI_TEST_SHIELD
#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test
#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR)
#error [NOT_SUPPORTED] Test not supported for this form factor
#else
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "mbed.h"
#include "mbed.h"
#include "i2c_api.h"
#include "pinmap.h"
#include "test_utils.h"
#include "I2CTester.h"
using namespace utest::v1;
#define NACK 0
#define ACK 1
#define TIMEOUT 2
#define I2C_DEV_ADDR 0x98//default i2c slave address on FPGA is 0x98 until modified
const int TRANSFER_COUNT = 300;
I2CTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins());
void test_i2c_init_free(PinName sda, PinName scl)
{
i2c_t obj = {};
memset(&obj, 0, sizeof(obj));
i2c_init(&obj, sda, scl);
i2c_frequency(&obj, 100000);
}
void i2c_test_write(PinName sda, PinName scl)
{
// Remap pins for test
tester.reset();
tester.pin_map_set(sda, MbedTester::LogicalPinI2CSda);
tester.pin_map_set(scl, MbedTester::LogicalPinI2CScl);
tester.pin_set_pull(sda, MbedTester::PullUp);
tester.pin_set_pull(scl, MbedTester::PullUp);
// Initialize mbed I2C pins
i2c_t i2c;
memset(&i2c, 0, sizeof(i2c));
i2c_init(&i2c, sda, scl);
i2c_frequency(&i2c, 100000);
// Reset tester stats and select I2C
tester.peripherals_reset();
tester.select_peripheral(I2CTester::PeripheralI2C);
// Data out and in buffers and initialization
uint8_t data_out[TRANSFER_COUNT];
for (int i = 0; i < TRANSFER_COUNT; i++) {
data_out[i] = i & 0xFF;
}
uint8_t data_in[TRANSFER_COUNT];
for (int i = 0; i < TRANSFER_COUNT; i++) {
data_in[i] = 0;
}
int num_writes;
int num_reads;
int num_acks;
int num_nacks;
int num_starts;
int num_stops;
uint32_t checksum;
int num_dev_addr_matches;
int ack_nack;//0 if NACK was received, 1 if ACK was received, 2 for timeout
// Reset tester stats and select I2C
tester.peripherals_reset();
tester.select_peripheral(MbedTester::PeripheralI2C);
// Write data for I2C complete transaction
// Will write 0-(TRANSFER_COUNT-1) to FPGA, checksum must match checksum calculated in parallel on FPGA
num_dev_addr_matches = 0;
num_writes = 0;
num_reads = 0;
num_starts = 0;
num_stops = 0;
num_acks = 0;
num_nacks = 0;
checksum = 0;
num_writes = i2c_write(&i2c, I2C_DEV_ADDR, (char *)data_out, TRANSFER_COUNT, true); //transaction ends with a stop condition
num_acks = num_writes + 1;
num_starts += 1;
num_stops += 1;
num_dev_addr_matches += 1;
for (int i = 0; i < TRANSFER_COUNT; i++) {
checksum += data_out[i];
}
// Verify that the transfer was successful
TEST_ASSERT_EQUAL(num_dev_addr_matches, tester.num_dev_addr_matches());
TEST_ASSERT_EQUAL(TRANSFER_COUNT, num_writes);
TEST_ASSERT_EQUAL(num_writes + 1, tester.transfer_count());
TEST_ASSERT_EQUAL(num_starts, tester.num_starts());
TEST_ASSERT_EQUAL(num_stops, tester.num_stops());
TEST_ASSERT_EQUAL(num_acks, tester.num_acks());
TEST_ASSERT_EQUAL(num_nacks, tester.num_nacks());
TEST_ASSERT_EQUAL(checksum, tester.get_receive_checksum());
TEST_ASSERT_EQUAL(0, tester.state_num());
TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 4], tester.get_prev_to_slave_4());
TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 3], tester.get_prev_to_slave_3());
TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 2], tester.get_prev_to_slave_2());
TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 1], tester.get_prev_to_slave_1());
TEST_ASSERT_EQUAL(num_writes, tester.num_writes());
TEST_ASSERT_EQUAL(num_reads, tester.num_reads());
tester.reset();
tester.pin_set_pull(sda, MbedTester::PullNone);
tester.pin_set_pull(scl, MbedTester::PullNone);
}
void i2c_test_read(PinName sda, PinName scl)
{
// Remap pins for test
tester.reset();
tester.pin_map_set(sda, MbedTester::LogicalPinI2CSda);
tester.pin_map_set(scl, MbedTester::LogicalPinI2CScl);
tester.pin_set_pull(sda, MbedTester::PullUp);
tester.pin_set_pull(scl, MbedTester::PullUp);
// Initialize mbed I2C pins
i2c_t i2c;
memset(&i2c, 0, sizeof(i2c));
i2c_init(&i2c, sda, scl);
i2c_frequency(&i2c, 100000);
// Reset tester stats and select I2C
tester.peripherals_reset();
tester.select_peripheral(I2CTester::PeripheralI2C);
// Data out and in buffers and initialization
uint8_t data_out[TRANSFER_COUNT];
for (int i = 0; i < TRANSFER_COUNT; i++) {
data_out[i] = i & 0xFF;
}
uint8_t data_in[TRANSFER_COUNT];
for (int i = 0; i < TRANSFER_COUNT; i++) {
data_in[i] = 0;
}
int num_writes;
int num_reads;
int num_acks;
int num_nacks;
int num_starts;
int num_stops;
uint32_t checksum;
int num_dev_addr_matches;
int ack_nack;//0 if NACK was received, 1 if ACK was received, 2 for timeout
// Reset tester stats and select I2C
tester.peripherals_reset();
tester.select_peripheral(MbedTester::PeripheralI2C);
// Read data for I2C complete transaction
// Will read <TRANSFER_COUNT> bytes, checksum must match checksum calculated in parallel on FPGA
num_dev_addr_matches = 0;
num_writes = 0;
num_reads = 0;
num_starts = 0;
num_stops = 0;
num_acks = 0;
num_nacks = 0;
checksum = 0;
num_reads = i2c_read(&i2c, (I2C_DEV_ADDR | 1), (char *)data_in, TRANSFER_COUNT, true); //transaction ends with a stop condition
num_starts += 1;
num_stops += 1;
num_acks += 1;
num_acks += TRANSFER_COUNT - 1;
num_nacks += 1;
num_dev_addr_matches += 1;
for (int i = 0; i < TRANSFER_COUNT; i++) {
checksum += data_in[i];
}
// Verify that the transfer was successful
TEST_ASSERT_EQUAL(num_dev_addr_matches, tester.num_dev_addr_matches());
TEST_ASSERT_EQUAL(TRANSFER_COUNT, num_reads);
TEST_ASSERT_EQUAL(num_reads + 1, tester.transfer_count());
TEST_ASSERT_EQUAL(num_starts, tester.num_starts());
TEST_ASSERT_EQUAL(num_stops, tester.num_stops());
TEST_ASSERT_EQUAL(num_acks, tester.num_acks());
TEST_ASSERT_EQUAL(num_nacks, tester.num_nacks());
TEST_ASSERT_EQUAL(checksum, tester.get_send_checksum());
TEST_ASSERT_EQUAL(0, tester.state_num());
TEST_ASSERT_EQUAL(((TRANSFER_COUNT + 1) & 0xFF), tester.get_next_from_slave());
TEST_ASSERT_EQUAL(num_writes, tester.num_writes());
TEST_ASSERT_EQUAL(num_reads, tester.num_reads());
tester.reset();
tester.pin_set_pull(sda, MbedTester::PullNone);
tester.pin_set_pull(scl, MbedTester::PullNone);
}
void i2c_test_byte_write(PinName sda, PinName scl)
{
// Remap pins for test
tester.reset();
tester.pin_map_set(sda, MbedTester::LogicalPinI2CSda);
tester.pin_map_set(scl, MbedTester::LogicalPinI2CScl);
tester.pin_set_pull(sda, MbedTester::PullUp);
tester.pin_set_pull(scl, MbedTester::PullUp);
// Initialize mbed I2C pins
i2c_t i2c;
memset(&i2c, 0, sizeof(i2c));
i2c_init(&i2c, sda, scl);
i2c_frequency(&i2c, 100000);
// Reset tester stats and select I2C
tester.peripherals_reset();
tester.select_peripheral(I2CTester::PeripheralI2C);
// Data out and in buffers and initialization
uint8_t data_out[TRANSFER_COUNT];
for (int i = 0; i < TRANSFER_COUNT; i++) {
data_out[i] = i & 0xFF;
}
uint8_t data_in[TRANSFER_COUNT];
for (int i = 0; i < TRANSFER_COUNT; i++) {
data_in[i] = 0;
}
int num_writes;
int num_reads;
int num_acks;
int num_nacks;
int num_starts;
int num_stops;
uint32_t checksum;
int num_dev_addr_matches;
int ack_nack;//0 if NACK was received, 1 if ACK was received, 2 for timeout
// Reset tester stats and select I2C
tester.peripherals_reset();
tester.select_peripheral(MbedTester::PeripheralI2C);
// Write data for I2C single byte transfers
// Will write 0-(TRANSFER_COUNT-1) to FPGA, checksum must match checksum calculated in parallel on FPGA
num_dev_addr_matches = 0;
num_writes = 0;
num_reads = 0;
num_starts = 0;
num_stops = 0;
num_acks = 0;
num_nacks = 0;
checksum = 0;
i2c_start(&i2c);//start condition
num_starts += 1;
i2c_byte_write(&i2c, I2C_DEV_ADDR);//send device address
num_dev_addr_matches += 1;
num_acks += 1;
for (int i = 0; i < TRANSFER_COUNT; i++) {
ack_nack = i2c_byte_write(&i2c, data_out[i]);//send data
if (ack_nack == ACK) {
num_acks += 1;
} else if (ack_nack == NACK) {
num_nacks += 1;
} else {
printf("Timeout error\n\r");
}
checksum += data_out[i];
num_writes += 1;
}
i2c_stop(&i2c);
num_stops += 1;
// Verify that the transfer was successful
TEST_ASSERT_EQUAL(num_dev_addr_matches, tester.num_dev_addr_matches());
TEST_ASSERT_EQUAL(TRANSFER_COUNT, num_writes);
TEST_ASSERT_EQUAL(num_writes + 1, tester.transfer_count());
TEST_ASSERT_EQUAL(num_starts, tester.num_starts());
TEST_ASSERT_EQUAL(num_stops, tester.num_stops());
TEST_ASSERT_EQUAL(num_acks, tester.num_acks());
TEST_ASSERT_EQUAL(num_nacks, tester.num_nacks());
TEST_ASSERT_EQUAL(checksum, tester.get_receive_checksum());
TEST_ASSERT_EQUAL(0, tester.state_num());
TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 4], tester.get_prev_to_slave_4());
TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 3], tester.get_prev_to_slave_3());
TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 2], tester.get_prev_to_slave_2());
TEST_ASSERT_EQUAL(data_out[TRANSFER_COUNT - 1], tester.get_prev_to_slave_1());
TEST_ASSERT_EQUAL(num_writes, tester.num_writes());
TEST_ASSERT_EQUAL(num_reads, tester.num_reads());
tester.reset();
tester.pin_set_pull(sda, MbedTester::PullNone);
tester.pin_set_pull(scl, MbedTester::PullNone);
}
void i2c_test_byte_read(PinName sda, PinName scl)
{
// Remap pins for test
tester.reset();
tester.pin_map_set(sda, MbedTester::LogicalPinI2CSda);
tester.pin_map_set(scl, MbedTester::LogicalPinI2CScl);
tester.pin_set_pull(sda, MbedTester::PullUp);
tester.pin_set_pull(scl, MbedTester::PullUp);
// Initialize mbed I2C pins
i2c_t i2c;
memset(&i2c, 0, sizeof(i2c));
i2c_init(&i2c, sda, scl);
i2c_frequency(&i2c, 100000);
// Reset tester stats and select I2C
tester.peripherals_reset();
tester.select_peripheral(I2CTester::PeripheralI2C);
// Data out and in buffers and initialization
uint8_t data_out[TRANSFER_COUNT];
for (int i = 0; i < TRANSFER_COUNT; i++) {
data_out[i] = i & 0xFF;
}
uint8_t data_in[TRANSFER_COUNT];
for (int i = 0; i < TRANSFER_COUNT; i++) {
data_in[i] = 0;
}
int num_writes;
int num_reads;
int num_acks;
int num_nacks;
int num_starts;
int num_stops;
uint32_t checksum;
int num_dev_addr_matches;
int ack_nack;//0 if NACK was received, 1 if ACK was received, 2 for timeout
// Reset tester stats and select I2C
tester.peripherals_reset();
tester.select_peripheral(MbedTester::PeripheralI2C);
for (int i = 0; i < TRANSFER_COUNT; i++) {
data_in[i] = 0;
}
// Read data for I2C single byte transfers
// Will read <TRANSFER_COUNT> bytes, checksum must match checksum calculated in parallel on FPGA
num_dev_addr_matches = 0;
num_writes = 0;
num_reads = 0;
num_starts = 0;
num_stops = 0;
num_acks = 0;
num_nacks = 0;
checksum = 0;
i2c_start(&i2c);//start condition
num_starts += 1;
i2c_byte_write(&i2c, (I2C_DEV_ADDR | 1));//send device address for reading
num_dev_addr_matches += 1;
num_acks += 1;
for (int i = 0; i < TRANSFER_COUNT; i++) {
if (num_reads == (TRANSFER_COUNT - 1)) {
data_in[i] = i2c_byte_read(&i2c, 1);//send NACK
checksum += data_in[i];
num_reads += 1;
num_nacks += 1;
} else {
data_in[i] = i2c_byte_read(&i2c, 0);//send ACK
checksum += data_in[i];
num_reads += 1;
num_acks += 1;
}
}
i2c_stop(&i2c);
num_stops += 1;
// Verify that the transfer was successful
TEST_ASSERT_EQUAL(num_dev_addr_matches, tester.num_dev_addr_matches());
TEST_ASSERT_EQUAL(TRANSFER_COUNT, num_reads);
TEST_ASSERT_EQUAL(num_reads + 1, tester.transfer_count());
TEST_ASSERT_EQUAL(num_starts, tester.num_starts());
TEST_ASSERT_EQUAL(num_stops, tester.num_stops());
TEST_ASSERT_EQUAL(num_acks, tester.num_acks());
TEST_ASSERT_EQUAL(num_nacks, tester.num_nacks());
TEST_ASSERT_EQUAL(checksum, tester.get_send_checksum());
TEST_ASSERT_EQUAL(0, tester.state_num());
TEST_ASSERT_EQUAL(((TRANSFER_COUNT + 2) & 0xFF), tester.get_next_from_slave());
TEST_ASSERT_EQUAL(num_writes, tester.num_writes());
TEST_ASSERT_EQUAL(num_reads, tester.num_reads());
tester.reset();
tester.pin_set_pull(sda, MbedTester::PullNone);
tester.pin_set_pull(scl, MbedTester::PullNone);
}
Case cases[] = {
Case("i2c - init/free test all pins", all_ports<I2CPort, DefaultFormFactor, test_i2c_init_free>),
Case("i2c - test write i2c API", all_peripherals<I2CPort, DefaultFormFactor, i2c_test_write>),
Case("i2c - test read i2c API", all_peripherals<I2CPort, DefaultFormFactor, i2c_test_read>),
Case("i2c - test single byte write i2c API", all_peripherals<I2CPort, DefaultFormFactor, i2c_test_byte_write>),
Case("i2c - test single byte read i2c API", all_peripherals<I2CPort, DefaultFormFactor, i2c_test_byte_read>)
};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(15, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
int main()
{
Harness::run(specification);
}
#endif /* !DEVICE_I2C */

View File

@ -0,0 +1,226 @@
/*
* Copyright (c) 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.
*/
#if !DEVICE_PWMOUT
#error [NOT_SUPPORTED] PWM not supported for this target
#elif !COMPONENT_FPGA_CI_TEST_SHIELD
#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test
#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR)
#error [NOT_SUPPORTED] Test not supported for this form factor
#else
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "mbed.h"
using namespace utest::v1;
#include "MbedTester.h"
#include "pinmap.h"
#include "test_utils.h"
#define pwm_debug_printf(...)
typedef enum {
PERIOD_WRITE,
PERIOD_MS_WRITE,
PERIOD_US_WRITE,
PERIOD_PULSEWIDTH,
PERIOD_PULSEWIDTH_MS,
PERIOD_PULSEWIDTH_US
} pwm_api_test_t;
#define NUM_OF_PERIODS 10
#define US_PER_SEC 1000000
#define US_PER_MS 1000
#define MS_PER_SEC 1000
#define DELTA_FACTOR 20 // 5% delta
#define PERIOD_US(PERIOD_MS) (((PERIOD_MS) * US_PER_MS))
#define PERIOD_FLOAT(PERIOD_MS) (((float)(PERIOD_MS) / US_PER_MS))
#define FILL_FLOAT(PRC) ((float)(PRC) / 100)
#define PULSE_HIGH_US(PERIOD_US, PRC) ((uint32_t)((PERIOD_US) * FILL_FLOAT(PRC)))
#define PULSE_LOW_US(PERIOD_US, PRC) ((uint32_t)((PERIOD_US) * (1.0f - FILL_FLOAT(PRC))))
MbedTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins());
void pwm_init_free(PinName pin)
{
pwmout_t pwm_out;
pwm_debug_printf("PWM init/free test on pin=%s (%i)\r\n", pinmap_ff_default_pin_to_string(pin), pin);
pwmout_init(&pwm_out, pin);
pwmout_free(&pwm_out);
}
void pwm_period_fill_test(PinName pin, uint32_t period_ms, uint32_t fill_prc, pwm_api_test_t api_test)
{
pwm_debug_printf("PWM test on pin = %s (%i)\r\n", pinmap_ff_default_pin_to_string(pin), pin);
pwm_debug_printf("Testing period = %lu ms, duty-cycle = %lu %%\r\n", period_ms, fill_prc);
pwm_debug_printf("Testing APIs = %d\r\n", (int)api_test);
tester.reset();
MbedTester::LogicalPin logical_pin = (MbedTester::LogicalPin)(MbedTester::LogicalPinIOMetrics0);
tester.pin_map_set(pin, logical_pin);
pwmout_t pwm_out;
pwmout_init(&pwm_out, pin);
core_util_critical_section_enter();
switch (api_test) {
case PERIOD_WRITE:
pwmout_period(&pwm_out, PERIOD_FLOAT(period_ms));
pwmout_write(&pwm_out, FILL_FLOAT(fill_prc));
break;
case PERIOD_MS_WRITE:
pwmout_period_ms(&pwm_out, (int)period_ms);
pwmout_write(&pwm_out, FILL_FLOAT(fill_prc));
break;
case PERIOD_US_WRITE:
pwmout_period_us(&pwm_out, PERIOD_US(period_ms));
pwmout_write(&pwm_out, FILL_FLOAT(fill_prc));
break;
case PERIOD_PULSEWIDTH:
pwmout_period(&pwm_out, PERIOD_FLOAT(period_ms));
pwmout_pulsewidth(&pwm_out, (float)PULSE_HIGH_US(PERIOD_US(period_ms), fill_prc) / US_PER_SEC);
break;
case PERIOD_PULSEWIDTH_MS:
pwmout_period(&pwm_out, PERIOD_FLOAT(period_ms));
pwmout_pulsewidth_ms(&pwm_out, (int)PULSE_HIGH_US(PERIOD_US(period_ms), fill_prc) / MS_PER_SEC);
break;
case PERIOD_PULSEWIDTH_US:
pwmout_period(&pwm_out, PERIOD_FLOAT(period_ms));
pwmout_pulsewidth_us(&pwm_out, (int)PULSE_HIGH_US(PERIOD_US(period_ms), fill_prc));
break;
}
tester.io_metrics_start();
wait(NUM_OF_PERIODS * PERIOD_FLOAT(period_ms));
tester.io_metrics_stop();
core_util_critical_section_exit();
const uint32_t expected_low_pulse_us = PULSE_LOW_US(PERIOD_US(period_ms), fill_prc);
const uint32_t expected_high_pulse_us = PULSE_HIGH_US(PERIOD_US(period_ms), fill_prc);
const uint32_t delta_low_pulse = (expected_low_pulse_us / DELTA_FACTOR);
const uint32_t delta_high_pulse = (expected_high_pulse_us / DELTA_FACTOR);
pwm_debug_printf("Minimum pulse low %lu us\r\n", tester.io_metrics_min_pulse_low(logical_pin) / 100);
pwm_debug_printf("Minimum pulse high %lu us\r\n", tester.io_metrics_min_pulse_high(logical_pin) / 100);
pwm_debug_printf("Maximum pulse low %lu us\r\n", tester.io_metrics_max_pulse_low(logical_pin) / 100);
pwm_debug_printf("Maximum pulse high %lu us\r\n", tester.io_metrics_max_pulse_high(logical_pin) / 100);
pwm_debug_printf("Rising edges %lu\r\n", tester.io_metrics_rising_edges(logical_pin));
pwm_debug_printf("Falling edges %lu\r\n", tester.io_metrics_falling_edges(logical_pin));
TEST_ASSERT_FLOAT_WITHIN(FILL_FLOAT(fill_prc) / DELTA_FACTOR, FILL_FLOAT(fill_prc), pwmout_read(&pwm_out));
TEST_ASSERT_UINT32_WITHIN(delta_low_pulse, expected_low_pulse_us, tester.io_metrics_min_pulse_low(logical_pin) / 100);
TEST_ASSERT_UINT32_WITHIN(delta_low_pulse, expected_low_pulse_us, tester.io_metrics_max_pulse_low(logical_pin) / 100);
TEST_ASSERT_UINT32_WITHIN(delta_high_pulse, expected_high_pulse_us, tester.io_metrics_min_pulse_high(logical_pin) / 100);
TEST_ASSERT_UINT32_WITHIN(delta_high_pulse, expected_high_pulse_us, tester.io_metrics_max_pulse_high(logical_pin) / 100);
TEST_ASSERT_UINT32_WITHIN(1, NUM_OF_PERIODS, tester.io_metrics_rising_edges(logical_pin));
TEST_ASSERT_UINT32_WITHIN(1, NUM_OF_PERIODS, tester.io_metrics_falling_edges(logical_pin));
pwmout_free(&pwm_out);
}
template<uint32_t period_ms, uint32_t fill_prc, pwm_api_test_t api_test>
void pwm_period_fill_test(PinName pin)
{
pwm_period_fill_test(pin, period_ms, fill_prc, api_test);
}
Case cases[] = {
// This will be run for all pins
Case("PWM - init/free test", all_ports<PWMPort, DefaultFormFactor, pwm_init_free>),
// This will be run for single pin
Case("PWM - period: 10 ms, fill: 10%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 10, PERIOD_WRITE> >),
Case("PWM - period: 10 ms, fill: 10%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 10, PERIOD_MS_WRITE> >),
Case("PWM - period: 10 ms, fill: 10%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 10, PERIOD_US_WRITE> >),
Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 10, PERIOD_PULSEWIDTH> >),
Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 10, PERIOD_PULSEWIDTH_MS> >),
Case("PWM - period: 10 ms, fill: 10%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 10, PERIOD_PULSEWIDTH_US> >),
Case("PWM - period: 10 ms, fill: 50%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 50, PERIOD_WRITE> >),
Case("PWM - period: 10 ms, fill: 50%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 50, PERIOD_MS_WRITE> >),
Case("PWM - period: 10 ms, fill: 50%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 50, PERIOD_US_WRITE> >),
Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 50, PERIOD_PULSEWIDTH> >),
Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 50, PERIOD_PULSEWIDTH_MS> >),
Case("PWM - period: 10 ms, fill: 50%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 50, PERIOD_PULSEWIDTH_US> >),
Case("PWM - period: 10 ms, fill: 90%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 90, PERIOD_WRITE> >),
Case("PWM - period: 10 ms, fill: 90%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 90, PERIOD_MS_WRITE> >),
Case("PWM - period: 10 ms, fill: 90%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 90, PERIOD_US_WRITE> >),
Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 90, PERIOD_PULSEWIDTH> >),
Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 90, PERIOD_PULSEWIDTH_MS> >),
Case("PWM - period: 10 ms, fill: 90%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<10, 90, PERIOD_PULSEWIDTH_US> >),
Case("PWM - period: 50 ms, fill: 10%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 10, PERIOD_WRITE> >),
Case("PWM - period: 50 ms, fill: 10%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 10, PERIOD_MS_WRITE> >),
Case("PWM - period: 50 ms, fill: 10%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 10, PERIOD_US_WRITE> >),
Case("PWM - period: 50 ms, fill: 10%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 10, PERIOD_PULSEWIDTH> >),
Case("PWM - period: 50 ms, fill: 10%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 10, PERIOD_PULSEWIDTH_MS> >),
Case("PWM - period: 50 ms, fill: 10%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 10, PERIOD_PULSEWIDTH_US> >),
Case("PWM - period: 50 ms, fill: 50%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 50, PERIOD_WRITE> >),
Case("PWM - period: 50 ms, fill: 50%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 50, PERIOD_MS_WRITE> >),
Case("PWM - period: 50 ms, fill: 50%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 50, PERIOD_US_WRITE> >),
Case("PWM - period: 50 ms, fill: 50%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 50, PERIOD_PULSEWIDTH> >),
Case("PWM - period: 50 ms, fill: 50%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 50, PERIOD_PULSEWIDTH_MS> >),
Case("PWM - period: 50 ms, fill: 50%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 50, PERIOD_PULSEWIDTH_US> >),
Case("PWM - period: 50 ms, fill: 90%, api: period/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 90, PERIOD_WRITE> >),
Case("PWM - period: 50 ms, fill: 90%, api: period_ms/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 90, PERIOD_MS_WRITE> >),
Case("PWM - period: 50 ms, fill: 90%, api: period_us/write", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 90, PERIOD_US_WRITE> >),
Case("PWM - period: 50 ms, fill: 90%, api: period/pulse_width", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 90, PERIOD_PULSEWIDTH> >),
Case("PWM - period: 50 ms, fill: 90%, api: period/pulse_width_ms", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 90, PERIOD_PULSEWIDTH_MS> >),
Case("PWM - period: 50 ms, fill: 90%, api: period/pulse_width_us", one_peripheral<PWMPort, DefaultFormFactor, pwm_period_fill_test<50, 90, PERIOD_PULSEWIDTH_US> >)
};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(120, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
int main()
{
Harness::run(specification);
}
#endif /* !DEVICE_PWMOUT */

View File

@ -0,0 +1,208 @@
/*
* Copyright (c) 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.
*/
#if !DEVICE_SPI
#error [NOT_SUPPORTED] SPI not supported for this target
#elif !COMPONENT_FPGA_CI_TEST_SHIELD
#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test
#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR)
#error [NOT_SUPPORTED] Test not supported for this form factor
#else
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "mbed.h"
using namespace utest::v1;
#include "SPIMasterTester.h"
#include "pinmap.h"
#include "test_utils.h"
typedef enum {
TRANSFER_SPI_MASTER_WRITE_SYNC,
TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC,
TRANSFER_SPI_MASTER_TRANSFER_ASYNC
} transfer_type_t;
#define FREQ_500_KHZ 500000
#define FREQ_1_MHZ 1000000
#define FREQ_2_MHZ 2000000
const int TRANSFER_COUNT = 300;
SPIMasterTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins());
spi_t spi;
static volatile bool async_trasfer_done;
#if DEVICE_SPI_ASYNCH
void spi_async_handler()
{
int event = spi_irq_handler_asynch(&spi);
if (event == SPI_EVENT_COMPLETE) {
async_trasfer_done = true;
}
}
#endif
void spi_test_init_free(PinName mosi, PinName miso, PinName sclk, PinName ssel)
{
spi_init(&spi, mosi, miso, sclk, ssel);
spi_format(&spi, 8, SPITester::Mode0, 0);
spi_frequency(&spi, 1000000);
spi_free(&spi);
}
void spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel, SPITester::SpiMode spi_mode, uint32_t sym_size, transfer_type_t transfer_type, uint32_t frequency)
{
uint32_t sym_mask = ((1 << sym_size) - 1);
// Remap pins for test
tester.reset();
tester.pin_map_set(mosi, MbedTester::LogicalPinSPIMosi);
tester.pin_map_set(miso, MbedTester::LogicalPinSPIMiso);
tester.pin_map_set(sclk, MbedTester::LogicalPinSPISclk);
tester.pin_map_set(ssel, MbedTester::LogicalPinSPISsel);
// Initialize mbed SPI pins
spi_init(&spi, mosi, miso, sclk, ssel);
spi_format(&spi, sym_size, spi_mode, 0);
spi_frequency(&spi, frequency);
// Configure spi_slave module
tester.set_mode(spi_mode);
tester.set_bit_order(SPITester::MSBFirst);
tester.set_sym_size(sym_size);
// Reset tester stats and select SPI
tester.peripherals_reset();
tester.select_peripheral(SPITester::PeripheralSPI);
uint32_t checksum = 0;
int result = 0;
uint8_t tx_buf[TRANSFER_COUNT] = {0};
uint8_t rx_buf[TRANSFER_COUNT] = {0};
// Send and receive test data
switch (transfer_type) {
case TRANSFER_SPI_MASTER_WRITE_SYNC:
for (int i = 0; i < TRANSFER_COUNT; i++) {
uint32_t data = spi_master_write(&spi, (0 - i) & sym_mask);
TEST_ASSERT_EQUAL(i & sym_mask, data);
checksum += (0 - i) & sym_mask;
}
break;
case TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC:
for (int i = 0; i < TRANSFER_COUNT; i++) {
tx_buf[i] = (0 - i) & sym_mask;
checksum += (0 - i) & sym_mask;
rx_buf[i] = 0xAA;
}
result = spi_master_block_write(&spi, (const char *)tx_buf, TRANSFER_COUNT, (char *)rx_buf, TRANSFER_COUNT, 0xF5);
for (int i = 0; i < TRANSFER_COUNT; i++) {
TEST_ASSERT_EQUAL(i & sym_mask, rx_buf[i]);
}
TEST_ASSERT_EQUAL(TRANSFER_COUNT, result);
break;
#if DEVICE_SPI_ASYNCH
case TRANSFER_SPI_MASTER_TRANSFER_ASYNC:
for (int i = 0; i < TRANSFER_COUNT; i++) {
tx_buf[i] = (0 - i) & sym_mask;
checksum += (0 - i) & sym_mask;
rx_buf[i] = 0xAA;
}
async_trasfer_done = false;
spi_master_transfer(&spi, tx_buf, TRANSFER_COUNT, rx_buf, TRANSFER_COUNT, 8, (uint32_t)spi_async_handler, 0, DMA_USAGE_NEVER);
while (!async_trasfer_done);
for (int i = 0; i < TRANSFER_COUNT; i++) {
TEST_ASSERT_EQUAL(i & sym_mask, rx_buf[i]);
}
break;
#endif
default:
TEST_ASSERT_MESSAGE(0, "Unsupported transfer type.");
break;
}
// Verify that the transfer was successful
TEST_ASSERT_EQUAL(TRANSFER_COUNT, tester.get_transfer_count());
TEST_ASSERT_EQUAL(checksum, tester.get_receive_checksum());
spi_free(&spi);
tester.reset();
}
template<SPITester::SpiMode spi_mode, uint32_t sym_size, transfer_type_t transfer_type, uint32_t frequency>
void spi_test_common(PinName mosi, PinName miso, PinName sclk, PinName ssel)
{
spi_test_common(mosi, miso, sclk, ssel, spi_mode, sym_size, transfer_type, frequency);
}
Case cases[] = {
// This will be run for all pins
Case("SPI - init/free test all pins", all_ports<SPIPort, DefaultFormFactor, spi_test_init_free>),
// This will be run for all peripherals
Case("SPI - basic test", all_peripherals<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ> >),
// This will be run for single pin configuration
Case("SPI - mode testing (MODE_1)", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode1, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ> >),
Case("SPI - mode testing (MODE_2)", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode2, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ> >),
Case("SPI - mode testing (MODE_3)", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode3, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ> >),
Case("SPI - symbol size testing (4)", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode0, 4, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ> >),
Case("SPI - symbol size testing (12)", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode0, 12, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ> >),
Case("SPI - symbol size testing (16)", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode0, 16, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_1_MHZ> >),
Case("SPI - frequency testing (500 kHz)", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_500_KHZ> >),
Case("SPI - frequency testing (2 MHz)", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_WRITE_SYNC, FREQ_2_MHZ> >),
Case("SPI - block write", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_BLOCK_WRITE_SYNC, FREQ_1_MHZ> >),
#if DEVICE_SPI_ASYNCH
Case("SPI - async mode", one_peripheral<SPIPort, DefaultFormFactor, spi_test_common<SPITester::Mode0, 8, TRANSFER_SPI_MASTER_TRANSFER_ASYNC, FREQ_1_MHZ> >)
#endif
};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(60, "default_auto");
return greentea_test_setup_handler(number_of_cases);
}
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
int main()
{
Harness::run(specification);
}
#endif /* !DEVICE_SPI */

View File

@ -0,0 +1,343 @@
/*
* Copyright (c) 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.
*/
#if !DEVICE_SERIAL
#error [NOT_SUPPORTED] SERIAL not supported for this target
#elif !COMPONENT_FPGA_CI_TEST_SHIELD
#error [NOT_SUPPORTED] FPGA CI Test Shield is needed to run this test
#elif !defined(TARGET_FF_ARDUINO) && !defined(MBED_CONF_TARGET_DEFAULT_FORM_FACTOR)
#error [NOT_SUPPORTED] Test not supported for this form factor
#else
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
using namespace utest::v1;
#include <stdlib.h>
#include "UARTTester.h"
#include "pinmap.h"
#include "test_utils.h"
#include "serial_api.h"
#include "us_ticker_api.h"
#define PUTC_REPS 16
#define GETC_REPS 16
// In the UART RX test, the request for the FPGA to start sending data is sent
// first. Then the execution is blocked at serial_getc() call. Since the DUT
// is not ready to receive UART data instantly after the request, the start of
// the actual transmission has to be dalyed.
// A measured delay for NUCLEO_F070RB is 193 us.
#define TX_START_DELAY_NS 250000
UARTTester tester(DefaultFormFactor::pins(), DefaultFormFactor::restricted_pins());
typedef struct {
serial_t *ser;
int *rx_buff;
uint32_t rx_cnt;
int *tx_buff;
uint32_t tx_cnt;
} serial_test_data_t;
static void test_irq_handler(uint32_t id, SerialIrq event)
{
serial_test_data_t *td = (serial_test_data_t *)id;
int c = 0x01; // arbitrary, non-zero value
if (event == RxIrq) {
c = serial_getc(td->ser);
core_util_critical_section_enter();
if (td->rx_cnt < GETC_REPS) {
td->rx_buff[td->rx_cnt] = c;
td->rx_cnt++;
}
core_util_critical_section_exit();
} else if (event == TxIrq) {
core_util_critical_section_enter();
if (td->tx_cnt < PUTC_REPS) {
c = td->tx_buff[td->tx_cnt];
td->tx_cnt++;
}
core_util_critical_section_exit();
// Send either one of tx_buff[] values or 0x01.
serial_putc(td->ser, c);
}
}
static void uart_test_common(int baudrate, int data_bits, SerialParity parity, int stop_bits, PinName tx, PinName rx, PinName cts = NC, PinName rts = NC)
{
// The FPGA CI shield only supports None, Odd & Even.
// Forced parity is not supported on Atmel, Freescale, Nordic & STM targets.
MBED_ASSERT(parity != ParityForced1 && parity != ParityForced0);
// STM-specific constraints
// Only 7, 8 & 9 data bits.
MBED_ASSERT(data_bits >= 7 && data_bits <= 9);
// Only Odd or Even parity for 7 data bits.
if (data_bits == 7) {
MBED_ASSERT(parity != ParityNone);
}
// Limit the actual TX & RX chars to 8 bits for this test.
int test_buff_bits = data_bits < 8 ? data_bits : 8;
// start_bit + data_bits + parity_bit + stop_bits
int packet_bits = 1 + data_bits + stop_bits + (parity == ParityNone ? 0 : 1);
us_timestamp_t packet_tx_time = 1000000 * packet_bits / baudrate;
const ticker_data_t *const us_ticker = get_us_ticker_data();
bool use_flow_control = (cts != NC && rts != NC) ? true : false;
// Remap pins for test
tester.reset();
tester.pin_map_set(tx, MbedTester::LogicalPinUARTRx);
tester.pin_map_set(rx, MbedTester::LogicalPinUARTTx);
if (use_flow_control) {
tester.pin_map_set(cts, MbedTester::LogicalPinUARTRts);
tester.pin_map_set(rts, MbedTester::LogicalPinUARTCts);
}
// Initialize mbed UART pins
serial_t serial;
serial_init(&serial, tx, rx);
serial_baud(&serial, baudrate);
serial_format(&serial, data_bits, parity, stop_bits);
if (use_flow_control) {
serial_set_flow_control(&serial, FlowControlRTSCTS, rts, cts);
} else {
serial_set_flow_control(&serial, FlowControlNone, NC, NC);
}
// Reset tester stats and select UART
tester.peripherals_reset();
tester.select_peripheral(MbedTester::PeripheralUART);
// Configure UART module
tester.set_baud((uint32_t)baudrate);
tester.set_bits((uint8_t)data_bits);
tester.set_stops((uint8_t)stop_bits);
switch (parity) {
case ParityOdd:
tester.set_parity(true, true);
break;
case ParityEven:
tester.set_parity(true, false);
break;
case ParityNone:
default:
tester.set_parity(false, false);
break;
}
if (use_flow_control) {
tester.cts_deassert_delay(0);
}
int rx_buff[GETC_REPS] = {};
int tx_buff[PUTC_REPS] = {};
volatile serial_test_data_t td = {
&serial,
rx_buff,
0,
tx_buff,
0
};
uint32_t checksum = 0;
// DUT TX / FPGA RX
int tx_val;
tester.rx_start();
for (uint32_t reps = 1; reps <= PUTC_REPS; reps++) {
tx_val = rand() % (1 << test_buff_bits);
checksum += tx_val;
serial_putc(&serial, tx_val);
us_timestamp_t end_ts = ticker_read_us(us_ticker) + 2 * packet_tx_time;
while (tester.rx_get_count() != reps && ticker_read_us(us_ticker) <= end_ts) {
// Wait (no longer than twice the time of one packet transfer) for
// the FPGA to receive data and update the byte counter.
}
TEST_ASSERT_EQUAL_UINT32(reps, tester.rx_get_count());
TEST_ASSERT_EQUAL(0, tester.rx_get_parity_errors());
TEST_ASSERT_EQUAL(0, tester.rx_get_stop_errors());
TEST_ASSERT_EQUAL(0, tester.rx_get_framing_errors());
TEST_ASSERT_EQUAL_UINT32(checksum, tester.rx_get_checksum());
TEST_ASSERT_EQUAL(tx_val, tester.rx_get_data());
}
tester.rx_stop();
// DUT RX / FPGA TX
// serial_getc() may return 16-bit as well as 8-bit value cast to an int.
// Use a random initial value, but make sure it is low enouth,
// so the FPGA will not overflow 8 bits when incrementing it.
uint16_t tester_buff = rand() % ((1 << test_buff_bits) - GETC_REPS);
tester.tx_set_next(tester_buff);
tester.tx_set_count(GETC_REPS);
if (!use_flow_control) {
tester.tx_set_delay(TX_START_DELAY_NS);
}
tester.tx_start(use_flow_control);
for (int i = 0; i < GETC_REPS; i++) {
rx_buff[i] = serial_getc(&serial);
}
tester.tx_stop();
for (int i = 0; i < GETC_REPS; tester_buff++, i++) {
TEST_ASSERT_EQUAL(tester_buff, rx_buff[i]);
}
serial_irq_handler(&serial, test_irq_handler, (uint32_t) &td);
// DUT TX (IRQ) / FPGA RX
tx_val = rand() % ((1 << test_buff_bits) - PUTC_REPS);
for (size_t i = 0; i < PUTC_REPS; tx_val++, i++) {
td.tx_buff[i] = tx_val;
checksum += tx_val;
}
tester.rx_start();
core_util_critical_section_enter();
td.tx_cnt = 0;
// Enable only the TX IRQ.
serial_irq_set(&serial, TxIrq, 1);
core_util_critical_section_exit();
while (core_util_atomic_load_u32(&td.tx_cnt) != PUTC_REPS) {
// Wait until the last byte is written to UART TX reg.
};
core_util_critical_section_enter();
serial_irq_set(&serial, TxIrq, 0);
core_util_critical_section_exit();
us_timestamp_t end_ts = ticker_read_us(us_ticker) + 2 * packet_tx_time;
while (ticker_read_us(us_ticker) <= end_ts) {
// Wait twice the time of one packet transfer for the FPGA
// to receive and process data.
};
tester.rx_stop();
TEST_ASSERT_EQUAL_UINT32(2 * PUTC_REPS, tester.rx_get_count());
TEST_ASSERT_EQUAL(0, tester.rx_get_parity_errors());
TEST_ASSERT_EQUAL(0, tester.rx_get_stop_errors());
TEST_ASSERT_EQUAL(0, tester.rx_get_framing_errors());
TEST_ASSERT_EQUAL_UINT32(checksum, tester.rx_get_checksum());
TEST_ASSERT_EQUAL(tx_val - 1, tester.rx_get_data());
// DUT RX (IRQ) / FPGA TX
// serial_getc() may return 16-bit as well as 8-bit value cast to an int.
// Use a random initial value, but make sure it is low enouth,
// so the FPGA will not overflow 8 bits when incrementing it.
tester_buff = rand() % ((1 << test_buff_bits) - GETC_REPS);
tester.tx_set_next(tester_buff);
tester.tx_set_count(GETC_REPS);
if (!use_flow_control) {
tester.tx_set_delay(TX_START_DELAY_NS);
}
core_util_critical_section_enter();
// Enable only the RX IRQ.
serial_irq_set(&serial, RxIrq, 1);
core_util_critical_section_exit();
tester.rx_start();
tester.tx_start(use_flow_control);
while (core_util_atomic_load_u32(&td.rx_cnt) != GETC_REPS) {
// Wait until the last byte is received to UART RX reg.
};
core_util_critical_section_enter();
serial_irq_set(&serial, RxIrq, 0);
core_util_critical_section_exit();
tester.tx_stop();
tester.rx_stop();
for (int i = 0; i < GETC_REPS; tester_buff++, i++) {
TEST_ASSERT_EQUAL(tester_buff, td.rx_buff[i]);
}
// Make sure TX IRQ was disabled during the last RX test.
TEST_ASSERT_EQUAL_UINT32(checksum, tester.rx_get_checksum());
TEST_ASSERT_EQUAL_UINT32(2 * PUTC_REPS, tester.rx_get_count());
// Cleanup
serial_free(&serial);
tester.reset();
}
void test_init_free(PinName tx, PinName rx, PinName cts = NC, PinName rts = NC)
{
bool use_flow_control = (cts != NC && rts != NC) ? true : false;
serial_t serial;
serial_init(&serial, tx, rx);
serial_baud(&serial, 9600);
serial_format(&serial, 8, ParityNone, 1);
if (use_flow_control) {
serial_set_flow_control(&serial, FlowControlRTSCTS, rts, cts);
}
serial_free(&serial);
}
void test_init_free_no_fc(PinName tx, PinName rx)
{
test_init_free(tx, rx);
}
template<int BAUDRATE, int DATA_BITS, SerialParity PARITY, int STOP_BITS>
void test_common(PinName tx, PinName rx, PinName cts, PinName rts)
{
uart_test_common(BAUDRATE, DATA_BITS, PARITY, STOP_BITS, tx, rx, cts, rts);
}
template<int BAUDRATE, int DATA_BITS, SerialParity PARITY, int STOP_BITS>
void test_common_no_fc(PinName tx, PinName rx)
{
uart_test_common(BAUDRATE, DATA_BITS, PARITY, STOP_BITS, tx, rx);
}
Case cases[] = {
// Every set of pins from every peripheral.
Case("init/free, FC on", all_ports<UARTPort, DefaultFormFactor, test_init_free>),
Case("init/free, FC off", all_ports<UARTNoFCPort, DefaultFormFactor, test_init_free_no_fc>),
// One set of pins from every peripheral.
Case("basic, 9600, 8N1, FC on", all_peripherals<UARTPort, DefaultFormFactor, test_common<9600, 8, ParityNone, 1> >),
Case("basic, 9600, 8N1, FC off", all_peripherals<UARTNoFCPort, DefaultFormFactor, test_common_no_fc<9600, 8, ParityNone, 1> >),
// One set of pins from one peripheral.
// baudrate
Case("19200, 8N1, FC on", one_peripheral<UARTPort, DefaultFormFactor, test_common<19200, 8, ParityNone, 1> >),
Case("19200, 8N1, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, test_common_no_fc<19200, 8, ParityNone, 1> >),
Case("38400, 8N1, FC on", one_peripheral<UARTPort, DefaultFormFactor, test_common<38400, 8, ParityNone, 1> >),
Case("38400, 8N1, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, test_common_no_fc<38400, 8, ParityNone, 1> >),
Case("115200, 8N1, FC on", one_peripheral<UARTPort, DefaultFormFactor, test_common<115200, 8, ParityNone, 1> >),
Case("115200, 8N1, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, test_common_no_fc<115200, 8, ParityNone, 1> >),
// data bits: not tested (some platforms support 8 bits only)
// parity
Case("9600, 8O1, FC on", one_peripheral<UARTPort, DefaultFormFactor, test_common<9600, 8, ParityOdd, 1> >),
Case("9600, 8E1, FC on", one_peripheral<UARTPort, DefaultFormFactor, test_common<9600, 8, ParityEven, 1> >),
// stop bits
Case("9600, 8N2, FC on", one_peripheral<UARTPort, DefaultFormFactor, test_common<9600, 8, ParityNone, 2> >),
Case("9600, 8N2, FC off", one_peripheral<UARTNoFCPort, DefaultFormFactor, test_common_no_fc<9600, 8, ParityNone, 2> >),
};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(240, "default_auto");
srand((unsigned) ticker_read_us(get_us_ticker_data()));
return greentea_test_setup_handler(number_of_cases);
}
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
int main()
{
Harness::run(specification);
}
#endif /* !DEVICE_SERIAL */

View File

@ -24,7 +24,7 @@
#include "hal/lp_ticker_api.h"
//FastModels not support timing test
#if defined(__ARM_FM)
#if defined(TARGET_ARM_FM)
#error [NOT_SUPPORTED] test not supported
#endif

View File

@ -19,6 +19,10 @@
#include "utest/utest.h"
#include "unity/unity.h"
#if defined(SKIP_TIME_DRIFT_TESTS)
#error [NOT_SUPPORTED] test not supported
#endif
#if defined(MBED_RTOS_SINGLE_THREAD)
#error [NOT_SUPPORTED] test not supported
#endif
@ -27,11 +31,6 @@
#error [NOT_SUPPORTED] test not supported
#endif
//FastModels not support time drifting test
#if defined(__ARM_FM)
#error [NOT_SUPPORTED] test not supported
#endif
using utest::v1::Case;
#if defined(__CORTEX_M23) || defined(__CORTEX_M33)

View File

@ -107,7 +107,7 @@ Case cases[] = {
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(10, "timing_drift_auto");
GREENTEA_SETUP(10, "default_auto");
return utest::v1::greentea_test_setup_handler(number_of_cases);
}

View File

@ -31,7 +31,7 @@ using namespace utest::v1;
#if defined(__CORTEX_M23) || defined(__CORTEX_M33)
#define THREAD_STACK_SIZE 512
#elif defined(__ARM_FM)
#elif defined(TARGET_ARM_FM)
#define THREAD_STACK_SIZE 512
#elif defined(TARGET_CY8CKIT_062_WIFI_BT_PSA)
#define THREAD_STACK_SIZE 512

View File

@ -39,7 +39,7 @@ volatile bool thread_should_continue = true;
#define THREAD_STACK_SIZE 512
#elif defined(__CORTEX_M23) || defined(__CORTEX_M33)
#define THREAD_STACK_SIZE 512
#elif defined(__ARM_FM)
#elif defined(TARGET_ARM_FM)
#define THREAD_STACK_SIZE 512
#elif defined(TARGET_CY8CKIT_062_WIFI_BT_PSA)
#define THREAD_STACK_SIZE 512
@ -122,7 +122,7 @@ void test_alloc_and_free(void)
int size = SIZE_INCREMENTS;
int loop = ALLOC_LOOP;
while (loop) {
data = malloc(size);
data = count < ALLOC_ARRAY_SIZE ? malloc(size) : NULL;
if (NULL != data) {
array[count++] = data;
memset((void *)data, 0xdeadbeef, size);
@ -211,7 +211,7 @@ Case cases[] = {
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(test_timeout, "timing_drift_auto");
GREENTEA_SETUP(test_timeout, "default_auto");
return utest::v1::greentea_test_setup_handler(number_of_cases);
}

View File

@ -31,6 +31,14 @@ extern "C" {
#define TEST_TICKS 42UL
#define DELAY_DELTA_US 2500ULL
/* Use a specific delta value for deep sleep, as entry/exit adds up extra latency.
* Use deep sleep latency if defined and add 1ms extra delta */
#if defined MBED_CONF_TARGET_DEEP_SLEEP_LATENCY
#define DEEP_SLEEP_DELAY_DELTA_US ((MBED_CONF_TARGET_DEEP_SLEEP_LATENCY * 1000ULL) + 1000ULL)
#else
#define DEEP_SLEEP_DELAY_DELTA_US 2500ULL
#endif
using namespace utest::v1;
const us_timestamp_t DELAY_US = 1000000ULL * TEST_TICKS / OS_TICK_FREQ;
@ -66,6 +74,11 @@ public:
{
return _sem.try_acquire_for(millisec);
}
void sem_acquire()
{
_sem.acquire();
}
};
timestamp_t mock_ticker_timestamp;
@ -275,9 +288,8 @@ void test_sleep(void)
st.schedule_tick(TEST_TICKS);
TEST_ASSERT_FALSE_MESSAGE(sleep_manager_can_deep_sleep(), "Deep sleep should be disallowed");
while (!st.sem_try_acquire(0)) {
sleep();
}
st.sem_acquire();
timer.stop();
sleep_manager_unlock_deep_sleep();
@ -305,7 +317,6 @@ void test_deepsleep(void)
* so we'll use the wait_ms() function for now.
*/
wait_ms(10);
// Regular Timer might be disabled during deepsleep.
LowPowerTimer lptimer;
SysTimerTest st;
@ -313,12 +324,10 @@ void test_deepsleep(void)
lptimer.start();
st.schedule_tick(TEST_TICKS);
TEST_ASSERT_TRUE_MESSAGE(sleep_manager_can_deep_sleep_test_check(), "Deep sleep should be allowed");
while (!st.sem_try_acquire(0)) {
sleep();
}
st.sem_acquire();
lptimer.stop();
TEST_ASSERT_UINT64_WITHIN(DELAY_DELTA_US, DELAY_US, lptimer.read_high_resolution_us());
TEST_ASSERT_UINT64_WITHIN(DEEP_SLEEP_DELAY_DELTA_US, DELAY_US, lptimer.read_high_resolution_us());
}
#endif
#endif

View File

@ -34,7 +34,7 @@
#define PARALLEL_THREAD_STACK_SIZE 512
#elif defined(__CORTEX_M23) || defined(__CORTEX_M33)
#define PARALLEL_THREAD_STACK_SIZE 512
#elif defined(__ARM_FM)
#elif defined(TARGET_ARM_FM)
#define PARALLEL_THREAD_STACK_SIZE 512
#elif defined(TARGET_CY8CKIT_062_WIFI_BT_PSA)
#define PARALLEL_THREAD_STACK_SIZE 512

View File

@ -20,9 +20,6 @@
(MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE == WIFI && !defined(MBED_CONF_NSAPI_DEFAULT_WIFI_SSID))
#error [NOT_SUPPORTED] No network configuration found for this target.
#endif
#ifndef MBED_CONF_APP_ECHO_SERVER_ADDR
#error [NOT_SUPPORTED] Requires parameters from mbed_app.json
#endif
#include "mbed.h"
#include "greentea-client/test_env.h"
@ -31,6 +28,10 @@
#include "utest/utest_stack_trace.h"
#include "tcp_tests.h"
#ifndef ECHO_SERVER_ADDR
#error [NOT_SUPPORTED] Requires parameters for echo server
#endif
using namespace utest::v1;
namespace {
@ -84,7 +85,7 @@ nsapi_error_t tcpsocket_connect_to_srv(TCPSocket &sock, uint16_t port)
{
SocketAddress tcp_addr;
NetworkInterface::get_default_instance()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &tcp_addr);
NetworkInterface::get_default_instance()->gethostbyname(ECHO_SERVER_ADDR, &tcp_addr);
tcp_addr.set_port(port);
printf("MBED: Server '%s', port %d\n", tcp_addr.get_ip_address(), tcp_addr.get_port());
@ -106,12 +107,12 @@ nsapi_error_t tcpsocket_connect_to_srv(TCPSocket &sock, uint16_t port)
nsapi_error_t tcpsocket_connect_to_echo_srv(TCPSocket &sock)
{
return tcpsocket_connect_to_srv(sock, MBED_CONF_APP_ECHO_SERVER_PORT);
return tcpsocket_connect_to_srv(sock, ECHO_SERVER_PORT);
}
nsapi_error_t tcpsocket_connect_to_discard_srv(TCPSocket &sock)
{
return tcpsocket_connect_to_srv(sock, MBED_CONF_APP_ECHO_SERVER_DISCARD_PORT);
return tcpsocket_connect_to_srv(sock, ECHO_SERVER_DISCARD_PORT);
}
bool is_tcp_supported()

View File

@ -18,6 +18,8 @@
#ifndef TCP_TESTS_H
#define TCP_TESTS_H
#include "../test_params.h"
NetworkInterface *get_interface();
void drop_bad_packets(TCPSocket &sock, int orig_timeout);
nsapi_version_t get_ip_version();

View File

@ -33,7 +33,7 @@ void TCPSOCKET_CONNECT_INVALID()
TEST_ASSERT(sock.connect(NULL, 9) < 0);
TEST_ASSERT(sock.connect("", 9) < 0);
TEST_ASSERT(sock.connect("", 0) < 0);
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.connect(MBED_CONF_APP_ECHO_SERVER_ADDR, 9));
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.connect(ECHO_SERVER_ADDR, ECHO_SERVER_DISCARD_PORT));
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close());
}

View File

@ -38,7 +38,7 @@ static nsapi_error_t _tcpsocket_connect_to_daytime_srv(TCPSocket &sock)
{
SocketAddress tcp_addr;
NetworkInterface::get_default_instance()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &tcp_addr);
NetworkInterface::get_default_instance()->gethostbyname(ECHO_SERVER_ADDR, &tcp_addr);
tcp_addr.set_port(13);
nsapi_error_t err = sock.open(NetworkInterface::get_default_instance());

View File

@ -33,7 +33,7 @@ static nsapi_error_t _tcpsocket_connect_to_chargen_srv(TCPSocket &sock)
{
SocketAddress tcp_addr;
NetworkInterface::get_default_instance()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &tcp_addr);
NetworkInterface::get_default_instance()->gethostbyname(ECHO_SERVER_ADDR, &tcp_addr);
tcp_addr.set_port(19);
nsapi_error_t err = sock.open(NetworkInterface::get_default_instance());

View File

@ -40,7 +40,7 @@ void TCPSOCKET_SETSOCKOPT_KEEPALIVE_VALID()
}
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, ret);
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.connect(MBED_CONF_APP_ECHO_SERVER_ADDR, 9));
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.connect(ECHO_SERVER_ADDR, 9));
// LWIP stack does not support getsockopt so the part below is commented out
// int32_t optval;
// unsigned int optlen;

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2018, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TEST_PARAMS_H
#define TEST_PARAMS_H
#ifndef MBED_CONF_APP_ECHO_SERVER_ADDR
#define ECHO_SERVER_ADDR "echo.mbedcloudtesting.com"
#else
#define ECHO_SERVER_ADDR MBED_CONF_APP_ECHO_SERVER_ADDR
#endif
#ifndef MBED_CONF_APP_ECHO_SERVER_PORT
#define ECHO_SERVER_PORT 7
#else
#define ECHO_SERVER_PORT MBED_CONF_APP_ECHO_SERVER_PORT
#endif
#ifndef MBED_CONF_APP_ECHO_SERVER_DISCARD_PORT
#define ECHO_SERVER_DISCARD_PORT 9
#else
#define ECHO_SERVER_DISCARD_PORT MBED_CONF_APP_ECHO_SERVER_DISCARD_PORT
#endif
#ifndef MBED_CONF_APP_ECHO_SERVER_PORT_TLS
#define ECHO_SERVER_PORT_TLS 2007
#else
#define ECHO_SERVER_PORT_TLS MBED_CONF_APP_ECHO_SERVER_PORT_TLS
#endif
#ifndef MBED_CONF_APP_ECHO_SERVER_DISCARD_PORT_TLS
#define ECHO_SERVER_DISCARD_PORT_TLS 2009
#else
#define ECHO_SERVER_DISCARD_PORT_TLS MBED_CONF_APP_ECHO_SERVER_DISCARD_PORT_TLS
#endif
#endif //TEST_PARAMS_H

View File

@ -20,9 +20,6 @@
(MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE == WIFI && !defined(MBED_CONF_NSAPI_DEFAULT_WIFI_SSID))
#error [NOT_SUPPORTED] No network configuration found for this target.
#endif
#ifndef MBED_CONF_APP_ECHO_SERVER_ADDR
#error [NOT_SUPPORTED] Requires echo-server-discard-port parameter from mbed_app.json
#endif
#include "mbed.h"
#include "greentea-client/test_env.h"
@ -31,6 +28,10 @@
#include "utest/utest_stack_trace.h"
#include "tls_tests.h"
#ifndef ECHO_SERVER_ADDR
#error [NOT_SUPPORTED] Requires parameters for echo server
#endif
#if defined(MBEDTLS_SSL_CLI_C) || defined(DOXYGEN_ONLY)
using namespace utest::v1;
@ -106,7 +107,7 @@ nsapi_error_t tlssocket_connect_to_srv(TLSSocket &sock, uint16_t port)
{
SocketAddress tls_addr;
NetworkInterface::get_default_instance()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &tls_addr);
NetworkInterface::get_default_instance()->gethostbyname(ECHO_SERVER_ADDR, &tls_addr);
tls_addr.set_port(port);
printf("MBED: Server '%s', port %d\n", tls_addr.get_ip_address(), tls_addr.get_port());
@ -134,12 +135,12 @@ nsapi_error_t tlssocket_connect_to_srv(TLSSocket &sock, uint16_t port)
nsapi_error_t tlssocket_connect_to_echo_srv(TLSSocket &sock)
{
return tlssocket_connect_to_srv(sock, MBED_CONF_APP_ECHO_SERVER_PORT_TLS);
return tlssocket_connect_to_srv(sock, ECHO_SERVER_PORT_TLS);
}
nsapi_error_t tlssocket_connect_to_discard_srv(TLSSocket &sock)
{
return tlssocket_connect_to_srv(sock, MBED_CONF_APP_ECHO_SERVER_DISCARD_PORT_TLS);
return tlssocket_connect_to_srv(sock, ECHO_SERVER_DISCARD_PORT_TLS);
}
bool is_tcp_supported()

View File

@ -18,6 +18,7 @@
#ifndef TLS_TESTS_H
#define TLS_TESTS_H
#include "../test_params.h"
#include "TLSSocket.h"
#if defined(MBEDTLS_SSL_CLI_C) || defined(DOXYGEN_ONLY)

View File

@ -33,12 +33,12 @@ void TLSSOCKET_CONNECT_INVALID()
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(NetworkInterface::get_default_instance()));
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.set_root_ca_cert(tls_global::cert));
TEST_ASSERT(sock.connect(NULL, MBED_CONF_APP_ECHO_SERVER_DISCARD_PORT_TLS) < 0);
TEST_ASSERT(sock.connect("", MBED_CONF_APP_ECHO_SERVER_DISCARD_PORT_TLS) < 0);
TEST_ASSERT(sock.connect(NULL, ECHO_SERVER_DISCARD_PORT_TLS) < 0);
TEST_ASSERT(sock.connect("", ECHO_SERVER_DISCARD_PORT_TLS) < 0);
TEST_ASSERT(sock.connect("", 0) < 0);
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK,
sock.connect(MBED_CONF_APP_ECHO_SERVER_ADDR, MBED_CONF_APP_ECHO_SERVER_DISCARD_PORT_TLS));
sock.connect(ECHO_SERVER_ADDR, ECHO_SERVER_DISCARD_PORT_TLS));
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close());
}

View File

@ -40,7 +40,7 @@ static nsapi_error_t _tlssocket_connect_to_daytime_srv(TLSSocket &sock)
{
SocketAddress tls_addr;
NetworkInterface::get_default_instance()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &tls_addr);
NetworkInterface::get_default_instance()->gethostbyname(ECHO_SERVER_ADDR, &tls_addr);
tls_addr.set_port(2013);
nsapi_error_t err = sock.open(NetworkInterface::get_default_instance());

View File

@ -32,7 +32,7 @@ void TLSSOCKET_NO_CERT()
TLSSocket sock;
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(NetworkInterface::get_default_instance()));
TEST_ASSERT_EQUAL(NSAPI_ERROR_AUTH_FAILURE,
sock.connect(MBED_CONF_APP_ECHO_SERVER_ADDR, MBED_CONF_APP_ECHO_SERVER_PORT_TLS));
sock.connect(ECHO_SERVER_ADDR, ECHO_SERVER_PORT_TLS));
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close());
}

View File

@ -33,7 +33,7 @@ void TLSSOCKET_SEND_CLOSED()
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(NetworkInterface::get_default_instance()));
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.set_root_ca_cert(tls_global::cert));
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK,
sock.connect(MBED_CONF_APP_ECHO_SERVER_ADDR, MBED_CONF_APP_ECHO_SERVER_PORT_TLS));
sock.connect(ECHO_SERVER_ADDR, ECHO_SERVER_PORT_TLS));
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close());
TEST_ASSERT_EQUAL(NSAPI_ERROR_NO_SOCKET, sock.send("12345", 5));
}

View File

@ -20,9 +20,6 @@
(MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE == WIFI && !defined(MBED_CONF_NSAPI_DEFAULT_WIFI_SSID))
#error [NOT_SUPPORTED] No network configuration found for this target.
#endif
#ifndef MBED_CONF_APP_ECHO_SERVER_ADDR
#error [NOT_SUPPORTED] Requires parameters from mbed_app.json
#endif
#include "mbed.h"
#include "greentea-client/test_env.h"
@ -31,6 +28,10 @@
#include "utest/utest_stack_trace.h"
#include "udp_tests.h"
#ifndef ECHO_SERVER_ADDR
#error [NOT_SUPPORTED] Requires parameters for echo server
#endif
using namespace utest::v1;
namespace {

View File

@ -18,6 +18,8 @@
#ifndef UDP_TESTS_H
#define UDP_TESTS_H
#include "../test_params.h"
NetworkInterface *get_interface();
void drop_bad_packets(UDPSocket &sock, int orig_timeout);
nsapi_version_t get_ip_version();

View File

@ -29,14 +29,12 @@ namespace {
static const int SIGNAL_SIGIO_RX = 0x1;
static const int SIGNAL_SIGIO_TX = 0x2;
static const int SIGIO_TIMEOUT = 5000; //[ms]
static const int WAIT2RECV_TIMEOUT = 5000; //[ms]
static const int RETRIES = 2;
static const double EXPECTED_LOSS_RATIO = 0.0;
static const double TOLERATED_LOSS_RATIO = 0.3;
UDPSocket sock;
Semaphore tx_sem(0, 1);
UDPSocket *sock;
EventFlags signals;
static const int BUFF_SIZE = 1200;
@ -60,8 +58,8 @@ static void _sigio_handler()
void UDPSOCKET_ECHOTEST()
{
SocketAddress udp_addr;
NetworkInterface::get_default_instance()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &udp_addr);
udp_addr.set_port(MBED_CONF_APP_ECHO_SERVER_PORT);
NetworkInterface::get_default_instance()->gethostbyname(ECHO_SERVER_ADDR, &udp_addr);
udp_addr.set_port(ECHO_SERVER_PORT);
UDPSocket sock;
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(NetworkInterface::get_default_instance()));
@ -110,72 +108,37 @@ void UDPSOCKET_ECHOTEST()
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close());
}
void udpsocket_echotest_nonblock_receiver(void *receive_bytes)
{
int expt2recv = *(int *)receive_bytes;
int recvd;
for (int retry_cnt = 0; retry_cnt <= RETRIES; retry_cnt++) {
recvd = sock.recvfrom(NULL, rx_buffer, expt2recv);
if (recvd == NSAPI_ERROR_WOULD_BLOCK) {
if (tc_exec_time.read() >= time_allotted) {
break;
}
signals.wait_all(SIGNAL_SIGIO_RX, WAIT2RECV_TIMEOUT);
--retry_cnt;
continue;
} else if (recvd < 0) {
printf("sock.recvfrom returned %d\n", recvd);
TEST_FAIL();
break;
} else if (recvd == expt2recv) {
break;
}
}
drop_bad_packets(sock, 0); // timeout equivalent to set_blocking(false)
tx_sem.release();
}
void UDPSOCKET_ECHOTEST_NONBLOCK()
{
tc_exec_time.start();
time_allotted = split2half_rmng_udp_test_time(); // [s]
SocketAddress udp_addr;
NetworkInterface::get_default_instance()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &udp_addr);
udp_addr.set_port(MBED_CONF_APP_ECHO_SERVER_PORT);
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(NetworkInterface::get_default_instance()));
sock.set_blocking(false);
sock.sigio(callback(_sigio_handler));
NetworkInterface::get_default_instance()->gethostbyname(ECHO_SERVER_ADDR, &udp_addr);
udp_addr.set_port(ECHO_SERVER_PORT);
sock = new UDPSocket();
if (sock == NULL) {
TEST_FAIL_MESSAGE("UDPSocket not created");
return;
}
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock->open(NetworkInterface::get_default_instance()));
sock->set_blocking(false);
sock->sigio(callback(_sigio_handler));
int sent;
int packets_sent = 0;
int packets_recv = 0;
Thread *thread;
unsigned char *stack_mem = (unsigned char *)malloc(OS_STACK_SIZE);
TEST_ASSERT_NOT_NULL(stack_mem);
for (int s_idx = 0; s_idx < sizeof(pkt_sizes) / sizeof(*pkt_sizes); ++s_idx) {
int pkt_s = pkt_sizes[s_idx];
int packets_sent_prev = packets_sent;
thread = new Thread(osPriorityNormal,
OS_STACK_SIZE,
stack_mem,
"receiver");
TEST_ASSERT_EQUAL(osOK, thread->start(callback(udpsocket_echotest_nonblock_receiver, &pkt_s)));
for (int retry_cnt = 0; retry_cnt <= RETRIES; retry_cnt++) {
fill_tx_buffer_ascii(tx_buffer, pkt_s);
sent = sock.sendto(udp_addr, tx_buffer, pkt_s);
sent = sock->sendto(udp_addr, tx_buffer, pkt_s);
if (sent == pkt_s) {
packets_sent++;
} else if (sent == NSAPI_ERROR_WOULD_BLOCK) {
if (tc_exec_time.read() >= time_allotted ||
osSignalWait(SIGNAL_SIGIO_TX, SIGIO_TIMEOUT).status == osEventTimeout) {
signals.wait_all(SIGNAL_SIGIO_TX, SIGIO_TIMEOUT) == osFlagsErrorTimeout) {
continue;
}
--retry_cnt;
@ -183,20 +146,36 @@ void UDPSOCKET_ECHOTEST_NONBLOCK()
printf("[Round#%02d - Sender] error, returned %d\n", s_idx, sent);
continue;
}
if (!tx_sem.try_acquire_for(WAIT2RECV_TIMEOUT * 2)) { // RX might wait up to WAIT2RECV_TIMEOUT before recvfrom
continue;
}
int recvd;
for (int retry_recv = 0; retry_recv <= RETRIES; retry_recv++) {
recvd = sock->recvfrom(NULL, rx_buffer, pkt_s);
if (recvd == NSAPI_ERROR_WOULD_BLOCK) {
if (tc_exec_time.read() >= time_allotted) {
break;
}
signals.wait_all(SIGNAL_SIGIO_RX, SIGIO_TIMEOUT);
--retry_recv;
continue;
} else if (recvd < 0) {
printf("sock.recvfrom returned %d\n", recvd);
TEST_FAIL();
break;
} else if (recvd == pkt_s) {
break;
}
}
if (recvd == pkt_s) {
break;
}
}
// Make sure that at least one packet of every size was sent.
TEST_ASSERT_TRUE(packets_sent > packets_sent_prev);
thread->join();
delete thread;
if (memcmp(tx_buffer, rx_buffer, pkt_s) == 0) {
packets_recv++;
}
}
free(stack_mem);
// Packet loss up to 30% tolerated
if (packets_sent > 0) {
@ -220,6 +199,7 @@ void UDPSOCKET_ECHOTEST_NONBLOCK()
#endif
}
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close());
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock->close());
delete sock;
tc_exec_time.stop();
}

View File

@ -71,8 +71,8 @@ static void _sigio_handler(osThreadId id)
void UDPSOCKET_ECHOTEST_BURST()
{
SocketAddress udp_addr;
NetworkInterface::get_default_instance()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &udp_addr);
udp_addr.set_port(MBED_CONF_APP_ECHO_SERVER_PORT);
NetworkInterface::get_default_instance()->gethostbyname(ECHO_SERVER_ADDR, &udp_addr);
udp_addr.set_port(ECHO_SERVER_PORT);
UDPSocket sock;
const int TIMEOUT = 5000; // [ms]
@ -154,8 +154,8 @@ void UDPSOCKET_ECHOTEST_BURST()
void UDPSOCKET_ECHOTEST_BURST_NONBLOCK()
{
SocketAddress udp_addr;
NetworkInterface::get_default_instance()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &udp_addr);
udp_addr.set_port(MBED_CONF_APP_ECHO_SERVER_PORT);
NetworkInterface::get_default_instance()->gethostbyname(ECHO_SERVER_ADDR, &udp_addr);
udp_addr.set_port(ECHO_SERVER_PORT);
UDPSocket sock;
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(NetworkInterface::get_default_instance()));

View File

@ -38,8 +38,8 @@ static void _sigio_handler(osThreadId id)
void UDPSOCKET_RECV_TIMEOUT()
{
SocketAddress udp_addr;
NetworkInterface::get_default_instance()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &udp_addr);
udp_addr.set_port(MBED_CONF_APP_ECHO_SERVER_PORT);
NetworkInterface::get_default_instance()->gethostbyname(ECHO_SERVER_ADDR, &udp_addr);
udp_addr.set_port(ECHO_SERVER_PORT);
static const int DATA_LEN = 100;
char buff[DATA_LEN] = {0};

View File

@ -33,12 +33,12 @@ void UDPSOCKET_SENDTO_INVALID()
TEST_ASSERT(sock.sendto("", 9, NULL, 0) < 0);
TEST_ASSERT(sock.sendto("", 0, NULL, 0) < 0);
nsapi_error_t result = sock.sendto(MBED_CONF_APP_ECHO_SERVER_ADDR, 9, NULL, 0);
nsapi_error_t result = sock.sendto(ECHO_SERVER_ADDR, 9, NULL, 0);
if (result != NSAPI_ERROR_UNSUPPORTED) {
TEST_ASSERT_EQUAL(0, result);
}
TEST_ASSERT_EQUAL(5, sock.sendto(MBED_CONF_APP_ECHO_SERVER_ADDR, 9, "hello", 5));
TEST_ASSERT_EQUAL(5, sock.sendto(ECHO_SERVER_ADDR, 9, "hello", 5));
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close());
}

View File

@ -30,7 +30,7 @@ void UDPSOCKET_SENDTO_REPEAT()
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(NetworkInterface::get_default_instance()));
SocketAddress udp_addr;
NetworkInterface::get_default_instance()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &udp_addr);
NetworkInterface::get_default_instance()->gethostbyname(ECHO_SERVER_ADDR, &udp_addr);
udp_addr.set_port(9);
int sent;

View File

@ -33,7 +33,7 @@ void UDPSOCKET_SENDTO_TIMEOUT()
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(NetworkInterface::get_default_instance()));
SocketAddress udp_addr;
NetworkInterface::get_default_instance()->gethostbyname(MBED_CONF_APP_ECHO_SERVER_ADDR, &udp_addr);
NetworkInterface::get_default_instance()->gethostbyname(ECHO_SERVER_ADDR, &udp_addr);
udp_addr.set_port(9);
Timer timer;

View File

@ -131,6 +131,10 @@ void NETWORKINTERFACE_STATUS_NONBLOCK()
status = wait_status_callback();
TEST_ASSERT_EQUAL(NSAPI_STATUS_DISCONNECTED, status);
wait(1); // In cellular there might still come disconnected messages from the network which are sent to callback.
// This would cause this test to fail as next connect is already ongoing. So wait here a while until (hopefully)
// all messages also from the network have arrived.
}
net->attach(NULL);

166
TESTS/usb_device/README.md Normal file
View File

@ -0,0 +1,166 @@
# Testing the Mbed OS USB device
## Setup
Before running tests, please make sure to use a
[top-level requirements.txt][LN-requirements] file to install all the
required Python modules.
```
pip install -r requirements.txt
```
Additional, platform-specific setup is described below.
See also [Known issues](#known-issues).
### Windows
1. Install a **generic USB driver** for two test devices.
1. Download `Zadig` application from [the Zadig website][LN-zadig].
1. Unplug the Mbed device.
1. Open `Zadig`.
1. Select *Device -> Load Preset Device*.
1. Open [TESTS/usb_device/basic/zadig_conf/mbed_os-usb_test_device1.cfg][LN-zadig_conf1]
1. Choose `libusb-win32 (v1.2.6.0)` driver.
1. Select `Install Driver` and click it.
1. Select *Device -> Load Preset Device*.
1. Open [TESTS/usb_device/basic/zadig_conf/mbed_os-usb_test_device2.cfg][LN-zadig_conf2]
1. Choose `libusb-win32 (v1.2.6.0)` driver.
1. Select `Install Driver` and click it.
1. Close `Zadig`.
1. Plug both USB interfaces (*DAPLink* and *USB device*).
### Linux
1. Install the `hidapi` Python module, otherwise some USB HID test cases will
be skipped. This module is not installed during the initial setup due to
external dependencies for Linux.
For Debian-based Linux distros, the dependencies can be installed as follows
(based on module's [README][LN-hidapi_readme]):
```bash
apt-get install python-dev libusb-1.0-0-dev libudev-dev
pip install --upgrade setuptools
```
To install the `hidapi` module itself, please use the attached
[requirements.txt][LN-hid_requirements] file:
```bash
pip install -r TESTS/usb_device/hid/requirements.txt
```
1. Update the `udev` rules for Mbed USB CDC device as follows
([source][LN-udev_rules]):
```bash
sudo tee /etc/udev/rules.d/99-ttyacms.rules >/dev/null <<EOF
ATTRS{idVendor}=="1f00" ATTRS{idProduct}=="2013", ENV{ID_MM_DEVICE_IGNORE}="1"
ATTRS{idVendor}=="1f00" ATTRS{idProduct}=="2012", ENV{ID_MM_DEVICE_IGNORE}="1"
EOF
sudo udevadm control --reload-rules
```
This will prevent the `ModemManager` daemon from automatically opening the
port and sending the `AT commands`, which it does for every new
`/dev/ttyACM` device registered in system.
### Mac
No setup method has been verified for this platform.
## Running tests
1. Plug both USB interfaces (*DAPLink* and *USB device*) to your host machine.
1. Run tests:
```
mbed test -t <toolchain> -m <target> -n tests-usb_device-*
```
## Known issues
### Insufficient user permissions on a Linux machine
Some of the tests require privileged access to the USB device. Running these
as an unprivileged user will manifest with either of the following errors:
* ```
[HTST][INF] Device not found
```
* ```
[HTST][INF] TEST ERROR: Failed with "The device has no langid". Tried 20 times.
```
#### Solution
Execute tests with elevated permissions using `sudo`:
```bash
mbed test -t <toolchain> -m <target> -n tests-usb_device-* --compile
sudo mbed test -t <toolchain> -m <target> -n tests-usb_device-* --run -v
```
Note only the `mbed test --run` command requires `sudo`. You can still
`mbed test --compile` as a normal user.
#### Alternative solution
Add an `udev` rule to set the ownership of the device node
[as shown here][LN-libusb_permissions].
### Data toggle reset test fails on a Linux machine
The `tests-usb_device-basic` / `"endpoint test data toggle reset"` test fails
with the following error:
```
[HTST][INF] TEST FAILED: Data toggle not reset when calling
ClearFeature(ENDPOINT_HALT) on an endpoint that has not been halted.
```
Implementations of the *xHCI* driver prior to version 4.17 of the Linux kernel did
not have the functionality necessary to test `"endpoint test data toggle reset"`.
Even though the data toggle is correctly reset on the device side, the host
side will not be synchronized and the test will falsely fail.
#### Solution
Make sure that **at least one** of the following prerequisites is met:
* using the Linux kernel ***4.17* or newer**,
* using the ***eHCI*** USB driver instead of *xHCI*.
Changing the USB driver may be as simple as updating one of the BIOS settings
on your machine. If you'd rather avoid rebooting, you can try
[using setpci command][LN-xhci_setpci].
#### Further reading
1. [the Linux kernel patch adding missing xHCI behavior][LN-linux_xhci_patch],
1. [LKML discussion explaining the details of this issue][LN-xhci_lkml_discussion].
### Mass storage tests are skipped on some targets
The `tests-usb_device-msd` test outputs the following message:
```
[CONN][RXD] SKIP: Not enough heap memory for HeapBlockDevice creation
```
#### Solution
A device with at least *70 kB* of RAM is required to run this test.
The FAT32 filesystem cannot be mounted on a device smaller than 64 kB.
The test can be easily extended to use any block device available in Mbed.
### Windows 8/10: Mass storage tests are failing on test file read
By default Windows 8 and 10 access and write to removable drives shortly after they are connected. It's caused by drive indexing mechanisms. Because disk used in test has only 64kB its content can be easily corrupted by writing large files, what actually was encountered during test runs.
To prevent Windows from writing to removable drives on connect drive indexing can be turned off with the following procedure:
- Start the program "gpedit.msc"
- Navigate to "Computer Configuration \ Administrative Templates \ Windows Components \ Search"
- Enable the policy "Do not allow locations on removable drives to be added to libraries."
### Isochronous endpoints are skipped in loopback tests
#### Unresolved
### Serial tests fail intermittently on a Linux machine
#### Unresolved
You may want to connect the device directly to the host machine with no hubs on the way.
<!-- LINKS -->
[LN-requirements]: ../../requirements.txt
[LN-zadig]: https://zadig.akeo.ie/
[LN-zadig_conf1]: basic/zadig_conf/mbed_os-usb_test_device1.cfg
[LN-zadig_conf2]: basic/zadig_conf/mbed_os-usb_test_device2.cfg
[LN-hidapi_readme]: https://github.com/trezor/cython-hidapi/blob/master/README.rst#install
[LN-hid_requirements]: hid/requirements.txt
[LN-udev_rules]: https://linux-tips.com/t/prevent-modem-manager-to-capture-usb-serial-devices/284
[LN-libusb_permissions]: https://stackoverflow.com/questions/3738173/why-does-pyusb-libusb-require-root-sudo-permissions-on-linux/8582398#8582398
[LN-linux_xhci_patch]: https://github.com/torvalds/linux/commit/f5249461b504d35aa1a40140983b7ec415807d9e
[LN-xhci_lkml_discussion]: https://lkml.org/lkml/2016/12/15/388
[LN-xhci_setpci]: https://linuxmusicians.com/viewtopic.php?t=16901

View File

@ -1,15 +0,0 @@
# Testing the USB device data toggle reset with a Linux host
When you run the `tests-usb_device-basic` test suite on a Linux machine, please make
sure that at least one of the following prerequisites are met:
* using the Linux kernel ***4.17* or newer**,
* using the ***eHCI*** USB driver instead of *xHCI*.
Implementations of the *xHCI* driver prior to version 4.17 of the Linux kernel did
not have the functionality necessary to test `"endpoint test data toggle reset"`.
Even though the data toggle is correctly reset on the device side, the host side will
not be synchronized and the test will falsely fail.
Further reading:
1. [the Linux kernel patch adding missing xHCI behavior](https://github.com/torvalds/linux/commit/f5249461b504d35aa1a40140983b7ec415807d9e),
1. [LKML discussion explaining the details of this issue](https://lkml.org/lkml/2016/12/15/388).

View File

@ -1,18 +0,0 @@
# Generic USB driver installation on Windows machines
In order to run the Mbed OS USB device test suite (`tests-usb_device-*`)
on Windows hosts you need to install generic USB drivers for two test devices.
1. Download *Zadig* application from https://zadig.akeo.ie/.
1. Unplug the Mbed device.
1. Open *Zadig*.
1. Select *Device -> Load Preset Device*.
1. Open `mbed_os-usb_test_device1.cfg`.
1. Choose `libusb-win32 (v1.2.6.0)` driver.
1. Select `Install Driver` and click it.
1. Select *Device -> Load Preset Device*.
1. Open `mbed_os-usb_test_device2.cfg`.
1. Choose `libusb-win32 (v1.2.6.0)` driver.
1. Select `Install Driver` and click it.
1. Close *Zadig*.
1. Plug both device USB interfaces (*DAPLink* and *USB device*).

View File

@ -1,23 +0,0 @@
# Testing the USB HID device with a Linux host
Before running `tests-usb_device-hid` test suite on a Linux machine, please
make sure to install the `hidapi` Python module first, otherwise some test
cases will be skipped. Due to external dependencies for Linux, this module
is not installed during the initial setup, to keep the process as simple
as possible.
For Debian-based Linux distros, the dependencies can be installed as follows
(based on module's [README][1]):
```bash
apt-get install python-dev libusb-1.0-0-dev libudev-dev
pip install --upgrade setuptools
```
To install the `hidapi` module itself, please use the attached
`TESTS/usb_device/hid/requirements.txt` file:
```bash
pip install -r requirements.txt
```
[1]: https://github.com/trezor/cython-hidapi/blob/master/README.rst#install

View File

@ -1,12 +0,0 @@
# USB mass storage test user guide
To run the tests-usb_device-msd test device with at least *70kB* of RAM is required.
Test creates 64kB `HeapBlockDevice` as block device and mounts FAT32 filesystem on it.
64kB block device is the smallest one that can mount FAT32 filesystem.
Test can be easily extended to use any block device available in Mbed
Test run command:
```bash
mbed test -t COMPILER -m TARGET -n tests-usb_device-msd
```

View File

@ -33,6 +33,17 @@
#error [NOT_SUPPORTED] USB Device not supported for this target
#endif
#define OS_WINDOWS 1
#define OS_LINUX 2
#define OS_MAC 3
// Host side unmount was disabled for windows machines.
// PowerShell execution policies/restrictions cause that
// on some windows machines unmount is failing
// To re-enable it comment out below line.
#define DISABLE_HOST_SIDE_UMOUNT
#ifdef MIN
#undef MIN
#endif
@ -250,13 +261,10 @@ void msd_process(USBMSD *msd)
*/
void storage_init()
{
if (mbed_heap_size >= MIN_HEAP_SIZE) {
TEST_ASSERT_MESSAGE(mbed_heap_size >= MIN_HEAP_SIZE, "Not enough heap memory for HeapBlockDevice creation");
FATFileSystem::format(get_heap_block_device());
bool result = prepare_storage(get_heap_block_device(), &heap_fs);
TEST_ASSERT_MESSAGE(result, "heap storage initialisation failed");
} else {
utest_printf("Not enough heap memory for HeapBlockDevice creation. Heap block device init skipped!!!\n");
}
}
/** Test mass storage device mount and unmount
@ -316,6 +324,12 @@ void mount_unmount_test(BlockDevice *bd, FileSystem *fs)
uint64_t ret_size = atoll(_key);
TEST_ASSERT_EQUAL_UINT64(get_fs_mount_size(fs), ret_size);
#ifdef DISABLE_HOST_SIDE_UMOUNT
greentea_send_kv("get_os_type", 0);
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
int32_t os_type = atoi(_value);
if (os_type != OS_WINDOWS) {
#endif
// unmount msd device on host side
greentea_send_kv("unmount", 0);
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
@ -326,9 +340,15 @@ void mount_unmount_test(BlockDevice *bd, FileSystem *fs)
if (!usb.media_removed()) {
TEST_ASSERT_EQUAL_LOOP(true, usb.media_removed(), i);
}
// unmount since media_removed doesn't disconnects device side
usb.disconnect();
#ifdef DISABLE_HOST_SIDE_UMOUNT
} else {
// unmount
usb.disconnect();
}
#endif
// check if device is detached on host side
greentea_send_kv("check_if_not_mounted", 0);
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
@ -428,19 +448,13 @@ void mount_unmount_and_data_test(BlockDevice *bd, FileSystem *fs)
void heap_block_device_mount_unmount_test()
{
if (mbed_heap_size < MIN_HEAP_SIZE) {
TEST_SKIP_MESSAGE("Not enough heap memory for HeapBlockDevice creation");
return;
}
TEST_ASSERT_MESSAGE(mbed_heap_size >= MIN_HEAP_SIZE, "Not enough heap memory for HeapBlockDevice creation");
mount_unmount_test<3>(get_heap_block_device(), &heap_fs);
}
void heap_block_device_mount_unmount_and_data_test()
{
if (mbed_heap_size < MIN_HEAP_SIZE) {
TEST_SKIP_MESSAGE("Not enough heap memory for HeapBlockDevice creation");
return;
}
TEST_ASSERT_MESSAGE(mbed_heap_size >= MIN_HEAP_SIZE, "Not enough heap memory for HeapBlockDevice creation");
mount_unmount_and_data_test(get_heap_block_device(), &heap_fs);
}

View File

@ -1,18 +0,0 @@
# `udev` rules for Mbed USB CDC device
Before running `tests-usb_device-serial` test suite on Debian-based Linux
distros, make sure to [update the `udev` rules][1] as follows:
```bash
sudo tee /etc/udev/rules.d/99-ttyacms.rules >/dev/null <<EOF
ATTRS{idVendor}=="1f00" ATTRS{idProduct}=="2013", ENV{ID_MM_DEVICE_IGNORE}="1"
ATTRS{idVendor}=="1f00" ATTRS{idProduct}=="2012", ENV{ID_MM_DEVICE_IGNORE}="1"
EOF
sudo udevadm control --reload-rules
```
This will prevent the `ModemManager` daemon from automatically opening the port
and sending the `AT commands`, which it does for every new `/dev/ttyACM` device
registered in system.
[1]: https://linux-tips.com/t/prevent-modem-manager-to-capture-usb-serial-devices/284

View File

@ -92,6 +92,7 @@ set(unittest-includes-base
"${PROJECT_SOURCE_DIR}/target_h/events"
"${PROJECT_SOURCE_DIR}/target_h/events/equeue"
"${PROJECT_SOURCE_DIR}/target_h/platform"
"${PROJECT_SOURCE_DIR}/target_h/drivers"
"${PROJECT_SOURCE_DIR}/stubs"
"${PROJECT_SOURCE_DIR}/.."
"${PROJECT_SOURCE_DIR}/../features"

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2018, 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.
*/
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "Watchdog.h"
using namespace mbed;
extern bool testcase;
// AStyle ignored as the definition is not clear due to preprocessor usage
// *INDENT-OFF*
class TestWatchdog : public testing::Test {
protected:
void SetUp()
{
}
void TearDown()
{
}
};
// *INDENT-ON*
TEST_F(TestWatchdog, test_watchdog_start_stop_get_timeout)
{
EXPECT_TRUE(Watchdog::get_instance().start(500));
EXPECT_FALSE(Watchdog::get_instance().start(2000));
EXPECT_TRUE(Watchdog::get_instance().stop());
EXPECT_FALSE(Watchdog::get_instance().stop());
EXPECT_EQ(500, Watchdog::get_instance().get_timeout());
}
TEST_F(TestWatchdog, test_watchdog_get_max_timeout)
{
EXPECT_EQ(0xFFFFFFFF, Watchdog::get_instance().get_max_timeout());
}

View File

@ -0,0 +1,28 @@
####################
# UNIT TESTS
####################
set(TEST_SUITE_NAME "Watchdog")
# Add test specific include paths
set(unittest-includes ${unittest-includes}
.
../hal
)
# Source files
set(unittest-sources
../drivers/Watchdog.cpp
)
# Test files
set(unittest-test-sources
drivers/Watchdog/test_watchdog.cpp
stubs/mbed_critical_stub.c
stubs/mbed_assert_stub.c
stubs/watchdog_api_stub.c
)
# defines
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEVICE_WATCHDOG -DMBED_WDOG_ASSERT=1")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEVICE_WATCHDOG -DMBED_WDOG_ASSERT=1")

View File

@ -603,15 +603,22 @@ TEST_F(TestAT_CellularContext, connect_disconnect_async)
ASSERT_EQ(network_cb_count, 5);
ASSERT_EQ(ctx1.connect(), NSAPI_ERROR_IS_CONNECTED);
EXPECT_TRUE(ctx1.is_connected() == true);
ASSERT_EQ(ctx1.disconnect(), NSAPI_ERROR_NO_MEMORY);
EXPECT_TRUE(ctx1.is_connected() == true);
struct equeue_event ptr;
equeue_stub.void_ptr = &ptr;
equeue_stub.call_cb_immediately = true;
ASSERT_EQ(ctx1.disconnect(), NSAPI_ERROR_OK);
EXPECT_TRUE(ctx1.is_connected() == false);
// sdet CellularDevice_stub::connect_counter = 0 so device is already attached and will return NSAPI_ERROR_ALREADY to context when calling connect
equeue_stub.void_ptr = &ptr;
equeue_stub.call_cb_immediately = false;
CellularDevice_stub::connect_counter = 0;
// queue can't allocate so return NSAPI_ERROR_NO_MEMORY
ASSERT_EQ(ctx1.connect(), NSAPI_ERROR_NO_MEMORY);
struct equeue_event ptr;
equeue_stub.void_ptr = &ptr;
equeue_stub.call_cb_immediately = true;
ASSERT_EQ(ctx1.connect(), NSAPI_ERROR_OK);

View File

@ -565,15 +565,15 @@ TEST_F(TestATHandler, test_ATHandler_read_bytes)
mbed_poll_stub::int_value = 1;;
// Read 5 bytes
EXPECT_TRUE(5 == at.read_bytes(buf, 5));
EXPECT_EQ(5, at.read_bytes(buf, 5));
EXPECT_TRUE(!memcmp(buf, table1, 5));
// get_char triggered above should have filled in the whole reading buffer(fill_buffer())
EXPECT_TRUE(filehandle_stub_table_pos == (strlen(table1) - 1));
EXPECT_EQ(filehandle_stub_table_pos, (strlen(table1)));
// Read another 8 bytes
EXPECT_TRUE(8 == at.read_bytes(buf, 8) && !memcmp(buf, table1 + 5, 8));
// Reading more than the 4 bytes left -> ERROR
EXPECT_TRUE(-1 == at.read_bytes(buf, 5));
EXPECT_TRUE(NSAPI_ERROR_DEVICE_ERROR == at.get_last_error());
EXPECT_EQ(-1, at.read_bytes(buf, 5));
EXPECT_EQ(NSAPI_ERROR_DEVICE_ERROR, at.get_last_error());
}
TEST_F(TestATHandler, test_ATHandler_read_string)

View File

@ -35,6 +35,7 @@ set(unittest-test-sources
stubs/cipher_stub.c
stubs/aes_stub.c
stubs/cmac_stub.c
stubs/mbed_assert_stub.c
../features/nanostack/coap-service/test/coap-service/unittest/stub/mbedtls_stub.c
)

View File

@ -20,4 +20,5 @@ set(unittest-test-sources
stubs/EventFlags_stub.cpp
stubs/Mutex_stub.cpp
stubs/CellularContext_stub.cpp
stubs/mbed_assert_stub.c
)

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2018-2019 Arm Limited and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "watchdog_api.h"
#if DEVICE_WATCHDOG
static uint32_t _timeout = 0;
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
{
_timeout = config->timeout_ms;
return WATCHDOG_STATUS_OK;
}
void hal_watchdog_kick(void)
{
}
watchdog_status_t hal_watchdog_stop(void)
{
return WATCHDOG_STATUS_OK;
}
uint32_t hal_watchdog_get_reload_value(void)
{
return _timeout;
}
watchdog_features_t hal_watchdog_get_platform_features(void)
{
watchdog_features_t features;
features.max_timeout = 0xFFFFFFFF;
return features;
}
#endif // DEVICE_WATCHDOG

View File

@ -0,0 +1,54 @@
/*
* 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.
*/
#ifndef MBED_LOWPOWERTICKER_H
#define MBED_LOWPOWERTICKER_H
#include "hal/ticker_api.h"
#include "Callback.h"
namespace mbed {
/** \addtogroup drivers */
/** mock Low Power Ticker
*
*/
class LowPowerTicker {
public:
LowPowerTicker()
{
}
virtual ~LowPowerTicker()
{
}
void attach_us(Callback<void()> func, us_timestamp_t t)
{
}
void detach()
{
}
};
} // namespace mbed
#endif

View File

@ -0,0 +1,52 @@
/*
* 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.
*/
#ifndef MBED_TICKER_H
#define MBED_TICKER_H
#include "drivers/TimerEvent.h"
#include "platform/Callback.h"
namespace mbed {
/** \addtogroup drivers */
/** mock Ticker
*
*/
class Ticker {
public:
Ticker()
{
}
void attach_us(Callback<void()> func, us_timestamp_t t)
{
}
void detach()
{
}
~Ticker()
{
}
};
} // namespace mbed
#endif

View File

@ -0,0 +1,135 @@
/** \addtogroup platform */
/** @{*/
/**
* \defgroup platform_Assert Assert macros
* @{
*/
/*
* 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.
*/
#ifndef MBED_ASSERT_H
#define MBED_ASSERT_H
#include "mbed_preprocessor.h"
#include "mbed_toolchain.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Internal mbed assert function which is invoked when MBED_ASSERT macro fails.
* This function is active only if NDEBUG is not defined prior to including this
* assert header file.
* In case of MBED_ASSERT failing condition, error() is called with the assertation message.
* @param expr Expression to be checked.
* @param file File where assertation failed.
* @param line Failing assertation line number.
*/
MBED_NORETURN void mbed_assert_internal(const char *expr, const char *file, int line);
#ifdef __cplusplus
}
#endif
/** MBED_ASSERT
* Declare runtime assertions: results in runtime error if condition is false
*
* @note
* Use of MBED_ASSERT is limited to Debug and Develop builds.
*
* @code
*
* int Configure(serial_t *obj) {
* MBED_ASSERT(obj);
* }
* @endcode
*/
#if defined( NDEBUG ) && !defined (MBED_WDOG_ASSERT)
#define MBED_ASSERT(expr) ((void)0)
#else
#define MBED_ASSERT(expr) \
do { \
if (!(expr)) { \
mbed_assert_internal(#expr, __FILE__, __LINE__); \
} \
} while (0)
#endif
/** MBED_STATIC_ASSERT
* Declare compile-time assertions, results in compile-time error if condition is false
*
* The assertion acts as a declaration that can be placed at file scope, in a
* code block (except after a label), or as a member of a C++ class/struct/union.
*
* @note
* Use of MBED_STATIC_ASSERT as a member of a struct/union is limited:
* - In C++, MBED_STATIC_ASSERT is valid in class/struct/union scope.
* - In C, MBED_STATIC_ASSERT is not valid in struct/union scope, and
* MBED_STRUCT_STATIC_ASSERT is provided as an alternative that is valid
* in C and C++ class/struct/union scope.
*
* @code
* MBED_STATIC_ASSERT(MBED_LIBRARY_VERSION >= 120,
* "The mbed library must be at least version 120");
*
* int main() {
* MBED_STATIC_ASSERT(sizeof(int) >= sizeof(char),
* "An int must be larger than a char");
* }
* @endcode
*/
#if defined(__cplusplus) && (__cplusplus >= 201103L || __cpp_static_assert >= 200410L)
#define MBED_STATIC_ASSERT(expr, msg) static_assert(expr, msg)
#elif !defined(__cplusplus) && __STDC_VERSION__ >= 201112L
#define MBED_STATIC_ASSERT(expr, msg) _Static_assert(expr, msg)
#elif defined(__cplusplus) && defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) \
&& (__GNUC__*100 + __GNUC_MINOR__) > 403L
#define MBED_STATIC_ASSERT(expr, msg) __extension__ static_assert(expr, msg)
#elif !defined(__cplusplus) && defined(__GNUC__) && !defined(__CC_ARM) \
&& (__GNUC__*100 + __GNUC_MINOR__) > 406L
#define MBED_STATIC_ASSERT(expr, msg) __extension__ _Static_assert(expr, msg)
#elif defined(__ICCARM__)
#define MBED_STATIC_ASSERT(expr, msg) static_assert(expr, msg)
#else
#define MBED_STATIC_ASSERT(expr, msg) \
enum {MBED_CONCAT(MBED_ASSERTION_AT_, __LINE__) = sizeof(char[(expr) ? 1 : -1])}
#endif
/** MBED_STRUCT_STATIC_ASSERT
* Declare compile-time assertions, results in compile-time error if condition is false
*
* Unlike MBED_STATIC_ASSERT, MBED_STRUCT_STATIC_ASSERT can and must be used
* as a member of a C/C++ class/struct/union.
*
* @code
* struct thing {
* MBED_STATIC_ASSERT(2 + 2 == 4,
* "Hopefully the universe is mathematically consistent");
* };
* @endcode
*/
#define MBED_STRUCT_STATIC_ASSERT(expr, msg) int : (expr) ? 0 : -1
#endif
/**@}*/
/**@}*/

View File

@ -15,3 +15,18 @@
* limitations under the License.
*/
/** Resets the processor and most of the sub-system
*
* @note Does not affect the debug sub-system
*/
#ifndef MBED_POWER_MGMT_H
#define MBED_POWER_MGMT_H
extern void mock_system_reset();
MBED_NORETURN static inline void system_reset(void)
{
mock_system_reset();
}
#endif

View File

@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined(MBED_CONF_NANOSTACK_CONFIGURATION) && DEVICE_SPI && DEVICE_INTERRUPTIN && defined(MBED_CONF_RTOS_PRESENT)
#include "nanostack/platform/arm_hal_phy.h"
#include "rf_configuration.h"
@ -167,3 +170,6 @@ uint32_t rf_conf_calculate_deviation(phy_modulation_index_e modulation_index, ui
}
return deviation;
}
#endif // MBED_CONF_NANOSTACK_CONFIGURATION && DEVICE_SPI && DEVICE_INTERRUPTIN && defined(MBED_CONF_RTOS_PRESENT)

View File

@ -8,6 +8,12 @@
* See BSD-3-Clause license in README.md
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include "t_cose_crypto.h"
#include "tfm_plat_defs.h"
#include "psa/crypto.h"

View File

@ -19,6 +19,12 @@
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_PSA_CRYPTO_C)
#include <stdlib.h>

View File

@ -127,7 +127,7 @@ static psa_status_t convert_status(int status)
* \param n[in] number of bits to shift right
* \return the result
*/
MBED_FORCEINLINE uint32_t lsr32(uint32_t x, uint32_t n)
static MBED_FORCEINLINE uint32_t lsr32(uint32_t x, uint32_t n)
{
return x >> n;
}
@ -140,7 +140,7 @@ MBED_FORCEINLINE uint32_t lsr32(uint32_t x, uint32_t n)
* \param n[in] number of bits to shift right
* \return the result
*/
MBED_FORCEINLINE uint64_t lsr64(uint64_t x, uint32_t n)
static MBED_FORCEINLINE uint64_t lsr64(uint64_t x, uint32_t n)
{
return x >> n;
}
@ -185,12 +185,8 @@ static void generate_fn(char *tdb_filename, uint32_t tdb_filename_size, psa_stor
psa_status_t psa_storage_set_impl(KVStore *kvstore, int32_t pid, psa_storage_uid_t uid,
uint32_t data_length, const void *p_data,
psa_storage_create_flags_t create_flags)
uint32_t kv_create_flags)
{
if ((create_flags & (~FLAGS_MSK)) != 0) {
return PSA_ERROR_NOT_SUPPORTED;
}
if (uid == 0) {
return PSA_ERROR_INVALID_ARGUMENT;
}
@ -198,11 +194,6 @@ psa_status_t psa_storage_set_impl(KVStore *kvstore, int32_t pid, psa_storage_uid
char kv_key[PSA_STORAGE_FILE_NAME_MAX] = {'\0'};
generate_fn(kv_key, PSA_STORAGE_FILE_NAME_MAX, uid, pid);
uint32_t kv_create_flags = 0;
if (create_flags & PSA_STORAGE_FLAG_WRITE_ONCE) {
kv_create_flags = KVStore::WRITE_ONCE_FLAG;
}
int status = kvstore->set(kv_key, p_data, data_length, kv_create_flags);
return convert_status(status);

View File

@ -36,7 +36,7 @@ typedef psa_status_t (*migrate_func_t)(mbed::KVStore *kvstore, const psa_storage
void psa_storage_handle_version(mbed::KVStore *kvstore, const char *version_key, const psa_storage_version_t *version,
migrate_func_t migrate_func);
psa_status_t psa_storage_set_impl(mbed::KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, uint32_t data_length, const void *p_data, psa_storage_create_flags_t create_flags);
psa_status_t psa_storage_set_impl(mbed::KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, uint32_t data_length, const void *p_data, uint32_t kv_create_flags);
psa_status_t psa_storage_get_impl(mbed::KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, uint32_t data_offset, uint32_t data_length, void *p_data);
psa_status_t psa_storage_get_info_impl(mbed::KVStore *kvstore, int32_t pid, psa_storage_uid_t uid, struct psa_storage_info_t *p_info);
psa_status_t psa_storage_remove_impl(mbed::KVStore *kvstore, int32_t pid, psa_storage_uid_t uid);

View File

@ -87,6 +87,10 @@ psa_status_t psa_its_set_impl(int32_t pid, psa_storage_uid_t uid, uint32_t data_
its_init();
}
if (create_flags & ~PSA_STORAGE_FLAG_WRITE_ONCE) {
return PSA_ERROR_NOT_SUPPORTED;
}
return psa_storage_set_impl(kvstore, pid, uid, data_length, p_data, create_flags);
}

View File

@ -39,6 +39,7 @@ extern "C"
#define PSA_PS_GLOBAL_PID 1
static KVStore *kvstore = NULL;
static uint32_t def_kvstore_flags = 0;
MBED_WEAK psa_status_t ps_version_migrate(KVStore *kvstore,
const psa_storage_version_t *old_version, const psa_storage_version_t *new_version)
@ -61,12 +62,18 @@ static void ps_init(void)
KVMap &kv_map = KVMap::get_instance();
psa_storage_version_t version = {PSA_PS_API_VERSION_MAJOR, PSA_PS_API_VERSION_MINOR};
kvstore = kv_map.get_main_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV));
if (!kvstore) {
KVStore *int_kvstore = kv_map.get_internal_kv_instance(STR_EXPAND(MBED_CONF_STORAGE_DEFAULT_KV));;
if (!kvstore || !int_kvstore) {
// Can only happen due to system misconfiguration.
// Thus considered as unrecoverable error for runtime.
error("Failed getting kvstore instance\n");
}
def_kvstore_flags = 0;
if (kvstore != int_kvstore) {
def_kvstore_flags = KVStore::REQUIRE_CONFIDENTIALITY_FLAG | KVStore::REQUIRE_REPLAY_PROTECTION_FLAG;
}
psa_storage_handle_version(kvstore, PS_VERSION_KEY, &version, ps_version_migrate);
}
@ -83,7 +90,16 @@ psa_status_t psa_ps_set(psa_storage_uid_t uid, uint32_t data_length, const void
ps_init();
}
return psa_storage_set_impl(kvstore, PSA_PS_GLOBAL_PID, uid, data_length, p_data, create_flags);
if (create_flags & ~PSA_STORAGE_FLAG_WRITE_ONCE) {
return PSA_ERROR_NOT_SUPPORTED;
}
uint32_t kv_create_flags = def_kvstore_flags;
if (create_flags & PSA_STORAGE_FLAG_WRITE_ONCE) {
kv_create_flags |= KVStore::WRITE_ONCE_FLAG;
}
return psa_storage_set_impl(kvstore, PSA_PS_GLOBAL_PID, uid, data_length, p_data, kv_create_flags);
}
psa_status_t psa_ps_get(psa_storage_uid_t uid, uint32_t data_offset, uint32_t data_length, void *p_data)

View File

@ -14,6 +14,10 @@
"REALTEK_RTL8195AM": {
"base-address": "0x1C0000",
"size": "0x40000"
},
"FVP_MPS2": {
"base-address": "0x00200000",
"size": "0x200000"
}
}
}

View File

@ -56,6 +56,7 @@ using namespace mbed;
#define SPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE 40
// Address Length
#define SPIF_ADDR_SIZE_3_BYTES 3
#define SPIF_ADDR_SIZE_4_BYTES 4
// Erase Types Params
#define SPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE 29
#define SPIF_BASIC_PARAM_ERASE_TYPE_2_BYTE 31
@ -88,7 +89,9 @@ enum spif_default_instructions {
SPIF_RSTEN = 0x66, // Reset Enable
SPIF_RST = 0x99, // Reset
SPIF_RDID = 0x9f, // Read Manufacturer and JDEC Device ID
SPIF_ULBPR = 0x98, // Clears all write-protection bits in the Block-Protection register
SPIF_ULBPR = 0x98, // Clears all write-protection bits in the Block-Protection register,
SPIF_4BEN = 0xB7, // Enable 4-byte address mode
SPIF_4BDIS = 0xE9, // Disable 4-byte address mode
};
// Mutex is used for some SPI Driver commands that must be done sequentially with no other commands in between
@ -117,7 +120,7 @@ SPIFBlockDevice::SPIFBlockDevice(
_region_erase_types_bitfield[0] = ERASE_BITMASK_NONE;
if (SPIF_BD_ERROR_OK != _spi_set_frequency(freq)) {
tr_error("ERROR: SPI Set Frequency Failed");
tr_error("SPI Set Frequency Failed");
}
_cs = 1;
@ -148,19 +151,16 @@ int SPIFBlockDevice::init()
// Soft Reset
if (-1 == _reset_flash_mem()) {
tr_error("ERROR: init - Unable to initialize flash memory, tests failed\n");
tr_error("init - Unable to initialize flash memory, tests failed");
status = SPIF_BD_ERROR_DEVICE_ERROR;
goto exit_point;
} else {
tr_info("INFO: Initialize flash memory OK\n");
}
/* Read Manufacturer ID (1byte), and Device ID (2bytes)*/
spi_status = _spi_send_general_command(SPIF_RDID, SPI_NO_ADDRESS_COMMAND, NULL, 0, (char *)vendor_device_ids,
data_length);
if (spi_status != SPIF_BD_ERROR_OK) {
tr_error("ERROR: init - Read Vendor ID Failed");
tr_error("init - Read Vendor ID Failed");
status = SPIF_BD_ERROR_DEVICE_ERROR;
goto exit_point;
}
@ -176,14 +176,14 @@ int SPIFBlockDevice::init()
//Synchronize Device
if (false == _is_mem_ready()) {
tr_error("ERROR: init - _is_mem_ready Failed");
tr_error("init - _is_mem_ready Failed");
status = SPIF_BD_ERROR_READY_FAILED;
goto exit_point;
}
/**************************** Parse SFDP Header ***********************************/
if (0 != _sfdp_parse_sfdp_headers(basic_table_addr, basic_table_size, sector_map_table_addr, sector_map_table_size)) {
tr_error("ERROR: init - Parse SFDP Headers Failed");
tr_error("init - Parse SFDP Headers Failed");
status = SPIF_BD_ERROR_PARSING_FAILED;
goto exit_point;
}
@ -191,7 +191,7 @@ int SPIFBlockDevice::init()
/**************************** Parse Basic Parameters Table ***********************************/
if (0 != _sfdp_parse_basic_param_table(basic_table_addr, basic_table_size)) {
tr_error("ERROR: init - Parse Basic Param Table Failed");
tr_error("init - Parse Basic Param Table Failed");
status = SPIF_BD_ERROR_PARSING_FAILED;
goto exit_point;
}
@ -202,10 +202,8 @@ int SPIFBlockDevice::init()
_region_high_boundary[0] = _device_size_bytes - 1;
if ((sector_map_table_addr != 0) && (0 != sector_map_table_size)) {
tr_info("INFO: init - Parsing Sector Map Table - addr: 0x%lxh, Size: %d", sector_map_table_addr,
sector_map_table_size);
if (0 != _sfdp_parse_sector_map_table(sector_map_table_addr, sector_map_table_size)) {
tr_error("ERROR: init - Parse Sector Map Table Failed");
tr_error("init - Parse Sector Map Table Failed");
status = SPIF_BD_ERROR_PARSING_FAILED;
goto exit_point;
}
@ -215,6 +213,13 @@ int SPIFBlockDevice::init()
// Dummy And Mode Cycles Back default 0
_dummy_and_mode_cycles = _write_dummy_and_mode_cycles;
_is_initialized = true;
tr_debug("Device size: %llu Kbytes", _device_size_bytes / 1024);
if (_device_size_bytes > (1 << 24)) {
tr_debug("Size is bigger than 16MB and thus address does not fit in 3 byte, switch to 4 byte address mode");
_spi_send_general_command(SPIF_4BEN, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0);
_address_size = SPIF_ADDR_SIZE_4_BYTES;
}
exit_point:
_mutex->unlock();
@ -243,7 +248,7 @@ int SPIFBlockDevice::deinit()
// Disable Device for Writing
status = _spi_send_general_command(SPIF_WRDI, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0);
if (status != SPIF_BD_ERROR_OK) {
tr_error("ERROR: Write Disable failed");
tr_error("Write Disable failed");
}
_is_initialized = false;
@ -260,7 +265,6 @@ int SPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
}
int status = SPIF_BD_ERROR_OK;
tr_info("INFO Read - Inst: 0x%xh", _read_instruction);
_mutex->lock();
// Set Dummy Cycles for Specific Read Command Mode
@ -286,8 +290,6 @@ int SPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
uint32_t offset = 0;
uint32_t chunk = 0;
tr_debug("DEBUG: program - Buff: 0x%lxh, addr: %llu, size: %llu", (uint32_t)buffer, addr, size);
while (size > 0) {
// Write on _page_size_bytes boundaries (Default 256 bytes a page)
@ -298,7 +300,7 @@ int SPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
//Send WREN
if (_set_write_enable() != 0) {
tr_error("ERROR: Write Enabe failed\n");
tr_error("Write Enabe failed");
program_failed = true;
status = SPIF_BD_ERROR_WREN_FAILED;
goto exit_point;
@ -311,7 +313,7 @@ int SPIFBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
size -= chunk;
if (false == _is_mem_ready()) {
tr_error("ERROR: Device not ready after write, failed\n");
tr_error("Device not ready after write, failed");
program_failed = true;
status = SPIF_BD_ERROR_READY_FAILED;
goto exit_point;
@ -345,15 +347,13 @@ int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size)
// Erase Types of selected region
uint8_t bitfield = _region_erase_types_bitfield[region];
tr_info("DEBUG: erase - addr: %llu, in_size: %llu", addr, in_size);
if ((addr + in_size) > _device_size_bytes) {
tr_error("ERROR: erase exceeds flash device size");
tr_error("erase exceeds flash device size");
return SPIF_BD_ERROR_INVALID_ERASE_PARAMS;
}
if (((addr % get_erase_size(addr)) != 0) || (((addr + in_size) % get_erase_size(addr + in_size - 1)) != 0)) {
tr_error("ERROR: invalid erase - unaligned address and size");
tr_error("invalid erase - unaligned address and size");
return SPIF_BD_ERROR_INVALID_ERASE_PARAMS;
}
@ -367,15 +367,10 @@ int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size)
offset = addr % _erase_type_size_arr[type];
chunk = ((offset + size) < _erase_type_size_arr[type]) ? size : (_erase_type_size_arr[type] - offset);
tr_debug("DEBUG: erase - addr: %llu, size:%d, Inst: 0x%xh, chunk: %lu , ",
addr, size, cur_erase_inst, chunk);
tr_debug("DEBUG: erase - Region: %d, Type:%d",
region, type);
_mutex->lock();
if (_set_write_enable() != 0) {
tr_error("ERROR: SPI Erase Device not ready - failed");
tr_error("SPI Erase Device not ready - failed");
erase_failed = true;
status = SPIF_BD_ERROR_READY_FAILED;
goto exit_point;
@ -393,7 +388,7 @@ int SPIFBlockDevice::erase(bd_addr_t addr, bd_size_t in_size)
}
if (false == _is_mem_ready()) {
tr_error("ERROR: SPI After Erase Device not ready - failed\n");
tr_error("SPI After Erase Device not ready - failed");
erase_failed = true;
status = SPIF_BD_ERROR_READY_FAILED;
goto exit_point;
@ -452,7 +447,7 @@ bd_size_t SPIFBlockDevice::get_erase_size(bd_addr_t addr)
}
if (i_ind == 4) {
tr_error("ERROR: no erase type was found for region addr");
tr_error("no erase type was found for region addr");
}
}
@ -555,8 +550,7 @@ spif_bd_error SPIFBlockDevice::_spi_send_program_command(int prog_inst, const vo
spif_bd_error SPIFBlockDevice::_spi_send_erase_command(int erase_inst, bd_addr_t addr, bd_size_t size)
{
tr_info("INFO: Erase Inst: 0x%xh, addr: %llu, size: %llu", erase_inst, addr, size);
addr = (((int)addr) & 0x00FFF000);
addr = (((int)addr) & 0xFFFFF000);
_spi_send_general_command(erase_inst, addr, NULL, 0, NULL, 0);
return SPIF_BD_ERROR_OK;
}
@ -612,19 +606,19 @@ int SPIFBlockDevice::_sfdp_parse_sector_map_table(uint32_t sector_map_table_addr
spif_bd_error status = _spi_send_read_command(SPIF_SFDP, sector_map_table, sector_map_table_addr /*address*/,
sector_map_table_size);
if (status != SPIF_BD_ERROR_OK) {
tr_error("ERROR: init - Read SFDP First Table Failed");
tr_error("init - Read SFDP First Table Failed");
return -1;
}
// Currently we support only Single Map Descriptor
if (!((sector_map_table[0] & 0x3) == 0x03) && (sector_map_table[1] == 0x0)) {
tr_error("ERROR: Sector Map - Supporting Only Single! Map Descriptor (not map commands)");
tr_error("Sector Map - Supporting Only Single! Map Descriptor (not map commands)");
return -1;
}
_regions_count = sector_map_table[2] + 1;
if (_regions_count > SPIF_MAX_REGIONS) {
tr_error("ERROR: Supporting up to %d regions, current setup to %d regions - fail",
tr_error("Supporting up to %d regions, current setup to %d regions - fail",
SPIF_MAX_REGIONS, _regions_count);
return -1;
}
@ -666,13 +660,13 @@ int SPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, si
spif_bd_error status = _spi_send_read_command(SPIF_SFDP, param_table, basic_table_addr /*address*/,
basic_table_size);
if (status != SPIF_BD_ERROR_OK) {
tr_error("ERROR: init - Read SFDP First Table Failed");
tr_error("init - Read SFDP First Table Failed");
return -1;
}
// Check address size, currently only supports 3byte addresses
if ((param_table[2] & 0x4) != 0 || (param_table[7] & 0x80) != 0) {
tr_error("ERROR: init - verify 3byte addressing Failed");
tr_error("init - verify 3byte addressing Failed");
return -1;
}
@ -683,6 +677,7 @@ int SPIFBlockDevice::_sfdp_parse_basic_param_table(uint32_t basic_table_addr, si
(param_table[5] << 8) |
param_table[4]);
_device_size_bytes = (density_bits + 1) / 8;
tr_debug("Density bits: %ld , device size: %llu bytes", density_bits, _device_size_bytes);
// Set Default read/program/erase Instructions
_read_instruction = SPIF_READ;
@ -718,23 +713,19 @@ int SPIFBlockDevice::_sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_t
spif_bd_error status = _spi_send_read_command(SPIF_SFDP, sfdp_header, addr /*address*/, data_length);
if (status != SPIF_BD_ERROR_OK) {
tr_error("ERROR: init - Read SFDP Failed");
tr_error("init - Read SFDP Failed");
return -1;
}
// Verify SFDP signature for sanity
// Also check that major/minor version is acceptable
if (!(memcmp(&sfdp_header[0], "SFDP", 4) == 0 && sfdp_header[5] == 1)) {
tr_error("ERROR: init - _verify SFDP signature and version Failed");
tr_error("init - _verify SFDP signature and version Failed");
return -1;
} else {
tr_info("INFO: init - verified SFDP Signature and version Successfully");
}
// Discover Number of Parameter Headers
int number_of_param_headers = (int)(sfdp_header[6]) + 1;
tr_debug("DEBUG: number of Param Headers: %d", number_of_param_headers);
addr += SPIF_SFDP_HEADER_SIZE;
data_length = SPIF_PARAM_HEADER_SIZE;
@ -744,27 +735,25 @@ int SPIFBlockDevice::_sfdp_parse_sfdp_headers(uint32_t &basic_table_addr, size_t
status = _spi_send_read_command(SPIF_SFDP, param_header, addr, data_length);
if (status != SPIF_BD_ERROR_OK) {
tr_error("ERROR: init - Read Param Table %d Failed", i_ind + 1);
tr_error("init - Read Param Table %d Failed", i_ind + 1);
return -1;
}
// The SFDP spec indicates the standard table is always at offset 0
// in the parameter headers, we check just to be safe
if (param_header[2] != 1) {
tr_error("ERROR: Param Table %d - Major Version should be 1!", i_ind + 1);
tr_error("Param Table %d - Major Version should be 1!", i_ind + 1);
return -1;
}
if ((param_header[0] == 0) && (param_header[7] == 0xFF)) {
// Found Basic Params Table: LSB=0x00, MSB=0xFF
tr_debug("DEBUG: Found Basic Param Table at Table: %d", i_ind + 1);
basic_table_addr = ((param_header[6] << 16) | (param_header[5] << 8) | (param_header[4]));
// Supporting up to 64 Bytes Table (16 DWORDS)
basic_table_size = ((param_header[3] * 4) < SFDP_DEFAULT_BASIC_PARAMS_TABLE_SIZE_BYTES) ? (param_header[3] * 4) : 64;
} else if ((param_header[0] == 81) && (param_header[7] == 0xFF)) {
// Found Sector Map Table: LSB=0x81, MSB=0xFF
tr_debug("DEBUG: Found Sector Map Table at Table: %d", i_ind + 1);
sector_map_table_addr = ((param_header[6] << 16) | (param_header[5] << 8) | (param_header[4]));
sector_map_table_size = param_header[3] * 4;
@ -783,9 +772,6 @@ unsigned int SPIFBlockDevice::_sfdp_detect_page_size(uint8_t *basic_param_table_
// Page Size is specified by 4 Bits (N), calculated by 2^N
int page_to_power_size = ((int)basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_PAGE_SIZE_BYTE]) >> 4;
page_size = local_math_power(2, page_to_power_size);
tr_debug("DEBUG: Detected Page Size: %d", page_size);
} else {
tr_debug("DEBUG: Using Default Page Size: %d", page_size);
}
return page_size;
}
@ -807,8 +793,6 @@ int SPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param
erase_type_inst_arr[i_ind] = 0xff; //0xFF default for unsupported type
erase_type_size_arr[i_ind] = local_math_power(2,
basic_param_table_ptr[SPIF_BASIC_PARAM_ERASE_TYPE_1_SIZE_BYTE + 2 * i_ind]); // Size given as 2^N
tr_info("DEBUG: Erase Type(A) %d - Inst: 0x%xh, Size: %d", (i_ind + 1), erase_type_inst_arr[i_ind],
erase_type_size_arr[i_ind]);
if (erase_type_size_arr[i_ind] > 1) {
// if size==1 type is not supported
erase_type_inst_arr[i_ind] = basic_param_table_ptr[SPIF_BASIC_PARAM_ERASE_TYPE_1_BYTE + 2 * i_ind];
@ -824,21 +808,19 @@ int SPIFBlockDevice::_sfdp_detect_erase_types_inst_and_size(uint8_t *basic_param
if (erase4k_inst != erase_type_inst_arr[i_ind]) {
//Verify 4KErase Type is identical to Legacy 4K erase type specified in Byte 1 of Param Table
erase4k_inst = erase_type_inst_arr[i_ind];
tr_warning("WARNING: _detectEraseTypesInstAndSize - Default 4K erase Inst is different than erase type Inst for 4K");
tr_warning("_detectEraseTypesInstAndSize - Default 4K erase Inst is different than erase type Inst for 4K");
}
}
_region_erase_types_bitfield[0] |= bitfield; // If there's no region map, set region "0" types bitfield as defualt;
}
tr_info("INFO: Erase Type %d - Inst: 0x%xh, Size: %d", (i_ind + 1), erase_type_inst_arr[i_ind],
erase_type_size_arr[i_ind]);
bitfield = bitfield << 1;
}
}
if (false == found_4Kerase_type) {
tr_warning("WARNING: Couldn't find Erase Type for 4KB size");
tr_warning("Couldn't find Erase Type for 4KB size");
}
return 0;
}
@ -859,7 +841,6 @@ int SPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_
read_inst = basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE];
_read_dummy_and_mode_cycles = (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] >> 5)
+ (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_222_READ_INST_BYTE - 1] & 0x1F);
tr_info("\nDEBUG: Read Bus Mode set to 2-2-2, Instruction: 0x%xh", read_inst);
break;
}
}
@ -869,7 +850,6 @@ int SPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_
read_inst = basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE];
_read_dummy_and_mode_cycles = (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] >> 5)
+ (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_122_READ_INST_BYTE - 1] & 0x1F);
tr_debug("\nDEBUG: Read Bus Mode set to 1-2-2, Instruction: 0x%xh", read_inst);
break;
}
if (examined_byte & 0x01) {
@ -877,12 +857,10 @@ int SPIFBlockDevice::_sfdp_detect_best_bus_read_mode(uint8_t *basic_param_table_
read_inst = basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE];
_read_dummy_and_mode_cycles = (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] >> 5)
+ (basic_param_table_ptr[SPIF_BASIC_PARAM_TABLE_112_READ_INST_BYTE - 1] & 0x1F);
tr_debug("\nDEBUG: Read Bus Mode set to 1-1-2, Instruction: 0x%xh", _read_instruction);
break;
}
*/
_read_dummy_and_mode_cycles = 0;
tr_debug("\nDEBUG: Read Bus Mode set to 1-1-1, Instruction: 0x%xh", read_inst);
} while (false);
return 0;
@ -893,13 +871,10 @@ int SPIFBlockDevice::_reset_flash_mem()
// Perform Soft Reset of the Device prior to initialization
int status = 0;
char status_value[2] = {0};
tr_info("INFO: _reset_flash_mem:\n");
//Read the Status Register from device
if (SPIF_BD_ERROR_OK == _spi_send_general_command(SPIF_RDSR, SPI_NO_ADDRESS_COMMAND, NULL, 0, status_value, 1)) {
// store received values in status_value
tr_debug("DEBUG: Reading Status Register Success: value = 0x%x\n", (int)status_value[0]);
} else {
tr_debug("ERROR: Reading Status Register failed\n");
status = -1;
}
@ -907,9 +882,8 @@ int SPIFBlockDevice::_reset_flash_mem()
//Send Reset Enable
if (SPIF_BD_ERROR_OK == _spi_send_general_command(SPIF_RSTEN, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
// store received values in status_value
tr_debug("DEBUG: Sending RSTEN Success\n");
} else {
tr_error("ERROR: Sending RSTEN failed\n");
tr_error("Sending RSTEN failed");
status = -1;
}
@ -917,9 +891,8 @@ int SPIFBlockDevice::_reset_flash_mem()
//Send Reset
if (SPIF_BD_ERROR_OK == _spi_send_general_command(SPIF_RST, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
// store received values in status_value
tr_debug("DEBUG: Sending RST Success\n");
} else {
tr_error("ERROR: Sending RST failed\n");
tr_error("Sending RST failed");
status = -1;
}
_is_mem_ready();
@ -942,12 +915,12 @@ bool SPIFBlockDevice::_is_mem_ready()
//Read the Status Register from device
if (SPIF_BD_ERROR_OK != _spi_send_general_command(SPIF_RDSR, SPI_NO_ADDRESS_COMMAND, NULL, 0, status_value,
1)) { // store received values in status_value
tr_error("ERROR: Reading Status Register failed\n");
tr_error("Reading Status Register failed");
}
} while ((status_value[0] & SPIF_STATUS_BIT_WIP) != 0 && retries < IS_MEM_READY_MAX_RETRIES);
if ((status_value[0] & SPIF_STATUS_BIT_WIP) != 0) {
tr_error("ERROR: _is_mem_ready FALSE\n");
tr_error("_is_mem_ready FALSE");
mem_ready = false;
}
return mem_ready;
@ -961,24 +934,24 @@ int SPIFBlockDevice::_set_write_enable()
do {
if (SPIF_BD_ERROR_OK != _spi_send_general_command(SPIF_WREN, SPI_NO_ADDRESS_COMMAND, NULL, 0, NULL, 0)) {
tr_error("ERROR:Sending WREN command FAILED\n");
tr_error("Sending WREN command FAILED");
break;
}
if (false == _is_mem_ready()) {
tr_error("ERROR: Device not ready, write failed");
tr_error("Device not ready, write failed");
break;
}
memset(status_value, 0, 2);
if (SPIF_BD_ERROR_OK != _spi_send_general_command(SPIF_RDSR, SPI_NO_ADDRESS_COMMAND, NULL, 0, status_value,
1)) { // store received values in status_value
tr_error("ERROR: Reading Status Register failed\n");
tr_error("Reading Status Register failed");
break;
}
if ((status_value[0] & SPIF_STATUS_BIT_WEL) == 0) {
tr_error("ERROR: _set_write_enable failed\n");
tr_error("_set_write_enable failed");
break;
}
status = 0;
@ -1031,7 +1004,7 @@ int SPIFBlockDevice::_utils_iterate_next_largest_erase_type(uint8_t &bitfield, i
}
if (i_ind == 4) {
tr_error("ERROR: no erase type was found for current region addr");
tr_error("no erase type was found for current region addr");
}
return largest_erase_type;

View File

@ -62,6 +62,14 @@ uint32_t I2CTester::get_receive_checksum()
return to_slave_checksum;
}
uint32_t I2CTester::get_send_checksum()
{
uint32_t from_slave_checksum = 0;
MBED_ASSERT(sizeof(from_slave_checksum) == TESTER_I2C_FROM_SLAVE_CHECKSUM_SIZE);
read(TESTER_I2C_FROM_SLAVE_CHECKSUM, (uint8_t *)&from_slave_checksum, sizeof(from_slave_checksum));
return from_slave_checksum;
}
uint8_t I2CTester::state_num()
{
uint8_t state_num = 0;
@ -71,9 +79,16 @@ uint8_t I2CTester::state_num()
uint8_t I2CTester::num_dev_addr_matches()
{
uint8_t num_correct = 0;
read(TESTER_I2C_NUMBER_DEV_ADDR_MATCHES, &num_correct, sizeof(num_correct));
return num_correct;
uint8_t num_dev_addr_matches = 0;
read(TESTER_I2C_NUMBER_DEV_ADDR_MATCHES, &num_dev_addr_matches, sizeof(num_dev_addr_matches));
return num_dev_addr_matches;
}
uint8_t I2CTester::num_dev_addr_mismatches()
{
uint8_t num_dev_addr_mismatches = 0;
read(TESTER_I2C_NUMBER_DEV_ADDR_MISMATCHES, &num_dev_addr_mismatches, sizeof(num_dev_addr_mismatches));
return num_dev_addr_mismatches;
}
void I2CTester::set_device_address(uint16_t addr)

View File

@ -61,10 +61,10 @@ public:
uint16_t num_nacks();
/**
* Read the number of transfers which have occurred, not including the device address byte
* Read the number of transfers which have occurred
*
* @return The number of I2C transfers that have completed since
* i2c was reset, not including the device address byte
* i2c was reset, including the device address byte.
*/
uint16_t transfer_count();
@ -75,6 +75,13 @@ public:
*/
uint32_t get_receive_checksum();
/**
* Read a checksum the tester calculated for data it has already sent
*
* @return The sum of all bytes the tester has sent since reset
*/
uint32_t get_send_checksum();
/**
* Get the I2C slave state number
*
@ -89,6 +96,13 @@ public:
*/
uint8_t num_dev_addr_matches();
/**
* Get the number of times the device address has been sent incorrectly
*
* @return The number of times the device address has been sent incorrectly
*/
uint8_t num_dev_addr_mismatches();
/**
* Set the I2C slave device address
*
@ -153,7 +167,7 @@ public:
uint8_t get_next_from_slave();
/**
* Read the number of writes which have occurred, not including the device address byte
* Read the number of writes which have occurred
*
* @return The number of I2C writes that have completed since
* i2c was reset, not including the device address byte
@ -164,7 +178,7 @@ public:
* Read the number of reads which have occurred
*
* @return The number of I2C reads that have completed since
* i2c was reset
* i2c was reset, not including the device address byte
*/
uint16_t num_reads();

View File

@ -55,7 +55,7 @@
* // Map D6 to LogicalPinGPIO0
* tester.pin_map_set(D6, MbedTester::LogicalPinGPIO0);
*
* // Toggle the LED
* // Toggle pin D6
* int toggle = 0;
* while (1) {
* tester.gpio_write(MbedTester::LogicalPinGPIO0, toggle, true);

Some files were not shown because too many files have changed in this diff Show More