spp_streamer.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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 MATTHIAS
  24. * RINGWALD 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. * contact@bluekitchen-gmbh.com
  35. *
  36. */
  37. #define BTSTACK_FILE__ "spp_streamer.c"
  38. /*
  39. * spp_streamer.c
  40. */
  41. // *****************************************************************************
  42. /* EXAMPLE_START(spp_streamer): Performance - Stream Data over SPP (Server)
  43. *
  44. * @text After RFCOMM connections gets open, request a
  45. * RFCOMM_EVENT_CAN_SEND_NOW via rfcomm_request_can_send_now_event().
  46. * @text When we get the RFCOMM_EVENT_CAN_SEND_NOW, send data and request another one.
  47. *
  48. * @text Note: To test, run the example, pair from a remote
  49. * device, and open the Virtual Serial Port.
  50. */
  51. // *****************************************************************************
  52. #include <stdint.h>
  53. #include <stdio.h>
  54. #include <stdlib.h>
  55. #include <string.h>
  56. #include <inttypes.h>
  57. #include "btstack.h"
  58. int btstack_main(int argc, const char * argv[]);
  59. #define RFCOMM_SERVER_CHANNEL 1
  60. #define TEST_COD 0x1234
  61. #define NUM_ROWS 25
  62. #define NUM_COLS 40
  63. #define DATA_VOLUME (10 * 1000 * 1000)
  64. static btstack_packet_callback_registration_t hci_event_callback_registration;
  65. static uint8_t test_data[NUM_ROWS * NUM_COLS];
  66. // SPP
  67. static uint8_t spp_service_buffer[150];
  68. static uint16_t spp_test_data_len;
  69. static uint16_t rfcomm_mtu;
  70. static uint16_t rfcomm_cid = 0;
  71. // static uint32_t data_to_send = DATA_VOLUME;
  72. /**
  73. * RFCOMM can make use for ERTM. Due to the need to re-transmit packets,
  74. * a large buffer is needed to still get high throughput
  75. */
  76. #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE_FOR_RFCOMM
  77. static uint8_t ertm_buffer[20000];
  78. static l2cap_ertm_config_t ertm_config = {
  79. 0, // ertm mandatory
  80. 8, // max transmit
  81. 2000,
  82. 12000,
  83. 1000, // l2cap ertm mtu
  84. 8,
  85. 8,
  86. 0, // No FCS
  87. };
  88. static int ertm_buffer_in_use;
  89. static void rfcomm_ertm_request_handler(rfcomm_ertm_request_t * ertm_request){
  90. printf("ERTM Buffer requested, buffer in use %u\n", ertm_buffer_in_use);
  91. if (ertm_buffer_in_use) return;
  92. ertm_buffer_in_use = 1;
  93. ertm_request->ertm_config = &ertm_config;
  94. ertm_request->ertm_buffer = ertm_buffer;
  95. ertm_request->ertm_buffer_size = sizeof(ertm_buffer);
  96. }
  97. static void rfcomm_ertm_released_handler(uint16_t ertm_id){
  98. printf("ERTM Buffer released, buffer in use %u, ertm_id %x\n", ertm_buffer_in_use, ertm_id);
  99. ertm_buffer_in_use = 0;
  100. }
  101. #endif
  102. /*
  103. * @section Track throughput
  104. * @text We calculate the throughput by setting a start time and measuring the amount of
  105. * data sent. After a configurable REPORT_INTERVAL_MS, we print the throughput in kB/s
  106. * and reset the counter and start time.
  107. */
  108. /* LISTING_START(tracking): Tracking throughput */
  109. #define REPORT_INTERVAL_MS 3000
  110. static uint32_t test_data_transferred;
  111. static uint32_t test_data_start;
  112. static void test_reset(void){
  113. test_data_start = btstack_run_loop_get_time_ms();
  114. test_data_transferred = 0;
  115. }
  116. static void test_track_transferred(int bytes_sent){
  117. test_data_transferred += bytes_sent;
  118. // evaluate
  119. uint32_t now = btstack_run_loop_get_time_ms();
  120. uint32_t time_passed = now - test_data_start;
  121. if (time_passed < REPORT_INTERVAL_MS) return;
  122. // print speed
  123. int bytes_per_second = test_data_transferred * 1000 / time_passed;
  124. printf("%u bytes -> %u.%03u kB/s\n", (int) test_data_transferred, (int) bytes_per_second / 1000, bytes_per_second % 1000);
  125. // restart
  126. test_data_start = now;
  127. test_data_transferred = 0;
  128. }
  129. /* LISTING_END(tracking): Tracking throughput */
  130. static void spp_create_test_data(void){
  131. int x,y;
  132. for (y=0;y<NUM_ROWS;y++){
  133. for (x=0;x<NUM_COLS-2;x++){
  134. test_data[y*NUM_COLS+x] = '0' + (x % 10);
  135. }
  136. test_data[y*NUM_COLS+NUM_COLS-2] = '\n';
  137. test_data[y*NUM_COLS+NUM_COLS-1] = '\r';
  138. }
  139. }
  140. static void spp_send_packet(void){
  141. rfcomm_send(rfcomm_cid, (uint8_t*) test_data, spp_test_data_len);
  142. test_track_transferred(spp_test_data_len);
  143. #if 0
  144. if (data_to_send <= spp_test_data_len){
  145. printf("SPP Streamer: enough data send, closing channel\n");
  146. rfcomm_disconnect(rfcomm_cid);
  147. rfcomm_cid = 0;
  148. return;
  149. }
  150. data_to_send -= spp_test_data_len;
  151. #endif
  152. rfcomm_request_can_send_now_event(rfcomm_cid);
  153. }
  154. /*
  155. * @section Packet Handler
  156. *
  157. * @text The packet handler of the combined example is just the combination of the individual packet handlers.
  158. */
  159. static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
  160. UNUSED(channel);
  161. bd_addr_t event_addr;
  162. uint8_t rfcomm_channel_nr;
  163. switch (packet_type) {
  164. case HCI_EVENT_PACKET:
  165. switch (hci_event_packet_get_type(packet)) {
  166. case HCI_EVENT_PIN_CODE_REQUEST:
  167. // inform about pin code request
  168. printf("Pin code request - using '0000'\n");
  169. hci_event_pin_code_request_get_bd_addr(packet, event_addr);
  170. gap_pin_code_response(event_addr, "0000");
  171. break;
  172. case HCI_EVENT_USER_CONFIRMATION_REQUEST:
  173. // inform about user confirmation request
  174. printf("SSP User Confirmation Request with numeric value '%06"PRIu32"'\n", little_endian_read_32(packet, 8));
  175. printf("SSP User Confirmation Auto accept\n");
  176. break;
  177. case RFCOMM_EVENT_INCOMING_CONNECTION:
  178. rfcomm_event_incoming_connection_get_bd_addr(packet, event_addr);
  179. rfcomm_channel_nr = rfcomm_event_incoming_connection_get_server_channel(packet);
  180. rfcomm_cid = rfcomm_event_incoming_connection_get_rfcomm_cid(packet);
  181. printf("RFCOMM channel %u requested for %s\n", rfcomm_channel_nr, bd_addr_to_str(event_addr));
  182. rfcomm_accept_connection(rfcomm_cid);
  183. break;
  184. case RFCOMM_EVENT_CHANNEL_OPENED:
  185. if (rfcomm_event_channel_opened_get_status(packet)) {
  186. printf("RFCOMM channel open failed, status %u\n", rfcomm_event_channel_opened_get_status(packet));
  187. } else {
  188. rfcomm_cid = rfcomm_event_channel_opened_get_rfcomm_cid(packet);
  189. rfcomm_mtu = rfcomm_event_channel_opened_get_max_frame_size(packet);
  190. printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n", rfcomm_cid, rfcomm_mtu);
  191. spp_test_data_len = rfcomm_mtu;
  192. if (spp_test_data_len > sizeof(test_data)){
  193. spp_test_data_len = sizeof(test_data);
  194. }
  195. // disable page/inquiry scan to get max performance
  196. gap_discoverable_control(0);
  197. gap_connectable_control(0);
  198. test_reset();
  199. rfcomm_request_can_send_now_event(rfcomm_cid);
  200. }
  201. break;
  202. case RFCOMM_EVENT_CAN_SEND_NOW:
  203. spp_send_packet();
  204. break;
  205. case RFCOMM_EVENT_CHANNEL_CLOSED:
  206. printf("RFCOMM channel closed\n");
  207. rfcomm_cid = 0;
  208. // re-enable page/inquiry scan again
  209. gap_discoverable_control(1);
  210. gap_connectable_control(1);
  211. break;
  212. default:
  213. break;
  214. }
  215. break;
  216. case RFCOMM_DATA_PACKET:
  217. test_track_transferred(size);
  218. #if 0
  219. // optional: print received data as ASCII text
  220. printf("RCV: '");
  221. for (i=0;i<size;i++){
  222. putchar(packet[i]);
  223. }
  224. printf("'\n");
  225. #endif
  226. break;
  227. default:
  228. break;
  229. }
  230. }
  231. /*
  232. * @section Main Application Setup
  233. *
  234. * @text As with the packet and the heartbeat handlers, the combined app setup contains the code from the individual example setups.
  235. */
  236. /* LISTING_START(MainConfiguration): Init L2CAP RFCOMM SDP SPP */
  237. int btstack_main(int argc, const char * argv[])
  238. {
  239. (void)argc;
  240. (void)argv;
  241. l2cap_init();
  242. rfcomm_init();
  243. rfcomm_register_service(packet_handler, RFCOMM_SERVER_CHANNEL, 0xffff);
  244. #ifdef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE_FOR_RFCOMM
  245. // setup ERTM management
  246. rfcomm_enable_l2cap_ertm(&rfcomm_ertm_request_handler, &rfcomm_ertm_released_handler);
  247. #endif
  248. // init SDP, create record for SPP and register with SDP
  249. sdp_init();
  250. memset(spp_service_buffer, 0, sizeof(spp_service_buffer));
  251. spp_create_sdp_record(spp_service_buffer, 0x10001, RFCOMM_SERVER_CHANNEL, "SPP Streamer");
  252. sdp_register_service(spp_service_buffer);
  253. // printf("SDP service record size: %u\n", de_get_len(spp_service_buffer));
  254. // register for HCI events
  255. hci_event_callback_registration.callback = &packet_handler;
  256. hci_add_event_handler(&hci_event_callback_registration);
  257. // short-cut to find other SPP Streamer
  258. gap_set_class_of_device(TEST_COD);
  259. gap_ssp_set_io_capability(SSP_IO_CAPABILITY_DISPLAY_YES_NO);
  260. gap_set_local_name("SPP Streamer 00:00:00:00:00:00");
  261. gap_discoverable_control(1);
  262. spp_create_test_data();
  263. // turn on!
  264. hci_power_control(HCI_POWER_ON);
  265. return 0;
  266. }
  267. /* LISTING_END */
  268. /* EXAMPLE_END */