Skip to content

Commit 10a1f09

Browse files
committed
Add Cordio HCI transport for mbed
1 parent 9a6dbfa commit 10a1f09

File tree

4 files changed

+303
-1
lines changed

4 files changed

+303
-1
lines changed

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ sentence=[BETA] Enables BLE connectivity on the Arduino MKR WiFi 1010 and Arduin
66
paragraph=This library currently supports creating a BLE peripheral.
77
category=Communication
88
url=https://github.com/arduino-libraries/ArduinoBLE
9-
architectures=samd,megaavr
9+
architectures=samd,megaavr,mbed
1010
includes=ArduinoBLE.h

src/utility/HCICordioTransport.cpp

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
/*
2+
This file is part of the ArduinoBLE library.
3+
Copyright (c) 2019 Arduino SA. All rights reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#ifdef ARDUINO_ARCH_MBED
21+
22+
#include <driver/CordioHCITransportDriver.h>
23+
#include <driver/CordioHCIDriver.h>
24+
25+
#include <mbed_config.h>
26+
27+
// Parts of this file are based on: https://github.com/ARMmbed/mbed-os-cordio-hci-passthrough/pull/2
28+
// With permission from the Arm Mbed team to re-license
29+
30+
#if CORDIO_ZERO_COPY_HCI
31+
#include <wsf_types.h>
32+
#include <wsf_buf.h>
33+
#include <wsf_msg.h>
34+
#include <wsf_os.h>
35+
#include <wsf_buf.h>
36+
#include <wsf_timer.h>
37+
38+
/* avoid many small allocs (and WSF doesn't have smaller buffers) */
39+
#define MIN_WSF_ALLOC (16)
40+
#endif //CORDIO_ZERO_COPY_HCI
41+
42+
#include "HCICordioTransport.h"
43+
44+
extern ble::vendor::cordio::CordioHCIDriver& ble_cordio_get_hci_driver();
45+
46+
namespace ble {
47+
namespace vendor {
48+
namespace cordio {
49+
struct CordioHCIHook {
50+
static CordioHCIDriver& getDriver() {
51+
return ble_cordio_get_hci_driver();
52+
}
53+
54+
static CordioHCITransportDriver& getTransportDriver() {
55+
return getDriver()._transport_driver;
56+
}
57+
58+
static void setDataReceivedHandler(void (*handler)(uint8_t*, uint8_t)) {
59+
getTransportDriver().set_data_received_handler(handler);
60+
}
61+
};
62+
}
63+
}
64+
}
65+
66+
using ble::vendor::cordio::CordioHCIHook;
67+
68+
#if CORDIO_ZERO_COPY_HCI
69+
extern uint8_t *SystemHeapStart;
70+
extern uint32_t SystemHeapSize;
71+
72+
void init_wsf(ble::vendor::cordio::buf_pool_desc_t& buf_pool_desc) {
73+
static bool init = false;
74+
75+
if (init) {
76+
return;
77+
}
78+
init = true;
79+
80+
// use the buffer for the WSF heap
81+
SystemHeapStart = buf_pool_desc.buffer_memory;
82+
SystemHeapSize = buf_pool_desc.buffer_size;
83+
84+
// Initialize buffers with the ones provided by the HCI driver
85+
uint16_t bytes_used = WsfBufInit(
86+
buf_pool_desc.pool_count,
87+
(wsfBufPoolDesc_t*)buf_pool_desc.pool_description
88+
);
89+
90+
// Raise assert if not enough memory was allocated
91+
MBED_ASSERT(bytes_used != 0);
92+
93+
SystemHeapStart += bytes_used;
94+
SystemHeapSize -= bytes_used;
95+
96+
WsfTimerInit();
97+
}
98+
99+
100+
extern "C" void wsf_mbed_ble_signal_event(void)
101+
{
102+
// do nothing
103+
}
104+
#endif //CORDIO_ZERO_COPY_HCI
105+
106+
static void bleLoop()
107+
{
108+
#if CORDIO_ZERO_COPY_HCI
109+
uint64_t last_update_us = 0;
110+
mbed::LowPowerTimer timer;
111+
112+
while (true) {
113+
last_update_us += (uint64_t) timer.read_high_resolution_us();
114+
timer.reset();
115+
116+
uint64_t last_update_ms = (last_update_us / 1000);
117+
wsfTimerTicks_t wsf_ticks = (last_update_ms / WSF_MS_PER_TICK);
118+
119+
if (wsf_ticks > 0) {
120+
WsfTimerUpdate(wsf_ticks);
121+
last_update_us -= (last_update_ms * 1000);
122+
}
123+
124+
wsfOsDispatcher();
125+
126+
bool sleep = false;
127+
{
128+
/* call needs interrupts disabled */
129+
mbed::CriticalSectionLock critical_section;
130+
if (wsfOsReadyToSleep()) {
131+
sleep = true;
132+
}
133+
}
134+
135+
uint64_t time_spent = (uint64_t) timer.read_high_resolution_us();
136+
137+
/* don't bother sleeping if we're already past tick */
138+
if (sleep && (WSF_MS_PER_TICK * 1000 > time_spent)) {
139+
/* sleep to maintain constant tick rate */
140+
wait_us(WSF_MS_PER_TICK * 1000 - time_spent);
141+
}
142+
}
143+
#else
144+
while(true) {
145+
rtos::Thread::wait(osWaitForever);
146+
}
147+
#endif // CORDIO_ZERO_COPY_HCI
148+
}
149+
150+
rtos::Thread bleLoopThread;
151+
152+
153+
HCICordioTransportClass::HCICordioTransportClass()
154+
{
155+
}
156+
157+
HCICordioTransportClass::~HCICordioTransportClass()
158+
{
159+
}
160+
161+
int HCICordioTransportClass::begin()
162+
{
163+
_rxBuf.clear();
164+
165+
#if CORDIO_ZERO_COPY_HCI
166+
ble::vendor::cordio::buf_pool_desc_t bufPoolDesc = CordioHCIHook::getDriver().get_buffer_pool_description();
167+
init_wsf(bufPoolDesc);
168+
#endif
169+
170+
CordioHCIHook::getDriver().initialize();
171+
bleLoopThread.start(bleLoop);
172+
173+
CordioHCIHook::setDataReceivedHandler(HCICordioTransportClass::onDataReceived);
174+
175+
return 1;
176+
}
177+
178+
void HCICordioTransportClass::end()
179+
{
180+
bleLoopThread.terminate();
181+
182+
CordioHCIHook::getDriver().terminate();
183+
}
184+
185+
void HCICordioTransportClass::wait(unsigned long timeout)
186+
{
187+
for (unsigned long start = millis(); (millis() - start) < timeout;) {
188+
if (available()) {
189+
break;
190+
}
191+
}
192+
}
193+
194+
int HCICordioTransportClass::available()
195+
{
196+
return _rxBuf.available();
197+
}
198+
199+
int HCICordioTransportClass::peek()
200+
{
201+
return _rxBuf.peek();
202+
}
203+
204+
int HCICordioTransportClass::read()
205+
{
206+
return _rxBuf.read_char();
207+
}
208+
209+
size_t HCICordioTransportClass::write(const uint8_t* data, size_t length)
210+
{
211+
uint8_t packetLength = length - 1;
212+
uint8_t packetType = data[0];
213+
214+
#if CORDIO_ZERO_COPY_HCI
215+
uint8_t* packet = (uint8_t*)WsfMsgAlloc(max(packetLength, MIN_WSF_ALLOC));
216+
217+
memcpy(packet, &data[1], packetLength);
218+
219+
return CordioHCIHook::getTransportDriver().write(packetType, packetLength, packet);
220+
#else
221+
return CordioHCIHook::.getTransportDriver().write(packetType, packetLength, &data[1]);
222+
#endif
223+
}
224+
225+
void HCICordioTransportClass::handleRxData(uint8_t* data, uint8_t len)
226+
{
227+
if (_rxBuf.availableForStore() < len) {
228+
// drop!
229+
return;
230+
}
231+
232+
for (int i = 0; i < len; i++) {
233+
_rxBuf.store_char(data[i]);
234+
}
235+
}
236+
237+
HCICordioTransportClass HCICordioTransport;
238+
HCITransportInterface& HCITransport = HCICordioTransport;
239+
240+
void HCICordioTransportClass::onDataReceived(uint8_t* data, uint8_t len)
241+
{
242+
HCICordioTransport.handleRxData(data, len);
243+
}
244+
245+
#endif

src/utility/HCICordioTransport.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
This file is part of the ArduinoBLE library.
3+
Copyright (c) 2019 Arduino SA. All rights reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#ifndef _HCI_CORDIO_TRANSPORT_H_
21+
#define _HCI_CORDIO_TRANSPORT_H_
22+
23+
#include <string.h>
24+
25+
#include "api/RingBuffer.h"
26+
27+
#include "HCITransport.h"
28+
29+
class HCICordioTransportClass : public HCITransportInterface {
30+
public:
31+
HCICordioTransportClass();
32+
virtual ~HCICordioTransportClass();
33+
34+
virtual int begin();
35+
virtual void end();
36+
37+
virtual void wait(unsigned long timeout);
38+
39+
virtual int available();
40+
virtual int peek();
41+
virtual int read();
42+
43+
virtual size_t write(const uint8_t* data, size_t length);
44+
45+
private:
46+
static void onDataReceived(uint8_t* data, uint8_t len);
47+
void handleRxData(uint8_t* data, uint8_t len);
48+
49+
private:
50+
RingBufferN<256> _rxBuf;
51+
};
52+
53+
#endif

src/utility/HCIUartTransport.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1818
*/
1919

20+
#ifndef ARDUINO_ARCH_MBED
21+
2022
#include "HCIUartTransport.h"
2123

2224
#if defined(ARDUINO_SAMD_MKRWIFI1010) || defined(ARDUINO_AVR_UNO_WIFI_REV2)
@@ -93,3 +95,5 @@ HCIUartTransportClass HCIUartTransport(SerialHCI, 119600);
9395
HCIUartTransportClass HCIUartTransport(SerialHCI, 912600);
9496
#endif
9597
HCITransportInterface& HCITransport = HCIUartTransport;
98+
99+
#endif

0 commit comments

Comments
 (0)