Skip to content

Commit cf79316

Browse files
committed
nrf: Fix ble uart using the new API
1 parent d5a71a4 commit cf79316

File tree

6 files changed

+169
-235
lines changed

6 files changed

+169
-235
lines changed

ports/nrf/bluetooth/ble_uart.c

Lines changed: 127 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* The MIT License (MIT)
55
*
66
* Copyright (c) 2017 Glenn Ruben Bakke
7+
* Copyright (c) 2018 Artur Pacholec
78
*
89
* Permission is hereby granted, free of charge, to any person obtaining a copy
910
* of this software and associated documentation files (the "Software"), to deal
@@ -24,252 +25,172 @@
2425
* THE SOFTWARE.
2526
*/
2627

27-
#if BLUETOOTH_SD
28-
2928
#include <string.h>
29+
30+
#include "ble.h"
3031
#include "ble_uart.h"
3132
#include "ringbuffer.h"
3233
#include "py/mphal.h"
34+
#include "py/runtime.h"
3335
#include "lib/utils/interrupt_char.h"
36+
#include "shared-bindings/bleio/Adapter.h"
37+
#include "shared-bindings/bleio/Characteristic.h"
38+
#include "shared-bindings/bleio/Device.h"
39+
#include "shared-bindings/bleio/Service.h"
40+
#include "shared-bindings/bleio/UUID.h"
3441

35-
#if MICROPY_PY_BLE_NUS
42+
#if (MICROPY_PY_BLE_NUS == 1)
3643

37-
static bleio_uuid_obj_t uuid_obj_service = {
38-
.base.type = &bleio_uuid_type,
39-
.type = UUID_128_BIT,
40-
.value = {0x01, 0x00}
41-
};
44+
static const char default_name[] = "CP-REPL"; // max 8 chars or uuid won't fit in adv data
45+
static const char NUS_UUID[] = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
4246

43-
static bleio_uuid_obj_t uuid_obj_char_tx = {
44-
.base.type = &bleio_uuid_type,
45-
.type = UUID_128_BIT,
46-
.value = {0x03, 0x00}
47-
};
47+
#define NUS_RX_UUID 0x0002
48+
#define NUS_TX_UUID 0x0003
49+
#define BUFFER_SIZE 128
4850

49-
static bleio_uuid_obj_t uuid_obj_char_rx = {
50-
.base.type = &bleio_uuid_type,
51-
.type = UUID_128_BIT,
52-
.value = {0x02, 0x00}
53-
};
51+
ringBuffer_typedef(uint8_t, ringbuffer_t);
5452

55-
static ubluepy_service_obj_t ble_uart_service = {
56-
.base.type = &ubluepy_service_type,
57-
.p_uuid = &uuid_obj_service,
58-
.type = UBLUEPY_SERVICE_PRIMARY
59-
};
53+
static bleio_device_obj_t m_device;
54+
static bleio_service_obj_t *m_nus;
55+
static bleio_characteristic_obj_t *m_tx_chara;
56+
static bleio_characteristic_obj_t *m_rx_chara;
6057

61-
static ubluepy_characteristic_obj_t ble_uart_char_rx = {
62-
.base.type = &ubluepy_characteristic_type,
63-
.p_uuid = &uuid_obj_char_rx,
64-
.props = UBLUEPY_PROP_WRITE | UBLUEPY_PROP_WRITE_WO_RESP,
65-
.attrs = 0,
66-
};
58+
static volatile bool m_cccd_enabled;
6759

68-
static ubluepy_characteristic_obj_t ble_uart_char_tx = {
69-
.base.type = &ubluepy_characteristic_type,
70-
.p_uuid = &uuid_obj_char_tx,
71-
.props = UBLUEPY_PROP_NOTIFY,
72-
.attrs = UBLUEPY_ATTR_CCCD,
60+
static uint8_t m_rx_ring_buffer_data[BUFFER_SIZE];
61+
static ringbuffer_t m_rx_ring_buffer = {
62+
.size = sizeof(m_rx_ring_buffer_data) + 1,
63+
.elems = m_rx_ring_buffer_data,
7364
};
7465

75-
static ubluepy_peripheral_obj_t ble_uart_peripheral = {
76-
.base.type = &ubluepy_peripheral_type,
77-
.conn_handle = 0xFFFF,
78-
};
66+
STATIC void on_ble_evt(ble_evt_t *ble_evt, void *param) {
67+
switch (ble_evt->header.evt_id) {
68+
case BLE_GAP_EVT_DISCONNECTED:
69+
{
70+
mp_obj_t device_obj = MP_OBJ_FROM_PTR(&m_device);
71+
mp_call_function_0(mp_load_attr(device_obj, qstr_from_str("start_advertising")));
72+
break;
73+
}
7974

80-
static volatile bool m_cccd_enabled;
81-
static volatile bool m_connected;
75+
case BLE_GATTS_EVT_WRITE:
76+
{
77+
ble_gatts_evt_write_t *write = &ble_evt->evt.gatts_evt.params.write;
78+
79+
if (write->handle == m_tx_chara->cccd_handle) {
80+
m_cccd_enabled = true;
81+
} else if (write->handle == m_rx_chara->handle) {
82+
for (size_t i = 0; i < write->len; ++i) {
83+
#if MICROPY_KBD_EXCEPTION
84+
if (write->data[i] == mp_interrupt_char) {
85+
mp_keyboard_interrupt();
86+
} else
87+
#endif
88+
{
89+
bufferWrite(&m_rx_ring_buffer, write->data[i]);
90+
}
91+
}
92+
}
93+
}
94+
}
95+
}
8296

83-
ringBuffer_typedef(uint8_t, ringbuffer_t);
97+
void ble_uart_init(void) {
98+
mp_obj_t device_obj = MP_OBJ_FROM_PTR(&m_device);
99+
m_device.base.type = &bleio_device_type;
100+
m_device.service_list = mp_obj_new_list(0, NULL);
101+
m_device.notif_handler = mp_const_none;
102+
m_device.conn_handler = mp_const_none;
103+
m_device.conn_handle = 0xFFFF;
104+
m_device.is_peripheral = true;
105+
m_device.name = mp_obj_new_str(default_name, strlen(default_name), false);
106+
common_hal_bleio_adapter_get_address(&m_device.address);
107+
108+
mp_obj_t nus_uuid_str = mp_obj_new_str(NUS_UUID, strlen(NUS_UUID), false);
109+
mp_obj_t nus_uuid_obj = bleio_uuid_type.make_new(&bleio_uuid_type, 1, 0, &nus_uuid_str);
110+
mp_obj_t nus_obj = bleio_service_type.make_new(&bleio_service_type, 1, 0, &nus_uuid_obj);
111+
m_nus = MP_OBJ_TO_PTR(nus_obj);
112+
mp_call_function_1(mp_load_attr(device_obj, qstr_from_str("add_service")), nus_obj);
113+
114+
mp_obj_t tx_uuid_int = mp_obj_new_int(NUS_TX_UUID);
115+
mp_obj_t tx_uuid_obj = bleio_uuid_type.make_new(&bleio_uuid_type, 1, 0, &tx_uuid_int);
116+
mp_obj_t tx_obj = bleio_characteristic_type.make_new(&bleio_characteristic_type, 1, 0, &tx_uuid_obj);
117+
m_tx_chara = MP_OBJ_TO_PTR(tx_obj);
118+
m_tx_chara->uuid->type = UUID_TYPE_128BIT;
119+
m_tx_chara->uuid->uuid_vs_idx = m_nus->uuid->uuid_vs_idx;
120+
m_tx_chara->props.notify = true;
121+
mp_call_function_1(mp_load_attr(nus_obj, qstr_from_str("add_characteristic")), tx_obj);
122+
123+
mp_obj_t rx_uuid_int = mp_obj_new_int(NUS_RX_UUID);
124+
mp_obj_t rx_uuid_obj = bleio_uuid_type.make_new(&bleio_uuid_type, 1, 0, &rx_uuid_int);
125+
mp_obj_t rx_obj = bleio_characteristic_type.make_new(&bleio_characteristic_type, 1, 0, &rx_uuid_obj);
126+
m_rx_chara = MP_OBJ_TO_PTR(rx_obj);
127+
m_rx_chara->uuid->type = UUID_TYPE_128BIT;
128+
m_rx_chara->uuid->uuid_vs_idx = m_nus->uuid->uuid_vs_idx;
129+
m_rx_chara->props.write = true;
130+
m_rx_chara->props.write_wo_resp = true;
131+
mp_call_function_1(mp_load_attr(nus_obj, qstr_from_str("add_characteristic")), rx_obj);
132+
133+
mp_call_function_0(mp_load_attr(device_obj, qstr_from_str("start_advertising")));
134+
135+
ble_drv_add_event_handler(on_ble_evt, &m_device);
84136

85-
static ringbuffer_t m_rx_ring_buffer;
86-
static ringbuffer_t * mp_rx_ring_buffer = &m_rx_ring_buffer;
87-
static uint8_t m_rx_ring_buffer_data[128];
137+
m_cccd_enabled = false;
88138

89-
static ubluepy_advertise_data_t m_adv_data_uart_service;
139+
while (!m_cccd_enabled) {
140+
#ifdef MICROPY_VM_HOOK_LOOP
141+
MICROPY_VM_HOOK_LOOP
142+
#endif
143+
}
144+
}
90145

91-
#if BLUETOOTH_WEBBLUETOOTH_REPL
92-
static ubluepy_advertise_data_t m_adv_data_eddystone_url;
93-
#endif // BLUETOOTH_WEBBLUETOOTH_REPL
146+
bool ble_uart_connected(void) {
147+
return (m_device.conn_handle != BLE_CONN_HANDLE_INVALID);
148+
}
94149

95-
int mp_hal_stdin_rx_chr(void) {
96-
while (isBufferEmpty(mp_rx_ring_buffer)) {
97-
;
150+
char ble_uart_rx_chr(void) {
151+
while (isBufferEmpty(&m_rx_ring_buffer)) {
152+
#ifdef MICROPY_VM_HOOK_LOOP
153+
MICROPY_VM_HOOK_LOOP
154+
#endif
98155
}
99156

100157
uint8_t byte;
101-
bufferRead(mp_rx_ring_buffer, byte);
158+
bufferRead(&m_rx_ring_buffer, byte);
102159
return (int)byte;
103160
}
104161

105-
bool mp_hal_stdin_any(void) {
106-
return !isBufferEmpty(mp_rx_ring_buffer);
162+
bool ble_uart_stdin_any(void) {
163+
return !isBufferEmpty(&m_rx_ring_buffer);
164+
}
165+
166+
void ble_uart_stdout_tx_str(const char *text) {
167+
mp_hal_stdout_tx_strn(text, strlen(text));
168+
}
169+
170+
int mp_hal_stdin_rx_chr(void) {
171+
return ble_uart_rx_chr();
107172
}
108173

109174
void mp_hal_stdout_tx_strn(const char *str, size_t len) {
110-
uint8_t *buf = (uint8_t *)str;
111175
size_t send_len;
112176

113177
while (len > 0) {
114-
if (len >= 20) {
115-
send_len = 20; // (GATT_MTU_SIZE_DEFAULT - 3)
178+
if (len >= BLE_GATT_ATT_MTU_DEFAULT - 3) {
179+
send_len = (BLE_GATT_ATT_MTU_DEFAULT - 3);
116180
} else {
117181
send_len = len;
118182
}
119183

120-
ubluepy_characteristic_obj_t * p_char = &ble_uart_char_tx;
184+
mp_buffer_info_t bufinfo = {
185+
.buf = (uint8_t*)str,
186+
.len = send_len,
187+
};
121188

122-
ble_drv_attr_s_notify(p_char->p_service->p_periph->conn_handle,
123-
p_char->handle,
124-
send_len,
125-
buf);
189+
common_hal_bleio_characteristic_write_value(m_tx_chara, &bufinfo);
126190

127191
len -= send_len;
128-
buf += send_len;
192+
str += send_len;
129193
}
130194
}
131195

132-
void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len) {
133-
mp_hal_stdout_tx_strn(str, len);
134-
}
135-
136-
STATIC void gap_event_handler(mp_obj_t self_in, uint16_t event_id, uint16_t conn_handle, uint16_t length, uint8_t * data) {
137-
ubluepy_peripheral_obj_t * self = MP_OBJ_TO_PTR(self_in);
138-
139-
if (event_id == 16) { // connect event
140-
self->conn_handle = conn_handle;
141-
m_connected = true;
142-
} else if (event_id == 17) { // disconnect event
143-
self->conn_handle = 0xFFFF; // invalid connection handle
144-
m_connected = false;
145-
ble_uart_advertise();
146-
}
147-
}
148-
149-
STATIC void gatts_event_handler(mp_obj_t self_in, uint16_t event_id, uint16_t attr_handle, uint16_t length, uint8_t * data) {
150-
ubluepy_peripheral_obj_t * self = MP_OBJ_TO_PTR(self_in);
151-
(void)self;
152-
153-
if (event_id == 80) { // gatts write
154-
if (ble_uart_char_tx.cccd_handle == attr_handle) {
155-
m_cccd_enabled = true;
156-
} else if (ble_uart_char_rx.handle == attr_handle) {
157-
for (uint16_t i = 0; i < length; i++) {
158-
#if MICROPY_KBD_EXCEPTION
159-
if (data[i] == mp_interrupt_char) {
160-
mp_keyboard_interrupt();
161-
} else
162-
#endif
163-
{
164-
bufferWrite(mp_rx_ring_buffer, data[i]);
165-
}
166-
}
167-
}
168-
}
169-
}
170-
171-
void ble_uart_init0(void) {
172-
uint8_t base_uuid[] = {0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E};
173-
uint8_t uuid_vs_idx;
174-
175-
(void)ble_drv_uuid_add_vs(base_uuid, &uuid_vs_idx);
176-
177-
uuid_obj_service.uuid_vs_idx = uuid_vs_idx;
178-
uuid_obj_char_tx.uuid_vs_idx = uuid_vs_idx;
179-
uuid_obj_char_rx.uuid_vs_idx = uuid_vs_idx;
180-
181-
(void)ble_drv_service_add(&ble_uart_service);
182-
ble_uart_service.char_list = mp_obj_new_list(0, NULL);
183-
184-
// add TX characteristic
185-
ble_uart_char_tx.service_handle = ble_uart_service.handle;
186-
bool retval = ble_drv_characteristic_add(&ble_uart_char_tx);
187-
if (retval) {
188-
ble_uart_char_tx.p_service = &ble_uart_service;
189-
}
190-
mp_obj_list_append(ble_uart_service.char_list, MP_OBJ_FROM_PTR(&ble_uart_char_tx));
191-
192-
// add RX characteristic
193-
ble_uart_char_rx.service_handle = ble_uart_service.handle;
194-
retval = ble_drv_characteristic_add(&ble_uart_char_rx);
195-
if (retval) {
196-
ble_uart_char_rx.p_service = &ble_uart_service;
197-
}
198-
mp_obj_list_append(ble_uart_service.char_list, MP_OBJ_FROM_PTR(&ble_uart_char_rx));
199-
200-
// setup the peripheral
201-
ble_uart_peripheral.service_list = mp_obj_new_list(0, NULL);
202-
mp_obj_list_append(ble_uart_peripheral.service_list, MP_OBJ_FROM_PTR(&ble_uart_service));
203-
ble_uart_service.p_periph = &ble_uart_peripheral;
204-
205-
ble_drv_gap_event_handler_set(MP_OBJ_FROM_PTR(&ble_uart_peripheral), gap_event_handler);
206-
ble_drv_gatts_event_handler_set(MP_OBJ_FROM_PTR(&ble_uart_peripheral), gatts_event_handler);
207-
208-
ble_uart_peripheral.conn_handle = 0xFFFF;
209-
210-
char device_name[] = "mpus";
211-
212-
mp_obj_t service_list = mp_obj_new_list(0, NULL);
213-
mp_obj_list_append(service_list, MP_OBJ_FROM_PTR(&ble_uart_service));
214-
215-
mp_obj_t * services = NULL;
216-
mp_uint_t num_services;
217-
mp_obj_get_array(service_list, &num_services, &services);
218-
219-
m_adv_data_uart_service.p_services = services;
220-
m_adv_data_uart_service.num_of_services = num_services;
221-
m_adv_data_uart_service.p_device_name = (uint8_t *)device_name;
222-
m_adv_data_uart_service.device_name_len = strlen(device_name);
223-
m_adv_data_uart_service.connectable = true;
224-
m_adv_data_uart_service.p_data = NULL;
225-
226-
#if BLUETOOTH_WEBBLUETOOTH_REPL
227-
// for now point eddystone URL to https://goo.gl/x46FES => https://glennrub.github.io/webbluetooth/micropython/repl/
228-
static uint8_t eddystone_url_data[27] = {0x2, 0x1, 0x6,
229-
0x3, 0x3, 0xaa, 0xfe,
230-
19, 0x16, 0xaa, 0xfe, 0x10, 0xee, 0x3, 'g', 'o', 'o', '.', 'g', 'l', '/', 'x', '4', '6', 'F', 'E', 'S'};
231-
// eddystone url adv data
232-
m_adv_data_eddystone_url.p_data = eddystone_url_data;
233-
m_adv_data_eddystone_url.data_len = sizeof(eddystone_url_data);
234-
m_adv_data_eddystone_url.connectable = false;
235-
#endif
236-
237-
m_cccd_enabled = false;
238-
239-
// initialize ring buffer
240-
m_rx_ring_buffer.size = sizeof(m_rx_ring_buffer_data) + 1;
241-
m_rx_ring_buffer.start = 0;
242-
m_rx_ring_buffer.end = 0;
243-
m_rx_ring_buffer.elems = m_rx_ring_buffer_data;
244-
245-
m_connected = false;
246-
247-
ble_uart_advertise();
248-
}
249-
250-
void ble_uart_advertise(void) {
251-
#if BLUETOOTH_WEBBLUETOOTH_REPL
252-
while (!m_connected) {
253-
(void)ble_drv_advertise_data(&m_adv_data_uart_service);
254-
mp_hal_delay_ms(500);
255-
(void)ble_drv_advertise_data(&m_adv_data_eddystone_url);
256-
mp_hal_delay_ms(500);
257-
}
258-
259-
ble_drv_advertise_stop();
260-
#else
261-
(void)ble_drv_advertise_data(&m_adv_data_uart_service);
262-
#endif // BLUETOOTH_WEBBLUETOOTH_REPL
263-
}
264-
265-
bool ble_uart_connected(void) {
266-
return (m_connected);
267-
}
268-
269-
bool ble_uart_enabled(void) {
270-
return (m_cccd_enabled);
271-
}
272-
273196
#endif // MICROPY_PY_BLE_NUS
274-
275-
#endif // BLUETOOTH_SD

0 commit comments

Comments
 (0)