| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- /*
- * Copyright (C) 2016 BlueKitchen GmbH
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * 4. Any redistribution, use, or modification is done solely for
- * personal benefit and not for any commercial purpose or for
- * monetary gain.
- *
- * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
- * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Please inquire about commercial licensing options at
- * contact@bluekitchen-gmbh.com
- *
- */
- #define BTSTACK_FILE__ "btstack_uart_block_posix.c"
- /*
- * btstack_uart_block_posix.c
- *
- * Common code to access serial port via asynchronous block read/write commands
- *
- */
- #include "btstack_uart_block.h"
- #include "btstack_run_loop.h"
- #include "btstack_debug.h"
- #include <termios.h> /* POSIX terminal control definitions */
- #include <fcntl.h> /* File control definitions */
- #include <unistd.h> /* UNIX standard function definitions */
- #include <string.h>
- #include <errno.h>
- #ifdef __APPLE__
- #include <sys/ioctl.h>
- #include <IOKit/serial/ioss.h>
- #endif
- // uart config
- static const btstack_uart_config_t * uart_config;
- // data source for integration with BTstack Runloop
- static btstack_data_source_t transport_data_source;
- // block write
- static int write_bytes_len;
- static const uint8_t * write_bytes_data;
- // block read
- static uint16_t read_bytes_len;
- static uint8_t * read_bytes_data;
- // callbacks
- static void (*block_sent)(void);
- static void (*block_received)(void);
- static int btstack_uart_posix_init(const btstack_uart_config_t * config){
- uart_config = config;
- return 0;
- }
- static void btstack_uart_posix_process_write(btstack_data_source_t *ds) {
-
- if (write_bytes_len == 0) return;
- uint32_t start = btstack_run_loop_get_time_ms();
- // write up to write_bytes_len to fd
- int bytes_written = (int) write(ds->source.fd, write_bytes_data, write_bytes_len);
- uint32_t end = btstack_run_loop_get_time_ms();
- if (end - start > 10){
- log_info("write took %u ms", end - start);
- }
- if (bytes_written == 0){
- log_error("wrote zero bytes\n");
- return;
- }
- if (bytes_written < 0) {
- log_error("write returned error\n");
- btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
- return;
- }
- write_bytes_data += bytes_written;
- write_bytes_len -= bytes_written;
- if (write_bytes_len){
- btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
- return;
- }
- btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
- // notify done
- if (block_sent){
- block_sent();
- }
- }
- static void btstack_uart_posix_process_read(btstack_data_source_t *ds) {
- if (read_bytes_len == 0) {
- log_info("called but no read pending");
- btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
- }
- uint32_t start = btstack_run_loop_get_time_ms();
-
- // read up to bytes_to_read data in
- ssize_t bytes_read = read(ds->source.fd, read_bytes_data, read_bytes_len);
- // log_info("btstack_uart_posix_process_read need %u bytes, got %d", read_bytes_len, (int) bytes_read);
- uint32_t end = btstack_run_loop_get_time_ms();
- if (end - start > 10){
- log_info("read took %u ms", end - start);
- }
- if (bytes_read == 0){
- log_error("read zero bytes\n");
- return;
- }
- if (bytes_read < 0) {
- //log_error("read returned error bytes_read:%d\n",bytes_read);
- return;
- }
- read_bytes_len -= bytes_read;
- read_bytes_data += bytes_read;
- if (read_bytes_len > 0) return;
-
- btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
- if (block_received){
- block_received();
- }
- }
- static void hci_uart_posix_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
- if (ds->source.fd < 0) return;
- switch (callback_type){
- case DATA_SOURCE_CALLBACK_READ:
- btstack_uart_posix_process_read(ds);
- break;
- case DATA_SOURCE_CALLBACK_WRITE:
- btstack_uart_posix_process_write(ds);
- break;
- default:
- break;
- }
- }
- static int btstack_uart_posix_set_baudrate(uint32_t baudrate){
- int fd = transport_data_source.source.fd;
- log_info("h4_set_baudrate %u", baudrate);
- #ifdef __APPLE__
- // From https://developer.apple.com/library/content/samplecode/SerialPortSample/Listings/SerialPortSample_SerialPortSample_c.html
- // The IOSSIOSPEED ioctl can be used to set arbitrary baud rates
- // other than those specified by POSIX. The driver for the underlying serial hardware
- // ultimately determines which baud rates can be used. This ioctl sets both the input
- // and output speed.
- speed_t speed = baudrate;
- if (ioctl(fd, IOSSIOSPEED, &speed) == -1) {
- log_error("btstack_uart_posix_set_baudrate: error calling ioctl(..., IOSSIOSPEED, %u) - %s(%d).\n", baudrate, strerror(errno), errno);
- return -1;
- }
- #else
- struct termios toptions;
- if (tcgetattr(fd, &toptions) < 0) {
- log_error("btstack_uart_posix_set_baudrate: Couldn't get term attributes");
- return -1;
- }
-
- speed_t brate = baudrate; // let you override switch below if needed
- switch(baudrate) {
- case 9600: brate=B9600; break;
- case 19200: brate=B19200; break;
- case 38400: brate=B38400; break;
- case 57600: brate=B57600; break;
- case 115200: brate=B115200; break;
- #ifdef B230400
- case 230400: brate=B230400; break;
- #endif
- #ifdef B460800
- case 460800: brate=B460800; break;
- #endif
- #ifdef B500000
- case 500000: brate=B500000; break;
- #endif
- #ifdef B576000
- case 576000: brate=B576000; break;
- #endif
- #ifdef B921600
- case 921600: brate=B921600; break;
- #endif
- #ifdef B1000000
- case 1000000: brate=B1000000; break;
- #endif
- #ifdef B1152000
- case 1152000: brate=B1152000; break;
- #endif
- #ifdef B1500000
- case 1500000: brate=B1500000; break;
- #endif
- #ifdef B2000000
- case 2000000: brate=B2000000; break;
- #endif
- #ifdef B2500000
- case 2500000: brate=B2500000; break;
- #endif
- #ifdef B3000000
- case 3000000: brate=B3000000; break;
- #endif
- #ifdef B3500000
- case 3500000: brate=B3500000; break;
- #endif
- #ifdef B400000
- case 4000000: brate=B4000000; break;
- #endif
- default:
- log_error("can't set baudrate %dn", baudrate );
- return -1;
- }
- cfsetospeed(&toptions, brate);
- cfsetispeed(&toptions, brate);
- if( tcsetattr(fd, TCSANOW, &toptions) < 0) {
- log_error("Couldn't set term attributes");
- return -1;
- }
- #endif
- return 0;
- }
- static void btstack_uart_posix_set_parity_option(struct termios * toptions, int parity){
- if (parity){
- // enable even parity
- toptions->c_cflag |= PARENB;
- } else {
- // disable even parity
- toptions->c_cflag &= ~PARENB;
- }
- }
- static void btstack_uart_posix_set_flowcontrol_option(struct termios * toptions, int flowcontrol){
- if (flowcontrol) {
- // with flow control
- toptions->c_cflag |= CRTSCTS;
- } else {
- // no flow control
- toptions->c_cflag &= ~CRTSCTS;
- }
- }
- static int btstack_uart_posix_set_parity(int parity){
- int fd = transport_data_source.source.fd;
- struct termios toptions;
- if (tcgetattr(fd, &toptions) < 0) {
- log_error("Couldn't get term attributes");
- return -1;
- }
- btstack_uart_posix_set_parity_option(&toptions, parity);
- if(tcsetattr(fd, TCSANOW, &toptions) < 0) {
- log_error("Couldn't set term attributes");
- return -1;
- }
- return 0;
- }
- static int btstack_uart_posix_set_flowcontrol(int flowcontrol){
- int fd = transport_data_source.source.fd;
- struct termios toptions;
- if (tcgetattr(fd, &toptions) < 0) {
- log_error("Couldn't get term attributes");
- return -1;
- }
- btstack_uart_posix_set_flowcontrol_option(&toptions, flowcontrol);
- if(tcsetattr(fd, TCSANOW, &toptions) < 0) {
- log_error("Couldn't set term attributes");
- return -1;
- }
- return 0;
- }
- static int btstack_uart_posix_open(void){
- const char * device_name = uart_config->device_name;
- const int flowcontrol = uart_config->flowcontrol;
- const uint32_t baudrate = uart_config->baudrate;
- struct termios toptions;
- int flags = O_RDWR | O_NOCTTY | O_NONBLOCK;
- int fd = open(device_name, flags);
- if (fd == -1) {
- log_error("Unable to open port %s", device_name);
- return -1;
- }
-
- if (tcgetattr(fd, &toptions) < 0) {
- log_error("Couldn't get term attributes");
- return -1;
- }
-
- cfmakeraw(&toptions); // make raw
- // 8N1
- toptions.c_cflag &= ~CSTOPB;
- toptions.c_cflag |= CS8;
- toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
- toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
-
- // see: http://unixwiz.net/techtips/termios-vmin-vtime.html
- toptions.c_cc[VMIN] = 1;
- toptions.c_cc[VTIME] = 0;
-
- // no parity
- btstack_uart_posix_set_parity_option(&toptions, 0);
- // flowcontrol
- btstack_uart_posix_set_flowcontrol_option(&toptions, flowcontrol);
- if(tcsetattr(fd, TCSANOW, &toptions) < 0) {
- log_error("Couldn't set term attributes");
- return -1;
- }
- // store fd in data source
- transport_data_source.source.fd = fd;
-
- // also set baudrate
- if (btstack_uart_posix_set_baudrate(baudrate) < 0){
- return -1;
- }
- // set up data_source
- btstack_run_loop_set_data_source_fd(&transport_data_source, fd);
- btstack_run_loop_set_data_source_handler(&transport_data_source, &hci_uart_posix_process);
- btstack_run_loop_add_data_source(&transport_data_source);
- // wait a bit - at least cheap FTDI232 clones might send the first byte out incorrectly
- rt_thread_mdelay(100);
- return 0;
- }
- static int btstack_uart_posix_close_new(void){
- // first remove run loop handler
- btstack_run_loop_remove_data_source(&transport_data_source);
-
- // then close device
- close(transport_data_source.source.fd);
- transport_data_source.source.fd = -1;
- return 0;
- }
- static void btstack_uart_posix_set_block_received( void (*block_handler)(void)){
- block_received = block_handler;
- }
- static void btstack_uart_posix_set_block_sent( void (*block_handler)(void)){
- block_sent = block_handler;
- }
- static void btstack_uart_posix_send_block(const uint8_t *data, uint16_t size){
- // setup async write
- write_bytes_data = data;
- write_bytes_len = size;
- // go
- // btstack_uart_posix_process_write(&transport_data_source);
- btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_WRITE);
- }
- static void btstack_uart_posix_receive_block(uint8_t *buffer, uint16_t len){
- read_bytes_data = buffer;
- read_bytes_len = len;
- btstack_run_loop_enable_data_source_callbacks(&transport_data_source, DATA_SOURCE_CALLBACK_READ);
- // go
- // btstack_uart_posix_process_read(&transport_data_source);
- }
- // static void btstack_uart_posix_set_sleep(uint8_t sleep){
- // }
- // static void btstack_uart_posix_set_csr_irq_handler( void (*csr_irq_handler)(void)){
- // }
- static const btstack_uart_block_t btstack_uart_posix = {
- /* int (*init)(hci_transport_config_uart_t * config); */ &btstack_uart_posix_init,
- /* int (*open)(void); */ &btstack_uart_posix_open,
- /* int (*close)(void); */ &btstack_uart_posix_close_new,
- /* void (*set_block_received)(void (*handler)(void)); */ &btstack_uart_posix_set_block_received,
- /* void (*set_block_sent)(void (*handler)(void)); */ &btstack_uart_posix_set_block_sent,
- /* int (*set_baudrate)(uint32_t baudrate); */ &btstack_uart_posix_set_baudrate,
- /* int (*set_parity)(int parity); */ &btstack_uart_posix_set_parity,
- /* int (*set_flowcontrol)(int flowcontrol); */ &btstack_uart_posix_set_flowcontrol,
- /* void (*receive_block)(uint8_t *buffer, uint16_t len); */ &btstack_uart_posix_receive_block,
- /* void (*send_block)(const uint8_t *buffer, uint16_t length); */ &btstack_uart_posix_send_block,
- /* int (*get_supported_sleep_modes); */ NULL,
- /* void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); */ NULL,
- /* void (*set_wakeup_handler)(void (*handler)(void)); */ NULL,
- };
- const btstack_uart_block_t * btstack_uart_block_posix_instance(void){
- return &btstack_uart_posix;
- }
|