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