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" 131f504dbdSmatthias.ringwald 140a974e0cSmatthias.ringwald // calculate combined ogf/ocf value 150a974e0cSmatthias.ringwald #define OPCODE(ogf, ocf) (ocf | ogf << 10) 16*02ea9861Smatthias.ringwald #define OGF_LINK_CONTROL 0x01 17*02ea9861Smatthias.ringwald #define OGF_CONTROLLER_BASEBAND 0x03 1893b8dc03Smatthias.ringwald 1993b8dc03Smatthias.ringwald hci_cmd_t hci_inquiry = { 20*02ea9861Smatthias.ringwald OPCODE(OGF_LINK_CONTROL, 0x01), "311" // LAP, Inquiry length, Num_responses 2193b8dc03Smatthias.ringwald }; 2293b8dc03Smatthias.ringwald 2393b8dc03Smatthias.ringwald hci_cmd_t hci_reset = { 24*02ea9861Smatthias.ringwald OPCODE(OGF_CONTROLLER_BASEBAND, 0x03), "" 25*02ea9861Smatthias.ringwald }; 26*02ea9861Smatthias.ringwald 27*02ea9861Smatthias.ringwald hci_cmd_t hci_create_connection = { 28*02ea9861Smatthias.ringwald OPCODE(OGF_LINK_CONTROL, 0x05), "B21121" 29*02ea9861Smatthias.ringwald // BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch 30*02ea9861Smatthias.ringwald }; 31*02ea9861Smatthias.ringwald 32*02ea9861Smatthias.ringwald hci_cmd_t hci_write_page_timeout = { 33*02ea9861Smatthias.ringwald OPCODE(OGF_CONTROLLER_BASEBAND, 0x18), "2" 34*02ea9861Smatthias.ringwald // Page_Timeout * 0.625 ms 35*02ea9861Smatthias.ringwald }; 36*02ea9861Smatthias.ringwald 37*02ea9861Smatthias.ringwald hci_cmd_t hci_host_buffer_size = { 38*02ea9861Smatthias.ringwald OPCODE(OGF_CONTROLLER_BASEBAND, 0x33), "2122" 39*02ea9861Smatthias.ringwald // Host_ACL_Data_Packet_Length:, Host_Synchronous_Data_Packet_Length:, Host_Total_Num_ACL_Data_Packets:, Host_Total_Num_Synchronous_Data_Packets: 4093b8dc03Smatthias.ringwald }; 4193b8dc03Smatthias.ringwald 4293b8dc03Smatthias.ringwald 43475c8125Smatthias.ringwald static hci_transport_t * hci_transport; 44*02ea9861Smatthias.ringwald static uint8_t * hci_cmd_buffer; 45475c8125Smatthias.ringwald 4656fe0872Smatthias.ringwald void hexdump(uint8_t *data, int size){ 4756fe0872Smatthias.ringwald int i; 4856fe0872Smatthias.ringwald for (i=0; i<size;i++){ 4956fe0872Smatthias.ringwald printf("%02X ", data[i]); 5056fe0872Smatthias.ringwald } 5156fe0872Smatthias.ringwald printf("\n"); 5256fe0872Smatthias.ringwald } 5356fe0872Smatthias.ringwald 5456fe0872Smatthias.ringwald #if 0 5556fe0872Smatthias.ringwald static void *hci_daemon_thread(void *arg){ 5656fe0872Smatthias.ringwald printf("HCI Daemon started\n"); 5756fe0872Smatthias.ringwald hci_run(transport, &config); 5856fe0872Smatthias.ringwald return NULL; 5956fe0872Smatthias.ringwald } 6056fe0872Smatthias.ringwald #endif 6156fe0872Smatthias.ringwald 62475c8125Smatthias.ringwald void hci_init(hci_transport_t *transport, void *config){ 63475c8125Smatthias.ringwald 64475c8125Smatthias.ringwald // reference to use transport layer implementation 65475c8125Smatthias.ringwald hci_transport = transport; 66475c8125Smatthias.ringwald 67*02ea9861Smatthias.ringwald // empty cmd buffer 68*02ea9861Smatthias.ringwald hci_cmd_buffer = malloc(3+255); 69*02ea9861Smatthias.ringwald 70475c8125Smatthias.ringwald // open unix socket 71475c8125Smatthias.ringwald 72475c8125Smatthias.ringwald // wait for connections 73475c8125Smatthias.ringwald 74475c8125Smatthias.ringwald // enter loop 75475c8125Smatthias.ringwald 76475c8125Smatthias.ringwald // handle events 77475c8125Smatthias.ringwald } 78475c8125Smatthias.ringwald 79475c8125Smatthias.ringwald int hci_power_control(HCI_POWER_MODE power_mode){ 80475c8125Smatthias.ringwald return 0; 81475c8125Smatthias.ringwald } 82475c8125Smatthias.ringwald 83475c8125Smatthias.ringwald void hci_run(){ 84475c8125Smatthias.ringwald while (1) { 85475c8125Smatthias.ringwald // construct file descriptor set to wait for 86475c8125Smatthias.ringwald // select 87475c8125Smatthias.ringwald 88475c8125Smatthias.ringwald // for each ready file in FD - call handle_data 89475c8125Smatthias.ringwald sleep(1); 90475c8125Smatthias.ringwald } 911f504dbdSmatthias.ringwald } 9293b8dc03Smatthias.ringwald 93*02ea9861Smatthias.ringwald int hci_send_cmd(hci_cmd_t *cmd, ...){ 94*02ea9861Smatthias.ringwald hci_cmd_buffer[0] = cmd->opcode & 0xff; 95*02ea9861Smatthias.ringwald hci_cmd_buffer[1] = cmd->opcode >> 8; 9693b8dc03Smatthias.ringwald int pos = 3; 9793b8dc03Smatthias.ringwald 9893b8dc03Smatthias.ringwald va_list argptr; 9993b8dc03Smatthias.ringwald va_start(argptr, cmd); 10093b8dc03Smatthias.ringwald const char *format = cmd->format; 10193b8dc03Smatthias.ringwald uint16_t word; 10293b8dc03Smatthias.ringwald uint32_t longword; 10393b8dc03Smatthias.ringwald uint8_t * bt_addr; 10493b8dc03Smatthias.ringwald while (*format) { 10593b8dc03Smatthias.ringwald switch(*format) { 10693b8dc03Smatthias.ringwald case '1': // 8 bit value 10793b8dc03Smatthias.ringwald case '2': // 16 bit value 10893b8dc03Smatthias.ringwald case 'H': // hci_handle 109554588a5Smatthias.ringwald word = va_arg(argptr, int); // minimal va_arg is int: 2 bytes on 8+16 bit CPUs 110*02ea9861Smatthias.ringwald hci_cmd_buffer[pos++] = word & 0xff; 11193b8dc03Smatthias.ringwald if (*format == '2') { 112*02ea9861Smatthias.ringwald hci_cmd_buffer[pos++] = word >> 8; 11393b8dc03Smatthias.ringwald } else if (*format == 'H') { 114554588a5Smatthias.ringwald // TODO 11593b8dc03Smatthias.ringwald } 11693b8dc03Smatthias.ringwald break; 11793b8dc03Smatthias.ringwald case '3': 11893b8dc03Smatthias.ringwald case '4': 11993b8dc03Smatthias.ringwald longword = va_arg(argptr, uint32_t); 12093b8dc03Smatthias.ringwald // longword = va_arg(argptr, int); 121*02ea9861Smatthias.ringwald hci_cmd_buffer[pos++] = longword; 122*02ea9861Smatthias.ringwald hci_cmd_buffer[pos++] = longword >> 8; 123*02ea9861Smatthias.ringwald hci_cmd_buffer[pos++] = longword >> 16; 12493b8dc03Smatthias.ringwald if (*format == '4'){ 125*02ea9861Smatthias.ringwald hci_cmd_buffer[pos++] = longword >> 24; 12693b8dc03Smatthias.ringwald } 12793b8dc03Smatthias.ringwald break; 12893b8dc03Smatthias.ringwald case 'B': // bt-addr 12993b8dc03Smatthias.ringwald bt_addr = va_arg(argptr, uint8_t *); 130*02ea9861Smatthias.ringwald hci_cmd_buffer[pos++] = bt_addr[5]; 131*02ea9861Smatthias.ringwald hci_cmd_buffer[pos++] = bt_addr[4]; 132*02ea9861Smatthias.ringwald hci_cmd_buffer[pos++] = bt_addr[3]; 133*02ea9861Smatthias.ringwald hci_cmd_buffer[pos++] = bt_addr[2]; 134*02ea9861Smatthias.ringwald hci_cmd_buffer[pos++] = bt_addr[1]; 135*02ea9861Smatthias.ringwald hci_cmd_buffer[pos++] = bt_addr[0]; 13693b8dc03Smatthias.ringwald break; 13793b8dc03Smatthias.ringwald default: 13893b8dc03Smatthias.ringwald break; 13993b8dc03Smatthias.ringwald } 14093b8dc03Smatthias.ringwald format++; 14193b8dc03Smatthias.ringwald }; 14293b8dc03Smatthias.ringwald va_end(argptr); 143*02ea9861Smatthias.ringwald hci_cmd_buffer[2] = pos - 3; 144*02ea9861Smatthias.ringwald // send packet 145*02ea9861Smatthias.ringwald return hci_transport->send_cmd_packet(hci_cmd_buffer, pos); 14693b8dc03Smatthias.ringwald }