hci skeleton done; not working yet
This commit is contained in:
parent
f879114c43
commit
11cb3e3b4b
@ -31,6 +31,8 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hci.h"
|
||||
|
||||
#include "py/gc.h"
|
||||
#include "py/mphal.h"
|
||||
#include "py/objstr.h"
|
||||
@ -178,10 +180,10 @@ char default_ble_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0
|
||||
// }
|
||||
|
||||
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 = tx;
|
||||
self->rx = rx;
|
||||
self->rts = rts;
|
||||
self->cts = cts;
|
||||
self->tx_pin = tx;
|
||||
self->rx_pin = rx;
|
||||
self->rts_pin = rts;
|
||||
self->cts_pin = cts;
|
||||
self->baudrate = baudrate;
|
||||
self->buffer_size = buffer_size;
|
||||
self->enabled = false;
|
||||
@ -195,6 +197,35 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -206,13 +237,14 @@ 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);
|
||||
|
||||
// ble_gap_addr_t local_address;
|
||||
// get_address(self, &local_address);
|
||||
uint8_t addr[6];
|
||||
hci_readBdAddr(addr);
|
||||
|
||||
bleio_address_obj_t *address = m_new_obj(bleio_address_obj_t);
|
||||
address->base.type = &bleio_address_type;
|
||||
|
||||
// common_hal_bleio_address_construct(address, local_address.addr, local_address.addr_type);
|
||||
// 0 is the type designating a public address.
|
||||
common_hal_bleio_address_construct(address, addr, 0);
|
||||
return address;
|
||||
}
|
||||
|
||||
|
@ -52,15 +52,15 @@ typedef struct {
|
||||
bleio_scanresults_obj_t* scan_results;
|
||||
mp_obj_t name;
|
||||
mp_obj_tuple_t *connection_objs;
|
||||
const mcu_pin_obj_t* tx;
|
||||
const mcu_pin_obj_t* rx;
|
||||
const mcu_pin_obj_t* rts;
|
||||
const mcu_pin_obj_t* cts;
|
||||
const mcu_pin_obj_t* tx_pin;
|
||||
const mcu_pin_obj_t* rx_pin;
|
||||
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_digitalio;
|
||||
digitalio_digitalinout_obj_t cts_digitalio;
|
||||
digitalio_digitalinout_obj_t rts_digitalinout;
|
||||
digitalio_digitalinout_obj_t cts_digitalinout;
|
||||
bool enabled;
|
||||
} bleio_adapter_obj_t;
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
/*
|
||||
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
|
||||
@ -9,7 +12,12 @@
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "HCI.h"
|
||||
#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
|
||||
@ -59,148 +67,369 @@
|
||||
|
||||
#define HCI_OE_USER_ENDED_CONNECTION 0x13
|
||||
|
||||
HCIClass::HCIClass() :
|
||||
_debug(NULL),
|
||||
_recvIndex(0),
|
||||
_pendingPkt(0)
|
||||
|
||||
#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");
|
||||
}
|
||||
}
|
||||
|
||||
HCIClass::~HCIClass()
|
||||
|
||||
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);
|
||||
// }
|
||||
}
|
||||
|
||||
int HCIClass::begin()
|
||||
STATIC void handleNumCompPkts(uint16_t handle, uint16_t numPkts)
|
||||
{
|
||||
_recvIndex = 0;
|
||||
|
||||
return HCITransport.begin();
|
||||
if (numPkts && pending_pkt > numPkts) {
|
||||
pending_pkt -= numPkts;
|
||||
} else {
|
||||
pending_pkt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void HCIClass::end()
|
||||
STATIC void handleEventPkt(uint8_t plen, uint8_t pdata[])
|
||||
{
|
||||
HCITransport.end();
|
||||
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 HCIClass::poll()
|
||||
{
|
||||
poll(0);
|
||||
void hci_init(bleio_adapter_obj_t *adapter_in) {
|
||||
adapter = adapter_in;
|
||||
recv_idx = 0;
|
||||
pending_pkt = 0;
|
||||
}
|
||||
|
||||
void HCIClass::poll(unsigned long timeout)
|
||||
{
|
||||
#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE)
|
||||
digitalWrite(NINA_RTS, LOW);
|
||||
#endif
|
||||
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);
|
||||
|
||||
if (timeout) {
|
||||
HCITransport.wait(timeout);
|
||||
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;
|
||||
|
||||
while (HCITransport.available()) {
|
||||
byte b = HCITransport.read();
|
||||
handleAclDataPkt(pktLen, &recv_buffer[1]);
|
||||
|
||||
_recvBuffer[_recvIndex++] = b;
|
||||
|
||||
if (_recvBuffer[0] == HCI_ACLDATA_PKT) {
|
||||
if (_recvIndex > 5 && _recvIndex >= (5 + (_recvBuffer[3] + (_recvBuffer[4] << 8)))) {
|
||||
if (_debug) {
|
||||
dumpPkt("HCI ACLDATA RX <- ", _recvIndex, _recvBuffer);
|
||||
common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, false);
|
||||
}
|
||||
#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE)
|
||||
digitalWrite(NINA_RTS, HIGH);
|
||||
#endif
|
||||
int pktLen = _recvIndex - 1;
|
||||
_recvIndex = 0;
|
||||
|
||||
handleAclDataPkt(pktLen, &_recvBuffer[1]);
|
||||
|
||||
#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE)
|
||||
digitalWrite(NINA_RTS, LOW);
|
||||
#endif
|
||||
} 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);
|
||||
}
|
||||
} else if (_recvBuffer[0] == HCI_EVENT_PKT) {
|
||||
if (_recvIndex > 3 && _recvIndex >= (3 + _recvBuffer[2])) {
|
||||
if (_debug) {
|
||||
dumpPkt("HCI EVENT RX <- ", _recvIndex, _recvBuffer);
|
||||
}
|
||||
#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE)
|
||||
digitalWrite(NINA_RTS, HIGH);
|
||||
#endif
|
||||
// received full event
|
||||
int pktLen = _recvIndex - 1;
|
||||
_recvIndex = 0;
|
||||
// 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, &_recvBuffer[1]);
|
||||
handleEventPkt(pktLen, &recv_buffer[1]);
|
||||
|
||||
#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE)
|
||||
digitalWrite(NINA_RTS, LOW);
|
||||
#endif
|
||||
common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, false);
|
||||
}
|
||||
} else {
|
||||
_recvIndex = 0;
|
||||
|
||||
if (_debug) {
|
||||
_debug->println(b, HEX);
|
||||
}
|
||||
recv_idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_METRO_M4_AIRLIFT_LITE)
|
||||
digitalWrite(NINA_RTS, HIGH);
|
||||
#endif
|
||||
common_hal_digitalio_digitalinout_set_value(&adapter->rts_digitalinout, true);
|
||||
}
|
||||
|
||||
int HCIClass::reset()
|
||||
|
||||
int hci_sendCommand(uint8_t ogf, uint16_t ocf, uint8_t plen, void* parameters)
|
||||
{
|
||||
return sendCommand(OGF_HOST_CTL << 10 | OCF_RESET);
|
||||
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 HCIClass::readLocalVersion(uint8_t& hciVer, uint16_t& hciRev, uint8_t& lmpVer, uint16_t& manufacturer, uint16_t& lmpSubVer)
|
||||
{
|
||||
int result = sendCommand(OGF_INFO_PARAM << 10 | OCF_READ_LOCAL_VERSION);
|
||||
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) {
|
||||
struct __attribute__ ((packed)) HCILocalVersion {
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t hciVer;
|
||||
uint16_t hciRev;
|
||||
uint8_t lmpVer;
|
||||
uint16_t manufacturer;
|
||||
uint16_t lmpSubVer;
|
||||
} *localVersion = (HCILocalVersion*)_cmdResponse;
|
||||
} HCILocalVersion;
|
||||
|
||||
hciVer = localVersion->hciVer;
|
||||
hciRev = localVersion->hciRev;
|
||||
lmpVer = localVersion->lmpVer;
|
||||
manufacturer = localVersion->manufacturer;
|
||||
lmpSubVer = localVersion->lmpSubVer;
|
||||
HCILocalVersion *localVersion = (HCILocalVersion*)cmd_response;
|
||||
*hciVer = localVersion->hciVer;
|
||||
*hciRev = localVersion->hciRev;
|
||||
*lmpVer = localVersion->lmpVer;
|
||||
*manufacturer = localVersion->manufacturer;
|
||||
*lmpSubVer = localVersion->lmpSubVer;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int HCIClass::readBdAddr(uint8_t addr[6])
|
||||
{
|
||||
int result = sendCommand(OGF_INFO_PARAM << 10 | OCF_READ_BD_ADDR);
|
||||
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, _cmdResponse, 6);
|
||||
memcpy(addr, cmd_response, 6);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int HCIClass::readRssi(uint16_t handle)
|
||||
{
|
||||
int result = sendCommand(OGF_STATUS_PARAM << 10 | OCF_READ_RSSI, sizeof(handle), &handle);
|
||||
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) {
|
||||
struct __attribute__ ((packed)) HCIReadRssi {
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint16_t handle;
|
||||
int8_t rssi;
|
||||
} *readRssi = (HCIReadRssi*)_cmdResponse;
|
||||
} HCIReadRssi;
|
||||
|
||||
HCIReadRssi *readRssi = (HCIReadRssi*)cmd_response;
|
||||
if (readRssi->handle == handle) {
|
||||
rssi = readRssi->rssi;
|
||||
}
|
||||
@ -209,38 +438,38 @@ int HCIClass::readRssi(uint16_t handle)
|
||||
return rssi;
|
||||
}
|
||||
|
||||
int HCIClass::setEventMask(uint64_t eventMask)
|
||||
{
|
||||
return sendCommand(OGF_HOST_CTL << 10 | OCF_SET_EVENT_MASK, sizeof(eventMask), &eventMask);
|
||||
int hci_setEventMask(uint64_t eventMask) {
|
||||
return hci_sendCommand(OGF_HOST_CTL, OCF_SET_EVENT_MASK, sizeof(eventMask), &eventMask);
|
||||
}
|
||||
|
||||
int HCIClass::readLeBufferSize(uint16_t& pktLen, uint8_t& maxPkt)
|
||||
int hci_readLeBufferSize(uint16_t *pktLen, uint8_t *maxPkt)
|
||||
{
|
||||
int result = sendCommand(OGF_LE_CTL << 10 | OCF_LE_READ_BUFFER_SIZE);
|
||||
int result = hci_sendCommand(OGF_LE_CTL, OCF_LE_READ_BUFFER_SIZE, 0, NULL);
|
||||
|
||||
if (result == 0) {
|
||||
struct __attribute__ ((packed)) HCILeBufferSize {
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint16_t pktLen;
|
||||
uint8_t maxPkt;
|
||||
} *leBufferSize = (HCILeBufferSize*)_cmdResponse;
|
||||
} HCILeBufferSize;
|
||||
|
||||
pktLen = leBufferSize->pktLen;
|
||||
_maxPkt = maxPkt = leBufferSize->maxPkt;
|
||||
HCILeBufferSize *leBufferSize = (HCILeBufferSize*)cmd_response;
|
||||
*pktLen = leBufferSize->pktLen;
|
||||
*maxPkt = leBufferSize->maxPkt;
|
||||
|
||||
#ifndef __AVR__
|
||||
ATT.setMaxMtu(pktLen - 9); // max pkt len - ACL header size
|
||||
// FIX (needed?) ATT.setMaxMtu(pktLen - 9); // max pkt len - ACL header size
|
||||
#endif
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int HCIClass::leSetRandomAddress(uint8_t addr[6])
|
||||
int hci_leSetRandomAddress(uint8_t addr[6])
|
||||
{
|
||||
return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_RANDOM_ADDRESS, 6, addr);
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_RANDOM_ADDRESS, 6, addr);
|
||||
}
|
||||
|
||||
int HCIClass::leSetAdvertisingParameters(uint16_t minInterval, uint16_t maxInterval,
|
||||
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,
|
||||
@ -266,10 +495,10 @@ int HCIClass::leSetAdvertisingParameters(uint16_t minInterval, uint16_t maxInter
|
||||
leAdvertisingParamters.chanMap = chanMap;
|
||||
leAdvertisingParamters.filter = filter;
|
||||
|
||||
return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_ADVERTISING_PARAMETERS, sizeof(leAdvertisingParamters), &leAdvertisingParamters);
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_ADVERTISING_PARAMETERS, sizeof(leAdvertisingParamters), &leAdvertisingParamters);
|
||||
}
|
||||
|
||||
int HCIClass::leSetAdvertisingData(uint8_t length, uint8_t data[])
|
||||
int hci_leSetAdvertisingData(uint8_t length, uint8_t data[])
|
||||
{
|
||||
struct __attribute__ ((packed)) HCILeAdvertisingData {
|
||||
uint8_t length;
|
||||
@ -280,10 +509,10 @@ int HCIClass::leSetAdvertisingData(uint8_t length, uint8_t data[])
|
||||
leAdvertisingData.length = length;
|
||||
memcpy(leAdvertisingData.data, data, length);
|
||||
|
||||
return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_ADVERTISING_DATA, sizeof(leAdvertisingData), &leAdvertisingData);
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_ADVERTISING_DATA, sizeof(leAdvertisingData), &leAdvertisingData);
|
||||
}
|
||||
|
||||
int HCIClass::leSetScanResponseData(uint8_t length, uint8_t data[])
|
||||
int hci_leSetScanResponseData(uint8_t length, uint8_t data[])
|
||||
{
|
||||
struct __attribute__ ((packed)) HCILeScanResponseData {
|
||||
uint8_t length;
|
||||
@ -294,15 +523,15 @@ int HCIClass::leSetScanResponseData(uint8_t length, uint8_t data[])
|
||||
leScanResponseData.length = length;
|
||||
memcpy(leScanResponseData.data, data, length);
|
||||
|
||||
return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_SCAN_RESPONSE_DATA, sizeof(leScanResponseData), &leScanResponseData);
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_RESPONSE_DATA, sizeof(leScanResponseData), &leScanResponseData);
|
||||
}
|
||||
|
||||
int HCIClass::leSetAdvertiseEnable(uint8_t enable)
|
||||
int hci_leSetAdvertiseEnable(uint8_t enable)
|
||||
{
|
||||
return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_ADVERTISE_ENABLE, sizeof(enable), &enable);
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_ADVERTISE_ENABLE, sizeof(enable), &enable);
|
||||
}
|
||||
|
||||
int HCIClass::leSetScanParameters(uint8_t type, uint16_t interval, uint16_t window,
|
||||
int hci_leSetScanParameters(uint8_t type, uint16_t interval, uint16_t window,
|
||||
uint8_t ownBdaddrType, uint8_t filter)
|
||||
{
|
||||
struct __attribute__ ((packed)) HCILeSetScanParameters {
|
||||
@ -319,10 +548,10 @@ int HCIClass::leSetScanParameters(uint8_t type, uint16_t interval, uint16_t wind
|
||||
leScanParameters.ownBdaddrType = ownBdaddrType;
|
||||
leScanParameters.filter = filter;
|
||||
|
||||
return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_SCAN_PARAMETERS, sizeof(leScanParameters), &leScanParameters);
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_PARAMETERS, sizeof(leScanParameters), &leScanParameters);
|
||||
}
|
||||
|
||||
int HCIClass::leSetScanEnable(uint8_t enabled, uint8_t duplicates)
|
||||
int hci_leSetScanEnable(uint8_t enabled, uint8_t duplicates)
|
||||
{
|
||||
struct __attribute__ ((packed)) HCILeSetScanEnableData {
|
||||
uint8_t enabled;
|
||||
@ -332,10 +561,10 @@ int HCIClass::leSetScanEnable(uint8_t enabled, uint8_t duplicates)
|
||||
leScanEnableData.enabled = enabled;
|
||||
leScanEnableData.duplicates = duplicates;
|
||||
|
||||
return sendCommand(OGF_LE_CTL << 10 | OCF_LE_SET_SCAN_ENABLE, sizeof(leScanEnableData), &leScanEnableData);
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE, sizeof(leScanEnableData), &leScanEnableData);
|
||||
}
|
||||
|
||||
int HCIClass::leCreateConn(uint16_t interval, uint16_t window, uint8_t initiatorFilter,
|
||||
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)
|
||||
@ -368,15 +597,15 @@ int HCIClass::leCreateConn(uint16_t interval, uint16_t window, uint8_t initiator
|
||||
leCreateConnData.minCeLength = minCeLength;
|
||||
leCreateConnData.maxCeLength = maxCeLength;
|
||||
|
||||
return sendCommand(OGF_LE_CTL << 10 | OCF_LE_CREATE_CONN, sizeof(leCreateConnData), &leCreateConnData);
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_CREATE_CONN, sizeof(leCreateConnData), &leCreateConnData);
|
||||
}
|
||||
|
||||
int HCIClass::leCancelConn()
|
||||
int hci_leCancelConn()
|
||||
{
|
||||
return sendCommand(OGF_LE_CTL << 10 | OCF_LE_CANCEL_CONN, 0, NULL);
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_CANCEL_CONN, 0, NULL);
|
||||
}
|
||||
|
||||
int HCIClass::leConnUpdate(uint16_t handle, uint16_t minInterval, uint16_t maxInterval,
|
||||
int hci_leConnUpdate(uint16_t handle, uint16_t minInterval, uint16_t maxInterval,
|
||||
uint16_t latency, uint16_t supervisionTimeout)
|
||||
{
|
||||
struct __attribute__ ((packed)) HCILeConnUpdateData {
|
||||
@ -397,279 +626,49 @@ int HCIClass::leConnUpdate(uint16_t handle, uint16_t minInterval, uint16_t maxIn
|
||||
leConnUpdateData.minCeLength = 0x0004;
|
||||
leConnUpdateData.maxCeLength = 0x0006;
|
||||
|
||||
return sendCommand(OGF_LE_CTL << 10 | OCF_LE_CONN_UPDATE, sizeof(leConnUpdateData), &leConnUpdateData);
|
||||
return hci_sendCommand(OGF_LE_CTL, OCF_LE_CONN_UPDATE, sizeof(leConnUpdateData), &leConnUpdateData);
|
||||
}
|
||||
|
||||
int HCIClass::sendAclPkt(uint16_t handle, uint8_t cid, uint8_t plen, void* data)
|
||||
{
|
||||
while (_pendingPkt >= _maxPkt) {
|
||||
poll();
|
||||
int hci_sendAclPkt(uint16_t handle, uint8_t cid, uint8_t plen, void* data) {
|
||||
while (pending_pkt >= max_pkt) {
|
||||
hci_poll();
|
||||
}
|
||||
|
||||
struct __attribute__ ((packed)) HCIACLHdr {
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t pktType;
|
||||
uint16_t handle;
|
||||
uint16_t dlen;
|
||||
uint16_t plen;
|
||||
uint16_t cid;
|
||||
} aclHdr = { HCI_ACLDATA_PKT, handle, uint8_t(plen + 4), plen, 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) {
|
||||
if (debug) {
|
||||
dumpPkt("HCI ACLDATA TX -> ", sizeof(aclHdr) + plen, txBuffer);
|
||||
}
|
||||
|
||||
_pendingPkt++;
|
||||
HCITransport.write(txBuffer, sizeof(aclHdr) + plen);
|
||||
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 HCIClass::disconnect(uint16_t handle)
|
||||
int hci_disconnect(uint16_t handle)
|
||||
{
|
||||
struct __attribute__ ((packed)) HCIDisconnectData {
|
||||
uint16_t handle;
|
||||
uint8_t reason;
|
||||
} disconnectData = { handle, HCI_OE_USER_ENDED_CONNECTION };
|
||||
|
||||
return sendCommand(OGF_LINK_CTL << 10 | OCF_DISCONNECT, sizeof(disconnectData), &disconnectData);
|
||||
return hci_sendCommand(OGF_LINK_CTL, OCF_DISCONNECT, sizeof(disconnectData), &disconnectData);
|
||||
}
|
||||
|
||||
void HCIClass::debug(Stream& stream)
|
||||
{
|
||||
_debug = &stream;
|
||||
}
|
||||
|
||||
void HCIClass::noDebug()
|
||||
{
|
||||
_debug = NULL;
|
||||
}
|
||||
|
||||
int HCIClass::sendCommand(uint16_t opcode, uint8_t plen, void* parameters)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
HCITransport.write(txBuffer, sizeof(pktHdr) + plen);
|
||||
|
||||
_cmdCompleteOpcode = 0xffff;
|
||||
_cmdCompleteStatus = -1;
|
||||
|
||||
for (unsigned long start = millis(); _cmdCompleteOpcode != opcode && millis() < (start + 1000);) {
|
||||
poll();
|
||||
}
|
||||
|
||||
return _cmdCompleteStatus;
|
||||
}
|
||||
|
||||
void HCIClass::handleAclDataPkt(uint8_t /*plen*/, uint8_t pdata[])
|
||||
{
|
||||
struct __attribute__ ((packed)) HCIACLHdr {
|
||||
uint16_t handle;
|
||||
uint16_t dlen;
|
||||
uint16_t len;
|
||||
uint16_t cid;
|
||||
} *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(_aclPktBuffer, &_recvBuffer[1], sizeof(HCIACLHdr) + aclHdr->dlen - 4);
|
||||
} else {
|
||||
// copy next chunk into the buffer
|
||||
HCIACLHdr* aclBufferHeader = (HCIACLHdr*)_aclPktBuffer;
|
||||
|
||||
memcpy(&_aclPktBuffer[sizeof(HCIACLHdr) + aclBufferHeader->dlen - 4], &_recvBuffer[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, &_aclPktBuffer[sizeof(HCIACLHdr)]);
|
||||
} else {
|
||||
// use the recv buffer
|
||||
ATT.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &_recvBuffer[1 + sizeof(HCIACLHdr)]);
|
||||
}
|
||||
} else if (aclHdr->cid == SIGNALING_CID) {
|
||||
L2CAPSignaling.handleData(aclHdr->handle & 0x0fff, aclHdr->len, &_recvBuffer[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);
|
||||
}
|
||||
}
|
||||
|
||||
void HCIClass::handleNumCompPkts(uint16_t /*handle*/, uint16_t numPkts)
|
||||
{
|
||||
if (numPkts && _pendingPkt > numPkts) {
|
||||
_pendingPkt -= numPkts;
|
||||
} else {
|
||||
_pendingPkt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void HCIClass::handleEventPkt(uint8_t /*plen*/, uint8_t pdata[])
|
||||
{
|
||||
struct __attribute__ ((packed)) HCIEventHdr {
|
||||
uint8_t evt;
|
||||
uint8_t plen;
|
||||
} *eventHdr = (HCIEventHdr*)pdata;
|
||||
|
||||
if (eventHdr->evt == EVT_DISCONN_COMPLETE) {
|
||||
struct __attribute__ ((packed)) DisconnComplete {
|
||||
uint8_t status;
|
||||
uint16_t handle;
|
||||
uint8_t reason;
|
||||
} *disconnComplete = (DisconnComplete*)&pdata[sizeof(HCIEventHdr)];
|
||||
|
||||
ATT.removeConnection(disconnComplete->handle, disconnComplete->reason);
|
||||
L2CAPSignaling.removeConnection(disconnComplete->handle, disconnComplete->reason);
|
||||
|
||||
HCI.leSetAdvertiseEnable(0x01);
|
||||
} else if (eventHdr->evt == EVT_CMD_COMPLETE) {
|
||||
struct __attribute__ ((packed)) CmdComplete {
|
||||
uint8_t ncmd;
|
||||
uint16_t opcode;
|
||||
uint8_t status;
|
||||
} *cmdCompleteHeader = (CmdComplete*)&pdata[sizeof(HCIEventHdr)];
|
||||
|
||||
_cmdCompleteOpcode = cmdCompleteHeader->opcode;
|
||||
_cmdCompleteStatus = cmdCompleteHeader->status;
|
||||
_cmdResponseLen = pdata[1] - sizeof(CmdComplete);
|
||||
_cmdResponse = &pdata[sizeof(HCIEventHdr) + sizeof(CmdComplete)];
|
||||
|
||||
} else if (eventHdr->evt == EVT_CMD_STATUS) {
|
||||
struct __attribute__ ((packed)) CmdStatus {
|
||||
uint8_t status;
|
||||
uint8_t ncmd;
|
||||
uint16_t opcode;
|
||||
} *cmdStatusHeader = (CmdStatus*)&pdata[sizeof(HCIEventHdr)];
|
||||
|
||||
_cmdCompleteOpcode = cmdStatusHeader->opcode;
|
||||
_cmdCompleteStatus = cmdStatusHeader->status;
|
||||
_cmdResponseLen = 0;
|
||||
} else if (eventHdr->evt == EVT_NUM_COMP_PKTS) {
|
||||
uint8_t numHandles = pdata[sizeof(HCIEventHdr)];
|
||||
uint16_t* data = (uint16_t*)&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) {
|
||||
struct __attribute__ ((packed)) LeMetaEventHeader {
|
||||
uint8_t subevent;
|
||||
} *leMetaHeader = (LeMetaEventHeader*)&pdata[sizeof(HCIEventHdr)];
|
||||
|
||||
if (leMetaHeader->subevent == EVT_LE_CONN_COMPLETE) {
|
||||
struct __attribute__ ((packed)) EvtLeConnectionComplete {
|
||||
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;
|
||||
} *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) {
|
||||
struct __attribute__ ((packed)) EvtLeAdvertisingReport {
|
||||
uint8_t status;
|
||||
uint8_t type;
|
||||
uint8_t peerBdaddrType;
|
||||
uint8_t peerBdaddr[6];
|
||||
uint8_t eirLength;
|
||||
uint8_t eirData[31];
|
||||
} *leAdvertisingReport = (EvtLeAdvertisingReport*)&pdata[sizeof(HCIEventHdr) + sizeof(LeMetaEventHeader)];
|
||||
|
||||
if (leAdvertisingReport->status == 0x01) {
|
||||
// last byte is RSSI
|
||||
int8_t rssi = leAdvertisingReport->eirData[leAdvertisingReport->eirLength];
|
||||
|
||||
GAP.handleLeAdvertisingReport(leAdvertisingReport->type,
|
||||
leAdvertisingReport->peerBdaddrType,
|
||||
leAdvertisingReport->peerBdaddr,
|
||||
leAdvertisingReport->eirLength,
|
||||
leAdvertisingReport->eirData,
|
||||
rssi);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HCIClass::dumpPkt(const char* prefix, uint8_t plen, uint8_t pdata[])
|
||||
{
|
||||
if (_debug) {
|
||||
_debug->print(prefix);
|
||||
|
||||
for (uint8_t i = 0; i < plen; i++) {
|
||||
byte b = pdata[i];
|
||||
|
||||
if (b < 16) {
|
||||
_debug->print("0");
|
||||
}
|
||||
|
||||
_debug->print(b, HEX);
|
||||
}
|
||||
|
||||
_debug->println();
|
||||
_debug->flush();
|
||||
}
|
||||
}
|
||||
`
|
||||
|
@ -248,7 +248,7 @@ endif
|
||||
|
||||
SRC_ASF := $(addprefix asf4/$(CHIP_FAMILY)/, $(SRC_ASF))
|
||||
|
||||
SRC_C = \
|
||||
SRC_C += \
|
||||
audio_dma.c \
|
||||
background.c \
|
||||
bindings/samd/Clock.c \
|
||||
|
@ -319,7 +319,7 @@ SRC_COMMON_HAL_ALL = \
|
||||
|
||||
ifeq ($(CIRCUITPY_BLEIO_HCI),1)
|
||||
SRC_C += \
|
||||
common_hal/_bleio/hci.c \
|
||||
common-hal/_bleio/hci.c \
|
||||
|
||||
endif
|
||||
|
||||
|
@ -64,20 +64,20 @@
|
||||
//| advertisements and it can advertise its own data. Furthermore, Adapters can accept incoming
|
||||
//| connections and also initiate connections."""
|
||||
//|
|
||||
|
||||
//| def __init__(self, *, tx: Pin, rx: Pin, rts: Pin, cts: Pin, baudrate: int = 115200, buffer_size: int = 256):
|
||||
//| You cannot create an instance of `_bleio.Adapter`.
|
||||
//| Use `_bleio.adapter` to access the sole instance available."""
|
||||
//|
|
||||
//| On boards that do not have native BLE. You can use HCI co-processor.
|
||||
|
||||
//| def hci_init(self, *, tx: Pin, rx: Pin, rts: Pin, 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
|
||||
//| 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.
|
||||
//|
|
||||
#if CIRCUITPY_BLEIO_HCI
|
||||
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) {
|
||||
@ -114,10 +114,14 @@ mp_obj_t bleio_adapter_hci_init(mp_uint_t n_args, const mp_obj_t *pos_args, mp_m
|
||||
|
||||
common_hal_bleio_adapter_hci_init(&common_hal_bleio_adapter_obj, tx, rx, rts, cts,
|
||||
baudrate, buffer_size);
|
||||
|
||||
return mp_const_none;
|
||||
#else
|
||||
mp_raise_RuntimeError(translate("hci_init not available"));
|
||||
return mp_const_none;
|
||||
#endif // CIRCUITPY_BLEIO_HCI
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_hci_init_obj, 1, bleio_adapter_hci_init);
|
||||
#endif // CIRCUITPY_BLEIO_HCI
|
||||
|
||||
//|
|
||||
//| enabled: Any = ...
|
||||
|
@ -112,7 +112,10 @@ NORETURN void mp_raise_bleio_SecurityError(const compressed_string_t* fmt, ...)
|
||||
|
||||
// Called when _bleio is imported.
|
||||
STATIC mp_obj_t bleio___init__(void) {
|
||||
#if !CIRCUITPY_BLEIO_HCI
|
||||
// HCI cannot be enabled on import, because we need to setup the HCI adapter first.
|
||||
common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, true);
|
||||
#endif
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_0(bleio___init___obj, bleio___init__);
|
||||
|
Loading…
x
Reference in New Issue
Block a user