2009-04-29 22:00:24 +00:00
|
|
|
/*
|
|
|
|
* hci.c
|
|
|
|
*
|
|
|
|
* Created by Matthias Ringwald on 4/29/09.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2009-05-03 21:28:40 +00:00
|
|
|
#include <unistd.h>
|
2009-05-09 17:34:17 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <string.h>
|
2009-05-09 17:43:27 +00:00
|
|
|
#include <stdio.h>
|
2009-04-29 22:00:24 +00:00
|
|
|
#include "hci.h"
|
|
|
|
|
2009-05-10 14:16:03 +00:00
|
|
|
// calculate combined ogf/ocf value
|
|
|
|
#define OPCODE(ogf, ocf) (ocf | ogf << 10)
|
2009-05-10 19:55:02 +00:00
|
|
|
#define OGF_LINK_CONTROL 0x01
|
|
|
|
#define OGF_CONTROLLER_BASEBAND 0x03
|
2009-05-09 17:34:17 +00:00
|
|
|
|
|
|
|
hci_cmd_t hci_inquiry = {
|
2009-05-10 19:55:02 +00:00
|
|
|
OPCODE(OGF_LINK_CONTROL, 0x01), "311" // LAP, Inquiry length, Num_responses
|
2009-05-09 17:34:17 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
hci_cmd_t hci_reset = {
|
2009-05-10 19:55:02 +00:00
|
|
|
OPCODE(OGF_CONTROLLER_BASEBAND, 0x03), ""
|
2009-05-09 17:34:17 +00:00
|
|
|
};
|
|
|
|
|
2009-05-10 19:55:02 +00:00
|
|
|
hci_cmd_t hci_create_connection = {
|
|
|
|
OPCODE(OGF_LINK_CONTROL, 0x05), "B21121"
|
|
|
|
// BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch
|
|
|
|
};
|
|
|
|
|
|
|
|
hci_cmd_t hci_write_page_timeout = {
|
|
|
|
OPCODE(OGF_CONTROLLER_BASEBAND, 0x18), "2"
|
|
|
|
// Page_Timeout * 0.625 ms
|
|
|
|
};
|
|
|
|
|
|
|
|
hci_cmd_t hci_host_buffer_size = {
|
|
|
|
OPCODE(OGF_CONTROLLER_BASEBAND, 0x33), "2122"
|
|
|
|
// Host_ACL_Data_Packet_Length:, Host_Synchronous_Data_Packet_Length:, Host_Total_Num_ACL_Data_Packets:, Host_Total_Num_Synchronous_Data_Packets:
|
|
|
|
};
|
2009-05-09 17:34:17 +00:00
|
|
|
|
2009-05-10 19:55:02 +00:00
|
|
|
|
|
|
|
static hci_transport_t * hci_transport;
|
|
|
|
static uint8_t * hci_cmd_buffer;
|
2009-05-03 21:28:40 +00:00
|
|
|
|
2009-05-09 17:43:27 +00:00
|
|
|
void hexdump(uint8_t *data, int size){
|
|
|
|
int i;
|
|
|
|
for (i=0; i<size;i++){
|
|
|
|
printf("%02X ", data[i]);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static void *hci_daemon_thread(void *arg){
|
|
|
|
printf("HCI Daemon started\n");
|
|
|
|
hci_run(transport, &config);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-05-03 21:28:40 +00:00
|
|
|
void hci_init(hci_transport_t *transport, void *config){
|
|
|
|
|
|
|
|
// reference to use transport layer implementation
|
|
|
|
hci_transport = transport;
|
|
|
|
|
2009-05-10 19:55:02 +00:00
|
|
|
// empty cmd buffer
|
|
|
|
hci_cmd_buffer = malloc(3+255);
|
|
|
|
|
2009-05-03 21:28:40 +00:00
|
|
|
// open unix socket
|
|
|
|
|
|
|
|
// wait for connections
|
|
|
|
|
|
|
|
// enter loop
|
|
|
|
|
|
|
|
// handle events
|
|
|
|
}
|
|
|
|
|
|
|
|
int hci_power_control(HCI_POWER_MODE power_mode){
|
|
|
|
return 0;
|
2009-04-29 22:00:24 +00:00
|
|
|
}
|
2009-05-03 21:28:40 +00:00
|
|
|
|
|
|
|
void hci_run(){
|
|
|
|
while (1) {
|
|
|
|
// construct file descriptor set to wait for
|
|
|
|
// select
|
|
|
|
|
|
|
|
// for each ready file in FD - call handle_data
|
|
|
|
sleep(1);
|
|
|
|
}
|
2009-05-09 17:34:17 +00:00
|
|
|
}
|
|
|
|
|
2009-05-10 19:55:02 +00:00
|
|
|
int hci_send_cmd(hci_cmd_t *cmd, ...){
|
|
|
|
hci_cmd_buffer[0] = cmd->opcode & 0xff;
|
|
|
|
hci_cmd_buffer[1] = cmd->opcode >> 8;
|
2009-05-09 17:34:17 +00:00
|
|
|
int pos = 3;
|
|
|
|
|
|
|
|
va_list argptr;
|
|
|
|
va_start(argptr, cmd);
|
|
|
|
const char *format = cmd->format;
|
|
|
|
uint16_t word;
|
|
|
|
uint32_t longword;
|
|
|
|
uint8_t * bt_addr;
|
|
|
|
while (*format) {
|
|
|
|
switch(*format) {
|
|
|
|
case '1': // 8 bit value
|
|
|
|
case '2': // 16 bit value
|
|
|
|
case 'H': // hci_handle
|
2009-05-09 17:45:45 +00:00
|
|
|
word = va_arg(argptr, int); // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
|
2009-05-10 19:55:02 +00:00
|
|
|
hci_cmd_buffer[pos++] = word & 0xff;
|
2009-05-09 17:34:17 +00:00
|
|
|
if (*format == '2') {
|
2009-05-10 19:55:02 +00:00
|
|
|
hci_cmd_buffer[pos++] = word >> 8;
|
2009-05-09 17:34:17 +00:00
|
|
|
} else if (*format == 'H') {
|
2009-05-09 17:45:45 +00:00
|
|
|
// TODO
|
2009-05-09 17:34:17 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
longword = va_arg(argptr, uint32_t);
|
|
|
|
// longword = va_arg(argptr, int);
|
2009-05-10 19:55:02 +00:00
|
|
|
hci_cmd_buffer[pos++] = longword;
|
|
|
|
hci_cmd_buffer[pos++] = longword >> 8;
|
|
|
|
hci_cmd_buffer[pos++] = longword >> 16;
|
2009-05-09 17:34:17 +00:00
|
|
|
if (*format == '4'){
|
2009-05-10 19:55:02 +00:00
|
|
|
hci_cmd_buffer[pos++] = longword >> 24;
|
2009-05-09 17:34:17 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'B': // bt-addr
|
|
|
|
bt_addr = va_arg(argptr, uint8_t *);
|
2009-05-10 19:55:02 +00:00
|
|
|
hci_cmd_buffer[pos++] = bt_addr[5];
|
|
|
|
hci_cmd_buffer[pos++] = bt_addr[4];
|
|
|
|
hci_cmd_buffer[pos++] = bt_addr[3];
|
|
|
|
hci_cmd_buffer[pos++] = bt_addr[2];
|
|
|
|
hci_cmd_buffer[pos++] = bt_addr[1];
|
|
|
|
hci_cmd_buffer[pos++] = bt_addr[0];
|
2009-05-09 17:34:17 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
format++;
|
|
|
|
};
|
|
|
|
va_end(argptr);
|
2009-05-10 19:55:02 +00:00
|
|
|
hci_cmd_buffer[2] = pos - 3;
|
|
|
|
// send packet
|
|
|
|
return hci_transport->send_cmd_packet(hci_cmd_buffer, pos);
|
2009-05-03 21:28:40 +00:00
|
|
|
}
|