1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <assert.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24
25 #include "sysinit/sysinit.h"
26 #include "host/ble_hs.h"
27 #include "host/ble_uuid.h"
28 #include "bleuart/bleuart.h"
29 #include "os/endian.h"
30
31 #include <rtthread.h>
32 #include <rtdevice.h>
33 #include <rthw.h>
34
35 #define MYNEWT_VAL_BLEUART_MAX_INPUT 128
36
37 #define ESC_KEY 0x1B
38 #define BACKSPACE_KEY 0x08
39 #define DELECT_KEY 0x7F
40
41 static void bleuart_deinit(void);
42
43 struct bleuart_console
44 {
45 struct rt_semaphore *rx_end;
46 struct rt_ringbuffer *rx_fifo;
47 rt_err_t (*old_rx_ind)(rt_device_t dev, rt_size_t size);
48 };
49
50 /* ble uart attr read handle */
51 uint16_t g_bleuart_attr_read_handle;
52
53 /* ble uart attr write handle */
54 uint16_t g_bleuart_attr_write_handle;
55
56 /* Pointer to a console buffer */
57 char *console_buf;
58
59 /* ble uart console */
60 static struct bleuart_console bleuart;
61
62 uint16_t g_console_conn_handle;
63 /**
64 * The vendor specific "bleuart" service consists of one write no-rsp characteristic
65 * and one notification only read charateristic
66 * o "write no-rsp": a single-byte characteristic that can be written only
67 * over a non-encrypted connection
68 * o "read": a single-byte characteristic that can always be read only via
69 * notifications
70 */
71
72 /* {6E400001-B5A3-F393-E0A9-E50E24DCCA9E} */
73 const ble_uuid128_t gatt_svr_svc_uart_uuid =
74 BLE_UUID128_INIT(0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0,
75 0x93, 0xf3, 0xa3, 0xb5, 0x01, 0x00, 0x40, 0x6e);
76
77 /* {6E400002-B5A3-F393-E0A9-E50E24DCCA9E} */
78 const ble_uuid128_t gatt_svr_chr_uart_write_uuid =
79 BLE_UUID128_INIT(0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0,
80 0x93, 0xf3, 0xa3, 0xb5, 0x02, 0x00, 0x40, 0x6e);
81
82
83 /* {6E400003-B5A3-F393-E0A9-E50E24DCCA9E} */
84 const ble_uuid128_t gatt_svr_chr_uart_read_uuid =
85 BLE_UUID128_INIT(0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0,
86 0x93, 0xf3, 0xa3, 0xb5, 0x03, 0x00, 0x40, 0x6e);
87
88 static int
89 gatt_svr_chr_access_uart_write(uint16_t conn_handle, uint16_t attr_handle,
90 struct ble_gatt_access_ctxt *ctxt, void *arg);
91
92 static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
93 {
94 /* Service: uart */
95 .type = BLE_GATT_SVC_TYPE_PRIMARY,
96 .uuid = &gatt_svr_svc_uart_uuid.u,
97 .characteristics = (struct ble_gatt_chr_def[]) { {
98 .uuid = &gatt_svr_chr_uart_read_uuid.u,
99 .val_handle = &g_bleuart_attr_read_handle,
100 .access_cb = gatt_svr_chr_access_uart_write,
101 .flags = BLE_GATT_CHR_F_NOTIFY,
102 }, {
103 /* Characteristic: Write */
104 .uuid = &gatt_svr_chr_uart_write_uuid.u,
105 .access_cb = gatt_svr_chr_access_uart_write,
106 .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_NO_RSP,
107 .val_handle = &g_bleuart_attr_write_handle,
108 }, {
109 0, /* No more characteristics in this service */
110 } },
111 },
112
113 {
114 0, /* No more services */
115 },
116 };
117
118 static int
gatt_svr_chr_access_uart_write(uint16_t conn_handle,uint16_t attr_handle,struct ble_gatt_access_ctxt * ctxt,void * arg)119 gatt_svr_chr_access_uart_write(uint16_t conn_handle, uint16_t attr_handle,
120 struct ble_gatt_access_ctxt *ctxt, void *arg)
121 {
122 struct os_mbuf *om = ctxt->om;
123 switch (ctxt->op) {
124 case BLE_GATT_ACCESS_OP_WRITE_CHR:
125 while(om) {
126 rt_device_write(rt_console_get_device(), 0, (char *)om->om_data, om->om_len);
127 om = SLIST_NEXT(om, om_next);
128 }
129 rt_device_write(rt_console_get_device(), 0, "\n", 1);
130 return 0;
131 default:
132 assert(0);
133 return BLE_ATT_ERR_UNLIKELY;
134 }
135 }
136
137 /**
138 * bleuart GATT server initialization
139 *
140 * @param eventq
141 * @return 0 on success; non-zero on failure
142 */
143 int
bleuart_gatt_svr_init(void)144 bleuart_gatt_svr_init(void)
145 {
146 int rc;
147
148 rc = ble_gatts_count_cfg(gatt_svr_svcs);
149 if (rc != 0) {
150 goto err;
151 }
152
153 rc = ble_gatts_add_svcs(gatt_svr_svcs);
154 if (rc != 0) {
155 return rc;
156 }
157
158 err:
159 return rc;
160 }
161
bleuart_rx_ind(rt_device_t dev,rt_size_t size)162 static rt_err_t bleuart_rx_ind(rt_device_t dev, rt_size_t size)
163 {
164 uint8_t ch;
165 int i;
166
167 for(i = 0; i < size; i++)
168 {
169 /* read a char */
170 if (rt_device_read(dev, 0, &ch, 1))
171 {
172 rt_ringbuffer_put_force(bleuart.rx_fifo, &ch, 1);
173 rt_sem_release(bleuart.rx_end);
174 }
175 }
176
177 return RT_EOK;
178 }
179
bleuart_read(void)180 static uint8_t bleuart_read(void)
181 {
182 uint8_t ch;
183
184 rt_sem_take(bleuart.rx_end, RT_WAITING_FOREVER);
185 rt_ringbuffer_getchar(bleuart.rx_fifo, &ch);
186
187 return ch;
188 }
189
190 /**
191 * Reads console and sends data over BLE
192 */
bleuart_uart_proc(void)193 static void bleuart_uart_proc(void)
194 {
195 int off = 0;
196 char ch;
197 struct os_mbuf *om;
198
199 rt_kprintf("======== Welcome to enter bluetooth uart mode ========\n");
200 rt_kprintf("Press 'ESC' to exit.\n");
201
202 /* process user input */
203 while (ESC_KEY != (ch = bleuart_read()))
204 {
205 if(ch != '\r' && ch != '\n')
206 {
207 if(ch == BACKSPACE_KEY || ch == DELECT_KEY)
208 {
209 if(off)
210 {
211 console_buf[off--] = 0;
212 rt_kprintf("\b \b");
213 }
214 }
215 else
216 {
217 console_buf[off++] = ch;
218 rt_kprintf("%c", ch);
219 continue;
220 }
221 }
222
223 console_buf[off] = '\0';
224 rt_kprintf("\n");
225 om = ble_hs_mbuf_from_flat(console_buf, off);
226 if (!om) {
227 return;
228 }
229 ble_gattc_notify_custom(g_console_conn_handle,
230 g_bleuart_attr_read_handle, om);
231 off = 0;
232 }
233
234 bleuart_deinit();
235 }
236
237 /**
238 * Sets the global connection handle
239 *
240 * @param connection handle
241 */
242 void
bleuart_set_conn_handle(uint16_t conn_handle)243 bleuart_set_conn_handle(uint16_t conn_handle) {
244 g_console_conn_handle = conn_handle;
245 }
246
bleuart_deinit(void)247 static void bleuart_deinit(void)
248 {
249 rt_base_t level;
250 rt_device_t uart_console;
251
252 level = rt_hw_interrupt_disable();
253 uart_console = rt_console_get_device();
254 if(uart_console)
255 {
256 rt_device_set_rx_indicate(uart_console, bleuart.old_rx_ind);
257 }
258 rt_hw_interrupt_enable(level);
259
260 if (console_buf != RT_NULL)
261 {
262 rt_free(console_buf);
263 console_buf = RT_NULL;
264 }
265
266 if (bleuart.rx_end != RT_NULL)
267 {
268 rt_sem_delete(bleuart.rx_end);
269 bleuart.rx_end = RT_NULL;
270 }
271
272 if (bleuart.rx_fifo != RT_NULL)
273 {
274 rt_ringbuffer_destroy(bleuart.rx_fifo);
275 bleuart.rx_fifo = RT_NULL;
276 }
277 }
278
279 /**
280 * BLEuart console initialization
281 *
282 * @param Maximum input
283 */
bleuart_init(void)284 int bleuart_init(void)
285 {
286 int rc;
287 rt_base_t level;
288 rt_device_t uart_console;
289
290 /* Ensure this function only gets called by sysinit. */
291 SYSINIT_ASSERT_ACTIVE();
292
293 /* create buffer for send */
294 console_buf = rt_malloc(MYNEWT_VAL(BLEUART_MAX_INPUT));
295 if (console_buf == RT_NULL)
296 {
297 rc = -RT_ENOMEM;
298 goto __exit;
299 }
300
301 /* create semaphore for the end of char recived */
302 bleuart.rx_end = rt_sem_create("bleuart", 0, RT_IPC_FLAG_FIFO);
303 if (bleuart.rx_end == RT_NULL)
304 {
305 rc = -RT_ENOMEM;
306 goto __exit;
307 }
308
309 /* create recived fifo */
310 bleuart.rx_fifo = rt_ringbuffer_create(MYNEWT_VAL(BLEUART_MAX_INPUT));
311 if (bleuart.rx_fifo == RT_NULL)
312 {
313 rc = -RT_ENOMEM;
314 goto __exit;
315 }
316
317 level = rt_hw_interrupt_disable();
318 uart_console = rt_console_get_device();
319 if(uart_console)
320 {
321 /* back uart console old indicate callback */
322 bleuart.old_rx_ind = uart_console->rx_indicate;
323 rt_device_set_rx_indicate(uart_console, bleuart_rx_ind);
324 }
325 rt_hw_interrupt_enable(level);
326
327 /* Reads console and sends data over BLE */
328 bleuart_uart_proc();
329
330 return RT_EOK;
331
332 __exit:
333 if (console_buf != RT_NULL)
334 {
335 rt_free(console_buf);
336 console_buf = RT_NULL;
337 }
338
339 if (bleuart.rx_end != RT_NULL)
340 {
341 rt_sem_delete(bleuart.rx_end);
342 bleuart.rx_end = RT_NULL;
343 }
344
345 if (bleuart.rx_fifo != RT_NULL)
346 {
347 rt_ringbuffer_destroy(bleuart.rx_fifo);
348 bleuart.rx_fifo = RT_NULL;
349 }
350
351 return rc;
352 }
353