xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/services/bleuart/src/ble_svc_uart.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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