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__ "spp_flowcontrol.c"
39
40 // *****************************************************************************
41 /* EXAMPLE_START(spp_flowcontrol): SPP Server - RFCOMM Flow Control
42 *
43 * @text This example adds explicit flow control for incoming RFCOMM data to the
44 * SPP heartbeat counter example. We will highlight the changes compared to the
45 * SPP counter example.
46 */
47 // *****************************************************************************
48
49 #include <stdint.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53
54 #include "btstack.h"
55
56 #define HEARTBEAT_PERIOD_MS 500
57 #define TEST_COD 0x1234
58 #define RFCOMM_SERVER_CHANNEL 1
59
60 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
61
62 static uint16_t rfcomm_channel_id;
63 static uint8_t rfcomm_send_credit = 0;
64 static uint8_t spp_service_buffer[150];
65 static btstack_packet_callback_registration_t hci_event_callback_registration;
66
67 /* @section SPP Service Setup
68 *
69 * @text Listing explicitFlowControl shows how to
70 * provide one initial credit during RFCOMM service initialization. Please note
71 * that providing a single credit effectively reduces the credit-based (sliding
72 * window) flow control to a stop-and-wait flow control that limits the data
73 * throughput substantially.
74 */
75
76 /* LISTING_START(explicitFlowControl): Providing one initial credit during RFCOMM service initialization */
spp_service_setup(void)77 static void spp_service_setup(void){
78
79 // register for HCI events
80 hci_event_callback_registration.callback = &packet_handler;
81 hci_add_event_handler(&hci_event_callback_registration);
82
83 // init L2CAP
84 l2cap_init();
85
86 // init RFCOMM
87 rfcomm_init();
88 // reserved channel, mtu limited by l2cap, 1 credit
89 rfcomm_register_service_with_initial_credits(&packet_handler, RFCOMM_SERVER_CHANNEL, 0xffff, 1);
90
91 // init SDP, create record for SPP and register with SDP
92 sdp_init();
93 memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
94 spp_create_sdp_record(spp_service_buffer, sdp_create_service_record_handle(), 1, "SPP Counter");
95 btstack_assert(de_get_len( spp_service_buffer) <= sizeof(spp_service_buffer));
96 sdp_register_service(spp_service_buffer);
97 }
98 /* LISTING_END */
99
100 /* @section Periodic Timer Setup
101 *
102 * @text Explicit credit management is
103 * recommended when received RFCOMM data cannot be processed immediately. In this
104 * example, delayed processing of received data is simulated with the help of a
105 * periodic timer as follows. When the packet handler receives a data packet, it
106 * does not provide a new credit, it sets a flag instead, see Listing phManual.
107 * If the flag is set, a new
108 * credit will be granted by the heartbeat handler, introducing a delay of up to 1
109 * second. The heartbeat handler code is shown in Listing hbhManual.
110 */
111
112 static btstack_timer_source_t heartbeat;
113
114 /* LISTING_START(hbhManual): Heartbeat handler with manual credit management */
heartbeat_handler(struct btstack_timer_source * ts)115 static void heartbeat_handler(struct btstack_timer_source *ts){
116 if (rfcomm_send_credit){
117 rfcomm_grant_credits(rfcomm_channel_id, 1);
118 rfcomm_send_credit = 0;
119 }
120 btstack_run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
121 btstack_run_loop_add_timer(ts);
122 }
123 /* LISTING_END */
124
one_shot_timer_setup(void)125 static void one_shot_timer_setup(void){
126 heartbeat.process = &heartbeat_handler;
127 btstack_run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS);
128 btstack_run_loop_add_timer(&heartbeat);
129 }
130
131 /* LISTING_START(phManual): Packet handler with manual credit management */
132 // Bluetooth logic
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)133 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
134 /* LISTING_PAUSE */
135 UNUSED(channel);
136
137 bd_addr_t event_addr;
138 uint8_t rfcomm_channel_nr;
139 uint16_t mtu;
140 int i;
141
142 switch (packet_type) {
143 case HCI_EVENT_PACKET:
144 switch (hci_event_packet_get_type(packet)) {
145
146 case HCI_EVENT_PIN_CODE_REQUEST:
147 // inform about pin code request
148 printf("Pin code request - using '0000'\n");
149 hci_event_pin_code_request_get_bd_addr(packet, event_addr);
150 gap_pin_code_response(event_addr, "0000");
151 break;
152
153 case RFCOMM_EVENT_INCOMING_CONNECTION:
154 rfcomm_event_incoming_connection_get_bd_addr(packet, event_addr);
155 rfcomm_channel_nr = rfcomm_event_incoming_connection_get_server_channel(packet);
156 rfcomm_channel_id = rfcomm_event_incoming_connection_get_rfcomm_cid(packet);
157 printf("RFCOMM channel %u requested for %s\n", rfcomm_channel_nr, bd_addr_to_str(event_addr));
158 rfcomm_accept_connection(rfcomm_channel_id);
159 break;
160
161 case RFCOMM_EVENT_CHANNEL_OPENED:
162 if (rfcomm_event_channel_opened_get_status(packet)) {
163 printf("RFCOMM channel open failed, status 0x%02x\n", rfcomm_event_channel_opened_get_status(packet));
164 } else {
165 rfcomm_channel_id = rfcomm_event_channel_opened_get_rfcomm_cid(packet);
166 mtu = rfcomm_event_channel_opened_get_max_frame_size(packet);
167 printf("RFCOMM channel open succeeded. New RFCOMM Channel ID 0x%02x, max frame size %u\n", rfcomm_channel_id, mtu);
168 }
169 break;
170
171 case RFCOMM_EVENT_CHANNEL_CLOSED:
172 rfcomm_channel_id = 0;
173 break;
174
175 default:
176 break;
177 }
178 break;
179 /* LISTING_RESUME */
180 case RFCOMM_DATA_PACKET:
181 for (i=0;i<size;i++){
182 putchar(packet[i]);
183 };
184 putchar('\n');
185 rfcomm_send_credit = 1;
186 break;
187 /* LISTING_PAUSE */
188 default:
189 break;
190 }
191 /* LISTING_RESUME */
192 }
193 /* LISTING_END */
194
195
196
197 int btstack_main(int argc, const char * argv[]);
btstack_main(int argc,const char * argv[])198 int btstack_main(int argc, const char * argv[]){
199
200 (void)argc;
201 (void)argv;
202
203 l2cap_init();
204
205 #ifdef ENABLE_BLE
206 // Initialize LE Security Manager. Needed for cross-transport key derivation
207 sm_init();
208 #endif
209
210 spp_service_setup();
211 one_shot_timer_setup();
212
213 puts("SPP FlowControl Demo: simulates processing on received data...\n\r");
214 gap_set_local_name("SPP Flowcontrol 00:00:00:00:00:00");
215 gap_discoverable_control(1);
216
217 // short-cut to find other SPP Streamer
218 gap_set_class_of_device(TEST_COD);
219
220 // turn on!
221 hci_power_control(HCI_POWER_ON);
222
223 return 0;
224 }
225 /* EXAMPLE_END */
226
227
228