added xiao nrf54l15 support for otbr
This commit is contained in:
31
src/main.c
Normal file
31
src/main.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#if defined(CONFIG_RCP_SAMPLE_HCI)
|
||||
#include "rcp_hci.h"
|
||||
#endif
|
||||
|
||||
LOG_MODULE_REGISTER(coprocessor_sample, CONFIG_OT_COPROCESSOR_LOG_LEVEL);
|
||||
|
||||
#define WELCOME_TEXT \
|
||||
"\n\r" \
|
||||
"\n\r" \
|
||||
"=========================================================\n\r" \
|
||||
"OpenThread Coprocessor application is now running on NCS.\n\r" \
|
||||
"=========================================================\n\r"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
LOG_INF(WELCOME_TEXT);
|
||||
|
||||
#if defined(CONFIG_RCP_SAMPLE_HCI)
|
||||
run_hci();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
74
src/nrf_802154_radio_wrapper.c
Normal file
74
src/nrf_802154_radio_wrapper.c
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
#include "nrf_802154_radio_wrapper.h"
|
||||
#include <nrf_802154.h>
|
||||
|
||||
#ifdef CONFIG_NETWORKING
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/net/ieee802154_radio.h>
|
||||
|
||||
static const struct device *const radio_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_ieee802154));
|
||||
static struct ieee802154_radio_api *radio_api;
|
||||
|
||||
#else
|
||||
static uint16_t get_capabilities(void)
|
||||
{
|
||||
nrf_802154_capabilities_t caps = nrf_802154_capabilities_get();
|
||||
|
||||
/* Convert nrf_802154_capabilities_t to ieee802154_hw_caps to keep backwards compatibility
|
||||
* See @ref ieee802154_hw_caps in zephyr/net/ieee802154_radio.h for more details.
|
||||
*/
|
||||
return /* IEEE802154_HW_FCS */ BIT(1) |
|
||||
/* IEEE802154_HW_PROMISC */ BIT(3) |
|
||||
/* IEEE802154_HW_FILTER */ BIT(2) |
|
||||
/* IEEE802154_HW_CSMA */ ((caps & NRF_802154_CAPABILITY_CSMA) ? BIT(4) : 0UL) |
|
||||
/* IEEE802154_HW_TX_RX_ACK */ BIT(5) |
|
||||
/* IEEE802154_HW_RX_TX_ACK */ BIT(7) |
|
||||
/* IEEE802154_HW_ENERGY_SCAN */ BIT(0) |
|
||||
/* IEEE802154_HW_TXTIME */
|
||||
((caps & NRF_802154_CAPABILITY_DELAYED_TX) ? BIT(8) : 0UL) |
|
||||
/* IEEE802154_HW_RXTIME */
|
||||
((caps & NRF_802154_CAPABILITY_DELAYED_RX) ? BIT(10) : 0UL) |
|
||||
/* IEEE802154_HW_SLEEP_TO_TX */ BIT(9) |
|
||||
/* IEEE802154_HW_TX_SEC */ BIT(12) |
|
||||
((caps & NRF_802154_CAPABILITY_SECURITY) ? BIT(11) : 0UL)
|
||||
#if defined(CONFIG_IEEE802154_NRF5_MULTIPLE_CCA)
|
||||
| /* IEEE802154_OPENTHREAD_HW_CAPS_BITS_START */ BIT(14)
|
||||
#endif
|
||||
#if defined(CONFIG_IEEE802154_SELECTIVE_TXCHANNEL)
|
||||
| /* IEEE802154_HW_SELECTIVE_TXCHANNEL */ BIT(13)
|
||||
#endif
|
||||
#if defined(CONFIG_IEEE802154_NRF5_CST_ENDPOINT)
|
||||
| /* IEEE802154_OPENTHREAD_HW_CAPS_BITS_START + 1*/ BIT(15)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool nrf_802154_radio_wrapper_auto_ack_get(void)
|
||||
{
|
||||
return nrf_802154_auto_ack_get();
|
||||
}
|
||||
|
||||
void nrf_802154_radio_wrapper_auto_ack_set(bool enabled)
|
||||
{
|
||||
nrf_802154_auto_ack_set(enabled);
|
||||
}
|
||||
|
||||
uint16_t nrf_802154_radio_wrapper_hw_capabilities_get(void)
|
||||
{
|
||||
#ifdef CONFIG_NETWORKING
|
||||
__ASSERT_NO_MSG(device_is_ready(radio_dev));
|
||||
|
||||
radio_api = (struct ieee802154_radio_api *)radio_dev->api;
|
||||
__ASSERT_NO_MSG(radio_api != NULL);
|
||||
|
||||
return radio_api->get_capabilities(radio_dev);
|
||||
#else
|
||||
return get_capabilities();
|
||||
#endif
|
||||
}
|
||||
44
src/nrf_802154_radio_wrapper.h
Normal file
44
src/nrf_802154_radio_wrapper.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#ifndef __NRF_802154_RADIO_WRAPPER_H__
|
||||
#define __NRF_802154_RADIO_WRAPPER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets current automatic acknowledgments mode state.
|
||||
*
|
||||
* @return true when auto ACK is set, false otherwise
|
||||
*/
|
||||
bool nrf_802154_radio_wrapper_auto_ack_get(void);
|
||||
|
||||
/**
|
||||
* Enables or disables the automatic acknowledgments mode (auto ACK).
|
||||
*
|
||||
* @param[in] enabled Value setting (true) or clearing (false)
|
||||
* auto ACK radio mode.
|
||||
*/
|
||||
void nrf_802154_radio_wrapper_auto_ack_set(bool enabled);
|
||||
|
||||
/**
|
||||
* Gets the device hardware capabilities
|
||||
*
|
||||
* @return 0 on failure; nonzero hw capabilities value
|
||||
* on success (@ref ieee802154_hw_caps).
|
||||
*/
|
||||
uint16_t nrf_802154_radio_wrapper_hw_capabilities_get(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __NRF_802154_RADIO_WRAPPER_H__ */
|
||||
381
src/rcp_hci.c
Normal file
381
src/rcp_hci.c
Normal file
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <zephyr/arch/cpu.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/drivers/uart.h>
|
||||
|
||||
#include <zephyr/net_buf.h>
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/l2cap.h>
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
#include <zephyr/bluetooth/buf.h>
|
||||
#include <zephyr/bluetooth/hci_raw.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(rcp_hci_module, CONFIG_OT_COPROCESSOR_LOG_LEVEL);
|
||||
|
||||
static const struct device *const hci_uart_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_c2h_uart));
|
||||
static K_THREAD_STACK_DEFINE(tx_thread_stack, CONFIG_BT_HCI_TX_STACK_SIZE);
|
||||
static struct k_thread tx_thread_data;
|
||||
static K_FIFO_DEFINE(tx_queue);
|
||||
|
||||
/* RX in terms of bluetooth communication */
|
||||
static K_FIFO_DEFINE(uart_tx_queue);
|
||||
|
||||
#define H4_CMD 0x01
|
||||
#define H4_ACL 0x02
|
||||
#define H4_SCO 0x03
|
||||
#define H4_EVT 0x04
|
||||
#define H4_ISO 0x05
|
||||
|
||||
/* Receiver states. */
|
||||
#define ST_IDLE 0 /* Waiting for packet type. */
|
||||
#define ST_HDR 1 /* Receiving packet header. */
|
||||
#define ST_PAYLOAD 2 /* Receiving packet payload. */
|
||||
#define ST_DISCARD 3 /* Dropping packet. */
|
||||
|
||||
#define H4_DISCARD_LEN 33
|
||||
|
||||
static int h4_read(const struct device *uart, uint8_t *buf, size_t len)
|
||||
{
|
||||
int rx = uart_fifo_read(uart, buf, len);
|
||||
|
||||
LOG_DBG("read %d req %d", rx, len);
|
||||
|
||||
return rx;
|
||||
}
|
||||
|
||||
static bool valid_type(uint8_t type)
|
||||
{
|
||||
return (type == H4_CMD) | (type == H4_ACL) | (type == H4_ISO);
|
||||
}
|
||||
|
||||
/* Function expects that type is validated and only CMD, ISO or ACL will be used. */
|
||||
static uint32_t get_len(const uint8_t *hdr_buf, uint8_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case H4_CMD:
|
||||
return ((const struct bt_hci_cmd_hdr *)hdr_buf)->param_len;
|
||||
case H4_ISO:
|
||||
return bt_iso_hdr_len(
|
||||
sys_le16_to_cpu(((const struct bt_hci_iso_hdr *)hdr_buf)->len));
|
||||
case H4_ACL:
|
||||
return sys_le16_to_cpu(((const struct bt_hci_acl_hdr *)hdr_buf)->len);
|
||||
default:
|
||||
LOG_ERR("Invalid type: %u", type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Function expects that type is validated and only CMD, ISO or ACL will be used. */
|
||||
static int hdr_len(uint8_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case H4_CMD:
|
||||
return sizeof(struct bt_hci_cmd_hdr);
|
||||
case H4_ISO:
|
||||
return sizeof(struct bt_hci_iso_hdr);
|
||||
case H4_ACL:
|
||||
return sizeof(struct bt_hci_acl_hdr);
|
||||
default:
|
||||
LOG_ERR("Invalid type: %u", type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void rx_isr(void)
|
||||
{
|
||||
static struct net_buf *buf;
|
||||
static int remaining;
|
||||
static uint8_t state;
|
||||
static uint8_t type;
|
||||
static uint8_t hdr_buf[MAX(sizeof(struct bt_hci_cmd_hdr), sizeof(struct bt_hci_acl_hdr))];
|
||||
int read;
|
||||
|
||||
do {
|
||||
switch (state) {
|
||||
case ST_IDLE:
|
||||
/* Get packet type */
|
||||
read = h4_read(hci_uart_dev, &type, sizeof(type));
|
||||
/* since we read in loop until no data is in the fifo,
|
||||
* it is possible that read = 0.
|
||||
*/
|
||||
if (read) {
|
||||
if (valid_type(type)) {
|
||||
/* Get expected header size and switch
|
||||
* to receiving header.
|
||||
*/
|
||||
remaining = hdr_len(type);
|
||||
state = ST_HDR;
|
||||
} else {
|
||||
LOG_WRN("Unknown header %d", type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ST_HDR:
|
||||
read = h4_read(hci_uart_dev, &hdr_buf[hdr_len(type) - remaining],
|
||||
remaining);
|
||||
remaining -= read;
|
||||
if (remaining == 0) {
|
||||
/* Header received. Allocate buffer and get
|
||||
* payload length. If allocation fails leave
|
||||
* interrupt. On failed allocation state machine
|
||||
* is reset.
|
||||
*/
|
||||
buf = bt_buf_get_tx(bt_buf_type_from_h4(type, BT_BUF_OUT),
|
||||
K_NO_WAIT, NULL, 0);
|
||||
if (!buf) {
|
||||
LOG_ERR("No available command buffers!");
|
||||
state = ST_IDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
remaining = get_len(hdr_buf, type);
|
||||
|
||||
net_buf_add_mem(buf, hdr_buf, hdr_len(type));
|
||||
if (remaining > net_buf_tailroom(buf)) {
|
||||
LOG_ERR("Not enough space in buffer");
|
||||
net_buf_unref(buf);
|
||||
state = ST_DISCARD;
|
||||
} else {
|
||||
state = ST_PAYLOAD;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ST_PAYLOAD:
|
||||
read = h4_read(hci_uart_dev, net_buf_tail(buf), remaining);
|
||||
buf->len += read;
|
||||
remaining -= read;
|
||||
if (remaining == 0) {
|
||||
/* Packet received */
|
||||
LOG_DBG("putting RX packet in queue.");
|
||||
k_fifo_put(&tx_queue, buf);
|
||||
state = ST_IDLE;
|
||||
}
|
||||
break;
|
||||
case ST_DISCARD: {
|
||||
uint8_t discard[H4_DISCARD_LEN];
|
||||
size_t to_read = MIN(remaining, sizeof(discard));
|
||||
|
||||
read = h4_read(hci_uart_dev, discard, to_read);
|
||||
remaining -= read;
|
||||
if (remaining == 0) {
|
||||
state = ST_IDLE;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
read = 0;
|
||||
__ASSERT_NO_MSG(0);
|
||||
break;
|
||||
}
|
||||
} while (read);
|
||||
}
|
||||
|
||||
static void tx_isr(void)
|
||||
{
|
||||
static struct net_buf *buf;
|
||||
int len;
|
||||
|
||||
if (!buf) {
|
||||
buf = k_fifo_get(&uart_tx_queue, K_NO_WAIT);
|
||||
if (!buf) {
|
||||
uart_irq_tx_disable(hci_uart_dev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
len = uart_fifo_fill(hci_uart_dev, buf->data, buf->len);
|
||||
net_buf_pull(buf, len);
|
||||
if (!buf->len) {
|
||||
net_buf_unref(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void bt_uart_isr(const struct device *unused, void *user_data)
|
||||
{
|
||||
ARG_UNUSED(unused);
|
||||
ARG_UNUSED(user_data);
|
||||
|
||||
if (!(uart_irq_rx_ready(hci_uart_dev) || uart_irq_tx_ready(hci_uart_dev))) {
|
||||
LOG_DBG("spurious interrupt");
|
||||
}
|
||||
|
||||
if (uart_irq_tx_ready(hci_uart_dev)) {
|
||||
tx_isr();
|
||||
}
|
||||
|
||||
if (uart_irq_rx_ready(hci_uart_dev)) {
|
||||
rx_isr();
|
||||
}
|
||||
}
|
||||
|
||||
static void tx_thread(void *p1, void *p2, void *p3)
|
||||
{
|
||||
while (1) {
|
||||
struct net_buf *buf;
|
||||
int err;
|
||||
|
||||
/* Wait until a buffer is available */
|
||||
buf = k_fifo_get(&tx_queue, K_FOREVER);
|
||||
/* Pass buffer to the stack */
|
||||
err = bt_send(buf);
|
||||
if (err) {
|
||||
LOG_ERR("Unable to send (err %d)", err);
|
||||
net_buf_unref(buf);
|
||||
}
|
||||
|
||||
/* Give other threads a chance to run if tx_queue keeps getting
|
||||
* new data all the time.
|
||||
*/
|
||||
k_yield();
|
||||
}
|
||||
}
|
||||
|
||||
static int h4_send(struct net_buf *buf)
|
||||
{
|
||||
LOG_DBG("buf %p type %u len %u", buf, buf->data[0], buf->len);
|
||||
|
||||
k_fifo_put(&uart_tx_queue, buf);
|
||||
uart_irq_tx_enable(hci_uart_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_ASSERT_HANDLER)
|
||||
void bt_ctlr_assert_handle(char *file, uint32_t line)
|
||||
{
|
||||
uint32_t len = 0U, pos = 0U;
|
||||
|
||||
/* Disable interrupts, this is unrecoverable */
|
||||
(void)irq_lock();
|
||||
|
||||
uart_irq_rx_disable(hci_uart_dev);
|
||||
uart_irq_tx_disable(hci_uart_dev);
|
||||
|
||||
if (file) {
|
||||
while (file[len] != '\0') {
|
||||
if (file[len] == '/') {
|
||||
pos = len + 1;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
file += pos;
|
||||
len -= pos;
|
||||
}
|
||||
|
||||
uart_poll_out(hci_uart_dev, H4_EVT);
|
||||
/* Vendor-Specific debug event */
|
||||
uart_poll_out(hci_uart_dev, 0xff);
|
||||
/* 0xAA + strlen + \0 + 32-bit line number */
|
||||
uart_poll_out(hci_uart_dev, 1 + len + 1 + 4);
|
||||
uart_poll_out(hci_uart_dev, 0xAA);
|
||||
|
||||
if (len) {
|
||||
while (*file != '\0') {
|
||||
uart_poll_out(hci_uart_dev, *file);
|
||||
file++;
|
||||
}
|
||||
uart_poll_out(hci_uart_dev, 0x00);
|
||||
}
|
||||
|
||||
uart_poll_out(hci_uart_dev, line >> 0 & 0xff);
|
||||
uart_poll_out(hci_uart_dev, line >> 8 & 0xff);
|
||||
uart_poll_out(hci_uart_dev, line >> 16 & 0xff);
|
||||
uart_poll_out(hci_uart_dev, line >> 24 & 0xff);
|
||||
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_ASSERT_HANDLER */
|
||||
|
||||
static int hci_uart_init(void)
|
||||
{
|
||||
LOG_DBG("");
|
||||
|
||||
if (!device_is_ready(hci_uart_dev)) {
|
||||
LOG_ERR("HCI UART %s is not ready", hci_uart_dev->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uart_irq_rx_disable(hci_uart_dev);
|
||||
uart_irq_tx_disable(hci_uart_dev);
|
||||
|
||||
uart_irq_callback_set(hci_uart_dev, bt_uart_isr);
|
||||
|
||||
uart_irq_rx_enable(hci_uart_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void run_hci(void)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
__ASSERT(hci_uart_dev, "UART device is NULL");
|
||||
/* incoming events and data from the controller */
|
||||
static K_FIFO_DEFINE(rx_queue);
|
||||
|
||||
/* Enable the raw interface, this will in turn open the HCI driver */
|
||||
bt_enable_raw(&rx_queue);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_WAIT_NOP)) {
|
||||
/* Issue a Command Complete with NOP */
|
||||
int i;
|
||||
|
||||
const struct {
|
||||
const uint8_t h4;
|
||||
const struct bt_hci_evt_hdr hdr;
|
||||
const struct bt_hci_evt_cmd_complete cc;
|
||||
} __packed cc_evt = {
|
||||
.h4 = H4_EVT,
|
||||
.hdr = {
|
||||
.evt = BT_HCI_EVT_CMD_COMPLETE,
|
||||
.len = sizeof(struct bt_hci_evt_cmd_complete),
|
||||
},
|
||||
.cc = {
|
||||
.ncmd = 1,
|
||||
.opcode = sys_cpu_to_le16(BT_OP_NOP),
|
||||
},
|
||||
};
|
||||
|
||||
for (i = 0; i < sizeof(cc_evt); i++) {
|
||||
uart_poll_out(hci_uart_dev, *(((const uint8_t *)&cc_evt) + i));
|
||||
}
|
||||
}
|
||||
|
||||
/* Spawn the TX thread and start feeding commands and data to the
|
||||
* controller
|
||||
*/
|
||||
k_thread_create(&tx_thread_data, tx_thread_stack, K_THREAD_STACK_SIZEOF(tx_thread_stack),
|
||||
tx_thread, NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
|
||||
k_thread_name_set(&tx_thread_data, "HCI uart TX");
|
||||
|
||||
while (1) {
|
||||
struct net_buf *buf;
|
||||
|
||||
buf = k_fifo_get(&rx_queue, K_FOREVER);
|
||||
err = h4_send(buf);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to send");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SYS_INIT(hci_uart_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
|
||||
12
src/rcp_hci.h
Normal file
12
src/rcp_hci.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
#ifndef __RCP_HCI_H__
|
||||
#define __RCP_HCI_H__
|
||||
|
||||
void run_hci(void);
|
||||
|
||||
#endif
|
||||
157
src/user_vendor_hook.cpp
Normal file
157
src/user_vendor_hook.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file shows how to implement the NCP vendor hook.
|
||||
*/
|
||||
#if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
|
||||
#include "nrf_802154_radio_wrapper.h"
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <ncp_base.hpp>
|
||||
#include <ncp_hdlc.hpp>
|
||||
#include <common/new.hpp>
|
||||
|
||||
#define VENDOR_SPINEL_PROP_VENDOR_NAME SPINEL_PROP_VENDOR__BEGIN
|
||||
#define VENDOR_SPINEL_PROP_AUTO_ACK_ENABLED SPINEL_PROP_VENDOR__BEGIN + 1
|
||||
#define VENDOR_SPINEL_PROP_HW_CAPABILITIES SPINEL_PROP_VENDOR__BEGIN + 2
|
||||
|
||||
LOG_MODULE_REGISTER(ncp_sample_vendor_hook, CONFIG_OT_COPROCESSOR_LOG_LEVEL);
|
||||
|
||||
namespace ot {
|
||||
namespace Ncp {
|
||||
|
||||
otError NcpBase::VendorCommandHandler(uint8_t aHeader, unsigned int aCommand)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
LOG_DBG("VendorCommandHandler");
|
||||
|
||||
switch (aCommand)
|
||||
{
|
||||
// TODO: Implement your command handlers here.
|
||||
|
||||
default:
|
||||
error = PrepareLastStatusResponse(aHeader, SPINEL_STATUS_INVALID_COMMAND);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void NcpBase::VendorHandleFrameRemovedFromNcpBuffer(Spinel::Buffer::FrameTag aFrameTag)
|
||||
{
|
||||
// This method is a callback which mirrors `NcpBase::HandleFrameRemovedFromNcpBuffer()`.
|
||||
// It is called when a spinel frame is sent and removed from NCP buffer.
|
||||
//
|
||||
// (a) This can be used to track and verify that a vendor spinel frame response is
|
||||
// delivered to the host (tracking the frame using its tag).
|
||||
//
|
||||
// (b) It indicates that NCP buffer space is now available (since a spinel frame is
|
||||
// removed). This can be used to implement reliability mechanisms to re-send
|
||||
// a failed spinel command response (or an async spinel frame) transmission
|
||||
// (failed earlier due to NCP buffer being full).
|
||||
|
||||
OT_UNUSED_VARIABLE(aFrameTag);
|
||||
}
|
||||
|
||||
otError NcpBase::VendorGetPropertyHandler(spinel_prop_key_t aPropKey)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
switch (aPropKey)
|
||||
{
|
||||
case VENDOR_SPINEL_PROP_VENDOR_NAME:
|
||||
LOG_DBG("Got NAME get property request");
|
||||
error = mEncoder.WriteUtf8("Nordic Seminconductor");
|
||||
break;
|
||||
case VENDOR_SPINEL_PROP_AUTO_ACK_ENABLED:
|
||||
LOG_DBG("Got VENDOR_SPINEL_PROP_AUTO_ACK_ENABLED get property request");
|
||||
error = mEncoder.WriteUint8(nrf_802154_radio_wrapper_auto_ack_get());
|
||||
break;
|
||||
case VENDOR_SPINEL_PROP_HW_CAPABILITIES:
|
||||
LOG_DBG("Got VENDOR_SPINEL_PROP_HW_CAPABILITIES get property request");
|
||||
error = mEncoder.WriteUint16(nrf_802154_radio_wrapper_hw_capabilities_get());
|
||||
break;
|
||||
|
||||
// TODO: Implement your get properties handlers here.
|
||||
default:
|
||||
error = OT_ERROR_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError NcpBase::VendorSetPropertyHandler(spinel_prop_key_t aPropKey)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
switch (aPropKey)
|
||||
{
|
||||
case VENDOR_SPINEL_PROP_AUTO_ACK_ENABLED: {
|
||||
LOG_DBG("Got VENDOR_SPINEL_PROP_AUTO_ACK_ENABLED set property request");
|
||||
|
||||
uint8_t mode = 0;
|
||||
SuccessOrExit(error = mDecoder.ReadUint8(mode));
|
||||
nrf_802154_radio_wrapper_auto_ack_set(mode);
|
||||
}
|
||||
break;
|
||||
|
||||
// TODO: Implement your set properties handlers here.
|
||||
default:
|
||||
error = OT_ERROR_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace Ncp
|
||||
} // namespace ot
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// When OPENTHREAD_ENABLE_NCP_VENDOR_HOOK is enabled, vendor code is
|
||||
// expected to provide the `otNcpInit()` function. The reason behind
|
||||
// this is to enable vendor code to define its own sub-class of
|
||||
// `NcpBase` or `NcpHdlc`/`NcpSpi`.
|
||||
//
|
||||
// Example below show how to add a vendor sub-class over `NcpHdlc`.
|
||||
|
||||
class NcpVendorUart : public ot::Ncp::NcpHdlc
|
||||
{
|
||||
|
||||
static int SendHdlc(const uint8_t *aBuf, uint16_t aBufLength)
|
||||
{
|
||||
return mSendCallback(aBuf, aBufLength);
|
||||
}
|
||||
|
||||
public:
|
||||
NcpVendorUart(ot::Instance *aInstance, otNcpHdlcSendCallback aSendCallback)
|
||||
: ot::Ncp::NcpHdlc(aInstance, &NcpVendorUart::SendHdlc)
|
||||
{
|
||||
OT_ASSERT(aSendCallback);
|
||||
mSendCallback = aSendCallback;
|
||||
}
|
||||
|
||||
// Add public/private methods or member variables
|
||||
private:
|
||||
static otNcpHdlcSendCallback mSendCallback;
|
||||
};
|
||||
|
||||
otNcpHdlcSendCallback NcpVendorUart::mSendCallback;
|
||||
|
||||
static OT_DEFINE_ALIGNED_VAR(sNcpVendorRaw, sizeof(NcpVendorUart), uint64_t);
|
||||
|
||||
|
||||
extern "C" void otNcpHdlcInit(otInstance *aInstance, otNcpHdlcSendCallback aSendCallback)
|
||||
{
|
||||
NcpVendorUart *ncpVendor = NULL;
|
||||
ot::Instance *instance = static_cast<ot::Instance *>(aInstance);
|
||||
|
||||
ncpVendor = new (&sNcpVendorRaw) NcpVendorUart(instance, aSendCallback);
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user