From 02697fafb38a0c6c86f6a4c9b5c7c7f044a14fb4 Mon Sep 17 00:00:00 2001 From: Matthew Blue <matthew.blue.neuro@gmail.com> Date: Thu, 19 Apr 2018 22:53:49 -0400 Subject: [PATCH] sys/cb_mux: initial support --- sys/cb_mux/Makefile | 1 + sys/cb_mux/cb_mux.c | 124 +++++++++++++++++++++++++++++++++++++ sys/include/cb_mux.h | 143 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 268 insertions(+) create mode 100644 sys/cb_mux/Makefile create mode 100644 sys/cb_mux/cb_mux.c create mode 100644 sys/include/cb_mux.h diff --git a/sys/cb_mux/Makefile b/sys/cb_mux/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/sys/cb_mux/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/cb_mux/cb_mux.c b/sys/cb_mux/cb_mux.c new file mode 100644 index 0000000000..0a8164ebcf --- /dev/null +++ b/sys/cb_mux/cb_mux.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2018 Acutam Automation, LLC + * + * 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 sys_cb_mux + * @{ + * + * @file + * @brief cb_mux implementation + * + * @author Matthew Blue <matthew.blue.neuro@gmail.com> + * @} + */ + +#include "cb_mux.h" +#include "utlist.h" + +void cb_mux_add(cb_mux_t **head, cb_mux_t *entry) +{ + LL_APPEND(*head, entry); +} + +void cb_mux_del(cb_mux_t **head, cb_mux_t *entry) +{ + LL_DELETE(*head, entry); +} + +cb_mux_t *cb_mux_find_cbid(cb_mux_t *head, cb_mux_cbid_t cbid_val) +{ + cb_mux_t *entry; + + LL_SEARCH_SCALAR(head, entry, cbid, cbid_val); + + return entry; +} + +cb_mux_t *cb_mux_find_low(cb_mux_t *head) +{ + cb_mux_t *entry; + cb_mux_t *entry_low = NULL; + cb_mux_cbid_t id = (cb_mux_cbid_t)(-1); + + LL_FOREACH(head, entry) { + /* Entry does not have lower ID */ + if (entry->cbid >= id) { + continue; + } + + id = entry->cbid; + entry_low = entry; + } + + return entry_low; +} + +cb_mux_t *cb_mux_find_high(cb_mux_t *head) +{ + cb_mux_t *entry; + cb_mux_t *entry_high = NULL; + cb_mux_cbid_t id = 0; + + LL_FOREACH(head, entry) { + /* Entry does not have higher ID */ + if (entry->cbid <= id) { + continue; + } + + id = entry->cbid; + entry_high = entry; + } + + return entry_high; +} + +cb_mux_cbid_t cb_mux_find_free_id(cb_mux_t *head) +{ + uint32_t free; + cb_mux_cbid_t block; + cb_mux_t *entry; + uint8_t num; + + /* Search for free IDs in blocks of 32 IDs */ + for (block = 0; block + 31 < (cb_mux_cbid_t)(-1); block += 32) { + /* Set all IDs in block to free */ + free = 0; + + LL_FOREACH(head, entry) { + /* cbid falls within this block */ + if ((entry->cbid >= block) && (entry->cbid < block + 32)) { + /* Set cbid to taken */ + free |= 1 << (entry->cbid & 0x1F); + } + } + + /* At least one ID in block free */ + if (~free) { + break; + } + } + + /* Find which ID in block was free */ + for (num = 0; num < 32; num++) { + if (~free & (1 << num)) { + return block | num; + } + } + + /* No free IDs */ + return (cb_mux_cbid_t)(-1); +} + +void cb_mux_iter(cb_mux_t *head, cb_mux_iter_t func, void *arg) +{ + cb_mux_t *entry; + + LL_FOREACH(head, entry) { + func(entry, arg); + } +} diff --git a/sys/include/cb_mux.h b/sys/include/cb_mux.h new file mode 100644 index 0000000000..8f28223c10 --- /dev/null +++ b/sys/include/cb_mux.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2018 Acutam Automation, LLC + * + * 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. + */ + +/** + * @defgroup sys_cb_mux Callback multiplexer + * @ingroup sys + * @brief cb_mux provides utilities for storing, retrieving, and managing + * callback information in a singly linked list. + * + * If an API provides the ability to call multiple callbacks, cb_mux can + * simplify handling of an arbitrary number of callbacks by requiring memory + * for a cb_mux entry to be passed along with other arguments. The cb_mux entry + * is then attached to a list using cb_mux_add. The code implementing that API + * can manage the list using the various utility functions that cb_mux provides. + * + * @{ + * + * @file + * @brief cb_mux interface definitions + * + * @author Matthew Blue <matthew.blue.neuro@gmail.com> + */ + +#ifndef CB_MUX_H +#define CB_MUX_H + +#include <stdint.h> + +/* For alternate cb_mux_cbid_t */ +#include "periph_cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HAVE_CB_MUX_CBID_T +/** + * @brief cb_mux identifier type + */ +typedef unsigned int cb_mux_cbid_t; +#endif + +/** + * @brief cb_mux callback type + */ +typedef void (*cb_mux_cb_t)(void *); + +/** + * @brief cb_mux list entry structure + */ +typedef struct cb_mux { + struct cb_mux *next; /**< next entry in the cb_mux list */ + cb_mux_cbid_t cbid; /**< identifier for this callback */ + void *info; /**< optional extra information */ + cb_mux_cb_t cb; /**< callback function */ + void *arg; /**< argument for callback function */ +} cb_mux_t; + +/** + * @brief cb_mux iterate function callback type for cb_mux_iter + */ +typedef void (*cb_mux_iter_t)(cb_mux_t *, void *); + +/** + * @brief Add a new entry to the end of a cb_mux list + * + * @param[in] head double pointer to first list entry + * @param[in] entry entry to add + */ +void cb_mux_add(cb_mux_t **head, cb_mux_t *entry); + +/** + * @brief Remove a entry from a cb_mux list + * + * @param[in] head double pointer to first list entry + * @param[in] entry entry to remove + */ +void cb_mux_del(cb_mux_t **head, cb_mux_t *entry); + +/** + * @brief Find an entry in the list by ID + * + * @param[in] head pointer to first list entry + * @param[in] cbid_val ID to find + * + * @return pointer to the list entry + */ +cb_mux_t *cb_mux_find_cbid(cb_mux_t *head, cb_mux_cbid_t cbid_val); + +/** + * @brief Find the entry with the lowest ID + * + * If there are multiple hits, this returns the oldest. + * + * @param[in] head pointer to first list entry + * + * @return pointer to the list entry + */ +cb_mux_t *cb_mux_find_low(cb_mux_t *head); + +/** + * @brief Find the entry with the highest ID + * + * If there are multiple hits, this returns the oldest. + * + * @param[in] head pointer to first list entry + * + * @return pointer to the list entry + */ +cb_mux_t *cb_mux_find_high(cb_mux_t *head); + +/** + * @brief Find the lowest unused ID + * + * Returns highest possible ID on failure + * + * @param[in] head pointer to first list entry + * + * @return lowest unused ID + */ +cb_mux_cbid_t cb_mux_find_free_id(cb_mux_t *head); + +/** + * @brief Run a function on every item in the cb_mux list + * + * @param[in] head pointer to first list entry + * @param[in] func function to run on each entry + * @param[in] arg argument for the function + */ +void cb_mux_iter(cb_mux_t *head, cb_mux_iter_t func, void *arg); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* CB_MUX_H */ -- GitLab