C++程序  |  313行  |  9.11 KB

/*
 *
 *  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;
}