btstack_uart_block_posix.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. /*
  2. * Copyright (C) 2016 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__ "btstack_uart_block_posix.c"
  38. /*
  39. * btstack_uart_block_posix.c
  40. *
  41. * Common code to access serial port via asynchronous block read/write commands
  42. *
  43. */
  44. #include "btstack_uart_block.h"
  45. #include "btstack_run_loop.h"
  46. #include "btstack_debug.h"
  47. #include <termios.h> /* POSIX terminal control definitions */
  48. #include <fcntl.h> /* File control definitions */
  49. #include <unistd.h> /* UNIX standard function definitions */
  50. #include <string.h>
  51. #include <errno.h>
  52. #ifdef __APPLE__
  53. #include <sys/ioctl.h>
  54. #include <IOKit/serial/ioss.h>
  55. #endif
  56. // uart config
  57. static const btstack_uart_config_t * uart_config;
  58. // data source for integration with BTstack Runloop
  59. static btstack_data_source_t transport_data_source;
  60. // block write
  61. static int write_bytes_len;
  62. static const uint8_t * write_bytes_data;
  63. // block read
  64. static uint16_t read_bytes_len;
  65. static uint8_t * read_bytes_data;
  66. // callbacks
  67. static void (*block_sent)(void);
  68. static void (*block_received)(void);
  69. static int btstack_uart_posix_init(const btstack_uart_config_t * config){
  70. uart_config = config;
  71. return 0;
  72. }
  73. static void btstack_uart_posix_process_write(btstack_data_source_t *ds) {
  74. if (write_bytes_len == 0) return;
  75. uint32_t start = btstack_run_loop_get_time_ms();
  76. // write up to write_bytes_len to fd
  77. int bytes_written = (int) write(ds->source.fd, write_bytes_data, write_bytes_len);
  78. uint32_t end = btstack_run_loop_get_time_ms();
  79. if (end - start > 10){
  80. log_info("write took %u ms", end - start);
  81. }
  82. if (bytes_written == 0){
  83. log_error("wrote zero bytes\n");
  84. return;
  85. }
  86. if (bytes_written < 0) {
  87. log_error("write returned error\n");
  88. btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
  89. return;
  90. }
  91. write_bytes_data += bytes_written;
  92. write_bytes_len -= bytes_written;
  93. if (write_bytes_len){
  94. btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
  95. return;
  96. }
  97. btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
  98. // notify done
  99. if (block_sent){
  100. block_sent();
  101. }
  102. }
  103. static void btstack_uart_posix_process_read(btstack_data_source_t *ds) {
  104. if (read_bytes_len == 0) {
  105. log_info("called but no read pending");
  106. btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
  107. }
  108. uint32_t start = btstack_run_loop_get_time_ms();
  109. // read up to bytes_to_read data in
  110. ssize_t bytes_read = read(ds->source.fd, read_bytes_data, read_bytes_len);
  111. // log_info("btstack_uart_posix_process_read need %u bytes, got %d", read_bytes_len, (int) bytes_read);
  112. uint32_t end = btstack_run_loop_get_time_ms();
  113. if (end - start > 10){
  114. log_info("read took %u ms", end - start);
  115. }
  116. if (bytes_read == 0){
  117. log_error("read zero bytes\n");
  118. return;
  119. }
  120. if (bytes_read < 0) {
  121. //log_error("read returned error bytes_read:%d\n",bytes_read);
  122. return;
  123. }
  124. read_bytes_len -= bytes_read;
  125. read_bytes_data += bytes_read;
  126. if (read_bytes_len > 0) return;
  127. btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
  128. if (block_received){
  129. block_received();
  130. }
  131. }
  132. static void hci_uart_posix_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
  133. if (ds->source.fd < 0) return;
  134. switch (callback_type){
  135. case DATA_SOURCE_CALLBACK_READ:
  136. btstack_uart_posix_process_read(ds);
  137. break;
  138. case DATA_SOURCE_CALLBACK_WRITE:
  139. btstack_uart_posix_process_write(ds);
  140. break;
  141. default:
  142. break;
  143. }
  144. }
  145. static int btstack_uart_posix_set_baudrate(uint32_t baudrate){
  146. int fd = transport_data_source.source.fd;
  147. log_info("h4_set_baudrate %u", baudrate);
  148. #ifdef __APPLE__
  149. // From https://developer.apple.com/library/content/samplecode/SerialPortSample/Listings/SerialPortSample_SerialPortSample_c.html
  150. // The IOSSIOSPEED ioctl can be used to set arbitrary baud rates
  151. // other than those specified by POSIX. The driver for the underlying serial hardware
  152. // ultimately determines which baud rates can be used. This ioctl sets both the input
  153. // and output speed.
  154. speed_t speed = baudrate;
  155. if (ioctl(fd, IOSSIOSPEED, &speed) == -1) {
  156. log_error("btstack_uart_posix_set_baudrate: error calling ioctl(..., IOSSIOSPEED, %u) - %s(%d).\n", baudrate, strerror(errno), errno);
  157. return -1;
  158. }
  159. #else
  160. struct termios toptions;
  161. if (tcgetattr(fd, &toptions) < 0) {
  162. log_error("btstack_uart_posix_set_baudrate: Couldn't get term attributes");
  163. return -1;
  164. }
  165. speed_t brate = baudrate; // let you override switch below if needed
  166. switch(baudrate) {
  167. case 9600: brate=B9600; break;
  168. case 19200: brate=B19200; break;
  169. case 38400: brate=B38400; break;
  170. case 57600: brate=B57600; break;
  171. case 115200: brate=B115200; break;
  172. #ifdef B230400
  173. case 230400: brate=B230400; break;
  174. #endif
  175. #ifdef B460800
  176. case 460800: brate=B460800; break;
  177. #endif
  178. #ifdef B500000
  179. case 500000: brate=B500000; break;
  180. #endif
  181. #ifdef B576000
  182. case 576000: brate=B576000; break;
  183. #endif
  184. #ifdef B921600
  185. case 921600: brate=B921600; break;
  186. #endif
  187. #ifdef B1000000
  188. case 1000000: brate=B1000000; break;
  189. #endif
  190. #ifdef B1152000
  191. case 1152000: brate=B1152000; break;
  192. #endif
  193. #ifdef B1500000
  194. case 1500000: brate=B1500000; break;
  195. #endif
  196. #ifdef B2000000
  197. case 2000000: brate=B2000000; break;
  198. #endif
  199. #ifdef B2500000
  200. case 2500000: brate=B2500000; break;
  201. #endif
  202. #ifdef B3000000
  203. case 3000000: brate=B3000000; break;
  204. #endif
  205. #ifdef B3500000
  206. case 3500000: brate=B3500000; break;
  207. #endif
  208. #ifdef B400000
  209. case 4000000: brate=B4000000; break;
  210. #endif
  211. default:
  212. log_error("can't set baudrate %dn", baudrate );
  213. return -1;
  214. }
  215. cfsetospeed(&toptions, brate);
  216. cfsetispeed(&toptions, brate);
  217. if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
  218. log_error("Couldn't set term attributes");
  219. return -1;
  220. }
  221. #endif
  222. return 0;
  223. }
  224. static void btstack_uart_posix_set_parity_option(struct termios * toptions, int parity){
  225. if (parity){
  226. // enable even parity
  227. toptions->c_cflag |= PARENB;
  228. } else {
  229. // disable even parity
  230. toptions->c_cflag &= ~PARENB;
  231. }
  232. }
  233. static void btstack_uart_posix_set_flowcontrol_option(struct termios * toptions, int flowcontrol){
  234. if (flowcontrol) {
  235. // with flow control
  236. toptions->c_cflag |= CRTSCTS;
  237. } else {
  238. // no flow control
  239. toptions->c_cflag &= ~CRTSCTS;
  240. }
  241. }
  242. static int btstack_uart_posix_set_parity(int parity){
  243. int fd = transport_data_source.source.fd;
  244. struct termios toptions;
  245. if (tcgetattr(fd, &toptions) < 0) {
  246. log_error("Couldn't get term attributes");
  247. return -1;
  248. }
  249. btstack_uart_posix_set_parity_option(&toptions, parity);
  250. if(tcsetattr(fd, TCSANOW, &toptions) < 0) {
  251. log_error("Couldn't set term attributes");
  252. return -1;
  253. }
  254. return 0;
  255. }
  256. static int btstack_uart_posix_set_flowcontrol(int flowcontrol){
  257. int fd = transport_data_source.source.fd;
  258. struct termios toptions;
  259. if (tcgetattr(fd, &toptions) < 0) {
  260. log_error("Couldn't get term attributes");
  261. return -1;
  262. }
  263. btstack_uart_posix_set_flowcontrol_option(&toptions, flowcontrol);
  264. if(tcsetattr(fd, TCSANOW, &toptions) < 0) {
  265. log_error("Couldn't set term attributes");
  266. return -1;
  267. }
  268. return 0;
  269. }
  270. static int btstack_uart_posix_open(void){
  271. const char * device_name = uart_config->device_name;
  272. const int flowcontrol = uart_config->flowcontrol;
  273. const uint32_t baudrate = uart_config->baudrate;
  274. struct termios toptions;
  275. int flags = O_RDWR | O_NOCTTY | O_NONBLOCK;
  276. int fd = open(device_name, flags);
  277. if (fd == -1) {
  278. log_error("Unable to open port %s", device_name);
  279. return -1;
  280. }
  281. if (tcgetattr(fd, &toptions) < 0) {
  282. log_error("Couldn't get term attributes");
  283. return -1;
  284. }
  285. cfmakeraw(&toptions); // make raw
  286. // 8N1
  287. toptions.c_cflag &= ~CSTOPB;
  288. toptions.c_cflag |= CS8;
  289. toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
  290. toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
  291. // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
  292. toptions.c_cc[VMIN] = 1;
  293. toptions.c_cc[VTIME] = 0;
  294. // no parity
  295. btstack_uart_posix_set_parity_option(&toptions, 0);
  296. // flowcontrol
  297. btstack_uart_posix_set_flowcontrol_option(&toptions, flowcontrol);
  298. if(tcsetattr(fd, TCSANOW, &toptions) < 0) {
  299. log_error("Couldn't set term attributes");
  300. return -1;
  301. }
  302. // store fd in data source
  303. transport_data_source.source.fd = fd;
  304. // also set baudrate
  305. if (btstack_uart_posix_set_baudrate(baudrate) < 0){
  306. return -1;
  307. }
  308. // set up data_source
  309. btstack_run_loop_set_data_source_fd(&transport_data_source, fd);
  310. btstack_run_loop_set_data_source_handler(&transport_data_source, &hci_uart_posix_process);
  311. btstack_run_loop_add_data_source(&transport_data_source);
  312. // wait a bit - at least cheap FTDI232 clones might send the first byte out incorrectly
  313. rt_thread_mdelay(100);
  314. return 0;
  315. }
  316. static int btstack_uart_posix_close_new(void){
  317. // first remove run loop handler
  318. btstack_run_loop_remove_data_source(&transport_data_source);
  319. // then close device
  320. close(transport_data_source.source.fd);
  321. transport_data_source.source.fd = -1;
  322. return 0;
  323. }
  324. static void btstack_uart_posix_set_block_received( void (*block_handler)(void)){
  325. block_received = block_handler;
  326. }
  327. static void btstack_uart_posix_set_block_sent( void (*block_handler)(void)){
  328. block_sent = block_handler;
  329. }
  330. static void btstack_uart_posix_send_block(const uint8_t *data, uint16_t size){
  331. // setup async write
  332. write_bytes_data = data;
  333. write_bytes_len = size;
  334. // go
  335. // btstack_uart_posix_process_write(&transport_data_source);
  336. btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_WRITE);
  337. }
  338. static void btstack_uart_posix_receive_block(uint8_t *buffer, uint16_t len){
  339. read_bytes_data = buffer;
  340. read_bytes_len = len;
  341. btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_READ);
  342. // go
  343. // btstack_uart_posix_process_read(&transport_data_source);
  344. }
  345. // static void btstack_uart_posix_set_sleep(uint8_t sleep){
  346. // }
  347. // static void btstack_uart_posix_set_csr_irq_handler( void (*csr_irq_handler)(void)){
  348. // }
  349. static const btstack_uart_block_t btstack_uart_posix = {
  350. /* int (*init)(hci_transport_config_uart_t * config); */ &btstack_uart_posix_init,
  351. /* int (*open)(void); */ &btstack_uart_posix_open,
  352. /* int (*close)(void); */ &btstack_uart_posix_close_new,
  353. /* void (*set_block_received)(void (*handler)(void)); */ &btstack_uart_posix_set_block_received,
  354. /* void (*set_block_sent)(void (*handler)(void)); */ &btstack_uart_posix_set_block_sent,
  355. /* int (*set_baudrate)(uint32_t baudrate); */ &btstack_uart_posix_set_baudrate,
  356. /* int (*set_parity)(int parity); */ &btstack_uart_posix_set_parity,
  357. /* int (*set_flowcontrol)(int flowcontrol); */ &btstack_uart_posix_set_flowcontrol,
  358. /* void (*receive_block)(uint8_t *buffer, uint16_t len); */ &btstack_uart_posix_receive_block,
  359. /* void (*send_block)(const uint8_t *buffer, uint16_t length); */ &btstack_uart_posix_send_block,
  360. /* int (*get_supported_sleep_modes); */ NULL,
  361. /* void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); */ NULL,
  362. /* void (*set_wakeup_handler)(void (*handler)(void)); */ NULL,
  363. };
  364. const btstack_uart_block_t * btstack_uart_block_posix_instance(void){
  365. return &btstack_uart_posix;
  366. }