| /* |
| * |
| * BlueZ - Bluetooth protocol stack for Linux |
| * |
| * Copyright (C) 2008-2009 Texas Instruments, Inc. |
| * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> |
| * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org> |
| * |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| * |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <stdio.h> |
| #include <errno.h> |
| #include <ctype.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <getopt.h> |
| #include <syslog.h> |
| #include <signal.h> |
| #include <sys/time.h> |
| #include <sys/socket.h> |
| |
| #include <bluetooth/bluetooth.h> |
| #include <bluetooth/hci.h> |
| #include <bluetooth/hci_lib.h> |
| #include <bluetooth/sco.h> |
| |
| /* Static Local variables */ |
| |
| /* BD Address of the BT head set */ |
| static bdaddr_t bdaddr; |
| |
| /* Buffer to receive data feom headset */ |
| static unsigned char *buffer; |
| |
| /* Default data size */ |
| static long data_size = 672; |
| |
| /* Handling termination of process through signals */ |
| static volatile int terminate = 0; |
| |
| /* Static functions declerations */ |
| static void send_hciCmd(int dev_id, int command_length, char **command); |
| |
| |
| /** Function to handle signal terminations */ |
| static void sig_term(int sig) { |
| terminate = 1; |
| } |
| |
| /** do_connect Function |
| * This function Creates the SCO connection to the BT headset |
| * |
| * Parameters : |
| * @ svr : BD address of headset |
| * Returns SCO socket id on success |
| * suitable error code |
| */ |
| static int do_connect(char *svr) |
| { |
| struct sockaddr_sco addr; |
| struct sco_conninfo conn; |
| socklen_t optlen; |
| int sk; |
| |
| /* Create socket */ |
| sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); |
| if (sk < 0) { |
| syslog(LOG_ERR, "Can't create socket: %s (%d)", |
| strerror(errno), errno); |
| return -1; |
| } |
| |
| /* Bind to local address */ |
| memset(&addr, 0, sizeof(addr)); |
| addr.sco_family = AF_BLUETOOTH; |
| bacpy(&addr.sco_bdaddr, &bdaddr); |
| |
| if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { |
| syslog(LOG_ERR, "Can't bind socket: %s (%d)", |
| strerror(errno), errno); |
| goto error; |
| } |
| |
| /* Connect to remote device */ |
| memset(&addr, 0, sizeof(addr)); |
| addr.sco_family = AF_BLUETOOTH; |
| str2ba(svr, &addr.sco_bdaddr); |
| |
| if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { |
| syslog(LOG_ERR, "Can't connect: %s (%d)", |
| strerror(errno), errno); |
| goto error; |
| } |
| |
| /* Get connection information */ |
| memset(&conn, 0, sizeof(conn)); |
| optlen = sizeof(conn); |
| |
| if (getsockopt(sk, SOL_SCO, SCO_CONNINFO, &conn, &optlen) < 0) { |
| syslog(LOG_ERR, "Can't get SCO connection information: %s (%d)", |
| strerror(errno), errno); |
| goto error; |
| } |
| |
| syslog(LOG_INFO, "Connected [handle %d, class 0x%02x%02x%02x]", |
| conn.hci_handle, |
| conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]); |
| |
| return sk; |
| |
| error: |
| close(sk); |
| return -1; |
| } |
| |
| /** dump_mode Function |
| * This function waits till disconnection is intiated from headset or from |
| * the application. |
| * |
| * Parameters : |
| * @ sk : SCO socket id |
| * Returns VOID |
| */ |
| static void dump_mode(int sk) |
| { |
| int len; |
| |
| /* Wait till disconnect is issued from the headset OR |
| * IF the application is killed using signals |
| */ |
| while ( ((len = read(sk, buffer, data_size)) > 0) && (!terminate) ) |
| syslog(LOG_INFO, "Recevied %d bytes", len); |
| } |
| |
| /** send_hciCmd Function |
| * This function takes the hci commands for the BT chip configurations, creates |
| * a hci channel to send the commadns through UART to configure BT chip |
| * |
| * Parameters : |
| * @ dev_id : HCI device ID |
| * @ command_length : Number of arguments of the command |
| * @ command : Pointer to command list |
| * Returns 0 upon success |
| * , different error messages depending upon the error. |
| */ |
| static void send_hciCmd(int dev_id, int command_length, char **command) |
| { |
| unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr = buf; |
| struct hci_filter flt; |
| hci_event_hdr *hdr; |
| int i, opt, len, dd; |
| uint16_t ocf; |
| uint8_t ogf; |
| |
| if (dev_id < 0) |
| dev_id = hci_get_route(NULL); |
| |
| errno = 0; |
| ogf = strtol(command[0], NULL, 16); |
| ocf = strtol(command[1], NULL, 16); |
| |
| for (i = 2, len = 0; i < command_length && len < sizeof(buf); i++, len++) |
| *ptr++ = (uint8_t) strtol(command[i], NULL, 16); |
| |
| dd = hci_open_dev(dev_id); |
| if (dd < 0) { |
| perror("Device open failed"); |
| return; |
| } |
| |
| /* Setup filter */ |
| hci_filter_clear(&flt); |
| hci_filter_set_ptype(HCI_EVENT_PKT, &flt); |
| hci_filter_all_events(&flt); |
| if (setsockopt(dd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { |
| perror("HCI filter setup failed"); |
| return; |
| } |
| |
| /* Send the BT chip configuration commands */ |
| if (hci_send_cmd(dd, ogf, ocf, len, buf) < 0) { |
| perror("Send failed"); |
| return; |
| } |
| |
| /* Wait for the command completion event */ |
| len = read(dd, buf, sizeof(buf)); |
| if (len < 0) { |
| perror("Read failed"); |
| return; |
| } |
| |
| hdr = (void *)(buf + 1); |
| ptr = buf + (1 + HCI_EVENT_HDR_SIZE); |
| len -= (1 + HCI_EVENT_HDR_SIZE); |
| |
| hci_close_dev(dd); |
| } |
| |
| /** USAGE Function |
| * This function displays the usage of the bt_sco_app application. |
| * |
| * Parameters : |
| * @ VOID |
| * Returns VOID |
| */ |
| static void usage(void) |
| { |
| printf("bt_scoapp\n" |
| "Usage:\n"); |
| printf("\tbt_scoapp [bd_addr]\n"); |
| } |
| |
| /** Main Function |
| * The main function takes the command line BD adress of headset as inputs , |
| * Calls the hci send configuration function and then creates a SCO connection. |
| * |
| * Parameters : |
| * @ argc : Number of arguments on the command line |
| * @ argv : Pointer to argument list - BD addr is the only valid argument. |
| * Returns 0 upon success |
| * , different error messages depending upon the error. |
| */ |
| int main(int argc ,char *argv[]) |
| { |
| struct sigaction sa; |
| int opt, i = 0, sk; |
| |
| /* BT PCM configurations commands */ |
| char *command[] = { "0x3f", "0x106", /* OCF and OGF */ |
| "0x80", "0x00", /* Bit clock - 128KHz*/ |
| "0x00", /* BT chip as Master*/ |
| "0x40", "0x1f", "0x00", "0x00", /* Sampling rate - 8KHz*/ |
| "0x01", "0x00", /* 50% Duty cycle*/ |
| "0x00", /* Frame sync at falling edge*/ |
| "0x00", /* FS Active high polarity*/ |
| "0x00", /* FS direction - [Reserved]*/ |
| "0x10", "0x00", /* CH1 16 -bit OUT size*/ |
| "0x01", "0x00", /* One Clock delay */ |
| "0x00", /* Data driven at rising edge*/ |
| "0x10", "0x00", /* CH1 16 -bit IN size */ |
| "0x01", "0x00", /* CH1 DAta IN One Clock delay*/ |
| "0x00", /* Data driven at sampling edge*/ |
| "0x00", /* Reserved bit*/ |
| "0x10", "0x00", /* CH2 16 -bit OUT size*/ |
| "0x11", "0x00", /* CH2 data OUT off set*/ |
| "0x00", /* Data driven at rising edge*/ |
| "0x10", "0x00", /* CH2 16 -bit IN size*/ |
| "0x11", "0x00", /* CH2 data IN off set*/ |
| "0x00", /* Data Sampled at rising edge*/ |
| "0x00" /* Reserved bit*/ |
| }; |
| int command_length = 36; /* Length of the BT configuration commands */ |
| |
| /* Check if the number of arguemts mentioned is 2 */ |
| if (argc != 2) |
| { |
| printf("\n Wrong input - No BD headset address specified"); |
| usage(); |
| exit(1); |
| } |
| |
| memset(&sa, 0, sizeof(sa)); |
| sa.sa_flags = SA_NOCLDSTOP; |
| sa.sa_handler = sig_term; |
| sigaction(SIGTERM, &sa, NULL); |
| sigaction(SIGINT, &sa, NULL); |
| sigaction(SIGCHLD, &sa, NULL); |
| sigaction(SIGPIPE, &sa, NULL); |
| |
| openlog("bt_sco_app", LOG_PERROR | LOG_PID, LOG_LOCAL0); |
| |
| /* Allocate memory for the buffer */ |
| if (!(buffer = malloc(data_size))) { |
| perror("Can't allocate data buffer"); |
| exit(1); |
| } |
| /* send the BT configuration commands */ |
| send_hciCmd(-1,command_length,command); |
| |
| sleep(2); /* wait for some time while BT chip is configured */ |
| |
| sk = do_connect(argv[1]); |
| if (sk < 0) |
| exit(1); |
| dump_mode(sk); |
| |
| syslog(LOG_INFO, "Exit"); |
| |
| closelog(); |
| |
| return 0; |
| } |