diff --git a/sys/include/net/l2scan_list.h b/sys/include/net/l2scan_list.h index fde5a445d0..7d88e3e220 100644 --- a/sys/include/net/l2scan_list.h +++ b/sys/include/net/l2scan_list.h @@ -35,7 +35,7 @@ extern "C" { * @brief Type of a Link Layer scan list */ typedef struct l2scan_list { - list_node_t *head; /**< Pointer to the list head node */ + list_node_t head; /**< List head, where head->next is the first element */ /* items */ } l2scan_list_t; @@ -65,6 +65,20 @@ void l2scan_list_insert(l2scan_list_t *list, size_t node_size, const netopt_scan_result_t *result); +/** + * @brief Copy the content of a L2 scan list to an array to get rid of the list overhead + * + * @param[in] list Pointer to list + * @param[out] nodes_array Buffer of nodes to store the result + * @param[in] nodes_numof Maximum number of nodes that can be copied + * @param[in] node_size Size of one node element in the array + * + * @return Number of copied nodes + */ +unsigned l2scan_list_to_array(const l2scan_list_t *list, + void *nodes_array, unsigned nodes_numof, + size_t node_size); + #ifdef __cplusplus } #endif diff --git a/sys/net/link_layer/l2scan_list/l2scan_list.c b/sys/net/link_layer/l2scan_list/l2scan_list.c index 7322a404b0..c4c92b67b7 100644 --- a/sys/net/link_layer/l2scan_list/l2scan_list.c +++ b/sys/net/link_layer/l2scan_list/l2scan_list.c @@ -49,8 +49,7 @@ static scan_list_node_t *_scan_list_get_insert(l2scan_list_t *list, lowest = result; /* override lowest element */ } } - list_node_t l = { .next = list->head }; - list_remove(&l, &lowest->node); + list_remove(&list->head, &lowest->node); return lowest; } @@ -58,7 +57,7 @@ void l2scan_list_empty(l2scan_list_t *list, list_node_t *nodes, unsigned nodes_numof, size_t node_size) { - list->head = NULL; + list->head.next = NULL; memset(nodes, 0, nodes_numof * node_size); } @@ -71,20 +70,25 @@ void l2scan_list_insert(l2scan_list_t *list, nodes_numof, node_size); *insert = (scan_list_node_t) { .node = { .next = NULL }, }; memcpy(&insert->result, result, node_size - sizeof(list_node_t)); - - if (!list->head) { - list->head = &insert->node; - } - else if (((scan_list_node_t *)list->head)->result.strength < result->strength) { - insert->node.next = list->head; - list->head = &insert->node; - } - else { - scan_list_node_t *next, *before = (scan_list_node_t *)list->head; - while ((next = (scan_list_node_t *)before->node.next) && - next->result.strength > result->strength) { - before = (scan_list_node_t *)before->node.next; - } - list_add(&before->node, &insert->node); + const scan_list_node_t *next; + list_node_t *before = &list->head; + while ((next = (scan_list_node_t *)before->next) && + next->result.strength > result->strength) { + before = before->next; } + list_add(before, &insert->node); +} + +unsigned l2scan_list_to_array(const l2scan_list_t *list, + void *nodes_array, unsigned nodes_numof, + size_t node_size) +{ + list_node_t *node = list->head.next; + uint8_t *buf = nodes_array; + size_t size = node_size - sizeof(*node); + unsigned i; + for (i = 0; i < nodes_numof && node; i++, buf += size, node = node->next) { + memcpy(buf, &node[1], size); + } + return i; } diff --git a/tests/net/l2scan_list/Makefile b/tests/net/l2scan_list/Makefile new file mode 100644 index 0000000000..c5a959c8db --- /dev/null +++ b/tests/net/l2scan_list/Makefile @@ -0,0 +1,6 @@ +include ../Makefile.net_common + +USEMODULE += embunit +USEMODULE += l2scan_list + +include $(RIOTBASE)/Makefile.include diff --git a/tests/net/l2scan_list/main.c b/tests/net/l2scan_list/main.c new file mode 100644 index 0000000000..f94784ab75 --- /dev/null +++ b/tests/net/l2scan_list/main.c @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2023 ML!PA Consulting GmbH + * + * 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 Unit tests for l2scan list + * + * @author Fabian Hüßler + */ + +#include +#include + +#include "embUnit.h" +#include "container.h" +#include "net/netopt.h" +#include "net/l2scan_list.h" + +typedef struct my_scan_result_node { + list_node_t node; + netopt_scan_result_t result; +} my_scan_result_node_t; + +static const netopt_scan_result_t _test_results[] = { + [0] = { + .channel = 11, + .strength = -40, + }, + [1] = { + .channel = 11, + .strength = -52, + }, + [2] = { + .channel = 6, + .strength = -53, + }, + [3] = { + .channel = 6, + .strength = -54, + }, + [4] = { + .channel = 6, + .strength = -55, + }, + [5] = { + .channel = 1, + .strength = -60, + }, + [6] = { + .channel = 1, + .strength = -70, + }, + [7] = { + .channel = 1, + .strength = -80, + } +}; + +struct { + my_scan_result_node_t *head; + my_scan_result_node_t result[ARRAY_SIZE(_test_results)]; +} _scan_list; + +static void test_l2scan_list_empty(void) +{ + l2scan_list_empty((l2scan_list_t *)&_scan_list, (list_node_t *)_scan_list.result, + ARRAY_SIZE(_scan_list.result), sizeof(my_scan_result_node_t)); + TEST_ASSERT(!_scan_list.head); +} + +static void test_l2scan_list_not_empty(void) +{ + l2scan_list_empty((l2scan_list_t *)&_scan_list, (list_node_t *)_scan_list.result, + ARRAY_SIZE(_scan_list.result), sizeof(my_scan_result_node_t)); + TEST_ASSERT(!_scan_list.head); + l2scan_list_insert((l2scan_list_t *)&_scan_list, (list_node_t *)_scan_list.result, + ARRAY_SIZE(_scan_list.result), sizeof(my_scan_result_node_t), + &_test_results[0]); + TEST_ASSERT(_scan_list.head); +} + +static void test_l2scan_list_insert(void) +{ + l2scan_list_empty((l2scan_list_t *)&_scan_list, (list_node_t *)_scan_list.result, + ARRAY_SIZE(_scan_list.result), sizeof(my_scan_result_node_t)); + TEST_ASSERT(!_scan_list.head); + /* random order insert */ + l2scan_list_insert((l2scan_list_t *)&_scan_list, (list_node_t *)_scan_list.result, + ARRAY_SIZE(_scan_list.result), sizeof(my_scan_result_node_t), + &_test_results[6]); + l2scan_list_insert((l2scan_list_t *)&_scan_list, (list_node_t *)_scan_list.result, + ARRAY_SIZE(_scan_list.result), sizeof(my_scan_result_node_t), + &_test_results[0]); + l2scan_list_insert((l2scan_list_t *)&_scan_list, (list_node_t *)_scan_list.result, + ARRAY_SIZE(_scan_list.result), sizeof(my_scan_result_node_t), + &_test_results[3]); + l2scan_list_insert((l2scan_list_t *)&_scan_list, (list_node_t *)_scan_list.result, + ARRAY_SIZE(_scan_list.result), sizeof(my_scan_result_node_t), + &_test_results[5]); + l2scan_list_insert((l2scan_list_t *)&_scan_list, (list_node_t *)_scan_list.result, + ARRAY_SIZE(_scan_list.result), sizeof(my_scan_result_node_t), + &_test_results[1]); + l2scan_list_insert((l2scan_list_t *)&_scan_list, (list_node_t *)_scan_list.result, + ARRAY_SIZE(_scan_list.result), sizeof(my_scan_result_node_t), + &_test_results[2]); + l2scan_list_insert((l2scan_list_t *)&_scan_list, (list_node_t *)_scan_list.result, + ARRAY_SIZE(_scan_list.result), sizeof(my_scan_result_node_t), + &_test_results[7]); + l2scan_list_insert((l2scan_list_t *)&_scan_list, (list_node_t *)_scan_list.result, + ARRAY_SIZE(_scan_list.result), sizeof(my_scan_result_node_t), + &_test_results[4]); + /* now expect it to be sorted by strength as it is in the test data */ + my_scan_result_node_t *node = _scan_list.head; + for (unsigned i = 0; i < ARRAY_SIZE(_test_results); i++) { + TEST_ASSERT(node); + TEST_ASSERT(node->result.channel == _test_results[i].channel); + TEST_ASSERT(node->result.strength == _test_results[i].strength); + node = (my_scan_result_node_t *)node->node.next; + } +} + +static void _setup(void) +{ + memset(&_scan_list, 0, sizeof(_scan_list)); +} + +Test* test_l2scan_list(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_l2scan_list_empty), + new_TestFixture(test_l2scan_list_not_empty), + new_TestFixture(test_l2scan_list_insert), + }; + + EMB_UNIT_TESTCALLER(tests_l2scan_list, _setup, NULL, fixtures); + return (Test *)&tests_l2scan_list; +} + +int main(void) +{ + TESTS_START(); + TESTS_RUN(test_l2scan_list()); + TESTS_END(); +}