1bcf00d8fSMatthias Ringwald /*
2bcf00d8fSMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH
3bcf00d8fSMatthias Ringwald *
4bcf00d8fSMatthias Ringwald * Redistribution and use in source and binary forms, with or without
5bcf00d8fSMatthias Ringwald * modification, are permitted provided that the following conditions
6bcf00d8fSMatthias Ringwald * are met:
7bcf00d8fSMatthias Ringwald *
8bcf00d8fSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright
9bcf00d8fSMatthias Ringwald * notice, this list of conditions and the following disclaimer.
10bcf00d8fSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright
11bcf00d8fSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the
12bcf00d8fSMatthias Ringwald * documentation and/or other materials provided with the distribution.
13bcf00d8fSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of
14bcf00d8fSMatthias Ringwald * contributors may be used to endorse or promote products derived
15bcf00d8fSMatthias Ringwald * from this software without specific prior written permission.
16bcf00d8fSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for
17bcf00d8fSMatthias Ringwald * personal benefit and not for any commercial purpose or for
18bcf00d8fSMatthias Ringwald * monetary gain.
19bcf00d8fSMatthias Ringwald *
20bcf00d8fSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21bcf00d8fSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22bcf00d8fSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25bcf00d8fSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26bcf00d8fSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27bcf00d8fSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28bcf00d8fSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29bcf00d8fSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30bcf00d8fSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31bcf00d8fSMatthias Ringwald * SUCH DAMAGE.
32bcf00d8fSMatthias Ringwald *
33bcf00d8fSMatthias Ringwald * Please inquire about commercial licensing options at
34bcf00d8fSMatthias Ringwald * [email protected]
35bcf00d8fSMatthias Ringwald *
36bcf00d8fSMatthias Ringwald */
37bcf00d8fSMatthias Ringwald
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "spp_flowcontrol.c"
39ab2c6ae4SMatthias Ringwald
40bcf00d8fSMatthias Ringwald // *****************************************************************************
41ec8ae085SMilanka Ringwald /* EXAMPLE_START(spp_flowcontrol): SPP Server - RFCOMM Flow Control
42bcf00d8fSMatthias Ringwald *
43bcf00d8fSMatthias Ringwald * @text This example adds explicit flow control for incoming RFCOMM data to the
44bcf00d8fSMatthias Ringwald * SPP heartbeat counter example. We will highlight the changes compared to the
45bcf00d8fSMatthias Ringwald * SPP counter example.
46bcf00d8fSMatthias Ringwald */
47bcf00d8fSMatthias Ringwald // *****************************************************************************
48bcf00d8fSMatthias Ringwald
49bcf00d8fSMatthias Ringwald #include <stdint.h>
50bcf00d8fSMatthias Ringwald #include <stdio.h>
51bcf00d8fSMatthias Ringwald #include <stdlib.h>
52bcf00d8fSMatthias Ringwald #include <string.h>
53bcf00d8fSMatthias Ringwald
54726a19abSMatthias Ringwald #include "btstack.h"
55bcf00d8fSMatthias Ringwald
56bcf00d8fSMatthias Ringwald #define HEARTBEAT_PERIOD_MS 500
5796cb50ecSMatthias Ringwald #define TEST_COD 0x1234
5896cb50ecSMatthias Ringwald #define RFCOMM_SERVER_CHANNEL 1
59bcf00d8fSMatthias Ringwald
60bcf00d8fSMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
61bcf00d8fSMatthias Ringwald
62bcf00d8fSMatthias Ringwald static uint16_t rfcomm_channel_id;
63bcf00d8fSMatthias Ringwald static uint8_t rfcomm_send_credit = 0;
64bcf00d8fSMatthias Ringwald static uint8_t spp_service_buffer[150];
65bcf00d8fSMatthias Ringwald static btstack_packet_callback_registration_t hci_event_callback_registration;
66bcf00d8fSMatthias Ringwald
67bcf00d8fSMatthias Ringwald /* @section SPP Service Setup
68bcf00d8fSMatthias Ringwald *
69bcf00d8fSMatthias Ringwald * @text Listing explicitFlowControl shows how to
70bcf00d8fSMatthias Ringwald * provide one initial credit during RFCOMM service initialization. Please note
71bcf00d8fSMatthias Ringwald * that providing a single credit effectively reduces the credit-based (sliding
72bcf00d8fSMatthias Ringwald * window) flow control to a stop-and-wait flow control that limits the data
73bcf00d8fSMatthias Ringwald * throughput substantially.
74bcf00d8fSMatthias Ringwald */
75bcf00d8fSMatthias Ringwald
76bcf00d8fSMatthias Ringwald /* LISTING_START(explicitFlowControl): Providing one initial credit during RFCOMM service initialization */
spp_service_setup(void)77bcf00d8fSMatthias Ringwald static void spp_service_setup(void){
78bcf00d8fSMatthias Ringwald
79bcf00d8fSMatthias Ringwald // register for HCI events
80bcf00d8fSMatthias Ringwald hci_event_callback_registration.callback = &packet_handler;
81bcf00d8fSMatthias Ringwald hci_add_event_handler(&hci_event_callback_registration);
82bcf00d8fSMatthias Ringwald
83bcf00d8fSMatthias Ringwald // init L2CAP
84bcf00d8fSMatthias Ringwald l2cap_init();
85bcf00d8fSMatthias Ringwald
86bcf00d8fSMatthias Ringwald // init RFCOMM
87bcf00d8fSMatthias Ringwald rfcomm_init();
88bcf00d8fSMatthias Ringwald // reserved channel, mtu limited by l2cap, 1 credit
8996cb50ecSMatthias Ringwald rfcomm_register_service_with_initial_credits(&packet_handler, RFCOMM_SERVER_CHANNEL, 0xffff, 1);
90bcf00d8fSMatthias Ringwald
91bcf00d8fSMatthias Ringwald // init SDP, create record for SPP and register with SDP
92bcf00d8fSMatthias Ringwald sdp_init();
93bcf00d8fSMatthias Ringwald memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
94*762141afSMatthias Ringwald spp_create_sdp_record(spp_service_buffer, sdp_create_service_record_handle(), 1, "SPP Counter");
95*762141afSMatthias Ringwald btstack_assert(de_get_len( spp_service_buffer) <= sizeof(spp_service_buffer));
96bcf00d8fSMatthias Ringwald sdp_register_service(spp_service_buffer);
97bcf00d8fSMatthias Ringwald }
98bcf00d8fSMatthias Ringwald /* LISTING_END */
99bcf00d8fSMatthias Ringwald
100bcf00d8fSMatthias Ringwald /* @section Periodic Timer Setup
101bcf00d8fSMatthias Ringwald *
102bcf00d8fSMatthias Ringwald * @text Explicit credit management is
103bcf00d8fSMatthias Ringwald * recommended when received RFCOMM data cannot be processed immediately. In this
104bcf00d8fSMatthias Ringwald * example, delayed processing of received data is simulated with the help of a
105bcf00d8fSMatthias Ringwald * periodic timer as follows. When the packet handler receives a data packet, it
106bcf00d8fSMatthias Ringwald * does not provide a new credit, it sets a flag instead, see Listing phManual.
107bcf00d8fSMatthias Ringwald * If the flag is set, a new
108bcf00d8fSMatthias Ringwald * credit will be granted by the heartbeat handler, introducing a delay of up to 1
109bcf00d8fSMatthias Ringwald * second. The heartbeat handler code is shown in Listing hbhManual.
110bcf00d8fSMatthias Ringwald */
111bcf00d8fSMatthias Ringwald
112bcf00d8fSMatthias Ringwald static btstack_timer_source_t heartbeat;
113bcf00d8fSMatthias Ringwald
114bcf00d8fSMatthias Ringwald /* LISTING_START(hbhManual): Heartbeat handler with manual credit management */
heartbeat_handler(struct btstack_timer_source * ts)115bcf00d8fSMatthias Ringwald static void heartbeat_handler(struct btstack_timer_source *ts){
116bcf00d8fSMatthias Ringwald if (rfcomm_send_credit){
117bcf00d8fSMatthias Ringwald rfcomm_grant_credits(rfcomm_channel_id, 1);
118bcf00d8fSMatthias Ringwald rfcomm_send_credit = 0;
119bcf00d8fSMatthias Ringwald }
120bcf00d8fSMatthias Ringwald btstack_run_loop_set_timer(ts, HEARTBEAT_PERIOD_MS);
121bcf00d8fSMatthias Ringwald btstack_run_loop_add_timer(ts);
122bcf00d8fSMatthias Ringwald }
123bcf00d8fSMatthias Ringwald /* LISTING_END */
124bcf00d8fSMatthias Ringwald
one_shot_timer_setup(void)125bcf00d8fSMatthias Ringwald static void one_shot_timer_setup(void){
126bcf00d8fSMatthias Ringwald heartbeat.process = &heartbeat_handler;
127bcf00d8fSMatthias Ringwald btstack_run_loop_set_timer(&heartbeat, HEARTBEAT_PERIOD_MS);
128bcf00d8fSMatthias Ringwald btstack_run_loop_add_timer(&heartbeat);
129bcf00d8fSMatthias Ringwald }
130bcf00d8fSMatthias Ringwald
131bcf00d8fSMatthias Ringwald /* LISTING_START(phManual): Packet handler with manual credit management */
132bcf00d8fSMatthias Ringwald // Bluetooth logic
packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)133bcf00d8fSMatthias Ringwald static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
134bcf00d8fSMatthias Ringwald /* LISTING_PAUSE */
13596cb50ecSMatthias Ringwald UNUSED(channel);
13696cb50ecSMatthias Ringwald
137bcf00d8fSMatthias Ringwald bd_addr_t event_addr;
138bcf00d8fSMatthias Ringwald uint8_t rfcomm_channel_nr;
139bcf00d8fSMatthias Ringwald uint16_t mtu;
140bcf00d8fSMatthias Ringwald int i;
141bcf00d8fSMatthias Ringwald
142bcf00d8fSMatthias Ringwald switch (packet_type) {
143bcf00d8fSMatthias Ringwald case HCI_EVENT_PACKET:
1440e2df43fSMatthias Ringwald switch (hci_event_packet_get_type(packet)) {
145bcf00d8fSMatthias Ringwald
146bcf00d8fSMatthias Ringwald case HCI_EVENT_PIN_CODE_REQUEST:
147bcf00d8fSMatthias Ringwald // inform about pin code request
14816f28706SMatthias Ringwald printf("Pin code request - using '0000'\n");
149a6ef64baSMilanka Ringwald hci_event_pin_code_request_get_bd_addr(packet, event_addr);
15016f28706SMatthias Ringwald gap_pin_code_response(event_addr, "0000");
151bcf00d8fSMatthias Ringwald break;
152bcf00d8fSMatthias Ringwald
153bcf00d8fSMatthias Ringwald case RFCOMM_EVENT_INCOMING_CONNECTION:
154caa82391SMilanka Ringwald rfcomm_event_incoming_connection_get_bd_addr(packet, event_addr);
155caa82391SMilanka Ringwald rfcomm_channel_nr = rfcomm_event_incoming_connection_get_server_channel(packet);
156caa82391SMilanka Ringwald rfcomm_channel_id = rfcomm_event_incoming_connection_get_rfcomm_cid(packet);
157caa82391SMilanka Ringwald printf("RFCOMM channel %u requested for %s\n", rfcomm_channel_nr, bd_addr_to_str(event_addr));
158bcf00d8fSMatthias Ringwald rfcomm_accept_connection(rfcomm_channel_id);
159bcf00d8fSMatthias Ringwald break;
160bcf00d8fSMatthias Ringwald
161f8f6a918SMatthias Ringwald case RFCOMM_EVENT_CHANNEL_OPENED:
162caa82391SMilanka Ringwald if (rfcomm_event_channel_opened_get_status(packet)) {
163fcd55a0bSMilanka Ringwald printf("RFCOMM channel open failed, status 0x%02x\n", rfcomm_event_channel_opened_get_status(packet));
164bcf00d8fSMatthias Ringwald } else {
165caa82391SMilanka Ringwald rfcomm_channel_id = rfcomm_event_channel_opened_get_rfcomm_cid(packet);
166caa82391SMilanka Ringwald mtu = rfcomm_event_channel_opened_get_max_frame_size(packet);
167fcd55a0bSMilanka Ringwald printf("RFCOMM channel open succeeded. New RFCOMM Channel ID 0x%02x, max frame size %u\n", rfcomm_channel_id, mtu);
168bcf00d8fSMatthias Ringwald }
169bcf00d8fSMatthias Ringwald break;
170bcf00d8fSMatthias Ringwald
171bcf00d8fSMatthias Ringwald case RFCOMM_EVENT_CHANNEL_CLOSED:
172bcf00d8fSMatthias Ringwald rfcomm_channel_id = 0;
173bcf00d8fSMatthias Ringwald break;
174bcf00d8fSMatthias Ringwald
175bcf00d8fSMatthias Ringwald default:
176bcf00d8fSMatthias Ringwald break;
177bcf00d8fSMatthias Ringwald }
178bcf00d8fSMatthias Ringwald break;
179bcf00d8fSMatthias Ringwald /* LISTING_RESUME */
180bcf00d8fSMatthias Ringwald case RFCOMM_DATA_PACKET:
181bcf00d8fSMatthias Ringwald for (i=0;i<size;i++){
182bcf00d8fSMatthias Ringwald putchar(packet[i]);
183bcf00d8fSMatthias Ringwald };
184bcf00d8fSMatthias Ringwald putchar('\n');
185bcf00d8fSMatthias Ringwald rfcomm_send_credit = 1;
186bcf00d8fSMatthias Ringwald break;
187bcf00d8fSMatthias Ringwald /* LISTING_PAUSE */
188bcf00d8fSMatthias Ringwald default:
189bcf00d8fSMatthias Ringwald break;
190bcf00d8fSMatthias Ringwald }
191bcf00d8fSMatthias Ringwald /* LISTING_RESUME */
192bcf00d8fSMatthias Ringwald }
193bcf00d8fSMatthias Ringwald /* LISTING_END */
194bcf00d8fSMatthias Ringwald
195bcf00d8fSMatthias Ringwald
196bcf00d8fSMatthias Ringwald
197bcf00d8fSMatthias Ringwald int btstack_main(int argc, const char * argv[]);
btstack_main(int argc,const char * argv[])198bcf00d8fSMatthias Ringwald int btstack_main(int argc, const char * argv[]){
199bcf00d8fSMatthias Ringwald
20096cb50ecSMatthias Ringwald (void)argc;
20196cb50ecSMatthias Ringwald (void)argv;
20296cb50ecSMatthias Ringwald
2038c9bb29eSMatthias Ringwald l2cap_init();
2048c9bb29eSMatthias Ringwald
2058c9bb29eSMatthias Ringwald #ifdef ENABLE_BLE
2068c9bb29eSMatthias Ringwald // Initialize LE Security Manager. Needed for cross-transport key derivation
2078c9bb29eSMatthias Ringwald sm_init();
2088c9bb29eSMatthias Ringwald #endif
2098c9bb29eSMatthias Ringwald
210bcf00d8fSMatthias Ringwald spp_service_setup();
211bcf00d8fSMatthias Ringwald one_shot_timer_setup();
212bcf00d8fSMatthias Ringwald
213bcf00d8fSMatthias Ringwald puts("SPP FlowControl Demo: simulates processing on received data...\n\r");
2140c2b8870SMatthias Ringwald gap_set_local_name("SPP Flowcontrol 00:00:00:00:00:00");
215bcf00d8fSMatthias Ringwald gap_discoverable_control(1);
216bcf00d8fSMatthias Ringwald
21796cb50ecSMatthias Ringwald // short-cut to find other SPP Streamer
21896cb50ecSMatthias Ringwald gap_set_class_of_device(TEST_COD);
21996cb50ecSMatthias Ringwald
220bcf00d8fSMatthias Ringwald // turn on!
221bcf00d8fSMatthias Ringwald hci_power_control(HCI_POWER_ON);
222bcf00d8fSMatthias Ringwald
223bcf00d8fSMatthias Ringwald return 0;
224bcf00d8fSMatthias Ringwald }
225bcf00d8fSMatthias Ringwald /* EXAMPLE_END */
226bcf00d8fSMatthias Ringwald
227bcf00d8fSMatthias Ringwald
228