xref: /btstack/src/hci.c (revision ba681a6c12f5a85a8248d6b22cd31d5f01c62811)
11f504dbdSmatthias.ringwald /*
21f504dbdSmatthias.ringwald  *  hci.c
31f504dbdSmatthias.ringwald  *
41f504dbdSmatthias.ringwald  *  Created by Matthias Ringwald on 4/29/09.
51f504dbdSmatthias.ringwald  *
61f504dbdSmatthias.ringwald  */
71f504dbdSmatthias.ringwald 
8475c8125Smatthias.ringwald #include <unistd.h>
993b8dc03Smatthias.ringwald #include <stdarg.h>
1093b8dc03Smatthias.ringwald #include <string.h>
1156fe0872Smatthias.ringwald #include <stdio.h>
121f504dbdSmatthias.ringwald #include "hci.h"
13d8905019Smatthias.ringwald #include "hci_dump.h"
1493b8dc03Smatthias.ringwald 
1516833f0aSmatthias.ringwald // the stack is here
1616833f0aSmatthias.ringwald static hci_stack_t       hci_stack;
1716833f0aSmatthias.ringwald 
1897addcc5Smatthias.ringwald /**
1997addcc5Smatthias.ringwald  * get link for given address
2097addcc5Smatthias.ringwald  *
2197addcc5Smatthias.ringwald  * @return connection OR NULL, if not found
2297addcc5Smatthias.ringwald  */
2397addcc5Smatthias.ringwald static hci_connection_t *link_for_addr(bd_addr_t addr){
2497addcc5Smatthias.ringwald     return NULL;
2597addcc5Smatthias.ringwald }
2697addcc5Smatthias.ringwald 
2797addcc5Smatthias.ringwald /**
28*ba681a6cSmatthias.ringwald  * Dummy handler called by HCI
2916833f0aSmatthias.ringwald  */
301cd208adSmatthias.ringwald static void dummy_handler(uint8_t *packet, uint16_t size){
3116833f0aSmatthias.ringwald }
3216833f0aSmatthias.ringwald 
33*ba681a6cSmatthias.ringwald /**
34*ba681a6cSmatthias.ringwald  * Dummy control handler
35*ba681a6cSmatthias.ringwald  */
36*ba681a6cSmatthias.ringwald static int null_control_function(void *config){
37*ba681a6cSmatthias.ringwald     return 0;
38*ba681a6cSmatthias.ringwald }
39*ba681a6cSmatthias.ringwald static const char * null_control_name(void *config){
40*ba681a6cSmatthias.ringwald     return "Hardware unknown";
41*ba681a6cSmatthias.ringwald }
42*ba681a6cSmatthias.ringwald static bt_control_t null_control = {
43*ba681a6cSmatthias.ringwald     null_control_function,
44*ba681a6cSmatthias.ringwald     null_control_function,
45*ba681a6cSmatthias.ringwald     null_control_function,
46*ba681a6cSmatthias.ringwald     null_control_name
47*ba681a6cSmatthias.ringwald };
48*ba681a6cSmatthias.ringwald 
4916833f0aSmatthias.ringwald static void acl_handler(uint8_t *packet, int size){
5016833f0aSmatthias.ringwald     hci_stack.acl_packet_handler(packet, size);
5194ab26f8Smatthias.ringwald 
5294ab26f8Smatthias.ringwald     // execute main loop
5394ab26f8Smatthias.ringwald     hci_run();
5416833f0aSmatthias.ringwald }
5522909952Smatthias.ringwald 
5616833f0aSmatthias.ringwald static void event_handler(uint8_t *packet, int size){
571281a47eSmatthias.ringwald     bd_addr_t addr;
5822909952Smatthias.ringwald 
593429f56bSmatthias.ringwald     // Get Num_HCI_Command_Packets
603429f56bSmatthias.ringwald     if (packet[0] == HCI_EVENT_COMMAND_COMPLETE ||
613429f56bSmatthias.ringwald         packet[0] == HCI_EVENT_COMMAND_STATUS){
623429f56bSmatthias.ringwald         hci_stack.num_cmd_packets = packet[2];
6322909952Smatthias.ringwald     }
6422909952Smatthias.ringwald 
653429f56bSmatthias.ringwald     // handle BT initialization
663429f56bSmatthias.ringwald     if (hci_stack.state == HCI_STATE_INITIALIZING){
677301ad89Smatthias.ringwald         // handle H4 synchronization loss on restart
687301ad89Smatthias.ringwald         // if (hci_stack.substate == 1 && packet[0] == HCI_EVENT_HARDWARE_ERROR){
697301ad89Smatthias.ringwald         //    hci_stack.substate = 0;
707301ad89Smatthias.ringwald         // }
717301ad89Smatthias.ringwald         // handle normal init sequence
723429f56bSmatthias.ringwald         if (hci_stack.substate % 2){
733429f56bSmatthias.ringwald             // odd: waiting for event
743429f56bSmatthias.ringwald             if (packet[0] == HCI_EVENT_COMMAND_COMPLETE){
753429f56bSmatthias.ringwald                 hci_stack.substate++;
763429f56bSmatthias.ringwald             }
773429f56bSmatthias.ringwald         }
7822909952Smatthias.ringwald     }
7922909952Smatthias.ringwald 
801281a47eSmatthias.ringwald     // link key request
813429f56bSmatthias.ringwald     if (packet[0] == HCI_EVENT_LINK_KEY_REQUEST){
821281a47eSmatthias.ringwald         bt_flip_addr(addr, &packet[2]);
831281a47eSmatthias.ringwald         hci_send_cmd(&hci_link_key_request_negative_reply, &addr);
841281a47eSmatthias.ringwald         return;
851281a47eSmatthias.ringwald     }
861281a47eSmatthias.ringwald 
871281a47eSmatthias.ringwald     // pin code request
883429f56bSmatthias.ringwald     if (packet[0] == HCI_EVENT_PIN_CODE_REQUEST){
891281a47eSmatthias.ringwald         bt_flip_addr(addr, &packet[2]);
901281a47eSmatthias.ringwald         hci_send_cmd(&hci_pin_code_request_reply, &addr, 4, "1234");
911281a47eSmatthias.ringwald     }
921281a47eSmatthias.ringwald 
9316833f0aSmatthias.ringwald     hci_stack.event_packet_handler(packet, size);
9494ab26f8Smatthias.ringwald 
9594ab26f8Smatthias.ringwald 	// execute main loop
9694ab26f8Smatthias.ringwald 	hci_run();
9716833f0aSmatthias.ringwald }
9816833f0aSmatthias.ringwald 
9916833f0aSmatthias.ringwald /** Register L2CAP handlers */
1001cd208adSmatthias.ringwald void hci_register_event_packet_handler(void (*handler)(uint8_t *packet, uint16_t size)){
10116833f0aSmatthias.ringwald     hci_stack.event_packet_handler = handler;
10216833f0aSmatthias.ringwald }
1031cd208adSmatthias.ringwald void hci_register_acl_packet_handler  (void (*handler)(uint8_t *packet, uint16_t size)){
10416833f0aSmatthias.ringwald     hci_stack.acl_packet_handler = handler;
10516833f0aSmatthias.ringwald }
10616833f0aSmatthias.ringwald 
10711e23e5fSmatthias.ringwald void hci_init(hci_transport_t *transport, void *config, bt_control_t *control){
108475c8125Smatthias.ringwald 
109475c8125Smatthias.ringwald     // reference to use transport layer implementation
11016833f0aSmatthias.ringwald     hci_stack.hci_transport = transport;
111475c8125Smatthias.ringwald 
11211e23e5fSmatthias.ringwald     // references to used control implementation
1137301ad89Smatthias.ringwald     if (control) {
11411e23e5fSmatthias.ringwald         hci_stack.control = control;
1157301ad89Smatthias.ringwald     } else {
1167301ad89Smatthias.ringwald         hci_stack.control = &null_control;
1177301ad89Smatthias.ringwald     }
11811e23e5fSmatthias.ringwald 
11911e23e5fSmatthias.ringwald     // reference to used config
12011e23e5fSmatthias.ringwald     hci_stack.config = config;
12111e23e5fSmatthias.ringwald 
12202ea9861Smatthias.ringwald     // empty cmd buffer
12316833f0aSmatthias.ringwald     hci_stack.hci_cmd_buffer = malloc(3+255);
12416833f0aSmatthias.ringwald 
12516833f0aSmatthias.ringwald     // higher level handler
12616833f0aSmatthias.ringwald     hci_stack.event_packet_handler = dummy_handler;
12716833f0aSmatthias.ringwald     hci_stack.acl_packet_handler = dummy_handler;
12816833f0aSmatthias.ringwald 
12916833f0aSmatthias.ringwald     // register packet handlers with transport
13016833f0aSmatthias.ringwald     transport->register_event_packet_handler( event_handler);
13116833f0aSmatthias.ringwald     transport->register_acl_packet_handler( acl_handler);
132475c8125Smatthias.ringwald }
133475c8125Smatthias.ringwald 
134475c8125Smatthias.ringwald int hci_power_control(HCI_POWER_MODE power_mode){
13511e23e5fSmatthias.ringwald     if (power_mode == HCI_POWER_ON) {
1367301ad89Smatthias.ringwald 
1377301ad89Smatthias.ringwald         // set up state machine
1387301ad89Smatthias.ringwald         hci_stack.num_cmd_packets = 1; // assume that one cmd can be sent
1397301ad89Smatthias.ringwald         hci_stack.state = HCI_STATE_INITIALIZING;
1407301ad89Smatthias.ringwald         hci_stack.substate = 0;
1417301ad89Smatthias.ringwald 
1427301ad89Smatthias.ringwald         // power on
14311e23e5fSmatthias.ringwald         hci_stack.control->on(hci_stack.config);
1447301ad89Smatthias.ringwald 
1457301ad89Smatthias.ringwald         // open low-level device
1467301ad89Smatthias.ringwald         hci_stack.hci_transport->open(hci_stack.config);
1477301ad89Smatthias.ringwald 
14811e23e5fSmatthias.ringwald     } else if (power_mode == HCI_POWER_OFF){
1497301ad89Smatthias.ringwald 
1507301ad89Smatthias.ringwald         // close low-level device
1517301ad89Smatthias.ringwald         hci_stack.hci_transport->close(hci_stack.config);
1527301ad89Smatthias.ringwald 
1537301ad89Smatthias.ringwald         // power off
15411e23e5fSmatthias.ringwald         hci_stack.control->off(hci_stack.config);
15511e23e5fSmatthias.ringwald     }
15668d92d03Smatthias.ringwald 
15768d92d03Smatthias.ringwald 	// trigger next/first action
15868d92d03Smatthias.ringwald 	hci_run();
15968d92d03Smatthias.ringwald 
160475c8125Smatthias.ringwald     return 0;
161475c8125Smatthias.ringwald }
162475c8125Smatthias.ringwald 
1633429f56bSmatthias.ringwald uint32_t hci_run(){
1643429f56bSmatthias.ringwald     uint8_t micro_packet;
1653429f56bSmatthias.ringwald     switch (hci_stack.state){
1663429f56bSmatthias.ringwald         case HCI_STATE_INITIALIZING:
1673429f56bSmatthias.ringwald             if (hci_stack.substate % 2) {
1683429f56bSmatthias.ringwald                 // odd: waiting for command completion
1693429f56bSmatthias.ringwald                 return 0;
1703429f56bSmatthias.ringwald             }
1713429f56bSmatthias.ringwald             if (hci_stack.num_cmd_packets == 0) {
1723429f56bSmatthias.ringwald                 // cannot send command yet
1733429f56bSmatthias.ringwald                 return 0;
1743429f56bSmatthias.ringwald             }
1753429f56bSmatthias.ringwald             switch (hci_stack.substate/2){
1763429f56bSmatthias.ringwald                 case 0:
17722909952Smatthias.ringwald                     hci_send_cmd(&hci_reset);
1783429f56bSmatthias.ringwald                     break;
1793429f56bSmatthias.ringwald 				case 1:
180f432a6ddSmatthias.ringwald 					hci_send_cmd(&hci_read_bd_addr);
181f432a6ddSmatthias.ringwald 					break;
182f432a6ddSmatthias.ringwald                 case 2:
1833429f56bSmatthias.ringwald                     // ca. 15 sec
1843429f56bSmatthias.ringwald                     hci_send_cmd(&hci_write_page_timeout, 0x6000);
1853429f56bSmatthias.ringwald                     break;
186f432a6ddSmatthias.ringwald 				case 3:
187bd67ef2fSmatthias.ringwald 					hci_send_cmd(&hci_write_scan_enable, 3); // 3 inq scan + page scan
188f432a6ddSmatthias.ringwald 					break;
189f432a6ddSmatthias.ringwald                 case 4:
1903429f56bSmatthias.ringwald                     // done.
1913429f56bSmatthias.ringwald                     hci_stack.state = HCI_STATE_WORKING;
1928adf0ddaSmatthias.ringwald                     micro_packet = HCI_EVENT_BTSTACK_WORKING;
1933429f56bSmatthias.ringwald                     hci_stack.event_packet_handler(&micro_packet, 1);
1943429f56bSmatthias.ringwald                     break;
1953429f56bSmatthias.ringwald                 default:
1963429f56bSmatthias.ringwald                     break;
197475c8125Smatthias.ringwald             }
1983429f56bSmatthias.ringwald             hci_stack.substate++;
1993429f56bSmatthias.ringwald             break;
2003429f56bSmatthias.ringwald         default:
2013429f56bSmatthias.ringwald             break;
2021f504dbdSmatthias.ringwald     }
20393b8dc03Smatthias.ringwald 
2043429f56bSmatthias.ringwald     // don't check for timetous yet
2053429f56bSmatthias.ringwald     return 0;
2063429f56bSmatthias.ringwald }
20716833f0aSmatthias.ringwald 
20816833f0aSmatthias.ringwald 
20943625864Smatthias.ringwald int hci_send_acl_packet(uint8_t *packet, int size){
21016833f0aSmatthias.ringwald     return hci_stack.hci_transport->send_acl_packet(packet, size);
21143625864Smatthias.ringwald }
21243625864Smatthias.ringwald 
21331452debSmatthias.ringwald int hci_send_cmd_packet(uint8_t *packet, int size){
21431452debSmatthias.ringwald     if (READ_CMD_OGF(packet) != OGF_BTSTACK) {
21531452debSmatthias.ringwald         hci_stack.num_cmd_packets--;
21631452debSmatthias.ringwald         return hci_stack.hci_transport->send_cmd_packet(packet, size);
21731452debSmatthias.ringwald     }
21831452debSmatthias.ringwald 
21931452debSmatthias.ringwald     hci_dump_packet( HCI_COMMAND_DATA_PACKET, 1, packet, size);
22031452debSmatthias.ringwald 
2218adf0ddaSmatthias.ringwald     // BTstack internal commands
2228adf0ddaSmatthias.ringwald     uint8_t event[3];
2238adf0ddaSmatthias.ringwald     switch (READ_CMD_OCF(packet)){
2248adf0ddaSmatthias.ringwald         case HCI_BTSTACK_GET_STATE:
2258adf0ddaSmatthias.ringwald             event[0] = HCI_EVENT_BTSTACK_STATE;
2268adf0ddaSmatthias.ringwald             event[1] = 1;
2278adf0ddaSmatthias.ringwald             event[2] = hci_stack.state;
22831452debSmatthias.ringwald             hci_dump_packet( HCI_EVENT_PACKET, 0, event, 3);
2298adf0ddaSmatthias.ringwald             hci_stack.event_packet_handler(event, 3);
2308adf0ddaSmatthias.ringwald             break;
2318adf0ddaSmatthias.ringwald         default:
2328adf0ddaSmatthias.ringwald             // TODO log into hci dump as vendor specific "event"
2338adf0ddaSmatthias.ringwald             printf("Error: command %u not implemented\n:", READ_CMD_OCF(packet));
2348adf0ddaSmatthias.ringwald             break;
2358adf0ddaSmatthias.ringwald     }
2368adf0ddaSmatthias.ringwald     return 0;
2378adf0ddaSmatthias.ringwald }
2388adf0ddaSmatthias.ringwald 
2391cd208adSmatthias.ringwald /**
2401cd208adSmatthias.ringwald  * pre: numcmds >= 0 - it's allowed to send a command to the controller
2411cd208adSmatthias.ringwald  */
2421cd208adSmatthias.ringwald int hci_send_cmd(hci_cmd_t *cmd, ...){
2431cd208adSmatthias.ringwald     va_list argptr;
2441cd208adSmatthias.ringwald     va_start(argptr, cmd);
2451cd208adSmatthias.ringwald     uint8_t * hci_cmd_buffer = hci_stack.hci_cmd_buffer;
2461cd208adSmatthias.ringwald     uint16_t size = hci_create_cmd_internal(hci_stack.hci_cmd_buffer, cmd, argptr);
2471cd208adSmatthias.ringwald     va_end(argptr);
2481cd208adSmatthias.ringwald     return hci_send_cmd_packet(hci_cmd_buffer, size);
24993b8dc03Smatthias.ringwald }