18caefee3SMatthias Ringwald /*
28caefee3SMatthias Ringwald * Copyright (C) 2009-2012 by Matthias Ringwald
38caefee3SMatthias Ringwald *
48caefee3SMatthias Ringwald * Redistribution and use in source and binary forms, with or without
58caefee3SMatthias Ringwald * modification, are permitted provided that the following conditions
68caefee3SMatthias Ringwald * are met:
78caefee3SMatthias Ringwald *
88caefee3SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright
98caefee3SMatthias Ringwald * notice, this list of conditions and the following disclaimer.
108caefee3SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright
118caefee3SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the
128caefee3SMatthias Ringwald * documentation and/or other materials provided with the distribution.
138caefee3SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of
148caefee3SMatthias Ringwald * contributors may be used to endorse or promote products derived
158caefee3SMatthias Ringwald * from this software without specific prior written permission.
168caefee3SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for
178caefee3SMatthias Ringwald * personal benefit and not for any commercial purpose or for
188caefee3SMatthias Ringwald * monetary gain.
198caefee3SMatthias Ringwald *
208caefee3SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
218caefee3SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
228caefee3SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
238caefee3SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
248caefee3SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
258caefee3SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
268caefee3SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
278caefee3SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
288caefee3SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
298caefee3SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
308caefee3SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
318caefee3SMatthias Ringwald * SUCH DAMAGE.
328caefee3SMatthias Ringwald *
3351acb414SMatthias Ringwald * Please inquire about commercial licensing options at [email protected]
348caefee3SMatthias Ringwald *
358caefee3SMatthias Ringwald */
368caefee3SMatthias Ringwald
378caefee3SMatthias Ringwald /*
388caefee3SMatthias Ringwald * hci_h4_transport.c
398caefee3SMatthias Ringwald *
408caefee3SMatthias Ringwald * HCI Transport API implementation for basic H4 protocol over POSIX
418caefee3SMatthias Ringwald *
428caefee3SMatthias Ringwald * Created by Matthias Ringwald on 4/29/09.
438caefee3SMatthias Ringwald */
448caefee3SMatthias Ringwald
457907f069SMatthias Ringwald #include "btstack_config.h"
468caefee3SMatthias Ringwald
478caefee3SMatthias Ringwald #include <stdio.h>
488caefee3SMatthias Ringwald
498caefee3SMatthias Ringwald #include "bluetoothdrv.h"
508caefee3SMatthias Ringwald
518caefee3SMatthias Ringwald #include <string.h>
528caefee3SMatthias Ringwald
5316ece135SMatthias Ringwald #include "btstack_debug.h"
548caefee3SMatthias Ringwald #include "hci.h"
558caefee3SMatthias Ringwald #include "hci_transport.h"
56*c8dfe071SMatthias Ringwald #include "hci_transport_h4.h"
578caefee3SMatthias Ringwald
587cd5ef95SMatthias Ringwald static void h4_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type);
598caefee3SMatthias Ringwald static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size);
608caefee3SMatthias Ringwald
618caefee3SMatthias Ringwald typedef struct hci_transport_h4 {
628caefee3SMatthias Ringwald hci_transport_t transport;
63ec820d77SMatthias Ringwald btstack_data_source_t *ds;
648caefee3SMatthias Ringwald /* power management support, e.g. used by iOS */
65ec820d77SMatthias Ringwald btstack_timer_source_t sleep_timer;
668caefee3SMatthias Ringwald } hci_transport_h4_t;
678caefee3SMatthias Ringwald
688caefee3SMatthias Ringwald // single instance
698caefee3SMatthias Ringwald static hci_transport_h4_t * hci_transport_h4 = NULL;
708caefee3SMatthias Ringwald
718caefee3SMatthias Ringwald static void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size) = dummy_handler;
728caefee3SMatthias Ringwald
738caefee3SMatthias Ringwald // packet bufffers
74fc6cde64SMatthias Ringwald static uint8_t hci_packet_out[1+HCI_OUTGOING_PACKET_BUFFER_SIZE]; // packet type + max(acl header + acl payload, cmd header + cmd data)
75fc6cde64SMatthias Ringwald static uint8_t hci_packet_in[ 1+HCI_INCOMING_PACKET_BUFFER_SIZE]; // packet type + max(acl header + acl payload, event header + event data)
768caefee3SMatthias Ringwald
h4_open(void)772531c97eSMatthias Ringwald static int h4_open(void){
788caefee3SMatthias Ringwald int fd = mtk_bt_enable();
798caefee3SMatthias Ringwald
808caefee3SMatthias Ringwald if (fd < 0) {
818caefee3SMatthias Ringwald log_error("mtk_bt_enable failed");
828caefee3SMatthias Ringwald return -1;
838caefee3SMatthias Ringwald }
848caefee3SMatthias Ringwald
858caefee3SMatthias Ringwald // set up data_source
86ec820d77SMatthias Ringwald hci_transport_h4->ds = (btstack_data_source_t*) malloc(sizeof(btstack_data_source_t));
878caefee3SMatthias Ringwald if (!hci_transport_h4->ds) return -1;
883a5c43eeSMatthias Ringwald memset(hci_transport_h4->ds, 0, sizeof(btstack_data_source_t));
893a5c43eeSMatthias Ringwald btstack_run_loop_set_data_source_fd(hci_transport_h4->ds, fd);
90835c1671SMatthias Ringwald btstack_run_loop_set_data_source_handler(hci_transport_h4->ds, &h4_process);
9124ced5a6SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(hci_transport_h4->ds, DATA_SOURCE_CALLBACK_READ);
92528a4a3bSMatthias Ringwald btstack_run_loop_add_data_source(hci_transport_h4->ds);
938caefee3SMatthias Ringwald return 0;
948caefee3SMatthias Ringwald }
958caefee3SMatthias Ringwald
h4_close(void)962531c97eSMatthias Ringwald static int h4_close(void){
978caefee3SMatthias Ringwald
98c6d79a84SMatthias Ringwald mtk_bt_disable(hci_transport_h4->ds->source.fd);
998caefee3SMatthias Ringwald
1008caefee3SMatthias Ringwald // first remove run loop handler
101528a4a3bSMatthias Ringwald btstack_run_loop_remove_data_source(hci_transport_h4->ds);
1028caefee3SMatthias Ringwald
1038caefee3SMatthias Ringwald // free struct
1048caefee3SMatthias Ringwald free(hci_transport_h4->ds);
1058caefee3SMatthias Ringwald hci_transport_h4->ds = NULL;
1068caefee3SMatthias Ringwald return 0;
1078caefee3SMatthias Ringwald }
1088caefee3SMatthias Ringwald
h4_send_packet(uint8_t packet_type,uint8_t * packet,int size)1098caefee3SMatthias Ringwald static int h4_send_packet(uint8_t packet_type, uint8_t * packet, int size){
1108caefee3SMatthias Ringwald
1118caefee3SMatthias Ringwald if (hci_transport_h4->ds == NULL) return -1;
1128caefee3SMatthias Ringwald
1138caefee3SMatthias Ringwald // preapare packet
1148caefee3SMatthias Ringwald hci_packet_out[0] = packet_type;
1158caefee3SMatthias Ringwald memcpy(&hci_packet_out[1], packet, size);
1168caefee3SMatthias Ringwald
1178caefee3SMatthias Ringwald // send
118c6d79a84SMatthias Ringwald int res = mtk_bt_write(hci_transport_h4->ds->source.fd, hci_packet_out, size + 1);
1198caefee3SMatthias Ringwald
1208caefee3SMatthias Ringwald return 0;
1218caefee3SMatthias Ringwald }
1228caefee3SMatthias Ringwald
h4_register_packet_handler(void (* handler)(uint8_t packet_type,uint8_t * packet,uint16_t size))1238caefee3SMatthias Ringwald static void h4_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
1248caefee3SMatthias Ringwald packet_handler = handler;
1258caefee3SMatthias Ringwald }
1268caefee3SMatthias Ringwald
h4_process(btstack_data_source_t * ds,btstack_data_source_callback_type_t callback_type)1277cd5ef95SMatthias Ringwald static void h4_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
128c6d79a84SMatthias Ringwald if (hci_transport_h4->ds->source.fd == 0) return;
1298caefee3SMatthias Ringwald
1308caefee3SMatthias Ringwald // read up to bytes_to_read data in
131c6d79a84SMatthias Ringwald ssize_t bytes_read = mtk_bt_read(hci_transport_h4->ds->source.fd, &hci_packet_in[0], sizeof(hci_packet_in));
1328caefee3SMatthias Ringwald
1338b26961aSMatthias Ringwald if (bytes_read == 0) return;
1348caefee3SMatthias Ringwald
1358caefee3SMatthias Ringwald // iterate over packets
1368caefee3SMatthias Ringwald uint16_t pos = 0;
1378caefee3SMatthias Ringwald while (pos < bytes_read) {
1388caefee3SMatthias Ringwald uint16_t packet_len;
1398caefee3SMatthias Ringwald switch(hci_packet_in[pos]){
1408caefee3SMatthias Ringwald case HCI_EVENT_PACKET:
1418caefee3SMatthias Ringwald packet_len = hci_packet_in[pos+2] + 3;
1428caefee3SMatthias Ringwald break;
1438caefee3SMatthias Ringwald case HCI_ACL_DATA_PACKET:
144f8fbdce0SMatthias Ringwald packet_len = little_endian_read_16(hci_packet_in, pos + 3) + 5;
1458caefee3SMatthias Ringwald break;
1468caefee3SMatthias Ringwald default:
1478caefee3SMatthias Ringwald log_error("h4_process: invalid packet type 0x%02x\n", hci_packet_in[pos]);
1488caefee3SMatthias Ringwald return;
1498caefee3SMatthias Ringwald }
1508caefee3SMatthias Ringwald
1518caefee3SMatthias Ringwald packet_handler(hci_packet_in[pos], &hci_packet_in[pos+1], packet_len-1);
1528caefee3SMatthias Ringwald pos += packet_len;
1538caefee3SMatthias Ringwald }
1548caefee3SMatthias Ringwald }
1558caefee3SMatthias Ringwald
dummy_handler(uint8_t packet_type,uint8_t * packet,uint16_t size)1568caefee3SMatthias Ringwald static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
1578caefee3SMatthias Ringwald }
1588caefee3SMatthias Ringwald
1598caefee3SMatthias Ringwald // get h4 singleton
hci_transport_h4_instance_for_uart(const btstack_uart_t * uart_driver)160793a0509SMatthias Ringwald const hci_transport_t * hci_transport_h4_instance_for_uart(const btstack_uart_t * uart_driver){
161793a0509SMatthias Ringwald (void) uart_driver;
1628caefee3SMatthias Ringwald if (hci_transport_h4 == NULL) {
1638caefee3SMatthias Ringwald hci_transport_h4 = (hci_transport_h4_t*)malloc( sizeof(hci_transport_h4_t));
1642531c97eSMatthias Ringwald memset(hci_transport_h4, 0, sizeof(hci_transport_h4_t));
1652531c97eSMatthias Ringwald hci_transport_h4->transport.name = "H4 MTK";
1668caefee3SMatthias Ringwald hci_transport_h4->transport.open = h4_open;
1678caefee3SMatthias Ringwald hci_transport_h4->transport.close = h4_close;
1688caefee3SMatthias Ringwald hci_transport_h4->transport.send_packet = h4_send_packet;
1698caefee3SMatthias Ringwald hci_transport_h4->transport.register_packet_handler = h4_register_packet_handler;
1708caefee3SMatthias Ringwald }
1718caefee3SMatthias Ringwald return (hci_transport_t *) hci_transport_h4;
1728caefee3SMatthias Ringwald }
173