use zephyr include files; wip: compiles
This commit is contained in:
parent
11cb3e3b4b
commit
a5ab2829eb
@ -31,7 +31,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hci.h"
|
||||
#include "hci_api.h"
|
||||
|
||||
#include "py/gc.h"
|
||||
#include "py/mphal.h"
|
||||
@ -179,13 +179,10 @@ char default_ble_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0
|
||||
// common_hal_bleio_adapter_set_name(self, (char*) default_ble_name);
|
||||
// }
|
||||
|
||||
void common_hal_bleio_adapter_hci_init(bleio_adapter_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, uint32_t baudrate, uint32_t buffer_size) {
|
||||
self->tx_pin = tx;
|
||||
self->rx_pin = rx;
|
||||
void common_hal_bleio_adapter_hci_init(bleio_adapter_obj_t *self, busio_uart_obj_t *uart, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts) {
|
||||
self->hci_uart = uart;
|
||||
self->rts_pin = rts;
|
||||
self->cts_pin = cts;
|
||||
self->baudrate = baudrate;
|
||||
self->buffer_size = buffer_size;
|
||||
self->enabled = false;
|
||||
}
|
||||
|
||||
@ -198,34 +195,15 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
common_hal_busio_uart_construct(
|
||||
&self->hci_uart,
|
||||
self->tx_pin, // tx pin
|
||||
self->rx_pin, // rx pin
|
||||
NULL, // rts pin
|
||||
NULL, // cts pin
|
||||
NULL, // rs485 dir pin
|
||||
false, // rs485 invert
|
||||
0, // timeout
|
||||
self->baudrate, // baudrate
|
||||
8, // nbits
|
||||
PARITY_NONE, // parity
|
||||
1, // stop bits
|
||||
self->buffer_size, // buffer size
|
||||
NULL, // buffer
|
||||
false // sigint_enabled
|
||||
);
|
||||
common_hal_digitalio_digitalinout_construct(&self->rts_digitalinout, self->rts_pin);
|
||||
common_hal_digitalio_digitalinout_construct(&self->cts_digitalinout, self->cts_pin);
|
||||
|
||||
hci_init(self);
|
||||
} else {
|
||||
common_hal_busio_uart_deinit(&self->hci_uart);
|
||||
common_hal_digitalio_digitalinout_deinit(&self->rts_digitalinout);
|
||||
common_hal_digitalio_digitalinout_deinit(&self->cts_digitalinout);
|
||||
}
|
||||
|
||||
|
||||
//FIX enable/disable HCI adapter, but don't reset it, since we don't know how.
|
||||
self->enabled = enabled;
|
||||
}
|
||||
@ -235,35 +213,22 @@ bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) {
|
||||
}
|
||||
|
||||
bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) {
|
||||
common_hal_bleio_adapter_set_enabled(self, true);
|
||||
|
||||
uint8_t addr[6];
|
||||
hci_readBdAddr(addr);
|
||||
bt_addr_le_t addr;
|
||||
hci_read_bd_addr(&addr.a);
|
||||
|
||||
bleio_address_obj_t *address = m_new_obj(bleio_address_obj_t);
|
||||
address->base.type = &bleio_address_type;
|
||||
|
||||
// 0 is the type designating a public address.
|
||||
common_hal_bleio_address_construct(address, addr, 0);
|
||||
common_hal_bleio_address_construct(address, addr.a.val, addr.type);
|
||||
return address;
|
||||
}
|
||||
|
||||
mp_obj_str_t* common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self) {
|
||||
uint16_t len = 0;
|
||||
// sd_ble_gap_device_name_get(NULL, &len);
|
||||
uint8_t buf[len];
|
||||
// uint32_t err_code = sd_ble_gap_device_name_get(buf, &len);
|
||||
// if (err_code != NRF_SUCCESS) {
|
||||
// return NULL;
|
||||
// }
|
||||
return mp_obj_new_str((char*) buf, len);
|
||||
return self->name;
|
||||
}
|
||||
|
||||
void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char* name) {
|
||||
// ble_gap_conn_sec_mode_t sec;
|
||||
// sec.lv = 0;
|
||||
// sec.sm = 0;
|
||||
// sd_ble_gap_device_name_set(&sec, (const uint8_t*) name, strlen(name));
|
||||
self->name = mp_obj_new_str(name, strlen(name));
|
||||
}
|
||||
|
||||
// STATIC bool scan_on_ble_evt(ble_evt_t *ble_evt, void *scan_results_in) {
|
||||
|
@ -52,13 +52,9 @@ typedef struct {
|
||||
bleio_scanresults_obj_t* scan_results;
|
||||
mp_obj_t name;
|
||||
mp_obj_tuple_t *connection_objs;
|
||||
const mcu_pin_obj_t* tx_pin;
|
||||
const mcu_pin_obj_t* rx_pin;
|
||||
busio_uart_obj_t* hci_uart;
|
||||
const mcu_pin_obj_t* rts_pin;
|
||||
const mcu_pin_obj_t* cts_pin;
|
||||
uint32_t baudrate;
|
||||
uint16_t buffer_size;
|
||||
busio_uart_obj_t hci_uart;
|
||||
digitalio_digitalinout_obj_t rts_digitalinout;
|
||||
digitalio_digitalinout_obj_t cts_digitalinout;
|
||||
bool enabled;
|
||||
|
@ -1,674 +0,0 @@
|
||||
/*
|
||||
This file is part of the ArduinoBLE library.
|
||||
Copyright (c) 2018 Arduino SA. All rights reserved.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "hci.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "supervisor/shared/tick.h"
|
||||
|
||||
#define ATT_CID 0x0004
|
||||
|
||||
#define HCI_COMMAND_PKT 0x01
|
||||
#define HCI_ACLDATA_PKT 0x02
|
||||
#define HCI_EVENT_PKT 0x04
|
||||
|
||||
#define EVT_DISCONN_COMPLETE 0x05
|
||||
#define EVT_CMD_COMPLETE 0xe
|
||||
#define EVT_CMD_STATUS 0x0f
|
||||
#define EVT_NUM_COMP_PKTS 0x13
|
||||
#define EVT_LE_META_EVENT 0x3e
|
||||
|
||||
#define EVT_LE_CONN_COMPLETE 0x01
|
||||
#define EVT_LE_ADVERTISING_REPORT 0x02
|
||||
|
||||
#define OGF_LINK_CTL 0x01
|
||||
#define OGF_HOST_CTL 0x03
|
||||
#define OGF_INFO_PARAM 0x04
|
||||
#define OGF_STATUS_PARAM 0x05
|
||||
#define OGF_LE_CTL 0x08
|
||||
|
||||
// OGF_LINK_CTL
|
||||
#define OCF_DISCONNECT 0x0006
|
||||
|
||||
// OGF_HOST_CTL
|
||||
#define OCF_SET_EVENT_MASK 0x0001
|
||||
#define OCF_RESET 0x0003
|
||||
|
||||
// OGF_INFO_PARAM
|
||||
#define OCF_READ_LOCAL_VERSION 0x0001
|
||||
#define OCF_READ_BD_ADDR 0x0009
|
||||
|
||||
// OGF_STATUS_PARAM
|
||||
#define OCF_READ_RSSI 0x0005
|
||||
|
||||
// OGF_LE_CTL
|
||||
#define OCF_LE_READ_BUFFER_SIZE 0x0002
|
||||
#define OCF_LE_SET_RANDOM_ADDRESS 0x0005
|
||||
#define OCF_LE_SET_ADVERTISING_PARAMETERS 0x0006
|
||||
#define OCF_LE_SET_ADVERTISING_DATA 0x0008
|
||||
#define OCF_LE_SET_SCAN_RESPONSE_DATA 0x0009
|
||||
#define OCF_LE_SET_ADVERTISE_ENABLE 0x000a
|
||||
#define OCF_LE_SET_SCAN_PARAMETERS 0x000b
|
||||
#define OCF_LE_SET_SCAN_ENABLE 0x000c
|
||||
#define OCF_LE_CREATE_CONN 0x000d
|
||||
#define OCF_LE_CANCEL_CONN 0x000e
|
||||
#define OCF_LE_CONN_UPDATE 0x0013
|
||||
|
||||
#define HCI_OE_USER_ENDED_CONNECTION 0x13
|
||||
|
||||
|
||||
#define RECV_BUFFER_SIZE (3 + 255)
|
||||
#define ACL_PKT_BUFFER_SIZE (255)
|
||||
|
||||
STATIC bleio_adapter_obj_t *adapter;
|
||||
|
||||
STATIC int recv_idx;
|
||||
STATIC uint8_t recv_buffer[RECV_BUFFER_SIZE];
|
||||
STATIC uint16_t cmd_complete_opcode;
|
||||
STATIC int cmd_complete_status;
|
||||
STATIC uint8_t cmd_response_len;
|
||||
STATIC uint8_t* cmd_response;
|
||||
|
||||
STATIC uint8_t max_pkt;
|
||||
STATIC uint8_t pending_pkt;
|
||||
|
||||
//FIX STATIC uint8_t acl_pkt_buffer[255];
|
||||
|
||||
STATIC bool debug = true;
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t evt;
|
||||
uint8_t plen;
|
||||
} HCIEventHdr;
|
||||
|
||||
STATIC void dumpPkt(const char* prefix, uint8_t plen, uint8_t pdata[])
|
||||
{
|
||||
if (debug) {
|
||||
mp_printf(&mp_plat_print, "%s", prefix);
|
||||
|
||||
for (uint8_t i = 0; i < plen; i++) {
|
||||
mp_printf(&mp_plat_print, "%02x", pdata[i]);
|
||||
}
|
||||
mp_printf(&mp_plat_print, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATIC void handleAclDataPkt(uint8_t plen, uint8_t pdata[])
|
||||
{
|
||||
// typedef struct __attribute__ ((packed)) {
|
||||
// uint16_t handle;
|
||||
// uint16_t dlen;
|
||||
// uint16_t len;
|
||||
// uint16_t cid;
|
||||
// } HCIACLHdr;
|
||||
|
||||
// HCIACLHdr *aclHdr = (HCIACLHdr*)pdata;
|
||||
|
||||
// uint16_t aclFlags = (aclHdr->handle & 0xf000) >> 12;
|
||||
|
||||
// if ((aclHdr->dlen - 4) != aclHdr->len) {
|
||||
// // packet is fragmented
|
||||
// if (aclFlags != 0x01) {
|
||||
// // copy into ACL buffer
|
||||
// memcpy(acl_pkt_buffer, &recv_buffer[1], sizeof(HCIACLHdr) + aclHdr->dlen - 4);
|
||||
// } else {
|
||||
// // copy next chunk into the buffer
|
||||
// HCIACLHdr* aclBufferHeader = (HCIACLHdr*)acl_pkt_buffer;
|
||||
|
||||
// memcpy(&acl_pkt_buffer[sizeof(HCIACLHdr) + aclBufferHeader->dlen - 4], &recv_buffer[1 + sizeof(aclHdr->handle) + sizeof(aclHdr->dlen)], aclHdr->dlen);
|
||||
|
||||
// aclBufferHeader->dlen += aclHdr->dlen;
|
||||
// aclHdr = aclBufferHeader;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if ((aclHdr->dlen - 4) != aclHdr->len) {
|
||||
// // don't have the full packet yet
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (aclHdr->cid == ATT_CID) {
|
||||
// if (aclFlags == 0x01) {
|
||||
// // use buffered packet
|
||||
// ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &acl_pkt_buffer[sizeof(HCIACLHdr)]);
|
||||
// } else {
|
||||
// // use the recv buffer
|
||||
// ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &recv_buffer[1 + sizeof(HCIACLHdr)]);
|
||||
// }
|
||||
// } else if (aclHdr->cid == SIGNALING_CID) {
|
||||
// L2CAPSignaling.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &recv_buffer[1 + sizeof(HCIACLHdr)]);
|
||||
// } else {
|
||||
// struct __attribute__ ((packed)) {
|
||||
// uint8_t op;
|
||||
// uint8_t id;
|
||||
// uint16_t length;
|
||||
// uint16_t reason;
|
||||
// uint16_t localCid;
|
||||
// uint16_t remoteCid;
|
||||
// } l2capRejectCid= { 0x01, 0x00, 0x006, 0x0002, aclHdr->cid, 0x0000 };
|
||||
|
||||
// sendAclPkt(aclHdr->handle & 0x0fff, 0x0005, sizeof(l2capRejectCid), &l2capRejectCid);
|
||||
// }
|
||||
}
|
||||
|
||||
STATIC void handleNumCompPkts(uint16_t handle, uint16_t numPkts)
|
||||
{
|
||||
if (numPkts && pending_pkt > numPkts) {
|
||||
pending_pkt -= numPkts;
|
||||
} else {
|
||||
pending_pkt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void handleEventPkt(uint8_t plen, uint8_t pdata[])
|
||||
{
|
||||
HCIEventHdr *eventHdr = (HCIEventHdr*)pdata;
|
||||
|
||||
if (eventHdr->evt == EVT_DISCONN_COMPLETE) {
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t status;
|
||||
uint16_t handle;
|
||||
uint8_t reason;
|
||||
} DisconnComplete;
|
||||
|
||||
DisconnComplete *disconnComplete = (DisconnComplete*)&pdata[sizeof(HCIEventHdr)];
|
||||
(void) disconnComplete;
|
||||
//FIX
|
||||
// ATT.removeConnection(disconnComplete->handle, disconnComplete->reason);
|
||||
// L2CAPSignaling.removeConnection(disconnComplete->handle, disconnComplete->reason);
|
||||
|
||||
hci_leSetAdvertiseEnable(0x01);
|
||||
} else if (eventHdr->evt == EVT_CMD_COMPLETE) {
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t ncmd;
|
||||
uint16_t opcode;
|
||||
uint8_t status;
|
||||
} CmdComplete;
|
||||
|
||||
CmdComplete *cmdCompleteHeader = (CmdComplete*)&pdata[sizeof(HCIEventHdr)];
|
||||
cmd_complete_opcode = cmdCompleteHeader->opcode;
|
||||
cmd_complete_status = cmdCompleteHeader->status;
|
||||
cmd_response_len = pdata[1] - sizeof(CmdComplete);
|
||||
cmd_response = &pdata[sizeof(HCIEventHdr) + sizeof(CmdComplete)];
|
||||
|
||||
} else if (eventHdr->evt == EVT_CMD_STATUS) {
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t status;
|
||||
uint8_t ncmd;
|
||||
uint16_t opcode;
|
||||
} CmdStatus;
|
||||
|
||||
CmdStatus *cmdStatusHeader = (CmdStatus*)&pdata[sizeof(HCIEventHdr)];
|
||||
cmd_complete_opcode = cmdStatusHeader->opcode;
|
||||
cmd_complete_status = cmdStatusHeader->status;
|
||||
cmd_response_len = 0;
|
||||
} else if (eventHdr->evt == EVT_NUM_COMP_PKTS) {
|
||||
uint8_t numHandles = pdata[sizeof(HCIEventHdr)];
|
||||
uint8_t* data = &pdata[sizeof(HCIEventHdr) + sizeof(numHandles)];
|
||||
|
||||
for (uint8_t i = 0; i < numHandles; i++) {
|
||||
handleNumCompPkts(data[0], data[1]);
|
||||
|
||||
data += 2;
|
||||
}
|
||||
} else if (eventHdr->evt == EVT_LE_META_EVENT) {
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t subevent;
|
||||
} LeMetaEventHeader;
|
||||
|
||||
LeMetaEventHeader *leMetaHeader = (LeMetaEventHeader*)&pdata[sizeof(HCIEventHdr)];
|
||||
if (leMetaHeader->subevent == EVT_LE_CONN_COMPLETE) {
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t status;
|
||||
uint16_t handle;
|
||||
uint8_t role;
|
||||
uint8_t peerBdaddrType;
|
||||
uint8_t peerBdaddr[6];
|
||||
uint16_t interval;
|
||||
uint16_t latency;
|
||||
uint16_t supervisionTimeout;
|
||||
uint8_t masterClockAccuracy;
|
||||
} EvtLeConnectionComplete;
|
||||
|
||||
EvtLeConnectionComplete *leConnectionComplete = (EvtLeConnectionComplete*)&pdata[sizeof(HCIEventHdr) + sizeof(LeMetaEventHeader)];
|
||||
|
||||
if (leConnectionComplete->status == 0x00) {
|
||||
// ATT.addConnection(leConnectionComplete->handle,
|
||||
// leConnectionComplete->role,
|
||||
// leConnectionComplete->peerBdaddrType,
|
||||
// leConnectionComplete->peerBdaddr,
|
||||
// leConnectionComplete->interval,
|
||||
// leConnectionComplete->latency,
|
||||
// leConnectionComplete->supervisionTimeout,
|
||||
// leConnectionComplete->masterClockAccuracy);
|
||||
|
||||
// L2CAPSignaling.addConnection(leConnectionComplete->handle,
|
||||
// leConnectionComplete->role,
|
||||
// leConnectionComplete->peerBdaddrType,
|
||||
// leConnectionComplete->peerBdaddr,
|
||||
// leConnectionComplete->interval,
|
||||
// leConnectionComplete->latency,
|
||||
// leConnectionComplete->supervisionTimeout,
|
||||
// leConnectionComplete->masterClockAccuracy);
|
||||
}
|
||||
} else if (leMetaHeader->subevent == EVT_LE_ADVERTISING_REPORT) {
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t status;
|
||||
uint8_t type;
|
||||
uint8_t peerBdaddrType;
|
||||
uint8_t peerBdaddr[6];
|
||||
uint8_t eirLength;
|
||||
uint8_t eirData[31];
|
||||
} EvtLeAdvertisingReport;
|
||||
|
||||
EvtLeAdvertisingReport*leAdvertisingReport = (EvtLeAdvertisingReport*)&pdata[sizeof(HCIEventHdr) + sizeof(LeMetaEventHeader)];
|
||||
|
||||
if (leAdvertisingReport->status == 0x01) {
|
||||
// last byte is RSSI
|
||||
//FIX int8_t rssi = leAdvertisingReport->eirData[leAdvertisingReport->eirLength];
|
||||
|
||||
// GAP.handleLeAdvertisingReport(leAdvertisingReport->type,
|
||||
// leAdvertisingReport->peerBdaddrType,
|
||||
// leAdvertisingReport->peerBdaddr,
|
||||
// leAdvertisingReport->eirLength,
|
||||
// leAdvertisingReport->eirData,
|
||||
// rssi);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hci_init(bleio_adapter_obj_t *adapter_in) {
|
||||
adapter = adapter_in;
|
||||
recv_idx = 0;
|
||||
pending_pkt = 0;
|
||||
}
|
||||
|
||||
void hci_poll(void) {
|
||||
// Assert RTS low to say we're ready to read data.
|
||||
common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, false);
|
||||
|
||||
int errcode = 0;
|
||||
while (common_hal_busio_uart_rx_characters_available(&adapter->hci_uart)) {
|
||||
// Read just one character.
|
||||
common_hal_busio_uart_read(&adapter->hci_uart, recv_buffer + recv_idx, 1, &errcode);
|
||||
recv_idx++;
|
||||
|
||||
if (recv_buffer[0] == HCI_ACLDATA_PKT) {
|
||||
if (recv_idx > 5 && recv_idx >= (5 + (recv_buffer[3] + (recv_buffer[4] << 8)))) {
|
||||
if (debug) {
|
||||
dumpPkt("HCI ACLDATA RX <- ", recv_idx, recv_buffer);
|
||||
}
|
||||
// Hold data while processing packet.
|
||||
common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true);
|
||||
size_t pktLen = recv_idx - 1;
|
||||
recv_idx = 0;
|
||||
|
||||
handleAclDataPkt(pktLen, &recv_buffer[1]);
|
||||
|
||||
common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, false);
|
||||
}
|
||||
} else if (recv_buffer[0] == HCI_EVENT_PKT) {
|
||||
if (recv_idx > 3 && recv_idx >= (3 + recv_buffer[2])) {
|
||||
if (debug) {
|
||||
dumpPkt("HCI EVENT RX <- ", recv_idx, recv_buffer);
|
||||
}
|
||||
// Hold data while processing packet.
|
||||
common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true);
|
||||
// Received full event. Reset buffer and handle packet.
|
||||
size_t pktLen = recv_idx - 1;
|
||||
recv_idx = 0;
|
||||
|
||||
handleEventPkt(pktLen, &recv_buffer[1]);
|
||||
|
||||
common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, false);
|
||||
}
|
||||
} else {
|
||||
recv_idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true);
|
||||
}
|
||||
|
||||
|
||||
int hci_sendCommand(uint8_t ogf, uint16_t ocf, uint8_t plen, void* parameters)
|
||||
{
|
||||
uint16_t opcode = ogf << 10 | ocf;
|
||||
|
||||
struct __attribute__ ((packed)) {
|
||||
uint8_t pktType;
|
||||
uint16_t opcode;
|
||||
uint8_t plen;
|
||||
} pktHdr = {HCI_COMMAND_PKT, opcode, plen};
|
||||
|
||||
uint8_t txBuffer[sizeof(pktHdr) + plen];
|
||||
memcpy(txBuffer, &pktHdr, sizeof(pktHdr));
|
||||
memcpy(&txBuffer[sizeof(pktHdr)], parameters, plen);
|
||||
|
||||
if (debug) {
|
||||
dumpPkt("HCI COMMAND TX -> ", sizeof(pktHdr) + plen, txBuffer);
|
||||
}
|
||||
|
||||
int errcode = 0;
|
||||
common_hal_busio_uart_write(&adapter->hci_uart, txBuffer, sizeof(pktHdr) + plen, &errcode);
|
||||
if (errcode) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd_complete_opcode = 0xffff;
|
||||
cmd_complete_status = -1;
|
||||
|
||||
// Wait up to one second for a response.
|
||||
for (uint64_t start = supervisor_ticks_ms64();
|
||||
cmd_complete_opcode != opcode && supervisor_ticks_ms64() < (start + 5000);
|
||||
) {
|
||||
hci_poll();
|
||||
}
|
||||
|
||||
return cmd_complete_status;
|
||||
}
|
||||
|
||||
int hci_reset(void) {
|
||||
return hci_sendCommand(OGF_HOST_CTL, OCF_RESET, 0, NULL);
|
||||
}
|
||||
|
||||
int hci_readLocalVersion(uint8_t *hciVer, uint16_t *hciRev, uint8_t *lmpVer, uint16_t *manufacturer, uint16_t *lmpSubVer) {
|
||||
int result = hci_sendCommand(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION, 0, NULL);
|
||||
|
||||
if (result == 0) {
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t hciVer;
|
||||
uint16_t hciRev;
|
||||
uint8_t lmpVer;
|
||||
uint16_t manufacturer;
|
||||
uint16_t lmpSubVer;
|
||||
} HCILocalVersion;
|
||||
|
||||
HCILocalVersion *localVersion = (HCILocalVersion*)cmd_response;
|
||||
*hciVer = localVersion->hciVer;
|
||||
*hciRev = localVersion->hciRev;
|
||||
*lmpVer = localVersion->lmpVer;
|
||||
*manufacturer = localVersion->manufacturer;
|
||||
*lmpSubVer = localVersion->lmpSubVer;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int hci_readBdAddr(uint8_t addr[6]) {
|
||||
int result = hci_sendCommand(OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL);
|
||||
|
||||
if (result == 0) {
|
||||
memcpy(addr, cmd_response, 6);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int hci_readRssi(uint16_t handle) {
|
||||
int result = hci_sendCommand(OGF_STATUS_PARAM, OCF_READ_RSSI, sizeof(handle), &handle);
|
||||
int rssi = 127;
|
||||
|
||||
if (result == 0) {
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint16_t handle;
|
||||
int8_t rssi;
|
||||
} HCIReadRssi;
|
||||
|
||||
HCIReadRssi *readRssi = (HCIReadRssi*)cmd_response;
|
||||
if (readRssi->handle == handle) {
|
||||
rssi = readRssi->rssi;
|
||||
}
|
||||
}
|
||||
|
||||
return rssi;
|
||||
}
|
||||
|
||||
int hci_setEventMask(uint64_t eventMask) {
|
||||
return hci_sendCommand(OGF_HOST_CTL, OCF_SET_EVENT_MASK, sizeof(eventMask), &eventMask);
|
||||
}
|
||||
|
||||
int hci_readLeBufferSize(uint16_t *pktLen, uint8_t *maxPkt)
|
||||
{
|
||||
int result = hci_sendCommand(OGF_LE_CTL, OCF_LE_READ_BUFFER_SIZE, 0, NULL);
|
||||
|
||||
if (result == 0) {
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint16_t pktLen;
|
||||
uint8_t maxPkt;
|
||||
} HCILeBufferSize;
|
||||
|
||||
HCILeBufferSize *leBufferSize = (HCILeBufferSize*)cmd_response;
|
||||
*pktLen = leBufferSize->pktLen;
|
||||
*maxPkt = leBufferSize->maxPkt;
|
||||
|
||||
#ifndef __AVR__
|
||||
// FIX (needed?) ATT.setMaxMtu(pktLen - 9); // max pkt len - ACL header size
|
||||
#endif
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int hci_leSetRandomAddress(uint8_t addr[6])
|
||||
{
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_RANDOM_ADDRESS, 6, addr);
|
||||
}
|
||||
|
||||
int hci_leSetAdvertisingParameters(uint16_t minInterval, uint16_t maxInterval,
|
||||
uint8_t advType, uint8_t ownBdaddrType,
|
||||
uint8_t directBdaddrType, uint8_t directBdaddr[6],
|
||||
uint8_t chanMap,
|
||||
uint8_t filter)
|
||||
{
|
||||
struct __attribute__ ((packed)) HCILeAdvertisingParameters {
|
||||
uint16_t minInterval;
|
||||
uint16_t maxInterval;
|
||||
uint8_t advType;
|
||||
uint8_t ownBdaddrType;
|
||||
uint8_t directBdaddrType;
|
||||
uint8_t directBdaddr[6];
|
||||
uint8_t chanMap;
|
||||
uint8_t filter;
|
||||
} leAdvertisingParamters;
|
||||
|
||||
leAdvertisingParamters.minInterval = minInterval;
|
||||
leAdvertisingParamters.maxInterval = maxInterval;
|
||||
leAdvertisingParamters.advType = advType;
|
||||
leAdvertisingParamters.ownBdaddrType = ownBdaddrType;
|
||||
leAdvertisingParamters.directBdaddrType = directBdaddrType;
|
||||
memcpy(leAdvertisingParamters.directBdaddr, directBdaddr, 6);
|
||||
leAdvertisingParamters.chanMap = chanMap;
|
||||
leAdvertisingParamters.filter = filter;
|
||||
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_ADVERTISING_PARAMETERS, sizeof(leAdvertisingParamters), &leAdvertisingParamters);
|
||||
}
|
||||
|
||||
int hci_leSetAdvertisingData(uint8_t length, uint8_t data[])
|
||||
{
|
||||
struct __attribute__ ((packed)) HCILeAdvertisingData {
|
||||
uint8_t length;
|
||||
uint8_t data[31];
|
||||
} leAdvertisingData;
|
||||
|
||||
memset(&leAdvertisingData, 0, sizeof(leAdvertisingData));
|
||||
leAdvertisingData.length = length;
|
||||
memcpy(leAdvertisingData.data, data, length);
|
||||
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_ADVERTISING_DATA, sizeof(leAdvertisingData), &leAdvertisingData);
|
||||
}
|
||||
|
||||
int hci_leSetScanResponseData(uint8_t length, uint8_t data[])
|
||||
{
|
||||
struct __attribute__ ((packed)) HCILeScanResponseData {
|
||||
uint8_t length;
|
||||
uint8_t data[31];
|
||||
} leScanResponseData;
|
||||
|
||||
memset(&leScanResponseData, 0, sizeof(leScanResponseData));
|
||||
leScanResponseData.length = length;
|
||||
memcpy(leScanResponseData.data, data, length);
|
||||
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_RESPONSE_DATA, sizeof(leScanResponseData), &leScanResponseData);
|
||||
}
|
||||
|
||||
int hci_leSetAdvertiseEnable(uint8_t enable)
|
||||
{
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_ADVERTISE_ENABLE, sizeof(enable), &enable);
|
||||
}
|
||||
|
||||
int hci_leSetScanParameters(uint8_t type, uint16_t interval, uint16_t window,
|
||||
uint8_t ownBdaddrType, uint8_t filter)
|
||||
{
|
||||
struct __attribute__ ((packed)) HCILeSetScanParameters {
|
||||
uint8_t type;
|
||||
uint16_t interval;
|
||||
uint16_t window;
|
||||
uint8_t ownBdaddrType;
|
||||
uint8_t filter;
|
||||
} leScanParameters;
|
||||
|
||||
leScanParameters.type = type;
|
||||
leScanParameters.interval = interval;
|
||||
leScanParameters.window = window;
|
||||
leScanParameters.ownBdaddrType = ownBdaddrType;
|
||||
leScanParameters.filter = filter;
|
||||
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_PARAMETERS, sizeof(leScanParameters), &leScanParameters);
|
||||
}
|
||||
|
||||
int hci_leSetScanEnable(uint8_t enabled, uint8_t duplicates)
|
||||
{
|
||||
struct __attribute__ ((packed)) HCILeSetScanEnableData {
|
||||
uint8_t enabled;
|
||||
uint8_t duplicates;
|
||||
} leScanEnableData;
|
||||
|
||||
leScanEnableData.enabled = enabled;
|
||||
leScanEnableData.duplicates = duplicates;
|
||||
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE, sizeof(leScanEnableData), &leScanEnableData);
|
||||
}
|
||||
|
||||
int hci_leCreateConn(uint16_t interval, uint16_t window, uint8_t initiatorFilter,
|
||||
uint8_t peerBdaddrType, uint8_t peerBdaddr[6], uint8_t ownBdaddrType,
|
||||
uint16_t minInterval, uint16_t maxInterval, uint16_t latency,
|
||||
uint16_t supervisionTimeout, uint16_t minCeLength, uint16_t maxCeLength)
|
||||
{
|
||||
struct __attribute__ ((packed)) HCILeCreateConnData {
|
||||
uint16_t interval;
|
||||
uint16_t window;
|
||||
uint8_t initiatorFilter;
|
||||
uint8_t peerBdaddrType;
|
||||
uint8_t peerBdaddr[6];
|
||||
uint8_t ownBdaddrType;
|
||||
uint16_t minInterval;
|
||||
uint16_t maxInterval;
|
||||
uint16_t latency;
|
||||
uint16_t supervisionTimeout;
|
||||
uint16_t minCeLength;
|
||||
uint16_t maxCeLength;
|
||||
} leCreateConnData;
|
||||
|
||||
leCreateConnData.interval = interval;
|
||||
leCreateConnData.window = window;
|
||||
leCreateConnData.initiatorFilter = initiatorFilter;
|
||||
leCreateConnData.peerBdaddrType = peerBdaddrType;
|
||||
memcpy(leCreateConnData.peerBdaddr, peerBdaddr, sizeof(leCreateConnData.peerBdaddr));
|
||||
leCreateConnData.ownBdaddrType = ownBdaddrType;
|
||||
leCreateConnData.minInterval = minInterval;
|
||||
leCreateConnData.maxInterval = maxInterval;
|
||||
leCreateConnData.latency = latency;
|
||||
leCreateConnData.supervisionTimeout = supervisionTimeout;
|
||||
leCreateConnData.minCeLength = minCeLength;
|
||||
leCreateConnData.maxCeLength = maxCeLength;
|
||||
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_CREATE_CONN, sizeof(leCreateConnData), &leCreateConnData);
|
||||
}
|
||||
|
||||
int hci_leCancelConn()
|
||||
{
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_CANCEL_CONN, 0, NULL);
|
||||
}
|
||||
|
||||
int hci_leConnUpdate(uint16_t handle, uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t supervisionTimeout)
|
||||
{
|
||||
struct __attribute__ ((packed)) HCILeConnUpdateData {
|
||||
uint16_t handle;
|
||||
uint16_t minInterval;
|
||||
uint16_t maxInterval;
|
||||
uint16_t latency;
|
||||
uint16_t supervisionTimeout;
|
||||
uint16_t minCeLength;
|
||||
uint16_t maxCeLength;
|
||||
} leConnUpdateData;
|
||||
|
||||
leConnUpdateData.handle = handle;
|
||||
leConnUpdateData.minInterval = minInterval;
|
||||
leConnUpdateData.maxInterval = maxInterval;
|
||||
leConnUpdateData.latency = latency;
|
||||
leConnUpdateData.supervisionTimeout = supervisionTimeout;
|
||||
leConnUpdateData.minCeLength = 0x0004;
|
||||
leConnUpdateData.maxCeLength = 0x0006;
|
||||
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_CONN_UPDATE, sizeof(leConnUpdateData), &leConnUpdateData);
|
||||
}
|
||||
|
||||
int hci_sendAclPkt(uint16_t handle, uint8_t cid, uint8_t plen, void* data) {
|
||||
while (pending_pkt >= max_pkt) {
|
||||
hci_poll();
|
||||
}
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t pktType;
|
||||
uint16_t handle;
|
||||
uint16_t dlen;
|
||||
uint16_t plen;
|
||||
uint16_t cid;
|
||||
} HCIACLHdr;
|
||||
|
||||
HCIACLHdr aclHdr = { HCI_ACLDATA_PKT, handle, (uint8_t)(plen + 4), plen, cid };
|
||||
|
||||
uint8_t txBuffer[sizeof(aclHdr) + plen];
|
||||
memcpy(txBuffer, &aclHdr, sizeof(aclHdr));
|
||||
memcpy(&txBuffer[sizeof(aclHdr)], data, plen);
|
||||
|
||||
if (debug) {
|
||||
dumpPkt("HCI ACLDATA TX -> ", sizeof(aclHdr) + plen, txBuffer);
|
||||
}
|
||||
|
||||
pending_pkt++;
|
||||
|
||||
int errcode = 0;
|
||||
common_hal_busio_uart_write(&adapter->hci_uart, txBuffer, sizeof(aclHdr) + plen, &errcode);
|
||||
if (errcode) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hci_disconnect(uint16_t handle)
|
||||
{
|
||||
struct __attribute__ ((packed)) HCIDisconnectData {
|
||||
uint16_t handle;
|
||||
uint8_t reason;
|
||||
} disconnectData = { handle, HCI_OE_USER_ENDED_CONNECTION };
|
||||
|
||||
return hci_sendCommand(OGF_LINK_CTL, OCF_DISCONNECT, sizeof(disconnectData), &disconnectData);
|
||||
}
|
646
devices/ble_hci/common-hal/_bleio/hci_api.c
Normal file
646
devices/ble_hci/common-hal/_bleio/hci_api.c
Normal file
@ -0,0 +1,646 @@
|
||||
/*
|
||||
This file is part of the ArduinoBLE library.
|
||||
Copyright (c) 2018 Arduino SA. All rights reserved.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "hci_api.h"
|
||||
|
||||
// Zephyr include files to define HCI communication values and structs.
|
||||
#include "hci_include/hci.h"
|
||||
#include "hci_include/hci_err.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "supervisor/shared/tick.h"
|
||||
|
||||
// HCI H4 protocol packet types: first byte in the packet.
|
||||
#define H4_CMD 0x01
|
||||
#define H4_ACL 0x02
|
||||
#define H4_SCO 0x03
|
||||
#define H4_EVT 0x04
|
||||
|
||||
//FIX replace
|
||||
#define ATT_CID 0x0004
|
||||
|
||||
#define RX_BUFFER_SIZE (3 + 255)
|
||||
#define ACL_PKT_BUFFER_SIZE (255)
|
||||
|
||||
#define CTS_TIMEOUT_MSECS (1000)
|
||||
#define RESPONSE_TIMEOUT_MSECS (1000)
|
||||
|
||||
STATIC bleio_adapter_obj_t *adapter;
|
||||
|
||||
STATIC uint8_t rx_buffer[RX_BUFFER_SIZE];
|
||||
STATIC size_t rx_idx;
|
||||
|
||||
STATIC size_t num_command_packets_allowed;
|
||||
STATIC size_t max_pkt;
|
||||
STATIC size_t pending_pkt;
|
||||
|
||||
// Results from parsing a command response packet.
|
||||
STATIC bool cmd_response_received;
|
||||
STATIC uint16_t cmd_response_opcode;
|
||||
STATIC uint8_t cmd_response_status;
|
||||
STATIC size_t cmd_response_len;
|
||||
STATIC uint8_t* cmd_response_data;
|
||||
|
||||
//FIX STATIC uint8_t acl_pkt_buffer[ACL_PKT_BUFFER_SIZE];
|
||||
|
||||
STATIC bool debug = true;
|
||||
|
||||
// These are the headers of the full packets that are sent over the serial interface.
|
||||
// They all have a one-byte type-field at the front, one of the H4_xxx packet types.
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t pkt_type;
|
||||
uint16_t opcode;
|
||||
uint8_t param_len;
|
||||
} h4_hci_cmd_hdr_t;
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t pkt_type;
|
||||
uint16_t handle;
|
||||
uint16_t total_data_len;
|
||||
uint16_t acl_data_len;
|
||||
uint16_t cid;
|
||||
} h4_hci_acl_hdr_t;
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t pkt_type;
|
||||
uint8_t evt;
|
||||
uint8_t param_len;
|
||||
} h4_hci_evt_hdr_t;
|
||||
|
||||
|
||||
|
||||
STATIC void dump_pkt(const char* prefix, uint8_t pkt_len, uint8_t pkt_data[]) {
|
||||
if (debug) {
|
||||
mp_printf(&mp_plat_print, "%s", prefix);
|
||||
for (uint8_t i = 0; i < pkt_len; i++) {
|
||||
mp_printf(&mp_plat_print, "%02x", pkt_data[i]);
|
||||
}
|
||||
mp_printf(&mp_plat_print, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void process_acl_data_pkt(uint8_t pkt_len, uint8_t pkt_data[]) {
|
||||
//FIX pkt_len is +1 than before, because it includes the pkt_type.
|
||||
// h4_hci_acl_hdr_t *aclHdr = (h4_hci_acl_hdr_t*)pkt_data;
|
||||
|
||||
// uint16_t aclFlags = (aclHdr->handle & 0xf000) >> 12;
|
||||
|
||||
// if ((aclHdr->data_len - 4) != aclHdr->len) {
|
||||
// // packet is fragmented
|
||||
// if (aclFlags != 0x01) {
|
||||
// // copy into ACL buffer
|
||||
// memcpy(acl_pkt_buffer, &rx_buffer[1], sizeof(HCIACLHdr) + aclHdr->data_len - 4);
|
||||
// } else {
|
||||
// // copy next chunk into the buffer
|
||||
// HCIACLHdr* aclBufferHeader = (HCIACLHdr*)acl_pkt_buffer;
|
||||
|
||||
// memcpy(&acl_pkt_buffer[sizeof(HCIACLHdr) + aclBufferHeader->data_len - 4], &rx_buffer[1 + sizeof(aclHdr->handle) + sizeof(aclHdr->data_len)], aclHdr->data_len);
|
||||
|
||||
// aclBufferHeader->data_len += aclHdr->data_len;
|
||||
// aclHdr = aclBufferHeader;
|
||||
// }
|
||||
// }
|
||||
|
||||
// if ((aclHdr->data_len - 4) != aclHdr->len) {
|
||||
// // don't have the full packet yet
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (aclHdr->cid == ATT_CID) {
|
||||
// if (aclFlags == 0x01) {
|
||||
// // use buffered packet
|
||||
// ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &acl_pkt_buffer[sizeof(HCIACLHdr)]);
|
||||
// } else {
|
||||
// // use the rx buffer
|
||||
// ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &rx_buffer[1 + sizeof(HCIACLHdr)]);
|
||||
// }
|
||||
// } else if (aclHdr->cid == SIGNALING_CID) {
|
||||
// L2CAPSignaling.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &rx_buffer[1 + sizeof(HCIACLHdr)]);
|
||||
// } else {
|
||||
// struct __attribute__ ((packed)) {
|
||||
// uint8_t op;
|
||||
// uint8_t id;
|
||||
// uint16_t length;
|
||||
// uint16_t reason;
|
||||
// uint16_t localCid;
|
||||
// uint16_t remoteCid;
|
||||
// } l2capRejectCid= { 0x01, 0x00, 0x006, 0x0002, aclHdr->cid, 0x0000 };
|
||||
|
||||
// sendAclPkt(aclHdr->handle & 0x0fff, 0x0005, sizeof(l2capRejectCid), &l2capRejectCid);
|
||||
// }
|
||||
}
|
||||
|
||||
// Process number of completed packets. Reduce number of pending packets by reported
|
||||
// number of completed.
|
||||
STATIC void process_num_comp_pkts(uint16_t handle, uint16_t num_pkts) {
|
||||
if (num_pkts && pending_pkt > num_pkts) {
|
||||
pending_pkt -= num_pkts;
|
||||
} else {
|
||||
pending_pkt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC void process_evt_pkt(size_t pkt_len, uint8_t pkt[])
|
||||
{
|
||||
h4_hci_evt_hdr_t *evt_hdr = (h4_hci_evt_hdr_t*) pkt;
|
||||
// The data itself, after the header.
|
||||
uint8_t *evt_data = pkt + sizeof(h4_hci_evt_hdr_t);
|
||||
|
||||
switch (evt_hdr->evt) {
|
||||
case BT_HCI_EVT_DISCONN_COMPLETE: {
|
||||
struct bt_hci_evt_disconn_complete *disconn_complete = (struct bt_hci_evt_disconn_complete*) evt_data;
|
||||
(void) disconn_complete;
|
||||
//FIX
|
||||
// ATT.removeConnection(disconn_complete->handle, disconn_complete->reason);
|
||||
// L2CAPSignaling.removeConnection(disconn_complete->handle, disconn_complete->reason);
|
||||
hci_le_set_advertise_enable(0x01);
|
||||
break;
|
||||
}
|
||||
|
||||
case BT_HCI_EVT_CMD_COMPLETE: {
|
||||
|
||||
struct cmd_complete_with_status {
|
||||
struct bt_hci_evt_cmd_complete cmd_complete;
|
||||
struct bt_hci_evt_cc_status cc_status;
|
||||
} __packed;
|
||||
|
||||
struct cmd_complete_with_status *evt = (struct cmd_complete_with_status *) evt_data;
|
||||
|
||||
num_command_packets_allowed = evt->cmd_complete.ncmd;
|
||||
|
||||
cmd_response_received = true;
|
||||
cmd_response_opcode = evt->cmd_complete.opcode;
|
||||
cmd_response_status = evt->cc_status.status;
|
||||
// All the bytes following status.
|
||||
cmd_response_data = &evt_data[sizeof(struct cmd_complete_with_status)];
|
||||
cmd_response_len = evt_hdr->param_len - sizeof(struct cmd_complete_with_status);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case BT_HCI_EVT_CMD_STATUS: {
|
||||
struct bt_hci_evt_cmd_status *evt = (struct bt_hci_evt_cmd_status *) evt_data;
|
||||
|
||||
num_command_packets_allowed = evt->ncmd;
|
||||
|
||||
cmd_response_received = true;
|
||||
cmd_response_opcode = evt->opcode;
|
||||
cmd_response_status = evt->status;
|
||||
cmd_response_data = NULL;
|
||||
cmd_response_len = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case BT_HCI_EVT_NUM_COMPLETED_PACKETS: {
|
||||
struct bt_hci_evt_num_completed_packets *evt = (struct bt_hci_evt_num_completed_packets *) evt_data;
|
||||
|
||||
// Start at zero-th pair: (conn handle, num completed packets).
|
||||
struct bt_hci_handle_count *handle_and_count = &(evt->h[0]);
|
||||
for (uint8_t i = 0; i < evt->num_handles; i++) {
|
||||
process_num_comp_pkts(handle_and_count->handle, handle_and_count->count);
|
||||
handle_and_count++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BT_HCI_EVT_LE_META_EVENT: {
|
||||
struct bt_hci_evt_le_meta_event *meta_evt = (struct bt_hci_evt_le_meta_event *) evt_data;
|
||||
// Start of the encapsulated LE event.
|
||||
uint8_t *le_evt = evt_data + sizeof (struct bt_hci_evt_le_meta_event);
|
||||
|
||||
if (meta_evt->subevent == BT_HCI_EVT_LE_CONN_COMPLETE) {
|
||||
struct bt_hci_evt_le_conn_complete *le_conn_complete =
|
||||
(struct bt_hci_evt_le_conn_complete *) le_evt;
|
||||
|
||||
if (le_conn_complete->status == 0x00) {
|
||||
// ATT.addConnection(le_conn_complete->handle,
|
||||
// le_conn_complete->role,
|
||||
// le_conn_complete->peer_addr //FIX struct
|
||||
// le_conn_complete->interval,
|
||||
// le_conn_complete->latency,
|
||||
// le_conn_complete->supv_timeout
|
||||
// le_conn_complete->clock_accuracy);
|
||||
|
||||
// L2CAPSignaling.addConnection(le_conn_complete->handle,
|
||||
// le_conn_complete->role,
|
||||
// le_conn_complete->peer_addr, //FIX struct
|
||||
// le_conn_complete->interval,
|
||||
// le_conn_complete->latency,
|
||||
// le_conn_complete->supv_timeout,
|
||||
// le_conn_complete->clock_accuracy);
|
||||
}
|
||||
} else if (meta_evt->subevent == BT_HCI_EVT_LE_ADVERTISING_REPORT) {
|
||||
struct bt_hci_evt_le_advertising_info *le_advertising_info =
|
||||
(struct bt_hci_evt_le_advertising_info *) le_evt;
|
||||
if (le_advertising_info->evt_type == BT_HCI_ADV_DIRECT_IND) { //FIX handle kind of advertising
|
||||
// last byte is RSSI
|
||||
// GAP.handleLeAdvertisingReport(leAdvertisingReport->type,
|
||||
// leAdvertisingReport->peerBdaddrType,
|
||||
// leAdvertisingReport->peerBdaddr,
|
||||
// leAdvertisingReport->eirLength,
|
||||
// leAdvertisingReport->eirData,
|
||||
// rssi); //FIX, don't separate
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void hci_init(bleio_adapter_obj_t *adapter_in) {
|
||||
adapter = adapter_in;
|
||||
rx_idx = 0;
|
||||
pending_pkt = 0;
|
||||
}
|
||||
|
||||
hci_result_t hci_poll_for_incoming_pkt(void) {
|
||||
// Assert RTS low to say we're ready to read data.
|
||||
common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, false);
|
||||
|
||||
int errcode = 0;
|
||||
bool packet_is_complete = false;
|
||||
|
||||
// Read bytes until we run out, or accumulate a complete packet.
|
||||
while (common_hal_busio_uart_rx_characters_available(adapter->hci_uart)) {
|
||||
common_hal_busio_uart_read(adapter->hci_uart, rx_buffer + rx_idx, 1, &errcode);
|
||||
if (!errcode) {
|
||||
return HCI_READ_ERROR;
|
||||
}
|
||||
rx_idx++;
|
||||
|
||||
switch (rx_buffer[0]) {
|
||||
case H4_ACL:
|
||||
if (rx_idx > sizeof(h4_hci_acl_hdr_t) &&
|
||||
rx_idx >= sizeof(h4_hci_acl_hdr_t) + ((h4_hci_acl_hdr_t *) rx_buffer)->total_data_len) {
|
||||
packet_is_complete = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case H4_EVT:
|
||||
if (rx_idx > sizeof(h4_hci_evt_hdr_t) &&
|
||||
rx_idx >= sizeof(h4_hci_evt_hdr_t) + ((h4_hci_evt_hdr_t *) rx_buffer)->param_len) {
|
||||
packet_is_complete = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown or bad packet type. Start over.
|
||||
rx_idx = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!packet_is_complete) {
|
||||
return HCI_OK;
|
||||
}
|
||||
|
||||
// Stop incoming data while processing packet.
|
||||
common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true);
|
||||
size_t pkt_len = rx_idx;
|
||||
rx_idx = 0;
|
||||
|
||||
switch (rx_buffer[0]) {
|
||||
case H4_ACL:
|
||||
if (debug) {
|
||||
dump_pkt("HCI EVENT RX <- ", rx_idx, rx_buffer);
|
||||
}
|
||||
|
||||
process_acl_data_pkt(pkt_len, rx_buffer);
|
||||
break;
|
||||
|
||||
case H4_EVT:
|
||||
if (debug) {
|
||||
dump_pkt("HCI ACLDATA RX <- ", rx_idx, rx_buffer);
|
||||
}
|
||||
|
||||
process_evt_pkt(pkt_len, rx_buffer);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true);
|
||||
|
||||
return HCI_OK;
|
||||
}
|
||||
|
||||
|
||||
// Returns
|
||||
STATIC hci_result_t write_pkt(uint8_t *buffer, size_t len) {
|
||||
// Wait for CTS to go low before writing to HCI adapter.
|
||||
uint64_t start = supervisor_ticks_ms64();
|
||||
while (common_hal_digitalio_digitalinout_get_value(&adapter->cts_digitalinout)) {
|
||||
RUN_BACKGROUND_TASKS;
|
||||
if (supervisor_ticks_ms64() - start > CTS_TIMEOUT_MSECS) {
|
||||
return HCI_WRITE_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
int errcode = 0;
|
||||
common_hal_busio_uart_write(adapter->hci_uart, buffer, len, &errcode);
|
||||
if (errcode) {
|
||||
return HCI_WRITE_ERROR;
|
||||
}
|
||||
|
||||
return HCI_OK;
|
||||
}
|
||||
|
||||
STATIC hci_result_t send_command(uint16_t opcode, uint8_t params_len, void* params) {
|
||||
uint8_t tx_buffer[sizeof(h4_hci_cmd_hdr_t) + params_len];
|
||||
|
||||
// cmd header is at the beginning of tx_buffer
|
||||
h4_hci_cmd_hdr_t *cmd_hdr = (h4_hci_cmd_hdr_t *) tx_buffer;
|
||||
cmd_hdr->pkt_type = H4_CMD;
|
||||
cmd_hdr->opcode = opcode;
|
||||
cmd_hdr->param_len = params_len;
|
||||
|
||||
// Copy the params data into the space after the header.
|
||||
memcpy(&tx_buffer[sizeof(h4_hci_cmd_hdr_t)], params, params_len);
|
||||
|
||||
if (debug) {
|
||||
dump_pkt("HCI COMMAND TX -> ", sizeof(tx_buffer), tx_buffer);
|
||||
}
|
||||
|
||||
int result = write_pkt(tx_buffer, sizeof(h4_hci_cmd_hdr_t) + params_len);
|
||||
if (result != HCI_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
cmd_response_received = false;
|
||||
|
||||
// Wait for a response. Note that other packets may be received that are not
|
||||
// command responses.
|
||||
uint64_t start = supervisor_ticks_ms64();
|
||||
while (1) {
|
||||
result = hci_poll_for_incoming_pkt();
|
||||
if (result != HCI_OK) {
|
||||
// I/O error.
|
||||
return result;
|
||||
}
|
||||
|
||||
if (cmd_response_received && cmd_response_opcode == opcode) {
|
||||
// If this is definitely a response to the command that was sent,
|
||||
// return the status value, which will will be
|
||||
// BT_HCI_ERR_SUCCESS (0x00) if the command succeeded,
|
||||
// or a BT_HCI_ERR_x value (> 0x00) if there ws a problem.
|
||||
return cmd_response_status;
|
||||
}
|
||||
|
||||
if (supervisor_ticks_ms64() - start > RESPONSE_TIMEOUT_MSECS) {
|
||||
return HCI_READ_TIMEOUT;
|
||||
}
|
||||
RUN_BACKGROUND_TASKS;
|
||||
}
|
||||
|
||||
// No I/O error, but no response sent back in time.
|
||||
return HCI_NO_RESPONSE;
|
||||
}
|
||||
|
||||
//FIX remove unused
|
||||
STATIC int __attribute__((unused)) send_acl_pkt(uint16_t handle, uint8_t cid, void* data, uint8_t data_len) {
|
||||
int result;
|
||||
while (pending_pkt >= max_pkt) {
|
||||
result = hci_poll_for_incoming_pkt();
|
||||
if (result != HCI_OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// data_len does not include cid.
|
||||
const size_t cid_len = sizeof(((h4_hci_acl_hdr_t *)0)->cid);
|
||||
// buf_len is size of entire packet including header.
|
||||
const size_t buf_len = sizeof(h4_hci_acl_hdr_t) + cid_len + data_len;
|
||||
uint8_t tx_buffer[buf_len];
|
||||
|
||||
h4_hci_acl_hdr_t *acl_hdr = (h4_hci_acl_hdr_t *) tx_buffer;
|
||||
acl_hdr->pkt_type = H4_ACL;
|
||||
acl_hdr->handle = handle;
|
||||
acl_hdr->total_data_len = (uint8_t)(cid_len + data_len);
|
||||
acl_hdr->acl_data_len = (uint8_t) data_len;
|
||||
acl_hdr->cid = cid;
|
||||
|
||||
memcpy(&tx_buffer[sizeof(h4_hci_acl_hdr_t)], data, data_len);
|
||||
|
||||
if (debug) {
|
||||
dump_pkt("HCI ACLDATA TX -> ", buf_len, tx_buffer);
|
||||
}
|
||||
|
||||
pending_pkt++;
|
||||
|
||||
int errcode = 0;
|
||||
common_hal_busio_uart_write(adapter->hci_uart, tx_buffer, buf_len, &errcode);
|
||||
if (errcode) {
|
||||
return HCI_WRITE_ERROR;
|
||||
}
|
||||
|
||||
return HCI_OK;
|
||||
}
|
||||
|
||||
hci_result_t hci_reset(void) {
|
||||
return send_command(BT_HCI_OP_RESET, 0, NULL);
|
||||
}
|
||||
|
||||
hci_result_t hci_read_local_version(uint8_t *hci_version, uint16_t *hci_revision, uint8_t *lmp_version, uint16_t *manufacturer, uint16_t *lmp_subversion) {
|
||||
hci_result_t result = send_command(BT_HCI_OP_READ_LOCAL_VERSION_INFO, 0, NULL);
|
||||
if (result == HCI_OK) {
|
||||
struct bt_hci_rp_read_local_version_info *response =
|
||||
(struct bt_hci_rp_read_local_version_info *) cmd_response_data;
|
||||
*hci_version = response->hci_version;
|
||||
*hci_revision = response->hci_revision;
|
||||
*lmp_version = response->lmp_version;
|
||||
*manufacturer = response->manufacturer;
|
||||
*lmp_subversion = response->lmp_subversion;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
hci_result_t hci_read_bd_addr(bt_addr_t *addr) {
|
||||
int result = send_command(BT_HCI_OP_READ_BD_ADDR, 0, NULL);
|
||||
if (result == HCI_OK) {
|
||||
struct bt_hci_rp_read_bd_addr *response = (struct bt_hci_rp_read_bd_addr *) cmd_response_data;
|
||||
memcpy(addr->val, response->bdaddr.val, sizeof(bt_addr_t));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
hci_result_t hci_read_rssi(uint16_t handle, int *rssi) {
|
||||
int result = send_command(BT_HCI_OP_READ_RSSI, sizeof(handle), &handle);
|
||||
if (result == HCI_OK) {
|
||||
struct bt_hci_rp_read_rssi *response = (struct bt_hci_rp_read_rssi *) cmd_response_data;
|
||||
if (response->handle != handle) {
|
||||
// Handle doesn't match.
|
||||
return HCI_NO_RESPONSE;
|
||||
}
|
||||
|
||||
*rssi = response->rssi;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
hci_result_t hci_set_evt_mask(uint64_t event_mask) {
|
||||
return send_command(BT_HCI_OP_SET_EVENT_MASK, sizeof(event_mask), &event_mask);
|
||||
}
|
||||
|
||||
hci_result_t hci_read_le_buffer_size(uint16_t *le_max_len, uint8_t *le_max_num) {
|
||||
int result = send_command(BT_HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
|
||||
if (result == HCI_OK) {
|
||||
struct bt_hci_rp_le_read_buffer_size *response =
|
||||
(struct bt_hci_rp_le_read_buffer_size *) cmd_response_data;
|
||||
*le_max_len = response->le_max_len;
|
||||
*le_max_num = response->le_max_num;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_random_address(uint8_t addr[6]) {
|
||||
return send_command(BT_HCI_OP_LE_SET_RANDOM_ADDRESS, 6, addr);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_advertising_parameters(uint16_t min_interval, uint16_t max_interval, uint8_t type, uint8_t own_addr_type, bt_addr_le_t *direct_addr, uint8_t channel_map, uint8_t filter_policy) {
|
||||
struct bt_hci_cp_le_set_adv_param params = {
|
||||
.min_interval = min_interval,
|
||||
.max_interval = max_interval,
|
||||
.type = type,
|
||||
.own_addr_type = own_addr_type,
|
||||
// .direct_addr set below.
|
||||
.channel_map = channel_map,
|
||||
.filter_policy = filter_policy,
|
||||
};
|
||||
params.direct_addr.type = direct_addr->type;
|
||||
memcpy(params.direct_addr.a.val, direct_addr->a.val, sizeof(params.direct_addr.a.val));
|
||||
|
||||
return send_command(BT_HCI_OP_LE_SET_ADV_PARAM, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_read_maximum_advertising_data_length(int *max_adv_data_len) {
|
||||
int result = send_command(BT_HCI_OP_LE_READ_MAX_ADV_DATA_LEN, 0, NULL);
|
||||
if (result == HCI_OK) {
|
||||
struct bt_hci_rp_le_read_max_adv_data_len *response =
|
||||
(struct bt_hci_rp_le_read_max_adv_data_len *) cmd_response_data;
|
||||
if (response->status == BT_HCI_ERR_SUCCESS) {
|
||||
*max_adv_data_len = response->max_adv_data_len;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_advertising_data(uint8_t len, uint8_t data[]) {
|
||||
struct bt_hci_cp_le_set_adv_data params = {
|
||||
// Zero out unused data bytes.
|
||||
.data = { 0 },
|
||||
};
|
||||
|
||||
params.len = len;
|
||||
memcpy(params.data, data, len);
|
||||
|
||||
// All data bytes are sent even if some are unused.
|
||||
return send_command(BT_HCI_OP_LE_SET_ADV_DATA, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_scan_response_data(uint8_t len, uint8_t data[]) {
|
||||
struct bt_hci_cp_le_set_scan_rsp_data params = {
|
||||
// Zero out unused data bytes.
|
||||
.data = { 0 },
|
||||
};
|
||||
params.len = len;
|
||||
memcpy(params.data, data, len);
|
||||
|
||||
// All data bytes are sent even if some are unused.
|
||||
return send_command(BT_HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_advertise_enable(uint8_t enable) {
|
||||
return send_command(BT_HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_scan_parameters(uint8_t scan_type, uint16_t interval, uint16_t window, uint8_t addr_type, uint8_t filter_policy) {
|
||||
struct bt_hci_cp_le_set_scan_param params = {
|
||||
.scan_type = scan_type,
|
||||
.interval = interval,
|
||||
.window = window,
|
||||
.addr_type = addr_type,
|
||||
.filter_policy = filter_policy,
|
||||
};
|
||||
|
||||
return send_command(BT_HCI_OP_LE_SET_SCAN_PARAM, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_set_scan_enable(uint8_t enable, uint8_t filter_dup) {
|
||||
struct bt_hci_cp_le_set_scan_enable params = {
|
||||
.enable = enable,
|
||||
.filter_dup = filter_dup,
|
||||
};
|
||||
|
||||
return send_command(BT_HCI_OP_LE_SET_SCAN_ENABLE, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_create_conn(uint16_t scan_interval, uint16_t scan_window, uint8_t filter_policy, bt_addr_le_t *peer_addr, uint8_t own_addr_type, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout, uint16_t min_ce_len, uint16_t max_ce_len) {
|
||||
struct bt_hci_cp_le_create_conn params = {
|
||||
.scan_interval = scan_interval,
|
||||
.scan_window = scan_window,
|
||||
.filter_policy = filter_policy,
|
||||
// .peer_addr is set below
|
||||
.own_addr_type = own_addr_type,
|
||||
.conn_interval_min = conn_interval_min,
|
||||
.conn_interval_max = conn_interval_max,
|
||||
.conn_latency = conn_latency,
|
||||
.supervision_timeout = supervision_timeout,
|
||||
.min_ce_len = min_ce_len,
|
||||
.max_ce_len = max_ce_len,
|
||||
};
|
||||
params.peer_addr.type = peer_addr->type;
|
||||
memcpy(params.peer_addr.a.val, peer_addr->a.val, sizeof(params.peer_addr.a.val));
|
||||
|
||||
return send_command(BT_HCI_OP_LE_CREATE_CONN, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_cancel_conn(void) {
|
||||
return send_command(BT_HCI_OP_CONNECT_CANCEL, 0, NULL);
|
||||
}
|
||||
|
||||
hci_result_t hci_le_conn_update(uint16_t handle, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout) {
|
||||
struct hci_cp_le_conn_update params = {
|
||||
.handle = handle,
|
||||
.conn_interval_min = conn_interval_min,
|
||||
.conn_interval_max = conn_interval_max,
|
||||
.conn_latency = conn_latency,
|
||||
.supervision_timeout = supervision_timeout,
|
||||
.min_ce_len = 4,
|
||||
.max_ce_len = 6,
|
||||
};
|
||||
|
||||
return send_command(BT_HCI_OP_LE_CONN_UPDATE, sizeof(params), ¶ms);
|
||||
}
|
||||
|
||||
hci_result_t hci_disconnect(uint16_t handle) {
|
||||
struct bt_hci_cp_disconnect params = {
|
||||
.handle = handle,
|
||||
.reason = BT_HCI_ERR_REMOTE_USER_TERM_CONN,
|
||||
};
|
||||
|
||||
return send_command(BT_HCI_OP_DISCONNECT, sizeof(params), ¶ms);
|
||||
}
|
69
devices/ble_hci/common-hal/_bleio/hci_api.h
Normal file
69
devices/ble_hci/common-hal/_bleio/hci_api.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
This file is part of the ArduinoBLE library.
|
||||
Copyright (c) 2018 Arduino SA. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H
|
||||
#define MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common-hal/_bleio/hci_include/hci.h"
|
||||
|
||||
#include "common-hal/_bleio/Adapter.h"
|
||||
|
||||
// An hci_result_t is one of the HCI_x values below,
|
||||
// or is it > 0 and is an HCI command status value (see hci_include/hci_err.h)
|
||||
typedef int hci_result_t;
|
||||
#define HCI_OK (0)
|
||||
#define HCI_NO_RESPONSE (-1)
|
||||
#define HCI_ERR_RESPONSE (-2)
|
||||
#define HCI_READ_TIMEOUT (-3)
|
||||
#define HCI_WRITE_TIMEOUT (-4)
|
||||
#define HCI_READ_ERROR (-5)
|
||||
#define HCI_WRITE_ERROR (-6)
|
||||
|
||||
void hci_init(bleio_adapter_obj_t *adapter_in);
|
||||
|
||||
hci_result_t hci_disconnect(uint16_t handle);
|
||||
|
||||
hci_result_t hci_le_cancel_conn(void);
|
||||
hci_result_t hci_le_conn_update(uint16_t handle, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout);
|
||||
hci_result_t hci_le_create_conn(uint16_t scan_interval, uint16_t scan_window, uint8_t filter_policy, bt_addr_le_t *peer_addr, uint8_t own_addr_type, uint16_t conn_interval_min, uint16_t conn_interval_max, uint16_t conn_latency, uint16_t supervision_timeout, uint16_t min_ce_len, uint16_t max_ce_len);
|
||||
|
||||
hci_result_t hci_le_read_maximum_advertising_data_length(int *max_adv_data_len);
|
||||
|
||||
hci_result_t hci_le_set_advertise_enable(uint8_t enable);
|
||||
hci_result_t hci_le_set_advertising_data(uint8_t length, uint8_t data[]);
|
||||
hci_result_t hci_le_set_advertising_parameters(uint16_t min_interval, uint16_t max_interval, uint8_t type, uint8_t own_addr_type, bt_addr_le_t *direct_addr, uint8_t channel_map, uint8_t filter_policy);
|
||||
hci_result_t hci_le_set_random_address(uint8_t addr[6]);
|
||||
hci_result_t hci_le_set_scan_enable(uint8_t enable, uint8_t filter_dup);
|
||||
hci_result_t hci_le_set_scan_parameters(uint8_t scan_type, uint16_t interval, uint16_t window, uint8_t addr_type, uint8_t filter_policy);
|
||||
hci_result_t hci_le_set_scan_response_data(uint8_t length, uint8_t data[]);
|
||||
|
||||
hci_result_t hci_poll_for_incoming_pkt(void);
|
||||
|
||||
hci_result_t hci_read_bd_addr(bt_addr_t *addr);
|
||||
hci_result_t hci_read_le_buffer_size(uint16_t *le_max_len, uint8_t *le_max_num);
|
||||
hci_result_t hci_read_local_version(uint8_t *hci_version, uint16_t *hci_revision, uint8_t *lmp_version, uint16_t *manufacturer, uint16_t *lmp_subversion);
|
||||
hci_result_t hci_read_rssi(uint16_t handle, int *rssi);
|
||||
|
||||
hci_result_t hci_reset(void);
|
||||
|
||||
hci_result_t hci_set_evt_mask(uint64_t event_mask);
|
||||
|
||||
#endif // MICROPY_INCLUDED_DEVICES_BLE_HCI_COMMON_HAL_BLEIO_HCI_H
|
1775
devices/ble_hci/common-hal/_bleio/hci_include/#hci.h#
Normal file
1775
devices/ble_hci/common-hal/_bleio/hci_include/#hci.h#
Normal file
File diff suppressed because it is too large
Load Diff
2
devices/ble_hci/common-hal/_bleio/hci_include/README.md
Normal file
2
devices/ble_hci/common-hal/_bleio/hci_include/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
The HCI-related include files here are copied from the Zephyr project:
|
||||
https://github.com/zephyrproject-rtos/zephyr/tree/master/include/bluetooth
|
100
devices/ble_hci/common-hal/_bleio/hci_include/addr.h
Normal file
100
devices/ble_hci/common-hal/_bleio/hci_include/addr.h
Normal file
@ -0,0 +1,100 @@
|
||||
// CircuitPython: Adapted from Zephyer include files.
|
||||
/** @file
|
||||
* @brief Bluetooth device address definitions and utilities.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
* Copyright 2020 Dan Halbert for Adafruit Industries
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* @brief Bluetooth device address definitions and utilities.
|
||||
* @defgroup bt_addr Device Address
|
||||
* @ingroup bluetooth
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define BT_ADDR_LE_PUBLIC 0x00
|
||||
#define BT_ADDR_LE_RANDOM 0x01
|
||||
#define BT_ADDR_LE_PUBLIC_ID 0x02
|
||||
#define BT_ADDR_LE_RANDOM_ID 0x03
|
||||
|
||||
/** Bluetooth Device Address */
|
||||
typedef struct {
|
||||
uint8_t val[6];
|
||||
} bt_addr_t;
|
||||
|
||||
/** Bluetooth LE Device Address */
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
bt_addr_t a;
|
||||
} bt_addr_le_t;
|
||||
|
||||
#define BT_ADDR_ANY ((bt_addr_t[]) { { { 0, 0, 0, 0, 0, 0 } } })
|
||||
#define BT_ADDR_NONE ((bt_addr_t[]) { { \
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } })
|
||||
#define BT_ADDR_LE_ANY ((bt_addr_le_t[]) { { 0, { { 0, 0, 0, 0, 0, 0 } } } })
|
||||
#define BT_ADDR_LE_NONE ((bt_addr_le_t[]) { { 0, \
|
||||
{ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } } })
|
||||
|
||||
static inline int bt_addr_cmp(const bt_addr_t *a, const bt_addr_t *b)
|
||||
{
|
||||
return memcmp(a, b, sizeof(*a));
|
||||
}
|
||||
|
||||
static inline int bt_addr_le_cmp(const bt_addr_le_t *a, const bt_addr_le_t *b)
|
||||
{
|
||||
return memcmp(a, b, sizeof(*a));
|
||||
}
|
||||
|
||||
static inline void bt_addr_copy(bt_addr_t *dst, const bt_addr_t *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void bt_addr_le_copy(bt_addr_le_t *dst, const bt_addr_le_t *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
#define BT_ADDR_IS_RPA(a) (((a)->val[5] & 0xc0) == 0x40)
|
||||
#define BT_ADDR_IS_NRPA(a) (((a)->val[5] & 0xc0) == 0x00)
|
||||
#define BT_ADDR_IS_STATIC(a) (((a)->val[5] & 0xc0) == 0xc0)
|
||||
|
||||
#define BT_ADDR_SET_RPA(a) ((a)->val[5] = (((a)->val[5] & 0x3f) | 0x40))
|
||||
#define BT_ADDR_SET_NRPA(a) ((a)->val[5] &= 0x3f)
|
||||
#define BT_ADDR_SET_STATIC(a) ((a)->val[5] |= 0xc0)
|
||||
|
||||
int bt_addr_le_create_nrpa(bt_addr_le_t *addr);
|
||||
int bt_addr_le_create_static(bt_addr_le_t *addr);
|
||||
|
||||
static inline bool bt_addr_le_is_rpa(const bt_addr_le_t *addr)
|
||||
{
|
||||
if (addr->type != BT_ADDR_LE_RANDOM) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return BT_ADDR_IS_RPA(&addr->a);
|
||||
}
|
||||
|
||||
static inline bool bt_addr_le_is_identity(const bt_addr_le_t *addr)
|
||||
{
|
||||
if (addr->type == BT_ADDR_LE_PUBLIC) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return BT_ADDR_IS_STATIC(&addr->a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_ADDR_H_ */
|
1764
devices/ble_hci/common-hal/_bleio/hci_include/hci.h
Normal file
1764
devices/ble_hci/common-hal/_bleio/hci_include/hci.h
Normal file
File diff suppressed because it is too large
Load Diff
92
devices/ble_hci/common-hal/_bleio/hci_include/hci_err.h
Normal file
92
devices/ble_hci/common-hal/_bleio/hci_include/hci_err.h
Normal file
@ -0,0 +1,92 @@
|
||||
/** @file
|
||||
* @brief Bluetooth Host Control Interface status codes.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_STATUS_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_STATUS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** HCI Error Codes, BT Core Spec v5.2 [Vol 1, Part F]. */
|
||||
#define BT_HCI_ERR_SUCCESS 0x00
|
||||
#define BT_HCI_ERR_UNKNOWN_CMD 0x01
|
||||
#define BT_HCI_ERR_UNKNOWN_CONN_ID 0x02
|
||||
#define BT_HCI_ERR_HW_FAILURE 0x03
|
||||
#define BT_HCI_ERR_PAGE_TIMEOUT 0x04
|
||||
#define BT_HCI_ERR_AUTH_FAIL 0x05
|
||||
#define BT_HCI_ERR_PIN_OR_KEY_MISSING 0x06
|
||||
#define BT_HCI_ERR_MEM_CAPACITY_EXCEEDED 0x07
|
||||
#define BT_HCI_ERR_CONN_TIMEOUT 0x08
|
||||
#define BT_HCI_ERR_CONN_LIMIT_EXCEEDED 0x09
|
||||
#define BT_HCI_ERR_SYNC_CONN_LIMIT_EXCEEDED 0x0a
|
||||
#define BT_HCI_ERR_CONN_ALREADY_EXISTS 0x0b
|
||||
#define BT_HCI_ERR_CMD_DISALLOWED 0x0c
|
||||
#define BT_HCI_ERR_INSUFFICIENT_RESOURCES 0x0d
|
||||
#define BT_HCI_ERR_INSUFFICIENT_SECURITY 0x0e
|
||||
#define BT_HCI_ERR_BD_ADDR_UNACCEPTABLE 0x0f
|
||||
#define BT_HCI_ERR_CONN_ACCEPT_TIMEOUT 0x10
|
||||
#define BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL 0x11
|
||||
#define BT_HCI_ERR_INVALID_PARAM 0x12
|
||||
#define BT_HCI_ERR_REMOTE_USER_TERM_CONN 0x13
|
||||
#define BT_HCI_ERR_REMOTE_LOW_RESOURCES 0x14
|
||||
#define BT_HCI_ERR_REMOTE_POWER_OFF 0x15
|
||||
#define BT_HCI_ERR_LOCALHOST_TERM_CONN 0x16
|
||||
#define BT_HCI_ERR_REPEATED_ATTEMPTS 0x17
|
||||
#define BT_HCI_ERR_PAIRING_NOT_ALLOWED 0x18
|
||||
#define BT_HCI_ERR_UNKNOWN_LMP_PDU 0x19
|
||||
#define BT_HCI_ERR_UNSUPP_REMOTE_FEATURE 0x1a
|
||||
#define BT_HCI_ERR_SCO_OFFSET_REJECTED 0x1b
|
||||
#define BT_HCI_ERR_SCO_INTERVAL_REJECTED 0x1c
|
||||
#define BT_HCI_ERR_SCO_AIR_MODE_REJECTED 0x1d
|
||||
#define BT_HCI_ERR_INVALID_LL_PARAM 0x1e
|
||||
#define BT_HCI_ERR_UNSPECIFIED 0x1f
|
||||
#define BT_HCI_ERR_UNSUPP_LL_PARAM_VAL 0x20
|
||||
#define BT_HCI_ERR_ROLE_CHANGE_NOT_ALLOWED 0x21
|
||||
#define BT_HCI_ERR_LL_RESP_TIMEOUT 0x22
|
||||
#define BT_HCI_ERR_LL_PROC_COLLISION 0x23
|
||||
#define BT_HCI_ERR_LMP_PDU_NOT_ALLOWED 0x24
|
||||
#define BT_HCI_ERR_ENC_MODE_NOT_ACCEPTABLE 0x25
|
||||
#define BT_HCI_ERR_LINK_KEY_CANNOT_BE_CHANGED 0x26
|
||||
#define BT_HCI_ERR_REQUESTED_QOS_NOT_SUPPORTED 0x27
|
||||
#define BT_HCI_ERR_INSTANT_PASSED 0x28
|
||||
#define BT_HCI_ERR_PAIRING_NOT_SUPPORTED 0x29
|
||||
#define BT_HCI_ERR_DIFF_TRANS_COLLISION 0x2a
|
||||
#define BT_HCI_ERR_QOS_UNACCEPTABLE_PARAM 0x2c
|
||||
#define BT_HCI_ERR_QOS_REJECTED 0x2d
|
||||
#define BT_HCI_ERR_CHAN_ASSESS_NOT_SUPPORTED 0x2e
|
||||
#define BT_HCI_ERR_INSUFF_SECURITY 0x2f
|
||||
#define BT_HCI_ERR_PARAM_OUT_OF_MANDATORY_RANGE 0x30
|
||||
#define BT_HCI_ERR_ROLE_SWITCH_PENDING 0x32
|
||||
#define BT_HCI_ERR_RESERVED_SLOT_VIOLATION 0x34
|
||||
#define BT_HCI_ERR_ROLE_SWITCH_FAILED 0x35
|
||||
#define BT_HCI_ERR_EXT_INQ_RESP_TOO_LARGE 0x36
|
||||
#define BT_HCI_ERR_SIMPLE_PAIR_NOT_SUPP_BY_HOST 0x37
|
||||
#define BT_HCI_ERR_HOST_BUSY_PAIRING 0x38
|
||||
#define BT_HCI_ERR_CONN_REJECTED_DUE_TO_NO_CHAN 0x39
|
||||
#define BT_HCI_ERR_CONTROLLER_BUSY 0x3a
|
||||
#define BT_HCI_ERR_UNACCEPT_CONN_PARAM 0x3b
|
||||
#define BT_HCI_ERR_ADV_TIMEOUT 0x3c
|
||||
#define BT_HCI_ERR_TERM_DUE_TO_MIC_FAIL 0x3d
|
||||
#define BT_HCI_ERR_CONN_FAIL_TO_ESTAB 0x3e
|
||||
#define BT_HCI_ERR_MAC_CONN_FAILED 0x3f
|
||||
#define BT_HCI_ERR_CLOCK_ADJUST_REJECTED 0x40
|
||||
#define BT_HCI_ERR_SUBMAP_NOT_DEFINED 0x41
|
||||
#define BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER 0x42
|
||||
#define BT_HCI_ERR_LIMIT_REACHED 0x43
|
||||
#define BT_HCI_ERR_OP_CANCELLED_BY_HOST 0x44
|
||||
#define BT_HCI_ERR_PACKET_TOO_LONG 0x45
|
||||
|
||||
#define BT_HCI_ERR_AUTHENTICATION_FAIL __DEPRECATED_MACRO BT_HCI_ERR_AUTH_FAIL
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_STATUS_H_ */
|
152
devices/ble_hci/common-hal/_bleio/hci_include/hci_raw.h
Normal file
152
devices/ble_hci/common-hal/_bleio/hci_include/hci_raw.h
Normal file
@ -0,0 +1,152 @@
|
||||
/** @file
|
||||
* @brief Bluetooth HCI RAW channel handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_RAW_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_RAW_H_
|
||||
|
||||
/**
|
||||
* @brief HCI RAW channel
|
||||
* @defgroup hci_raw HCI RAW channel
|
||||
* @ingroup bluetooth
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_TX_BUFFER_SIZE)
|
||||
#define BT_L2CAP_MTU (CONFIG_BT_CTLR_TX_BUFFER_SIZE - BT_L2CAP_HDR_SIZE)
|
||||
#else
|
||||
#define BT_L2CAP_MTU 65 /* 64-byte public key + opcode */
|
||||
#endif /* CONFIG_BT_CTLR */
|
||||
|
||||
/** Data size needed for ACL buffers */
|
||||
#define BT_BUF_ACL_SIZE BT_L2CAP_BUF_SIZE(BT_L2CAP_MTU)
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_TX_BUFFERS)
|
||||
#define BT_HCI_ACL_COUNT CONFIG_BT_CTLR_TX_BUFFERS
|
||||
#else
|
||||
#define BT_HCI_ACL_COUNT 6
|
||||
#endif
|
||||
|
||||
#define BT_BUF_TX_SIZE MAX(BT_BUF_RX_SIZE, BT_BUF_ACL_SIZE)
|
||||
|
||||
/** @brief Send packet to the Bluetooth controller
|
||||
*
|
||||
* Send packet to the Bluetooth controller. Caller needs to
|
||||
* implement netbuf pool.
|
||||
*
|
||||
* @param buf netbuf packet to be send
|
||||
*
|
||||
* @return Zero on success or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_send(struct net_buf *buf);
|
||||
|
||||
enum {
|
||||
/** Passthrough mode
|
||||
*
|
||||
* While in this mode the buffers are passed as is between the stack
|
||||
* and the driver.
|
||||
*/
|
||||
BT_HCI_RAW_MODE_PASSTHROUGH = 0x00,
|
||||
|
||||
/** H:4 mode
|
||||
*
|
||||
* While in this mode H:4 headers will added into the buffers
|
||||
* according to the buffer type when coming from the stack and will be
|
||||
* removed and used to set the buffer type.
|
||||
*/
|
||||
BT_HCI_RAW_MODE_H4 = 0x01,
|
||||
};
|
||||
|
||||
/** @brief Set Bluetooth RAW channel mode
|
||||
*
|
||||
* Set access mode of Bluetooth RAW channel.
|
||||
*
|
||||
* @param mode Access mode.
|
||||
*
|
||||
* @return Zero on success or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_hci_raw_set_mode(uint8_t mode);
|
||||
|
||||
/** @brief Get Bluetooth RAW channel mode
|
||||
*
|
||||
* Get access mode of Bluetooth RAW channel.
|
||||
*
|
||||
* @return Access mode.
|
||||
*/
|
||||
uint8_t bt_hci_raw_get_mode(void);
|
||||
|
||||
#define BT_HCI_ERR_EXT_HANDLED 0xff
|
||||
|
||||
/** Helper macro to define a command extension
|
||||
*
|
||||
* @param _op Opcode of the command.
|
||||
* @param _min_len Minimal length of the command.
|
||||
* @param _func Handler function to be called.
|
||||
*/
|
||||
#define BT_HCI_RAW_CMD_EXT(_op, _min_len, _func) \
|
||||
{ \
|
||||
.op = _op, \
|
||||
.min_len = _min_len, \
|
||||
.func = _func, \
|
||||
}
|
||||
|
||||
struct bt_hci_raw_cmd_ext {
|
||||
/** Opcode of the command */
|
||||
uint16_t op;
|
||||
|
||||
/** Minimal length of the command */
|
||||
size_t min_len;
|
||||
|
||||
/** Handler function.
|
||||
*
|
||||
* Handler function to be called when a command is intercepted.
|
||||
*
|
||||
* @param buf Buffer containing the command.
|
||||
*
|
||||
* @return HCI Status code or BT_HCI_ERR_EXT_HANDLED if command has
|
||||
* been handled already and a response has been sent as oppose to
|
||||
* BT_HCI_ERR_SUCCESS which just indicates that the command can be
|
||||
* sent to the controller to be processed.
|
||||
*/
|
||||
uint8_t (*func)(struct net_buf *buf);
|
||||
};
|
||||
|
||||
/** @brief Register Bluetooth RAW command extension table
|
||||
*
|
||||
* Register Bluetooth RAW channel command extension table, opcodes in this
|
||||
* table are intercepted to sent to the handler function.
|
||||
*
|
||||
* @param cmds Pointer to the command extension table.
|
||||
* @param size Size of the command extension table.
|
||||
*/
|
||||
void bt_hci_raw_cmd_ext_register(struct bt_hci_raw_cmd_ext *cmds, size_t size);
|
||||
|
||||
/** @brief Enable Bluetooth RAW channel:
|
||||
*
|
||||
* Enable Bluetooth RAW HCI channel.
|
||||
*
|
||||
* @param rx_queue netbuf queue where HCI packets received from the Bluetooth
|
||||
* controller are to be queued. The queue is defined in the caller while
|
||||
* the available buffers pools are handled in the stack.
|
||||
*
|
||||
* @return Zero on success or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_enable_raw(struct k_fifo *rx_queue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_RAW_H_ */
|
379
devices/ble_hci/common-hal/_bleio/hci_include/hci_vs.h
Normal file
379
devices/ble_hci/common-hal/_bleio/hci_include/hci_vs.h
Normal file
@ -0,0 +1,379 @@
|
||||
/* hci_vs.h - Bluetooth Host Control Interface Vendor Specific definitions */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017-2018 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2015-2016 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_HCI_VS_H_
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_HCI_VS_H_
|
||||
|
||||
#include <bluetooth/hci.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BT_VS_CMD_BIT_VERSION 0
|
||||
#define BT_VS_CMD_BIT_SUP_CMD 1
|
||||
#define BT_VS_CMD_BIT_SUP_FEAT 2
|
||||
#define BT_VS_CMD_BIT_SET_EVT_MASK 3
|
||||
#define BT_VS_CMD_BIT_RESET 4
|
||||
#define BT_VS_CMD_BIT_WRITE_BDADDR 5
|
||||
#define BT_VS_CMD_BIT_SET_TRACE_ENABLE 6
|
||||
#define BT_VS_CMD_BIT_READ_BUILD_INFO 7
|
||||
#define BT_VS_CMD_BIT_READ_STATIC_ADDRS 8
|
||||
#define BT_VS_CMD_BIT_READ_KEY_ROOTS 9
|
||||
#define BT_VS_CMD_BIT_READ_CHIP_TEMP 10
|
||||
#define BT_VS_CMD_BIT_READ_HOST_STACK_CMD 11
|
||||
#define BT_VS_CMD_BIT_SET_SCAN_REP_ENABLE 12
|
||||
#define BT_VS_CMD_BIT_WRITE_TX_POWER 13
|
||||
#define BT_VS_CMD_BIT_READ_TX_POWER 14
|
||||
|
||||
#define BT_VS_CMD_SUP_FEAT(cmd) BT_LE_FEAT_TEST(cmd, \
|
||||
BT_VS_CMD_BIT_SUP_FEAT)
|
||||
#define BT_VS_CMD_READ_STATIC_ADDRS(cmd) BT_LE_FEAT_TEST(cmd, \
|
||||
BT_VS_CMD_BIT_READ_STATIC_ADDRS)
|
||||
#define BT_VS_CMD_READ_KEY_ROOTS(cmd) BT_LE_FEAT_TEST(cmd, \
|
||||
BT_VS_CMD_BIT_READ_KEY_ROOTS)
|
||||
|
||||
#define BT_HCI_VS_HW_PLAT_INTEL 0x0001
|
||||
#define BT_HCI_VS_HW_PLAT_NORDIC 0x0002
|
||||
#define BT_HCI_VS_HW_PLAT_NXP 0x0003
|
||||
|
||||
#define BT_HCI_VS_HW_VAR_NORDIC_NRF51X 0x0001
|
||||
#define BT_HCI_VS_HW_VAR_NORDIC_NRF52X 0x0002
|
||||
#define BT_HCI_VS_HW_VAR_NORDIC_NRF53X 0x0003
|
||||
|
||||
#define BT_HCI_VS_FW_VAR_STANDARD_CTLR 0x0001
|
||||
#define BT_HCI_VS_FW_VAR_VS_CTLR 0x0002
|
||||
#define BT_HCI_VS_FW_VAR_FW_LOADER 0x0003
|
||||
#define BT_HCI_VS_FW_VAR_RESCUE_IMG 0x0004
|
||||
#define BT_HCI_OP_VS_READ_VERSION_INFO BT_OP(BT_OGF_VS, 0x0001)
|
||||
struct bt_hci_rp_vs_read_version_info {
|
||||
uint8_t status;
|
||||
uint16_t hw_platform;
|
||||
uint16_t hw_variant;
|
||||
uint8_t fw_variant;
|
||||
uint8_t fw_version;
|
||||
uint16_t fw_revision;
|
||||
uint32_t fw_build;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_SUPPORTED_COMMANDS BT_OP(BT_OGF_VS, 0x0002)
|
||||
struct bt_hci_rp_vs_read_supported_commands {
|
||||
uint8_t status;
|
||||
uint8_t commands[64];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_SUPPORTED_FEATURES BT_OP(BT_OGF_VS, 0x0003)
|
||||
struct bt_hci_rp_vs_read_supported_features {
|
||||
uint8_t status;
|
||||
uint8_t features[8];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_SET_EVENT_MASK BT_OP(BT_OGF_VS, 0x0004)
|
||||
struct bt_hci_cp_vs_set_event_mask {
|
||||
uint8_t event_mask[8];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_VS_RESET_SOFT 0x00
|
||||
#define BT_HCI_VS_RESET_HARD 0x01
|
||||
#define BT_HCI_OP_VS_RESET BT_OP(BT_OGF_VS, 0x0005)
|
||||
struct bt_hci_cp_vs_reset {
|
||||
uint8_t type;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_WRITE_BD_ADDR BT_OP(BT_OGF_VS, 0x0006)
|
||||
struct bt_hci_cp_vs_write_bd_addr {
|
||||
bt_addr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_VS_TRACE_DISABLED 0x00
|
||||
#define BT_HCI_VS_TRACE_ENABLED 0x01
|
||||
|
||||
#define BT_HCI_VS_TRACE_HCI_EVTS 0x00
|
||||
#define BT_HCI_VS_TRACE_VDC 0x01
|
||||
#define BT_HCI_OP_VS_SET_TRACE_ENABLE BT_OP(BT_OGF_VS, 0x0007)
|
||||
struct bt_hci_cp_vs_set_trace_enable {
|
||||
uint8_t enable;
|
||||
uint8_t type;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_BUILD_INFO BT_OP(BT_OGF_VS, 0x0008)
|
||||
struct bt_hci_rp_vs_read_build_info {
|
||||
uint8_t status;
|
||||
uint8_t info[0];
|
||||
} __packed;
|
||||
|
||||
struct bt_hci_vs_static_addr {
|
||||
bt_addr_t bdaddr;
|
||||
uint8_t ir[16];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_STATIC_ADDRS BT_OP(BT_OGF_VS, 0x0009)
|
||||
struct bt_hci_rp_vs_read_static_addrs {
|
||||
uint8_t status;
|
||||
uint8_t num_addrs;
|
||||
struct bt_hci_vs_static_addr a[0];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_KEY_HIERARCHY_ROOTS BT_OP(BT_OGF_VS, 0x000a)
|
||||
struct bt_hci_rp_vs_read_key_hierarchy_roots {
|
||||
uint8_t status;
|
||||
uint8_t ir[16];
|
||||
uint8_t er[16];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_CHIP_TEMP BT_OP(BT_OGF_VS, 0x000b)
|
||||
struct bt_hci_rp_vs_read_chip_temp {
|
||||
uint8_t status;
|
||||
int8_t temps;
|
||||
} __packed;
|
||||
|
||||
struct bt_hci_vs_cmd {
|
||||
uint16_t vendor_id;
|
||||
uint16_t opcode_base;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_VS_VID_ANDROID 0x0001
|
||||
#define BT_HCI_VS_VID_MICROSOFT 0x0002
|
||||
#define BT_HCI_OP_VS_READ_HOST_STACK_CMDS BT_OP(BT_OGF_VS, 0x000c)
|
||||
struct bt_hci_rp_vs_read_host_stack_cmds {
|
||||
uint8_t status;
|
||||
uint8_t num_cmds;
|
||||
struct bt_hci_vs_cmd c[0];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_VS_SCAN_REQ_REPORTS_DISABLED 0x00
|
||||
#define BT_HCI_VS_SCAN_REQ_REPORTS_ENABLED 0x01
|
||||
#define BT_HCI_OP_VS_SET_SCAN_REQ_REPORTS BT_OP(BT_OGF_VS, 0x000d)
|
||||
struct bt_hci_cp_vs_set_scan_req_reports {
|
||||
uint8_t enable;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_VS_LL_HANDLE_TYPE_ADV 0x00
|
||||
#define BT_HCI_VS_LL_HANDLE_TYPE_SCAN 0x01
|
||||
#define BT_HCI_VS_LL_HANDLE_TYPE_CONN 0x02
|
||||
#define BT_HCI_VS_LL_TX_POWER_LEVEL_NO_PREF 0x7F
|
||||
#define BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL BT_OP(BT_OGF_VS, 0x000e)
|
||||
struct bt_hci_cp_vs_write_tx_power_level {
|
||||
uint8_t handle_type;
|
||||
uint16_t handle;
|
||||
int8_t tx_power_level;
|
||||
} __packed;
|
||||
|
||||
struct bt_hci_rp_vs_write_tx_power_level {
|
||||
uint8_t status;
|
||||
uint8_t handle_type;
|
||||
uint16_t handle;
|
||||
int8_t selected_tx_power;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_TX_POWER_LEVEL BT_OP(BT_OGF_VS, 0x000f)
|
||||
struct bt_hci_cp_vs_read_tx_power_level {
|
||||
uint8_t handle_type;
|
||||
uint16_t handle;
|
||||
} __packed;
|
||||
|
||||
struct bt_hci_rp_vs_read_tx_power_level {
|
||||
uint8_t status;
|
||||
uint8_t handle_type;
|
||||
uint16_t handle;
|
||||
int8_t tx_power_level;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OP_VS_READ_USB_TRANSPORT_MODE BT_OP(BT_OGF_VS, 0x0010)
|
||||
|
||||
struct bt_hci_rp_vs_read_usb_transport_mode {
|
||||
uint8_t status;
|
||||
uint8_t num_supported_modes;
|
||||
uint8_t supported_mode[0];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_VS_USB_H2_MODE 0x00
|
||||
#define BT_HCI_VS_USB_H4_MODE 0x01
|
||||
|
||||
#define BT_HCI_OP_VS_SET_USB_TRANSPORT_MODE BT_OP(BT_OGF_VS, 0x0011)
|
||||
|
||||
struct bt_hci_cp_vs_set_usb_transport_mode {
|
||||
uint8_t mode;
|
||||
} __packed;
|
||||
|
||||
/* Events */
|
||||
|
||||
struct bt_hci_evt_vs {
|
||||
uint8_t subevent;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_EVT_VS_FATAL_ERROR 0x02
|
||||
struct bt_hci_evt_vs_fatal_error {
|
||||
uint64_t pc;
|
||||
uint8_t err_info[0];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_VS_TRACE_LMP_TX 0x01
|
||||
#define BT_HCI_VS_TRACE_LMP_RX 0x02
|
||||
#define BT_HCI_VS_TRACE_LLCP_TX 0x03
|
||||
#define BT_HCI_VS_TRACE_LLCP_RX 0x04
|
||||
#define BT_HCI_VS_TRACE_LE_CONN_IND 0x05
|
||||
#define BT_HCI_EVT_VS_TRACE_INFO 0x03
|
||||
struct bt_hci_evt_vs_trace_info {
|
||||
uint8_t type;
|
||||
uint8_t data[0];
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_EVT_VS_SCAN_REQ_RX 0x04
|
||||
struct bt_hci_evt_vs_scan_req_rx {
|
||||
bt_addr_le_t addr;
|
||||
int8_t rssi;
|
||||
} __packed;
|
||||
|
||||
/* Event mask bits */
|
||||
|
||||
#define BT_EVT_MASK_VS_FATAL_ERROR BT_EVT_BIT(1)
|
||||
#define BT_EVT_MASK_VS_TRACE_INFO BT_EVT_BIT(2)
|
||||
#define BT_EVT_MASK_VS_SCAN_REQ_RX BT_EVT_BIT(3)
|
||||
|
||||
/* Mesh HCI commands */
|
||||
#define BT_HCI_MESH_REVISION 0x01
|
||||
|
||||
#define BT_HCI_OP_VS_MESH BT_OP(BT_OGF_VS, 0x0042)
|
||||
#define BT_HCI_MESH_EVT_PREFIX 0xF0
|
||||
|
||||
struct bt_hci_cp_mesh {
|
||||
uint8_t opcode;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OC_MESH_GET_OPTS 0x00
|
||||
struct bt_hci_rp_mesh_get_opts {
|
||||
uint8_t status;
|
||||
uint8_t opcode;
|
||||
uint8_t revision;
|
||||
uint8_t ch_map;
|
||||
int8_t min_tx_power;
|
||||
int8_t max_tx_power;
|
||||
uint8_t max_scan_filter;
|
||||
uint8_t max_filter_pattern;
|
||||
uint8_t max_adv_slot;
|
||||
uint8_t max_tx_window;
|
||||
uint8_t evt_prefix_len;
|
||||
uint8_t evt_prefix;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_MESH_PATTERN_LEN_MAX 0x0f
|
||||
|
||||
#define BT_HCI_OC_MESH_SET_SCAN_FILTER 0x01
|
||||
struct bt_hci_mesh_pattern {
|
||||
uint8_t pattern_len;
|
||||
uint8_t pattern[0];
|
||||
} __packed;
|
||||
|
||||
struct bt_hci_cp_mesh_set_scan_filter {
|
||||
uint8_t scan_filter;
|
||||
uint8_t filter_dup;
|
||||
uint8_t num_patterns;
|
||||
struct bt_hci_mesh_pattern patterns[0];
|
||||
} __packed;
|
||||
struct bt_hci_rp_mesh_set_scan_filter {
|
||||
uint8_t status;
|
||||
uint8_t opcode;
|
||||
uint8_t scan_filter;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OC_MESH_ADVERTISE 0x02
|
||||
struct bt_hci_cp_mesh_advertise {
|
||||
uint8_t adv_slot;
|
||||
uint8_t own_addr_type;
|
||||
bt_addr_t random_addr;
|
||||
uint8_t ch_map;
|
||||
int8_t tx_power;
|
||||
uint8_t min_tx_delay;
|
||||
uint8_t max_tx_delay;
|
||||
uint8_t retx_count;
|
||||
uint8_t retx_interval;
|
||||
uint8_t scan_delay;
|
||||
uint16_t scan_duration;
|
||||
uint8_t scan_filter;
|
||||
uint8_t data_len;
|
||||
uint8_t data[31];
|
||||
} __packed;
|
||||
struct bt_hci_rp_mesh_advertise {
|
||||
uint8_t status;
|
||||
uint8_t opcode;
|
||||
uint8_t adv_slot;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OC_MESH_ADVERTISE_TIMED 0x03
|
||||
struct bt_hci_cp_mesh_advertise_timed {
|
||||
uint8_t adv_slot;
|
||||
uint8_t own_addr_type;
|
||||
bt_addr_t random_addr;
|
||||
uint8_t ch_map;
|
||||
int8_t tx_power;
|
||||
uint8_t retx_count;
|
||||
uint8_t retx_interval;
|
||||
uint32_t instant;
|
||||
uint16_t tx_delay;
|
||||
uint16_t tx_window;
|
||||
uint8_t data_len;
|
||||
uint8_t data[31];
|
||||
} __packed;
|
||||
struct bt_hci_rp_mesh_advertise_timed {
|
||||
uint8_t status;
|
||||
uint8_t opcode;
|
||||
uint8_t adv_slot;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OC_MESH_ADVERTISE_CANCEL 0x04
|
||||
struct bt_hci_cp_mesh_advertise_cancel {
|
||||
uint8_t adv_slot;
|
||||
} __packed;
|
||||
struct bt_hci_rp_mesh_advertise_cancel {
|
||||
uint8_t status;
|
||||
uint8_t opcode;
|
||||
uint8_t adv_slot;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_OC_MESH_SET_SCANNING 0x05
|
||||
struct bt_hci_cp_mesh_set_scanning {
|
||||
uint8_t enable;
|
||||
uint8_t ch_map;
|
||||
uint8_t scan_filter;
|
||||
} __packed;
|
||||
struct bt_hci_rp_mesh_set_scanning {
|
||||
uint8_t status;
|
||||
uint8_t opcode;
|
||||
} __packed;
|
||||
|
||||
/* Events */
|
||||
struct bt_hci_evt_mesh {
|
||||
uint8_t prefix;
|
||||
uint8_t subevent;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_EVT_MESH_ADV_COMPLETE 0x00
|
||||
struct bt_hci_evt_mesh_adv_complete {
|
||||
uint8_t adv_slot;
|
||||
} __packed;
|
||||
|
||||
#define BT_HCI_EVT_MESH_SCANNING_REPORT 0x01
|
||||
struct bt_hci_evt_mesh_scan_report {
|
||||
bt_addr_le_t addr;
|
||||
uint8_t chan;
|
||||
int8_t rssi;
|
||||
uint32_t instant;
|
||||
uint8_t data_len;
|
||||
uint8_t data[0];
|
||||
} __packed;
|
||||
struct bt_hci_evt_mesh_scanning_report {
|
||||
uint8_t num_reports;
|
||||
struct bt_hci_evt_mesh_scan_report reports[0];
|
||||
} __packed;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_HCI_VS_H_ */
|
@ -319,7 +319,7 @@ SRC_COMMON_HAL_ALL = \
|
||||
|
||||
ifeq ($(CIRCUITPY_BLEIO_HCI),1)
|
||||
SRC_C += \
|
||||
common-hal/_bleio/hci.c \
|
||||
common-hal/_bleio/hci_api.c \
|
||||
|
||||
endif
|
||||
|
||||
|
@ -68,52 +68,37 @@
|
||||
//| Use `_bleio.adapter` to access the sole instance available."""
|
||||
//|
|
||||
|
||||
//| def hci_init(self, *, tx: Pin, rx: Pin, rts: Pin, cts: Pin, baudrate: int = 115200, buffer_size: int = 256):
|
||||
//| def hci_init(self, *, uart: busio.UART, cts: Pin, baudrate: int = 115200, buffer_size: int = 256):
|
||||
//| On boards that do not have native BLE, you can an use HCI co-processor.
|
||||
//| Call `_bleio.adapter.hci_init()` passing it the pins used to communicate
|
||||
//| Call `_bleio.adapter.hci_init()` passing it the uart and pins used to communicate
|
||||
//| with the co-processor, such as an Adafruit AirLift.
|
||||
//| The co-processor must have been reset and put into BLE mode beforehand
|
||||
//| by the appropriate pin manipulation.
|
||||
//| The `tx`, `rx`, `rts`, and `cs` pins are used to communicate with the HCI co-processor in HCI mode.
|
||||
//| The `uart` object, and `rts` and `cs` pins are used to
|
||||
//| communicate with the HCI co-processor in HCI mode.
|
||||
//|
|
||||
mp_obj_t bleio_adapter_hci_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
#if CIRCUITPY_BLEIO_HCI
|
||||
bleio_adapter_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
|
||||
if (self->enabled) {
|
||||
mp_raise_ValueError(translate("HCI Adapter is already enabled"));
|
||||
}
|
||||
|
||||
enum { ARG_tx, ARG_rx, ARG_rts, ARG_cts, ARG_baudrate, ARG_buffer_size };
|
||||
enum { ARG_uart, ARG_rts, ARG_cts };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_tx, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_rx, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_uart, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_rts, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_cts, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
|
||||
{ MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 115200 } },
|
||||
{ MP_QSTR_buffer_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 256 } },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
const mcu_pin_obj_t *tx = validate_obj_is_free_pin(args[ARG_tx].u_obj);
|
||||
const mcu_pin_obj_t *rx = validate_obj_is_free_pin(args[ARG_rx].u_obj);
|
||||
busio_uart_obj_t *uart = args[ARG_uart].u_obj;
|
||||
if (!MP_OBJ_IS_TYPE(uart, &busio_uart_type)) {
|
||||
mp_raise_ValueError(translate("Expected a UART"));
|
||||
}
|
||||
const mcu_pin_obj_t *rts = validate_obj_is_free_pin(args[ARG_rts].u_obj);
|
||||
const mcu_pin_obj_t *cts = validate_obj_is_free_pin(args[ARG_cts].u_obj);
|
||||
|
||||
if (args[ARG_baudrate].u_int <= 0) {
|
||||
mp_raise_ValueError(translate("baudrate must be > 0"));
|
||||
}
|
||||
const uint32_t baudrate = args[ARG_baudrate].u_int;
|
||||
|
||||
if (args[ARG_buffer_size].u_int <= 1) {
|
||||
mp_raise_ValueError(translate("buffer_size must be >= 1"));
|
||||
}
|
||||
const uint32_t buffer_size = args[ARG_buffer_size].u_int;
|
||||
|
||||
common_hal_bleio_adapter_hci_init(&common_hal_bleio_adapter_obj, tx, rx, rts, cts,
|
||||
baudrate, buffer_size);
|
||||
common_hal_bleio_adapter_hci_init(self, uart, rts, cts);
|
||||
|
||||
return mp_const_none;
|
||||
#else
|
||||
@ -268,7 +253,7 @@ STATIC mp_obj_t bleio_adapter_stop_advertising(mp_obj_t self_in) {
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(bleio_adapter_stop_advertising_obj, bleio_adapter_stop_advertising);
|
||||
|
||||
//| def start_scan(self, prefixes: sequence = b"", *, buffer_size: int = 512, extended: bool = False, timeout: float = None, interval: float = 0.1, window: float = 0.1, minimum_rssi: int = -80, active: bool = True) -> Any:
|
||||
//| def start_scan(self, *, prefixes: sequence = b"", buffer_size: int = 512, extended: bool = False, timeout: float = None, interval: float = 0.1, window: float = 0.1, minimum_rssi: int = -80, active: bool = True) -> Any:
|
||||
//| """Starts a BLE scan and returns an iterator of results. Advertisements and scan responses are
|
||||
//| filtered and returned separately.
|
||||
//|
|
||||
|
@ -38,7 +38,7 @@
|
||||
const mp_obj_type_t bleio_adapter_type;
|
||||
|
||||
#if CIRCUITPY_BLEIO_HCI
|
||||
void common_hal_bleio_adapter_hci_init(bleio_adapter_obj_t *self, const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, uint32_t baudrate, uint32_t buffer_size);
|
||||
void common_hal_bleio_adapter_hci_init(bleio_adapter_obj_t *self, busio_uart_obj_t *uart, const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts);
|
||||
#endif // CIRCUITPY_BLEIO_HCI
|
||||
|
||||
bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self);
|
||||
|
@ -43,8 +43,9 @@
|
||||
//| way around."""
|
||||
//|
|
||||
//| def monotonic() -> Any:
|
||||
//| """Returns an always increasing value of time with an unknown reference
|
||||
//| point. Only use it to compare against other values from `monotonic`.
|
||||
//| """Returns an always increasing value of time, in fractional seconds,
|
||||
//| with an unknown reference point.
|
||||
//| Only use it to compare against other values from `monotonic`.
|
||||
//|
|
||||
//| :return: the current monotonic time
|
||||
//| :rtype: float"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user