-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add test for periph timer #30
base: master
Are you sure you want to change the base?
Changes from 4 commits
69ba06e
9b6c3bb
396edad
5ab0c74
509a3bc
e0192e8
93db06a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
include ../Makefile.tests_common | ||
|
||
USEMODULE += shell | ||
FEATURES_REQUIRED += periph_timer | ||
FEATURES_REQUIRED += periph_gpio | ||
|
||
CFLAGS += -DRIOT_APPLICATION=\"$(APPLICATION)\" | ||
|
||
include $(RIOTBASE)/Makefile.include |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# periph timer test | ||
|
||
This application provides a wrapper for testing the periph_timer api via the | ||
RIOT shell. To capture fast low level timing events some functions provide | ||
additional parameters to signal events over gpio pins e.g. before calling a | ||
timer function or on ISR callback execution. | ||
While this test can be run manually and with any external measurement equipment, | ||
it is recommended to use it together with the provided robot test on a PHiLIP- | ||
based HIL setup. | ||
Consult the 'help' shell command for available actions. | ||
|
||
Running this test with robot framework is done with this command: | ||
`BOARD=whatever PORT=/dev/ttyACM0 PHILIP_PORT=/dev/ttyACM1 DEBUG0_PORT=1 DEBUG0_PIN=3 make robot-test` | ||
|
||
Where DEBUG0_PORT and DEBUG0_PIN are the RIOT specific pin identifiers of the | ||
DUT pin that is connected to PHiLIPs DEBUG0 pin. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,308 @@ | ||
/* | ||
* Copyright (C) 2019 HAW Hamburg | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser | ||
* General Public License v2.1. See the file LICENSE in the top level | ||
* directory for more details. | ||
*/ | ||
|
||
/** | ||
* @ingroup tests | ||
* @{ | ||
* | ||
* @file | ||
* @brief Test application for periph timer API | ||
* | ||
* @author Michel Rottleuthner <[email protected]> | ||
* | ||
* @} | ||
*/ | ||
|
||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <errno.h> | ||
#include <string.h> | ||
|
||
#include "shell.h" | ||
#include "periph/timer.h" | ||
#include "periph/gpio.h" | ||
#include "mutex.h" | ||
|
||
#define ARG_ERROR (-1) | ||
#define CONVERT_ERROR (-32768) | ||
#define RESULT_OK (0) | ||
#define RESULT_ERROR (-1) | ||
#define INVALID_ARGS puts("Error: Invalid number of arguments"); | ||
|
||
#define CB_TOGGLE_STR "cb_toggle" | ||
#define CB_HIGH_STR "cb_high" | ||
#define CB_LOW_STR "cb_low" | ||
|
||
static mutex_t cb_mutex; | ||
|
||
static inline int _get_num(const char *str) | ||
{ | ||
errno = 0; | ||
char *temp; | ||
long val = strtol(str, &temp, 0); | ||
|
||
if (temp == str || *temp != '\0' || | ||
((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE)) { | ||
val = CONVERT_ERROR; | ||
} | ||
return (int)val; | ||
} | ||
|
||
static int _check_param(int argc, char **argv, int c_min, int c_max, char *use) | ||
{ | ||
int dev; | ||
|
||
if (argc - 1 < c_min || argc - 1 > c_max) { | ||
printf("Usage: %s %s\n", argv[0], use); | ||
INVALID_ARGS; | ||
return ARG_ERROR; | ||
} | ||
|
||
dev = _get_num(argv[1]); | ||
if (dev < 0 || dev >= (int)TIMER_NUMOF) { | ||
printf("Error: No device, only %d supported\n", (int)TIMER_NUMOF); | ||
return ARG_ERROR; | ||
} | ||
return dev; | ||
} | ||
|
||
static int _print_cmd_result(const char *cmd, bool success, int ret) | ||
{ | ||
printf("%s: %s(): [%d]\n", success ? "Success" : "Error", cmd, ret); | ||
return success ? RESULT_OK : RESULT_ERROR; | ||
} | ||
|
||
static gpio_t _get_pin(const char *port_str, const char *pin_str) | ||
{ | ||
int port = _get_num(port_str); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. error case is not checked here and below, i.e. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
int pin = _get_num(pin_str); | ||
|
||
return GPIO_PIN(port, pin); | ||
} | ||
|
||
void cb_toggle(void *arg, int channel) | ||
{ | ||
(void)channel; | ||
gpio_t pin = (gpio_t)(intptr_t)arg; | ||
gpio_toggle(pin); | ||
mutex_unlock(&cb_mutex); | ||
} | ||
|
||
void cb_high(void *arg, int channel) | ||
{ | ||
(void)channel; | ||
gpio_t pin = (gpio_t)(intptr_t)arg; | ||
gpio_set(pin); | ||
mutex_unlock(&cb_mutex); | ||
} | ||
|
||
void cb_low(void *arg, int channel) | ||
{ | ||
(void)channel; | ||
gpio_t pin = (gpio_t)(intptr_t)arg; | ||
gpio_clear(pin); | ||
mutex_unlock(&cb_mutex); | ||
} | ||
|
||
int cmd_timer_bench_read(int argc, char **argv) | ||
{ | ||
int timer_dev = _check_param(argc, argv, 4, 4, | ||
"timerdev repeat_cnt gpio_port gpio_pin"); | ||
|
||
if (timer_dev == ARG_ERROR) { | ||
return -1; | ||
} | ||
|
||
uint32_t repeat_cnt = _get_num(argv[2]); | ||
|
||
gpio_t pin = _get_pin(argv[3], argv[4]); | ||
|
||
gpio_toggle(pin); | ||
|
||
for (uint32_t i = 0; i < repeat_cnt; i++) { | ||
timer_read(timer_dev); | ||
} | ||
|
||
gpio_toggle(pin); | ||
|
||
printf("Success: cmd_timer_read_bench()\n"); | ||
return RESULT_OK; | ||
} | ||
|
||
int cmd_timer_init(int argc, char **argv) | ||
{ | ||
int timer_dev = _check_param(argc, argv, 5, 5, | ||
"dev freq cb gpio_port gpio_pin"); | ||
|
||
if (timer_dev == ARG_ERROR) { | ||
return -1; | ||
} | ||
|
||
unsigned long freq = _get_num(argv[2]); | ||
|
||
timer_cb_t cb = NULL; | ||
|
||
if (strncmp(CB_TOGGLE_STR, argv[3], strlen(argv[3])) == 0) { | ||
cb = cb_toggle; | ||
} | ||
|
||
if (strncmp(CB_HIGH_STR, argv[3], strlen(argv[3])) == 0) { | ||
cb = cb_high; | ||
} | ||
|
||
if (strncmp(CB_LOW_STR, argv[3], strlen(argv[3])) == 0) { | ||
cb = cb_low; | ||
} | ||
|
||
if(cb == NULL) { | ||
printf("no valid callback name given. Valid values or %s, %s or %s\n", | ||
CB_TOGGLE_STR, CB_HIGH_STR, CB_LOW_STR); | ||
return -2; | ||
} | ||
|
||
gpio_t pin = _get_pin(argv[4], argv[5]); | ||
|
||
gpio_init(pin, GPIO_OUT); | ||
|
||
int res = timer_init(timer_dev, freq, cb, (void*)(intptr_t)pin); | ||
|
||
return _print_cmd_result("timer_init", res == 0, res); | ||
} | ||
|
||
int _timer_set(int argc, char **argv, bool absolute) | ||
{ | ||
int res; | ||
int timer_dev = _check_param(argc, argv, 5, 5, | ||
"dev channel ticks gpio_port gpio_pin"); | ||
|
||
if (timer_dev == ARG_ERROR) { | ||
return -1; | ||
} | ||
|
||
unsigned long chan = _get_num(argv[2]); | ||
unsigned long timeout = _get_num(argv[3]); | ||
gpio_t pin = _get_pin(argv[4], argv[5]); | ||
|
||
mutex_lock(&cb_mutex); | ||
|
||
if (absolute) { | ||
gpio_toggle(pin); | ||
res = timer_set_absolute(timer_dev, chan, timeout); | ||
} | ||
else { | ||
gpio_toggle(pin); | ||
res = timer_set(timer_dev, chan, timeout); | ||
} | ||
|
||
/* wait for unlock by cb */ | ||
mutex_lock(&cb_mutex); | ||
|
||
/* reset mutex state */ | ||
mutex_unlock(&cb_mutex); | ||
return res; | ||
} | ||
|
||
int cmd_timer_set(int argc, char **argv) | ||
{ | ||
int res = _timer_set(argc, argv, false); | ||
return _print_cmd_result("timer_set", res == 1, res); | ||
} | ||
|
||
int cmd_timer_absolute(int argc, char **argv) | ||
{ | ||
int res = _timer_set(argc, argv, true); | ||
return _print_cmd_result("timer_set_absolute", res == 1, res); | ||
} | ||
|
||
int cmd_timer_clear(int argc, char **argv) | ||
{ | ||
int timer_dev = _check_param(argc, argv, 2, 2, "dev channel"); | ||
|
||
if (timer_dev == ARG_ERROR) { | ||
return -1; | ||
} | ||
|
||
unsigned long chan = _get_num(argv[2]); | ||
|
||
int res = timer_clear(timer_dev, chan); | ||
|
||
return _print_cmd_result("timer_clear", res == 1, res); | ||
} | ||
|
||
int cmd_timer_read(int argc, char **argv) | ||
{ | ||
int timer_dev = _check_param(argc, argv, 1, 1, "dev"); | ||
|
||
if (timer_dev == ARG_ERROR) { | ||
return -1; | ||
} | ||
|
||
int res = timer_read(timer_dev); | ||
return _print_cmd_result("timer_read", true, res); | ||
} | ||
|
||
int cmd_timer_start(int argc, char **argv) | ||
{ | ||
int timer_dev = _check_param(argc, argv, 1, 1, "dev"); | ||
|
||
if (timer_dev == ARG_ERROR) { | ||
return -1; | ||
} | ||
|
||
timer_start(timer_dev); | ||
puts("Success: timer_start()\n"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. better use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
return 0; | ||
} | ||
|
||
int cmd_timer_stop(int argc, char **argv) | ||
{ | ||
int timer_dev = _check_param(argc, argv, 1, 1, "dev"); | ||
|
||
if (timer_dev == ARG_ERROR) { | ||
return -1; | ||
} | ||
|
||
timer_stop(timer_dev); | ||
puts("Success: timer_stop()\n"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here, use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
return 0; | ||
} | ||
|
||
int cmd_get_metadata(int argc, char **argv) | ||
{ | ||
(void)argv; | ||
(void)argc; | ||
|
||
printf("Success: [%s, %s]\n", RIOT_BOARD, RIOT_APPLICATION); | ||
|
||
return 0; | ||
} | ||
|
||
static const shell_command_t shell_commands[] = { | ||
{ "timer_read_bench", "execute multiple reads to determine overhead", | ||
cmd_timer_bench_read }, | ||
{ "timer_init", "init_timer", cmd_timer_init }, | ||
{ "timer_set", "set timer to relative value", cmd_timer_set }, | ||
{ "timer_absolute", "set timer to absolute value", cmd_timer_absolute }, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
{ "timer_clear", "clear timer", cmd_timer_clear }, | ||
{ "timer_read", "read timer", cmd_timer_read }, | ||
{ "timer_start", "start timer", cmd_timer_start }, | ||
{ "timer_stop", "stop timer", cmd_timer_stop }, | ||
{ "get_metadata", "Get the metadata of the test firmware", | ||
cmd_get_metadata }, | ||
{ NULL, NULL, NULL } | ||
}; | ||
|
||
int main(void) | ||
{ | ||
puts("Start: Test for the timer API"); | ||
|
||
char line_buf[SHELL_DEFAULT_BUFSIZE]; | ||
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); | ||
|
||
return 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the error case is not evaluated in many cases where this function is used. Maybe change to
and return value by reference and error as return?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done