分类: LINUX
2008-10-30 18:07:23
自己写的简单的实验代码,贴上来看看,有兴趣的话,大家可以交流
/******************************************************************************/
/** **/
/** MODULES USED **/
/** **/
/******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "msgqueue.h"
/******************************************************************************/
/** **/
/** DEFINITIONS AND MACROS **/
/** **/
/******************************************************************************/
#define DONGLE_ADDR "00:11:67:58:D1:0F" /*ISSC*/
#define HEAD_SET_ADDR "83:82:5B:00:A5:A3" /*NK-808 channel 1*/
#define HEAD_SET_CHAN 1
//#define PCM_DATA_PATH "/tmp/sco.dat"
//#define PCM_DATA_PATH "/mnt/heart.pcm"
#define PCM_DATA_PATH "/mnt/tianhou.pcm"
#define RECV_BUFFER 64
#define SEND_BUFFER 64
typedef pthread_t thread_T;
typedef void *(*pthread_startroutine_t) (void *);
typedef void *pthread_addr_t;
typedef void threadArg_T;
typedef void (*threadFunc_T)(void *);
/*debugging micro*/
#ifdef ENABLE_DEBUG
int DebugEnabled = 0;
#else
#define DebugEnabled 1
#endif
#define DDBG(fmts) if(DebugEnabled)printf(fmts)
#define DBG(fmts,args) if(DebugEnabled)printf(fmts,args)
#define DBG2(fmts,arg1,arg2) if(DebugEnabled)printf(fmts,arg1,arg2)
/******************************************************************************/
/** **/
/** TYPEDEF AND STRUCTURE **/
/** **/
/******************************************************************************/
struct _dongle_priv {
int hci_sock;
int sco_sock;
int device_channel;
char ag_addr[20]; /* adddress of adapter */
char hs_addr[20];
unsigned char isServiceConnected;
char isScoConnected;
char isRunning;
char callSetup;
char callAccept;
};
typedef struct _dongle_priv bt_data;
/******************************************************************************/
/** **/
/** GLOBAL VARIABLES **/
/** **/
/******************************************************************************/
bt_data * BTd;
static sem_t Sem;
/******************************************************************************/
/** **/
/** LOCAL FUNCTIONS **/
/** **/
/******************************************************************************/
thread_T thread_create(int priority, threadFunc_T startFunc, threadArg_T *arg)
{
thread_T thread;
pthread_attr_t thread_attr;
struct sched_param param;
pthread_attr_init(&thread_attr);
/* pthread_attr_setinheritsched(PTHREAD_EXPLICT_SCHED); */
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
param.sched_priority = priority;
pthread_attr_setschedparam(&thread_attr, ¶m);
pthread_create(&thread, &thread_attr, (pthread_startroutine_t)startFunc,
(pthread_addr_t)arg);
return(thread);
}
void set_bit(int offset)
{
BTd->isServiceConnected |= (0x01<
static int rfcomm_connect(bdaddr_t * src, bdaddr_t * dst, uint8_t channel)
{
struct sockaddr_rc addr;
int s;
if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.rc_family = AF_BLUETOOTH;
bacpy(&addr.rc_bdaddr, src);
addr.rc_channel = 0;
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
printf("rfcomm bind error\n");
close(s);
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.rc_family = AF_BLUETOOTH;
bacpy(&addr.rc_bdaddr, dst);
addr.rc_channel = channel;
if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
printf("rfcomm connect error\n");
close(s);
return -1;
} else{
printf("connecting successfully sock %d\n",s);
}
return s;
}
static int sco_connect(bdaddr_t *src, bdaddr_t *dst)
{
struct sockaddr_sco addr;
//struct sco_conninfo conn;
//struct sco_options opts;
int s;
if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sco_family = AF_BLUETOOTH;
bacpy(&addr.sco_bdaddr, src);
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
close(s);
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sco_family = AF_BLUETOOTH;
bacpy(&addr.sco_bdaddr, dst);
if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0 ){
close(s);
printf("sco connecting failed\n");
return -1;
}
return s;
}
static int start_rfcomm_link(char *dst , char *src , int channel)
{
bdaddr_t usb_dongle_addr,head_set_addr;
int fd;
if (!dst||!src){
return -1;
}
str2ba(src,&usb_dongle_addr);
str2ba(dst,&head_set_addr);
fd = rfcomm_connect(&usb_dongle_addr,&head_set_addr,channel);
return fd;
}
static int start_sco_link(char *dst , char *src)
{
bdaddr_t usb_dongle_addr,head_set_addr;
int fd;
//uint16_t sco_handle, sco_mtu;
if (!dst||!src){
return -1;
}
str2ba(src,&usb_dongle_addr);
str2ba(dst,&head_set_addr);
fd = sco_connect(&usb_dongle_addr,&head_set_addr);
return fd;
}
static int cind_cmd_str(char *cmd)
{
if (!cmd){
return -1;
}
memset(cmd,0,sizeof(cmd));
strcpy(cmd,"\r\n+CIND:(\"service\",(0,1)),(\"call\",(0,1)),(\"callsetup\",(0,3)),(\"signal\",(0-5)),(\"roam\",(0-1))\r\n");
return 0;
}
static int at_rx(int fd_at, char *receive)
{
int retval,ret;
fd_set rfds;
struct timeval tv;
FD_ZERO(&rfds);
FD_SET(fd_at, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 5000;
if (!receive){
return -1;
}
memset(receive,0,sizeof(receive));
if ((retval = select(fd_at+1, &rfds, NULL, NULL, &tv)) > 0){
memset(receive,0,RECV_BUFFER);
ret = read(fd_at,receive,RECV_BUFFER);
if (ret > 0){
DBG("recving from headset %s\n",receive);
} else if (-1 == ret){
close(fd_at);
BTd->isRunning = 0;
}
} else if (!retval){
//DDBG("time out\n");
}
return 0;
}
static int at_tx(int fd_at,char* send)
{
if (strlen(send)){
DBG("AG Sending %s\n",send);
write(fd_at,send,strlen(send));
}
return 0;
}
static int at_txrx(int fd_at,char* send, char *receive)
{
int ret = 0;
fd_set rfds;
struct timeval tv;
int retval;
FD_ZERO(&rfds);
FD_SET(fd_at, &rfds);
tv.tv_sec = 3;
tv.tv_usec = 0;
memset(receive,0,sizeof(receive));
if (strlen(send)){
DBG("AG Sending %s\n",send);
write(fd_at,send,strlen(send));
}
if ((retval = select(fd_at+1, &rfds, NULL, NULL, &tv)) > 0){
memset(receive,0,RECV_BUFFER);
ret = read(fd_at,receive,RECV_BUFFER);
if (ret){
DBG("[at_rxtx]recving from headset %s\n",receive);
}
} else if (!retval){
//DDBG("time out\n");
}
return 0;
}
static void monitor_headset(int fd_rfcomm)
{
char recv_buf[RECV_BUFFER] = {0};
char send_buf[SEND_BUFFER] = {0};
while (1 == BTd->isRunning){
at_rx(fd_rfcomm, recv_buf);
if (strstr(recv_buf,"AT+BRSF")){
at_tx(fd_rfcomm,"\r\n+BRSF:49\r");
at_tx(fd_rfcomm,"\r\nOK\r\n");
set_bit(0);
continue;
}
if (strstr(recv_buf,"AT+CIND=?")){
cind_cmd_str(send_buf);
at_tx(fd_rfcomm,send_buf);
at_tx(fd_rfcomm,"\r\nOK\r\n");
set_bit(1);
continue;
}
if (strstr(recv_buf,"AT+CIND")){
at_tx(fd_rfcomm,"\r\n+CIND:1,0,0,2,0\r\n");
at_tx(fd_rfcomm,"\r\nOK\r\n");
set_bit(2);
continue;
}
if (strstr(recv_buf,"AT+CMER")){
at_tx(fd_rfcomm,"\r\nOK\r\n");
set_bit(3);
continue;
}
//Standard call hold and multiparty handling AT command
if (strstr(recv_buf,"AT+CHLD")){
at_tx(fd_rfcomm,"\r\n+CHLD:0\r\n");
at_tx(fd_rfcomm,"\r\nOK\r\n");
set_bit(4);
continue;
}
//Standard “Call Waiting notification” AT command
if (strstr(recv_buf,"AT+CCWA")){
at_tx(fd_rfcomm,"\r\nOK\r\n");
set_bit(5);
continue;
}
//volume setting
if (strstr(recv_buf,"AT+VGS")){
at_tx(fd_rfcomm,"\r\nOK\r\n");
set_bit(6);
continue;
}
//volume setting
if (strstr(recv_buf,"AT+VGM")){
at_tx(fd_rfcomm,"\r\nOK\r\n");
set_bit(7);
continue;
}
if (strstr(recv_buf,"ATA")){
//CallingAccept = 1;
BTd->callAccept = 1;
DDBG("ATA is received\n");
at_tx(fd_rfcomm,"\r\nOK\r\n");
at_tx(fd_rfcomm,"\r\n+CIEV=2,1\r\n");
continue;
}
}
}
static void audio_loop(int fd_sco)
{
char recv_buf[RECV_BUFFER] = {0};
int retval,ret;
fd_set rfds;
struct timeval tv;
FD_ZERO(&rfds);
FD_SET(fd_sco, &rfds);
tv.tv_sec = 3;
tv.tv_usec = 0;
memset(recv_buf,0,RECV_BUFFER);
if ((retval = select(fd_sco+1, &rfds, NULL, NULL, &tv)) > 0){
ret = read(fd_sco,recv_buf,1023);
if (ret){
//DBG("recving from headset %s\n",receive);
//DBG("recv_length %d\n",ret);
//DBG("%x\n",recv_buf);
}
write(fd_sco,recv_buf,ret);
} else if (!retval){
//DDBG("time out\n");
}
}
static int get_file_size(char *file_path)
{
FILE * fd;
int start,end,fileLen;
fd = fopen(file_path,"r");
if (fd){
fseek(fd, 0, SEEK_SET);
start = ftell(fd);
fseek(fd, 0, SEEK_END);
end = ftell(fd);
fileLen = end - start + 1;
/*move to the head*/
fseek(fd, 0, SEEK_SET);
DBG("audio fileLength %d\n",fileLen);
fclose(fd);
return fileLen;
} else{
return -1;
}
}
static unsigned char * fill_pcm_buffer(char * pcm_file_path,int *length)
{
int size = 0;
FILE *fd;
unsigned char * pcmDataPtr;
if (!pcm_file_path){
return NULL;
}
size = get_file_size(pcm_file_path);
if (size > 0){
*length = size;
pcmDataPtr = (unsigned char *)malloc(size);
if (!pcmDataPtr){
DDBG("can't allocate memory\n");
return NULL;
}
memset(pcmDataPtr,0,size);
fd = fopen(pcm_file_path,"r");
if (!fd){
return NULL;
}
fread(pcmDataPtr,1,size,fd);
fclose(fd);
return pcmDataPtr;
} else{
return NULL;
}
}
static bt_data * init_bt_para()
{
bt_data * btd;
btd = (bt_data *)malloc(sizeof(bt_data));
if (!btd){
printf("opps can't allocate resource!\n");
exit(-1);
}
memset(btd,0,sizeof(*btd));
strcpy(btd->ag_addr,DONGLE_ADDR);
strcpy(btd->hs_addr,HEAD_SET_ADDR);
btd->device_channel = HEAD_SET_CHAN;
btd->callSetup = 0;
btd->callAccept = 0;
btd->isRunning = 0;
btd->isServiceConnected = 0;
btd->isScoConnected = 0;
btd->hci_sock = -1;
btd->sco_sock = -1;
return btd;
}
static int ring_headset(int fd_rfcomm)
{
char recv_buf[RECV_BUFFER] = {0};
sem_wait(&Sem);
at_txrx(fd_rfcomm,"\r\nRING\r\n",recv_buf);
while (!strstr(recv_buf,"ATA")&&!BTd->callAccept){
at_txrx(fd_rfcomm,"\r\nRING\r\n",recv_buf);
}
at_tx(fd_rfcomm,"\r\nOK\r\n");
at_tx(fd_rfcomm,"\r\n+CIEV:2,1\r\n");
sem_destroy(&Sem);
return 0;
}
static void play_pcm_audio(int fd_sco,unsigned char * pcm_buffer,int max_length,int times)
{
#define OFFSET 48
int i;
int cur = 0;
int retval;
unsigned char *pdata;
unsigned char buffer[64];
fd_set rfds,wfds;
struct timeval tv;
unsigned int sector = 300*1024;
if (!pcm_buffer){
return -1;
}
FD_ZERO(&rfds);
FD_SET(fd_sco, &rfds);
FD_ZERO(&wfds);
FD_SET(fd_sco, &wfds);
tv.tv_sec = 0;
tv.tv_usec =8000;
pdata = pcm_buffer;
for (i = 0 ; i < times ; i++){
while (cur < max_length){
if ((retval = select(fd_sco+1, NULL, &wfds, NULL, &tv)) > 0){
//fread(receive,1,OFFSET,fd_music);
//memset(buffer,0,sizeof(buffer));
//memcpy(buffer,pdata,OFFSET);
printf("twins\r\n");
//printf("twins\r\n");
//usleep(1);
//printf("\r\n");
write(fd_sco,pdata,48);
cur += OFFSET;
pdata += OFFSET;
if (cur > sector){
sleep(5);
sector += 300*1024;
}
}
}
printf("music data is finished\n");
sleep(2);
pdata = pcm_buffer;
cur = 0;
sector = 300*1024;
}
//close(fd_sco);
free(pcm_buffer);
printf("audio transfer over\n");
return;
}
void init_hcid_conf()
{
system("hcid -f /etc/bluetooth/hcid.conf");
}
int main()
{
int fd_rfcomm,fd_sco;
unsigned char * pcm_buffer;
int max_length;
bt_data *btd;
init_hcid_conf();
btd = init_bt_para();
BTd = btd;
fd_rfcomm = start_rfcomm_link(btd->hs_addr, btd->ag_addr, btd->device_channel);
if (fd_rfcomm < 0){
exit(-1);
}
btd->isRunning = 1;
btd->hci_sock = fd_rfcomm;
thread_create(50, (threadFunc_T)monitor_headset, (threadArg_T *)btd->hci_sock);
thread_create(50, (threadFunc_T)ring_headset, (threadArg_T *)btd->hci_sock);
pcm_buffer = fill_pcm_buffer(PCM_DATA_PATH, &max_length);
while (1){
if (btd->isServiceConnected == 0xff&&!btd->callSetup){
//printf("service level connection finished\n");
//ready to make/accept a call
at_tx(fd_rfcomm,"\r\n+CIEV=3,1\r\n");
sem_post(&Sem);
//CallSetup = 1;
btd->callSetup = 1;
}
if (0 == btd->isScoConnected){
fd_sco = start_sco_link(btd->hs_addr,btd->ag_addr);
}
if (fd_sco > 0){
//printf("sco link successfully!\n");
btd->sco_sock = fd_sco;
btd->isScoConnected = 1;
}
if (btd->callAccept == 1){
play_pcm_audio(btd->sco_sock, pcm_buffer, max_length,1);
break;
}
}
//sleep(80);
close(btd->sco_sock);
close(btd->hci_sock);
}