1 /*
2 * Copyright (C) 2014 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * 4. Any redistribution, use, or modification is done solely for
17 * personal benefit and not for any commercial purpose or for
18 * monetary gain.
19 *
20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Please inquire about commercial licensing options at
34 * [email protected]
35 *
36 */
37
38 #define BTSTACK_FILE__ "ublox_spp_le_counter.c"
39
40 // *****************************************************************************
41 /* EXAMPLE_START(ublox_spp_le_counter): LE u-blox SPP-like Heartbeat Server
42 *
43 */
44 // *****************************************************************************
45
46 #include <stdint.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50
51 #include "btstack.h"
52 #include "ble/gatt-service/device_information_service_server.h"
53 #include "ble/gatt-service/ublox_spp_service_server.h"
54
55 // ublox_spp_le_counter.gatt contains the declaration of the provided GATT Services + Characteristics
56 // ublox_spp_le_counter.h contains the binary representation of ublox_spp_le_counter.gatt
57 // it is generated by the build system by calling: $BTSTACK_ROOT/tool/compile_gatt.py ublox_spp_le_counter.gatt ublox_spp_le_counter.h
58 // it needs to be regenerated when the GATT Database declared in ublox_spp_le_counter.gatt file is modified
59 #include "ublox_spp_le_counter.h"
60
61
62 #define HEARTBEAT_PERIOD_MS 1000
63
64 /* @section Main Application Setup
65 *
66 * @text Listing MainConfiguration shows main application code.
67 * It initializes L2CAP, the Security Manager and configures the ATT Server with the pre-compiled
68 * ATT Database generated from $ublox_le_counter.gatt$.
69 * Additionally, it enables the Battery Service Server with the current battery level.
70 * Finally, it configures the advertisements
71 * and the heartbeat handler and boots the Bluetooth stack.
72 * In this example, the Advertisement contains the Flags attribute and the device name.
73 * The flag 0x06 indicates: LE General Discoverable Mode and BR/EDR not supported.
74 */
75
76 /* LISTING_START(MainConfiguration): Init L2CAP SM ATT Server and start heartbeat timer */
77 static btstack_timer_source_t heartbeat;
78 static hci_con_handle_t con_handle = HCI_CON_HANDLE_INVALID;
79 static btstack_context_callback_registration_t send_request;
80 static btstack_packet_callback_registration_t hci_event_callback_registration;
81
82 const uint8_t adv_data[] = {
83 // Flags general discoverable, BR/EDR not supported
84 2, BLUETOOTH_DATA_TYPE_FLAGS, 0x06,
85 // Name
86 5, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, '6', '-','5', '6',
87 // UUID ...
88 17, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS, 0x1, 0xd7, 0xe9, 0x1, 0x4f, 0xf3, 0x44, 0xe7, 0x83, 0x8f, 0xe2, 0x26, 0xb9, 0xe1, 0x56, 0x24,
89 };
90
91 const uint8_t adv_data_len = sizeof(adv_data);
92
93 /* LISTING_END */
94
95 /*
96 * @section Heartbeat Handler
97 *
98 * @text The heartbeat handler updates the value of the single Characteristic provided in this example,
99 * and request a ATT_EVENT_CAN_SEND_NOW to send a notification if enabled see Listing heartbeat.
100 */
101
102 /* LISTING_START(heartbeat): Hearbeat Handler */
103 static int counter = 0;
104 static char counter_string[30];
105 static int counter_string_len;
106
beat(void)107 static void beat(void){
108 counter++;
109 counter_string_len = snprintf(counter_string, sizeof(counter_string), "BTstack counter %03u", counter);
110 }
111
ublox_can_send(void * context)112 static void ublox_can_send(void * context){
113 UNUSED(context);
114 beat();
115 printf("SEND: %s\n", counter_string);
116 ublox_spp_service_server_send(con_handle, (uint8_t*) counter_string, counter_string_len);
117 }
118
heartbeat_handler(struct btstack_timer_source * ts)119 static void heartbeat_handler(struct btstack_timer_source *ts){
120 if (con_handle != HCI_CON_HANDLE_INVALID) {
121 send_request.callback = &ublox_can_send;
122 ublox_spp_service_server_request_can_send_now(&send_request, con_handle);
123 }
124 btstack_run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
125 btstack_run_loop_add_timer(ts);
126 }
127 /* LISTING_END */
128
ublox_spp_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)129 static void ublox_spp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
130 UNUSED(channel);
131 switch (packet_type){
132 case HCI_EVENT_PACKET:
133 if (hci_event_packet_get_type(packet) != HCI_EVENT_GATTSERVICE_META) break;
134 switch (hci_event_gattservice_meta_get_subevent_code(packet)){
135 case GATTSERVICE_SUBEVENT_SPP_SERVICE_CONNECTED:
136 con_handle = gattservice_subevent_spp_service_connected_get_con_handle(packet);
137 printf("Connected with handle 0x%04x\n", con_handle);
138 break;
139 case GATTSERVICE_SUBEVENT_SPP_SERVICE_DISCONNECTED:
140 con_handle = HCI_CON_HANDLE_INVALID;
141 break;
142 default:
143 break;
144 }
145 break;
146 case RFCOMM_DATA_PACKET:
147 printf("RECV: ");
148 printf_hexdump(packet, size);
149 break;
150 default:
151 break;
152 }
153 }
154
155 /*
156 * @section Packet Handler
157 *
158 * @text The packet handler is used to:
159 * - stop the counter after a disconnect
160 */
161
162 /* LISTING_START(packetHandler): Packet Handler */
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)163 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
164 UNUSED(channel);
165 UNUSED(size);
166
167 switch (packet_type) {
168 case HCI_EVENT_PACKET:
169 switch (hci_event_packet_get_type(packet)) {
170 case HCI_EVENT_DISCONNECTION_COMPLETE:
171 con_handle = HCI_CON_HANDLE_INVALID;
172 break;
173 default:
174 break;
175 }
176 break;
177 default:
178 break;
179 }
180 }
181 /* LISTING_END */
182
183
184 int btstack_main(void);
btstack_main(void)185 int btstack_main(void)
186 {
187 // register for HCI events
188 hci_event_callback_registration.callback = &packet_handler;
189 hci_add_event_handler(&hci_event_callback_registration);
190
191 l2cap_init();
192
193 // setup SM: Display only
194 sm_init();
195
196 // setup ATT server
197 att_server_init(profile_data, NULL, NULL);
198 // setup device information service
199 device_information_service_server_init();
200 // setup Nordic SPP service
201 ublox_spp_service_server_init(&ublox_spp_packet_handler);
202
203 // setup advertisements
204 uint16_t adv_int_min = 0x0030;
205 uint16_t adv_int_max = 0x0030;
206 uint8_t adv_type = 0;
207 bd_addr_t null_addr;
208 memset(null_addr, 0, 6);
209 gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, null_addr, 0x07, 0x00);
210 gap_advertisements_set_data(adv_data_len, (uint8_t*) adv_data);
211 gap_advertisements_enable(1);
212
213 // set one-shot timer
214 heartbeat.process = &heartbeat_handler;
215 btstack_run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS);
216 btstack_run_loop_add_timer(&heartbeat);
217
218 // beat once
219 beat();
220
221 // turn on!
222 hci_power_control(HCI_POWER_ON);
223
224 return 0;
225 }
226 /* EXAMPLE_END */
227