1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/congure/test/congure_test.c
Marian Buschsieweke 5ea582b3dd
sys/shell_commands: convert to SHELL_COMMAND()
Make use of XFA for shell commands
2022-06-07 09:25:04 +02:00

396 lines
11 KiB
C

/*
* Copyright (C) 2021 Freie Universität Berlin
*
* 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.
*/
/**
* @{
*
* @file
* @author Martine S. Lenders <m.lenders@fu-berlin.de>
*/
#include <limits.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include "clist.h"
#include "congure/test.h"
#include "fmt.h"
#include "shell.h"
static congure_snd_msg_t _msgs_pool[CONFIG_CONGURE_TEST_LOST_MSG_POOL_SIZE];
static unsigned _msgs_pool_idx;
static clist_node_t _msgs;
static bool _scn_u32_dec_with_zero(const char *str, size_t n, uint32_t *res)
{
if ((n == 1) && str[0] == '0') {
*res = 0;
}
else if ((*res = scn_u32_dec(str, n)) == 0) {
return false;
}
return true;
}
int congure_test_clear_state(int argc, char **argv)
{
memset(congure_test_get_state(), 0, sizeof(congure_test_snd_t));
congure_test_msgs_reset(argc, argv);
return 0;
}
SHELL_COMMAND(cong_clear, "Clears CongURE state object",
congure_test_clear_state);
int congure_test_call_setup(int argc, char **argv)
{
congure_test_snd_t *c = congure_test_get_state();
uint32_t id = 0;
if (argc > 1) {
if (!_scn_u32_dec_with_zero(argv[1], strlen(argv[1]), &id)) {
print_str("{\"error\":\"`id` expected to be integer\"}\n");
return 1;
}
}
if (congure_test_snd_setup(c, (unsigned)id) < 0) {
print_str("{\"error\":\"`id` is invalid\"}");
return 1;
}
print_str("{");
print_str("\"success\":\"0x");
print_u32_hex((intptr_t)c);
print_str("\"}\n");
return 0;
}
SHELL_COMMAND(cong_setup,
"Calls the setup function for the CongURE state object",
congure_test_call_setup);
static inline bool _check_driver(congure_test_snd_t *c)
{
if (c->super.driver == NULL) {
print_str("{\"error\":\"State object not set up\"}\n");
return false;
}
return true;
}
int congure_test_call_init(int argc, char **argv)
{
congure_test_snd_t *c = congure_test_get_state();
uint32_t ctx;
size_t arglen;
if (!_check_driver(c)) {
return 1;
}
if (argc < 2) {
print_str("{\"error\":\"`ctx` argument expected\"}\n");
return 1;
}
arglen = strlen(argv[1]);
if ((arglen < 3) || ((argv[1][0] != '0') && (argv[1][1] != 'x'))) {
print_str("{\"error\":\"`ctx` expected to be hex\"}\n");
return 1;
}
ctx = scn_u32_hex(&argv[1][2], arglen - 2);
c->super.driver->init(&c->super, (void *)((intptr_t)ctx));
print_str("{\"success\":null}\n");
return 0;
}
SHELL_COMMAND(cong_init, "Calls init method of the CongURE state object",
congure_test_call_init);
int congure_test_call_inter_msg_interval(int argc, char **argv)
{
congure_test_snd_t *c = congure_test_get_state();
uint32_t msg_size;
int32_t res;
(void)argc;
(void)argv;
if (!_check_driver(c)) {
return 1;
}
if (argc < 2) {
print_str("{\"error\":\"`msg_size` argument expected\"}\n");
return 1;
}
if (!_scn_u32_dec_with_zero(argv[1], strlen(argv[1]), &msg_size)) {
print_str("{\"error\":\"`msg_size` expected to be integer\"}\n");
return 1;
}
res = c->super.driver->inter_msg_interval(&c->super, msg_size);
print_str("{\"success\":");
print_s32_dec(res);
print_str("}\n");
return 0;
}
SHELL_COMMAND(cong_imi,
"Calls inter_message_interval method of the CongURE state object",
congure_test_call_inter_msg_interval);
int congure_test_add_msg(int argc, char **argv)
{
uint32_t tmp;
if (argc < 4) {
print_str("{\"error\":\"At least 3 arguments `msg_send_time`, "
"`msg_size`, `msg_resends` expected\"}\n");
return 1;
}
if (_msgs_pool_idx >= ARRAY_SIZE(_msgs_pool)) {
print_str("{\"error\":\"List element pool depleted\"}\n");
return 1;
}
_msgs_pool[_msgs_pool_idx].super.next = NULL;
if (!_scn_u32_dec_with_zero(argv[1], strlen(argv[1]), &tmp)) {
print_str("{\"error\":\"`msg_send_time` expected to be "
"integer\"}\n");
return 1;
}
_msgs_pool[_msgs_pool_idx].send_time = tmp;
if (!_scn_u32_dec_with_zero(argv[2], strlen(argv[2]), &tmp)) {
print_str("{\"error\":\"`msg_size` expected to be integer\"}\n");
return 1;
}
_msgs_pool[_msgs_pool_idx].size = tmp;
if (!_scn_u32_dec_with_zero(argv[3], strlen(argv[3]), &tmp)) {
print_str("{\"error\":\"`msg_resends` expected to be "
"integer\"}\n");
return 1;
}
_msgs_pool[_msgs_pool_idx].resends = tmp;
clist_rpush(&_msgs, &_msgs_pool[_msgs_pool_idx++].super);
print_str("{\"success\":null}\n");
return 0;
}
SHELL_COMMAND(cong_add_msg,
"Adds a message to the list of messages to be reported with "
"report_msgs_lost or report_msgs_timeout",
congure_test_add_msg);
int congure_test_msgs_reset(int argc, char **argv)
{
(void)argc;
(void)argv;
_msgs.next = NULL;
_msgs_pool_idx = 0;
print_str("{\"success\":null}\n");
return 0;
}
SHELL_COMMAND(cong_msgs_reset,
"Resets the list of messages to be reported with report_msgs_lost or "
"report_msgs_timeout",
congure_test_msgs_reset);
static int _call_report_msg_sent(int argc, char **argv)
{
congure_test_snd_t *c = congure_test_get_state();
uint32_t msg_size;
if (argc < 2) {
print_str("{\"error\":\"`msg_size` argument expected\"}\n");
return 1;
}
if (!_scn_u32_dec_with_zero(argv[1], strlen(argv[1]), &msg_size)) {
print_str("{\"error\":\"`msg_size` expected to be integer\"}\n");
return 1;
}
c->super.driver->report_msg_sent(&c->super, (unsigned)msg_size);
print_str("{\"success\":null}\n");
return 0;
}
static int _call_report_msg_discarded(int argc, char **argv)
{
congure_test_snd_t *c = congure_test_get_state();
uint32_t msg_size;
if (argc < 2) {
print_str("{\"error\":\"`msg_size` argument expected\"}\n");
return 1;
}
if (!_scn_u32_dec_with_zero(argv[1], strlen(argv[1]), &msg_size)) {
print_str("{\"error\":\"`msg_size` expected to be integer\"}\n");
return 1;
}
c->super.driver->report_msg_discarded(&c->super, (unsigned)msg_size);
print_str("{\"success\":null}\n");
return 0;
}
static int _call_report_msgs_timeout_lost(void (*method)(congure_snd_t *,
congure_snd_msg_t *))
{
congure_test_snd_t *c = congure_test_get_state();
if (_msgs.next == NULL) {
print_str("{\"error\":\"Message not initialized\"}\n");
return 1;
}
method(&c->super, (congure_snd_msg_t *)_msgs.next);
print_str("{\"success\":null}\n");
return 0;
}
static int _call_report_msgs_timeout(int argc, char **argv)
{
congure_test_snd_t *c = congure_test_get_state();
(void)argc;
(void)argv;
return _call_report_msgs_timeout_lost(c->super.driver->report_msgs_timeout);
}
static int _call_report_msgs_lost(int argc, char **argv)
{
congure_test_snd_t *c = congure_test_get_state();
(void)argc;
(void)argv;
return _call_report_msgs_timeout_lost(c->super.driver->report_msgs_lost);
}
static int _call_report_msg_acked(int argc, char **argv)
{
static congure_snd_ack_t ack = { .size = 0 };
congure_test_snd_t *c = congure_test_get_state();
uint32_t tmp;
if (_msgs.next == NULL) {
print_str("{\"error\":\"Message not initialized\"}\n");
return 1;
}
if (argc < 7) {
print_str("{\"error\":\"At least 6 arguments `ack_recv_time`, "
"`ack_id`, `ack_size`, `ack_clean`, `ack_wnd`, `ack_delay` "
"expected\"}\n");
return 1;
}
if (!_scn_u32_dec_with_zero(argv[1], strlen(argv[1]), &tmp)) {
print_str("{\"error\":\"`ack_recv_time` expected to be integer\"}\n");
return 1;
}
ack.recv_time = tmp;
if (!_scn_u32_dec_with_zero(argv[2], strlen(argv[2]), &tmp)) {
print_str("{\"error\":\"`ack_id` expected to be integer\"}\n");
return 1;
}
ack.id = tmp;
if (!_scn_u32_dec_with_zero(argv[3], strlen(argv[3]), &tmp)) {
print_str("{\"error\":\"`ack_size` expected to be integer\"}\n");
return 1;
}
ack.size = tmp;
if (!_scn_u32_dec_with_zero(argv[4], strlen(argv[4]), &tmp)) {
print_str("{\"error\":\"`ack_clean` expected to be integer\"}\n");
return 1;
}
ack.clean = (bool)tmp;
if (!_scn_u32_dec_with_zero(argv[5], strlen(argv[5]), &tmp)) {
print_str("{\"error\":\"`ack_wnd` expected to be integer\"}\n");
return 1;
}
if (tmp > CONGURE_WND_SIZE_MAX) {
print_str("{\"error\":\"`ack_wnd` not 16 bit wide\"}\n");
return 1;
}
ack.wnd = (uint16_t)tmp;
if (!_scn_u32_dec_with_zero(argv[6], strlen(argv[6]), &tmp)) {
print_str("{\"error\":\"`ack_delay` expected to be integer\"}\n");
return 1;
}
if (tmp > UINT16_MAX) {
print_str("{\"error\":\"`ack_delay` not 16 bit wide\"}\n");
return 1;
}
ack.delay = (uint16_t)tmp;
c->super.driver->report_msg_acked(&c->super,
(congure_snd_msg_t *)_msgs.next, &ack);
print_str("{\"success\":null}\n");
return 0;
}
static int _call_report_ecn_ce(int argc, char **argv)
{
congure_test_snd_t *c = congure_test_get_state();
uint32_t time;
if (argc < 2) {
print_str("{\"error\":\"`time` argument expected\"}\n");
return 1;
}
if (!_scn_u32_dec_with_zero(argv[1], strlen(argv[1]), &time)) {
print_str("{\"error\":\"`time` expected to be integer\"}\n");
return 1;
}
c->super.driver->report_ecn_ce(&c->super, time);
print_str("{\"success\":null}\n");
return 0;
}
int congure_test_call_report(int argc, char **argv)
{
if (!_check_driver(congure_test_get_state())) {
return 1;
}
if (argc < 2) {
print_str("{\"error\":\"No report command provided\"}\n");
return 1;
}
if (strcmp(argv[1], "msg_sent") == 0) {
return _call_report_msg_sent(argc - 1, &argv[1]);
}
else if (strcmp(argv[1], "msg_discarded") == 0) {
return _call_report_msg_discarded(argc - 1, &argv[1]);
}
else if (strcmp(argv[1], "msgs_timeout") == 0) {
return _call_report_msgs_timeout(argc - 1, &argv[1]);
}
else if (strcmp(argv[1], "msgs_lost") == 0) {
return _call_report_msgs_lost(argc - 1, &argv[1]);
}
else if (strcmp(argv[1], "msg_acked") == 0) {
return _call_report_msg_acked(argc - 1, &argv[1]);
}
else if (strcmp(argv[1], "ecn_ce") == 0) {
return _call_report_ecn_ce(argc - 1, &argv[1]);
}
print_str("{\"error\":\"Unknown command `");
print_str(argv[1]);
print_str("`\"}\n");
return 1;
}
SHELL_COMMAND(cong_report,
"Calls a report_* method of the CongURE state object",
congure_test_call_report);
/** @} */