#include #include #include #include #include #include "mw_main.h" #include "mw_uart.h" #include "mw_bt.h" #include "bt_hci.h" #include "bt_l2cap.h" static uint8_t local_bdaddr[6]; uint8_t *bt_hci_get_local_bdaddr(void) { return local_bdaddr; } static void bt_print_bd_addr(uint8_t *bd_addr) { #if defined MW_DEVBOARD_V2 int i; char nums[4]; for (i=5; i>=0; i--) { snprintf(nums, 4, "%02x", bd_addr[i]); debug_uart_tx(nums); if (i>0) debug_uart_tx_char(':'); } #endif } void bt_hci_process_acl_packet(unsigned char *packet) { #if defined MW_DEVBOARD_V2 char tstr[32]; #endif uint16_t dlen; uint16_t handle; L2CAP_PB_FLAG PB; L2CAP_BC_FLAG BC; uint16_t channel; uint16_t mlen; // debug_uart_tx("ACL packet, "); handle = packet[0] | ((packet[1] & 0x0f) << 8); // snprintf(tstr, 32, "handle 0x%04x ", handle); // debug_uart_tx(tstr); PB = (packet[1] >> 4) & 0x03; BC = (packet[1] >> 6) & 0x03; // snprintf(tstr, 32, "PB 0x%02x BC 0x%02x ", PB, BC); // debug_uart_tx(tstr); dlen = packet[2] | ((uint16_t)packet[3] << 8); // snprintf(tstr, 32, "len 0x%04x \n", dlen); // debug_uart_tx(tstr); // debug_dump_hex(dlen+4, packet); channel = packet[4+2] | (packet[4+3] << 8); mlen = packet[4] | (packet[4+1] << 8); switch (channel) { case L2CAP_CID_SIGNALING: bt_l2cap_proc_signalling(handle, (packet+8), mlen); break; case L2CAP_CID_CONNECTIONLESS_CHANNEL: break; case L2CAP_CID_ATTRIBUTE_PROTOCOL: break; case L2CAP_CID_SIGNALING_LE: break; case L2CAP_CID_SECURITY_MANAGER_PROTOCOL: break; default: if (channel > 0x3f) { // just for sure, add a 0 as string delimiter packet[mlen+8] = 0x00; bt_l2cap_proc_dyn_channel(channel, handle, (packet+8), mlen); } else { #if defined MW_DEVBOARD_V2 snprintf(tstr, 32, "L2CAP unhandled CID 0x%04x\n", channel); debug_uart_tx(tstr); #endif } break; } } void bt_hci_process_event_packet(unsigned char *packet) { #if defined MW_DEVBOARD_V2 char tstr[32]; #endif int i; // uint8_t bd_addr[6]; uint32_t dev_type; // debug_uart_tx("Event packet, "); // snprintf(tstr, 32, "evt 0x%02x: ", packet[0]); // debug_uart_tx(tstr); switch (packet[0]) { case HCI_EVENT_INQUIRY_COMPLETE: debug_uart_tx("inq complete\n"); break; case HCI_EVENT_INQUIRY_RESULT: debug_uart_tx("inq result\n"); break; case HCI_EVENT_CONNECTION_COMPLETE: debug_uart_tx("con complete from "); #if defined MW_DEVBOARD_V2 bt_print_bd_addr((packet+5)); snprintf(tstr, 32, " status 0x%02x handle 0x%02x", packet[2], packet[3]); debug_uart_tx(tstr); snprintf(tstr, 32, " type 0x%02x enc 0x%02x\n", packet[11], packet[12]); debug_uart_tx(tstr); if (packet[2] == 0x00) debug_uart_tx("connection established\n"); else debug_uart_tx("connection failed\n"); #endif break; case HCI_EVENT_CONNECTION_REQUEST: { uint8_t bd_addr[7]; switch (packet[11]) { case HCI_LINK_TYPE_SCO: debug_uart_tx("SCO"); break; case HCI_LINK_TYPE_ACL: debug_uart_tx("ACL"); break; case HCI_LINK_TYPE_ESCO: debug_uart_tx("eSCO"); break; default: debug_uart_tx("unknown type"); break; } debug_uart_tx(" con req from "); for (i=0; i<6; i++) { bd_addr[i] = packet[i+2]; } bt_print_bd_addr(bd_addr); dev_type = (uint32_t)packet[8] << 16; dev_type |= (uint32_t)packet[9] << 8; dev_type |= packet[10]; #if defined MW_DEVBOARD_V2 snprintf(tstr, 32, " rem. dtype 0x%06lx\n", dev_type); debug_uart_tx(tstr); #endif //memcpy(tstr, bd_addr, 6); //tstr[6] = 0x01; /* remain slave */ bd_addr[6] = 0x01; /* remain slave */ bt_hci_cmd(HCI_LINK_CTRL_OGF, HCI_ACCEPT_CONN_REQ_OCF, 7, bd_addr); } break; case HCI_EVENT_DISCONNECTION_COMPLETE: debug_uart_tx("discon complete\n"); break; case HCI_EVENT_AUTHENTICATION_COMPLETE_EVENT: debug_uart_tx("auth complete\n"); break; case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: debug_uart_tx("rem name req complete\n"); break; case HCI_EVENT_ENCRYPTION_CHANGE: debug_uart_tx("enc change\n"); break; case HCI_EVENT_CHANGE_CONNECTION_LINK_KEY_COMPLETE: debug_uart_tx("change con link key complete\n"); break; case HCI_EVENT_MASTER_LINK_KEY_COMPLETE: debug_uart_tx("master link key complete\n"); break; case HCI_EVENT_READ_REMOTE_SUPPORTED_FEATURES_COMPLETE: debug_uart_tx("read rem feat. complete\n"); break; case HCI_EVENT_READ_REMOTE_VERSION_INFORMATION_COMPLETE: debug_uart_tx("read rem version complete\n"); break; case HCI_EVENT_QOS_SETUP_COMPLETE: debug_uart_tx("qos setup complete\n"); break; case HCI_EVENT_COMMAND_COMPLETE: // snprintf(tstr, 32, "%d cmd(s) complete: 0x%02x%02x=%d", packet[2], packet[3], packet[4], packet[5]); // debug_uart_tx(tstr); if (packet[2] > 0 && packet[3] == ((HCI_R_BD_ADDR_OCF | (HCI_INFO_PARAM_OGF << 10)) & 0xff) && packet[4] == (((HCI_R_BD_ADDR_OCF | (HCI_INFO_PARAM_OGF << 10)) & 0xff00) >> 8)) { // read local bdaddr memcpy(local_bdaddr, (packet+6), 6); #if defined MW_DEVBOARD_V2 debug_uart_tx("local bdaddr = "); bt_print_bd_addr((uint8_t *)(packet+6)); debug_uart_tx("\n"); #endif } break; case HCI_EVENT_COMMAND_STATUS: debug_uart_tx("cmd status\n"); break; case HCI_EVENT_HARDWARE_ERROR: #if defined MW_DEVBOARD_V2 debug_uart_tx("hardw err"); snprintf(tstr, 32, " 0x%02x\n", packet[2]); debug_uart_tx(tstr); #endif break; case HCI_EVENT_FLUSH_OCCURED: debug_uart_tx("flush occured\n"); break; case HCI_EVENT_ROLE_CHANGE: debug_uart_tx("role change\n"); break; case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS: debug_uart_tx("numb compl. packets\n"); break; case HCI_EVENT_MODE_CHANGE_EVENT: debug_uart_tx("mode change\n"); break; case HCI_EVENT_RETURN_LINK_KEYS: debug_uart_tx("return link keys\n"); break; case HCI_EVENT_PIN_CODE_REQUEST: debug_uart_tx("pin code request\n"); #if defined MW_DEVBOARD_V2 debug_uart_tx("from "); bt_print_bd_addr((uint8_t *)(packet+2)); debug_uart_tx("\n"); #endif memmove(packet, (packet+2), 6); packet[6] = 0x04; // PIN has length of 4 memcpy((packet+7), BT_PIN, 4); packet[7] = '4'; packet[8] = '3'; packet[9] = '1'; packet[10] = '2'; bt_hci_cmd(HCI_LINK_CTRL_OGF, HCI_PIN_CODE_REQ_REP_OCF, 11, packet); break; case HCI_EVENT_LINK_KEY_REQUEST: debug_uart_tx("link key request\n"); break; case HCI_EVENT_LINK_KEY_NOTIFICATION: debug_uart_tx("link key notify\n"); break; case HCI_EVENT_DATA_BUFFER_OVERFLOW: debug_uart_tx("evt data buf overflow\n"); break; case HCI_EVENT_MAX_SLOTS_CHANGED: debug_uart_tx("max slots changed\n"); break; case HCI_EVENT_READ_CLOCK_OFFSET_COMPLETE: debug_uart_tx("read clock offset compl.\n"); break; case HCI_EVENT_PACKET_TYPE_CHANGED: debug_uart_tx("packet type changed\n"); break; case HCI_EVENT_PAGE_SCAN_REPETION_MODE_CHANGE: debug_uart_tx("page scan repetition mode changed\n"); break; case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI: debug_uart_tx("inq result with RSSI\n"); break; case HCI_EVENT_EXTENDED_INQUIRY_RESPONSE: debug_uart_tx("ext. inq. resp.\n"); break; case HCI_EVENT_LE_META: debug_uart_tx("LE meta\n"); break; case HCI_EVENT_VENDOR_SPECIFIC: debug_uart_tx("vend. spec.\n"); break; default: debug_uart_tx("unknown\n"); break; } // debug_uart_tx("\n"); // for (i=2; i<=(packet[1]+1); i++) { // snprintf(tstr, 32, " 0x%02x", packet[i]); // debug_uart_tx(tstr); // } // debug_uart_tx("\n"); } typedef enum { HCI_PACKET_START = 0, HCI_CMD_PACKET, HCI_ACL_PACKET_HEADER, HCI_ACL_PACKET_DATA, HCI_SCO_PACKET, HCI_EVENT_PACKET_HEADER, HCI_EVENT_PACKET_DATA, HCI_EHCILL_PACKET, EHCILL_SLEEPING } bt_hci_state_t; static bt_hci_state_t state = HCI_PACKET_START; unsigned char bt_feed_packet_data(unsigned char pdata) { char tstr[32]; static unsigned char packet[255]; static uint16_t bytes_left = 0; static uint16_t pdata_pos = 0; // snprintf(tstr, 32, "bt 0x%02x ", pdata); // debug_uart_tx(tstr); switch (state) { case HCI_PACKET_START: switch (pdata) { case HCI_EVENT_PACKET: state = HCI_EVENT_PACKET_HEADER; bytes_left = 1; pdata_pos = 0; memset(packet, 0, 64); break; case HCI_ACL_DATA_PACKET: state = HCI_ACL_PACKET_HEADER; bytes_left = 3; pdata_pos = 0; memset(packet, 0, 64); break; case EHCILL_GO_TO_SLEEP_IND: debug_uart_tx("eHCILL go to sleep ind\n"); state = HCI_PACKET_START; // disable BT UART? // mabye UCA1CTL1 = UCSWRST ? pdata = EHCILL_GO_TO_SLEEP_ACK; mw_bt_uart_tx(&pdata, 0x01); // pull RTS -> stop data BT_IO_POUT |= BT_IO_RTS; // enable IRQ on CTS P1IFG &= ~BT_IO_CTS; P1IE |= BT_IO_CTS; state = EHCILL_SLEEPING; break; case EHCILL_GO_TO_SLEEP_ACK: debug_uart_tx("eHCILL go to sleep ack\n"); state = HCI_PACKET_START; break; case EHCILL_WAKE_UP_IND: debug_uart_tx("eHCILL wake up ind\n"); state = HCI_PACKET_START; break; case EHCILL_WAKE_UP_ACK: debug_uart_tx("eHCILL wake up ack\n"); state = HCI_PACKET_START; break; default: debug_uart_tx("unexpected packet start\n"); break; } break; case HCI_EVENT_PACKET_HEADER: if (bytes_left != 0) { packet[pdata_pos++] = pdata; bytes_left--; } else { state = HCI_EVENT_PACKET_DATA; packet[pdata_pos++] = pdata; bytes_left = pdata; } break; case HCI_EVENT_PACKET_DATA: packet[pdata_pos++] = pdata; bytes_left--; if (bytes_left == 0) { state = HCI_PACKET_START; bt_hci_process_event_packet(packet); } break; case HCI_ACL_PACKET_HEADER: if (bytes_left != 0) { packet[pdata_pos++] = pdata; bytes_left--; } else { state = HCI_ACL_PACKET_DATA; packet[pdata_pos] = pdata; bytes_left = (packet[pdata_pos-1] | (packet[pdata_pos] << 8)); // snprintf(tstr, 32, "ACL data len 0x%04x\n", bytes_left); // debug_uart_tx(tstr); // snprintf(tstr, 32, "%d (0x%02x 0x%02x)\n", pdata_pos, packet[pdata_pos-1], packet[pdata_pos]); // debug_uart_tx(tstr); pdata_pos++; } break; case HCI_ACL_PACKET_DATA: // snprintf(tstr, 32, "%02x ", pdata); // debug_uart_tx(tstr); packet[pdata_pos++] = pdata; bytes_left--; if (bytes_left == 0) { // debug_uart_tx("\n"); state = HCI_PACKET_START; bt_hci_process_acl_packet(packet); } break; default: debug_uart_tx("hosed HCI state!\n"); snprintf(tstr, 32, " state = %d\n", state); debug_uart_tx(tstr); break; }; // one byte consumed return 1; } typedef struct { uint8_t type; uint16_t cmd; uint8_t length; } __attribute__((packed)) bt_hci_cmd_t; void bt_hci_cmd(const uint8_t OGF, const uint8_t OCF, const uint8_t data_len, const void *data) { bt_hci_cmd_t packet; // refuse any HCI if interface is not enabled if (mw_bt_is_enabled() == 0) return; if (state == EHCILL_SLEEPING) { uint8_t ehcill_p = EHCILL_WAKE_UP_IND; debug_uart_tx("wakeup HCILL\n"); state = HCI_PACKET_START; mw_bt_uart_tx(&ehcill_p, 1); __delay_cycles(300000); BT_IO_POUT &= ~BT_IO_RTS; // drop RTS -> start data } packet.type = HCI_COMMAND_PACKET; packet.cmd = OCF | (OGF<<10); packet.length = data_len; mw_bt_uart_tx(&packet, sizeof(bt_hci_cmd_t)); if (data_len > 0 && data != NULL) mw_bt_uart_tx(data, data_len); } typedef struct { uint16_t acl_handle; uint16_t max_interval; uint16_t min_interval; uint16_t sniff_attempt; uint16_t sniff_timeout; } __attribute__((packed)) bt_hci_sniff_cmd_t; void bt_hci_set_sniff_mode(const uint16_t acl_handle, const uint16_t max_interval, const uint16_t min_interval, const uint16_t sniff_attempt, const uint16_t sniff_timeout) { bt_hci_sniff_cmd_t sniff_cmd; sniff_cmd.acl_handle = acl_handle; sniff_cmd.max_interval = max_interval; sniff_cmd.min_interval = min_interval; sniff_cmd.sniff_attempt = sniff_attempt; sniff_cmd.sniff_timeout = sniff_timeout; bt_hci_cmd(HCI_LINK_POLICY_OGF, HCI_SNIFF_MODE_OCF, sizeof(sniff_cmd), &sniff_cmd); } typedef struct { uint8_t type; uint16_t handle; uint16_t total_length; uint16_t data_length; uint16_t channel; } __attribute__((packed)) bt_hci_acl_t; void bt_acl_send(const uint16_t handle, const uint8_t PB, const uint8_t BC, const uint16_t channel, const uint16_t dlen, const void *dat) { bt_hci_acl_t packet; // refuse any HCI if interface is not enabled if (mw_bt_is_enabled() == 0) return; packet.type = HCI_ACL_DATA_PACKET; packet.handle = handle | ((PB & 0x03) << 12) | ((BC & 0x03) << 14); packet.total_length = dlen + 4; packet.data_length = dlen; packet.channel = channel; mw_bt_uart_tx(&packet, sizeof(bt_hci_acl_t)); mw_bt_uart_tx(dat, dlen); } void bt_hci_init(void) { state = HCI_PACKET_START; } void bt_hci_ehcill_wake(void) { const uint8_t ehcill_p = EHCILL_WAKE_UP_ACK; debug_uart_tx("HCILL wakeup\n"); P1IE &= ~BT_IO_CTS; P1IFG &= ~BT_IO_CTS; state = HCI_PACKET_START; BT_IO_POUT &= ~BT_IO_RTS; // drop RTS -> start data mw_bt_uart_tx(&ehcill_p, 1); //__delay_cycles(160000); }