xref: /btstack/example/spp_flowcontrol.c (revision e3ba22907f903f11cd12321c31e7936b8dd1157e)
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 */
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, 0x10001, 1, "SPP Counter");
95     sdp_register_service(spp_service_buffer);
96     printf("SDP service buffer size: %u\n\r", (uint16_t) de_get_len(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 */
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 
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
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[]);
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