use zephyr include files; wip: compiles

This commit is contained in:
Dan Halbert 2020-07-08 09:33:41 -04:00
parent 11cb3e3b4b
commit a5ab2829eb
16 changed files with 5005 additions and 753 deletions

View File

@ -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) {

View File

@ -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;

View File

@ -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);
}

View 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), &params);
}
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), &params);
}
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), &params);
}
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), &params);
}
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), &params);
}
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), &params);
}
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), &params);
}
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), &params);
}

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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_ */

File diff suppressed because it is too large Load Diff

View 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_ */

View 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_ */

View 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_ */

View File

@ -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

View File

@ -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.
//|

View File

@ -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);

View File

@ -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"""