summaryrefslogtreecommitdiff
path: root/net/nimble/transport/ram/src/ble_hci_ram.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/nimble/transport/ram/src/ble_hci_ram.c')
-rw-r--r--net/nimble/transport/ram/src/ble_hci_ram.c229
1 files changed, 229 insertions, 0 deletions
diff --git a/net/nimble/transport/ram/src/ble_hci_ram.c b/net/nimble/transport/ram/src/ble_hci_ram.c
new file mode 100644
index 00000000..e3d236ea
--- /dev/null
+++ b/net/nimble/transport/ram/src/ble_hci_ram.c
@@ -0,0 +1,229 @@
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include "os/os.h"
+#include "util/mem.h"
+#include "nimble/ble.h"
+#include "nimble/ble_hci_trans.h"
+#include "transport/ram/ble_hci_ram.h"
+
+/** Default configuration. */
+const struct ble_hci_ram_cfg ble_hci_ram_cfg_dflt = {
+ .num_evt_hi_bufs = 2,
+ .num_evt_lo_bufs = 8,
+
+ /* The largest event the nimble controller will send is 70 bytes. */
+ .evt_buf_sz = 70,
+};
+
+static ble_hci_trans_rx_cmd_fn *ble_hci_ram_rx_cmd_hs_cb;
+static void *ble_hci_ram_rx_cmd_hs_arg;
+
+static ble_hci_trans_rx_cmd_fn *ble_hci_ram_rx_cmd_ll_cb;
+static void *ble_hci_ram_rx_cmd_ll_arg;
+
+static ble_hci_trans_rx_acl_fn *ble_hci_ram_rx_acl_hs_cb;
+static void *ble_hci_ram_rx_acl_hs_arg;
+
+static ble_hci_trans_rx_acl_fn *ble_hci_ram_rx_acl_ll_cb;
+static void *ble_hci_ram_rx_acl_ll_arg;
+
+static struct os_mempool ble_hci_ram_evt_hi_pool;
+static void *ble_hci_ram_evt_hi_buf;
+static struct os_mempool ble_hci_ram_evt_lo_pool;
+static void *ble_hci_ram_evt_lo_buf;
+
+static uint8_t *ble_hci_ram_hs_cmd_buf;
+static uint8_t ble_hci_ram_hs_cmd_buf_alloced;
+
+void
+ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb,
+ void *cmd_arg,
+ ble_hci_trans_rx_acl_fn *acl_cb,
+ void *acl_arg)
+{
+ ble_hci_ram_rx_cmd_hs_cb = cmd_cb;
+ ble_hci_ram_rx_cmd_hs_arg = cmd_arg;
+ ble_hci_ram_rx_acl_hs_cb = acl_cb;
+ ble_hci_ram_rx_acl_hs_arg = acl_arg;
+}
+
+void
+ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb,
+ void *cmd_arg,
+ ble_hci_trans_rx_acl_fn *acl_cb,
+ void *acl_arg)
+{
+ ble_hci_ram_rx_cmd_ll_cb = cmd_cb;
+ ble_hci_ram_rx_cmd_ll_arg = cmd_arg;
+ ble_hci_ram_rx_acl_ll_cb = acl_cb;
+ ble_hci_ram_rx_acl_ll_arg = acl_arg;
+}
+
+int
+ble_hci_trans_hs_cmd_tx(uint8_t *cmd)
+{
+ int rc;
+
+ assert(ble_hci_ram_rx_cmd_ll_cb != NULL);
+
+ rc = ble_hci_ram_rx_cmd_ll_cb(cmd, ble_hci_ram_rx_cmd_ll_arg);
+ return rc;
+}
+
+int
+ble_hci_trans_ll_evt_tx(uint8_t *hci_ev)
+{
+ int rc;
+
+ assert(ble_hci_ram_rx_cmd_hs_cb != NULL);
+
+ rc = ble_hci_ram_rx_cmd_hs_cb(hci_ev, ble_hci_ram_rx_cmd_hs_arg);
+ return rc;
+}
+
+int
+ble_hci_trans_hs_acl_tx(struct os_mbuf *om)
+{
+ int rc;
+
+ assert(ble_hci_ram_rx_acl_ll_cb != NULL);
+
+ rc = ble_hci_ram_rx_acl_ll_cb(om, ble_hci_ram_rx_acl_ll_arg);
+ return rc;
+}
+
+int
+ble_hci_trans_ll_acl_tx(struct os_mbuf *om)
+{
+ int rc;
+
+ assert(ble_hci_ram_rx_acl_hs_cb != NULL);
+
+ rc = ble_hci_ram_rx_acl_hs_cb(om, ble_hci_ram_rx_acl_hs_arg);
+ return rc;
+}
+
+uint8_t *
+ble_hci_trans_buf_alloc(int type)
+{
+ uint8_t *buf;
+
+ switch (type) {
+ case BLE_HCI_TRANS_BUF_EVT_HI:
+ buf = os_memblock_get(&ble_hci_ram_evt_hi_pool);
+ if (buf == NULL) {
+ /* If no high-priority event buffers remain, try to grab a
+ * low-priority one.
+ */
+ buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO);
+ }
+ break;
+
+ case BLE_HCI_TRANS_BUF_EVT_LO:
+ buf = os_memblock_get(&ble_hci_ram_evt_lo_pool);
+ break;
+
+ case BLE_HCI_TRANS_BUF_CMD:
+ assert(!ble_hci_ram_hs_cmd_buf_alloced);
+ ble_hci_ram_hs_cmd_buf_alloced = 1;
+ buf = ble_hci_ram_hs_cmd_buf;
+ break;
+
+ default:
+ assert(0);
+ buf = NULL;
+ }
+
+ return buf;
+}
+
+void
+ble_hci_trans_buf_free(uint8_t *buf)
+{
+ int rc;
+
+ if (buf == ble_hci_ram_hs_cmd_buf) {
+ assert(ble_hci_ram_hs_cmd_buf_alloced);
+ ble_hci_ram_hs_cmd_buf_alloced = 0;
+ } else if (os_memblock_from(&ble_hci_ram_evt_hi_pool, buf)) {
+ rc = os_memblock_put(&ble_hci_ram_evt_hi_pool, buf);
+ assert(rc == 0);
+ } else {
+ assert(os_memblock_from(&ble_hci_ram_evt_lo_pool, buf));
+ rc = os_memblock_put(&ble_hci_ram_evt_lo_pool, buf);
+ assert(rc == 0);
+ }
+}
+
+static void
+ble_hci_ram_free_mem(void)
+{
+ free(ble_hci_ram_evt_hi_buf);
+ ble_hci_ram_evt_hi_buf = NULL;
+
+ free(ble_hci_ram_evt_lo_buf);
+ ble_hci_ram_evt_lo_buf = NULL;
+
+ free(ble_hci_ram_hs_cmd_buf);
+ ble_hci_ram_hs_cmd_buf = NULL;
+ ble_hci_ram_hs_cmd_buf_alloced = 0;
+}
+
+int
+ble_hci_trans_reset(void)
+{
+ /* No work to do. All allocated buffers are owned by the host or
+ * controller, and they will get freed by their owners.
+ */
+ return 0;
+}
+
+/**
+ * Initializes the RAM HCI transport module.
+ *
+ * @param cfg The settings to initialize the HCI RAM
+ * transport with.
+ *
+ * @return 0 on success;
+ * A BLE_ERR_[...] error code on failure.
+ */
+int
+ble_hci_ram_init(const struct ble_hci_ram_cfg *cfg)
+{
+ int rc;
+
+ ble_hci_ram_free_mem();
+
+ rc = mem_malloc_mempool(&ble_hci_ram_evt_hi_pool,
+ cfg->num_evt_hi_bufs,
+ cfg->evt_buf_sz,
+ "ble_hci_ram_evt_hi_pool",
+ &ble_hci_ram_evt_hi_buf);
+ if (rc != 0) {
+ rc = ble_err_from_os(rc);
+ goto err;
+ }
+
+ rc = mem_malloc_mempool(&ble_hci_ram_evt_lo_pool,
+ cfg->num_evt_lo_bufs,
+ cfg->evt_buf_sz,
+ "ble_hci_ram_evt_lo_pool",
+ &ble_hci_ram_evt_lo_buf);
+ if (rc != 0) {
+ rc = ble_err_from_os(rc);
+ goto err;
+ }
+
+ ble_hci_ram_hs_cmd_buf = malloc(BLE_HCI_TRANS_CMD_SZ);
+ if (ble_hci_ram_hs_cmd_buf == NULL) {
+ rc = BLE_ERR_MEM_CAPACITY;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ ble_hci_ram_free_mem();
+ return rc;
+}