⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 states.c

📁 linux蓝牙剖面实现
💻 C
📖 第 1 页 / 共 2 页
字号:
			syslog(LOG_NOTICE, "unable to connect to headset: %s", strerror(errcode));			/* go to default state : idle */		}	}}struct State HeadsetConnectingState = {	.name = "Connecting",	.pollEvents = {		[IDX_CTL_APPL_SRV_SOCK]   = POLLIN,		[IDX_RFCOMM_SOCK] = POLLOUT,	 },	.readRfcomm    = headsetConnectingReadRfcomm,	.readCtlAppl   = unconnectedReadCtlAppl,	.getNextState  = genericGetNextState,};/* Connected State */static void headsetConnectedEnter(struct State *this){	/* killing useless sockets */	if(hspd_sockets[IDX_PCM_APPL_SOCK] != 0) {		close(hspd_sockets[IDX_PCM_APPL_SOCK]);		hspd_sockets[IDX_PCM_APPL_SOCK] = 0;	}	if(hspd_sockets[IDX_SCO_SOCK] != 0) {		close(hspd_sockets[IDX_SCO_SOCK]);		hspd_sockets[IDX_SCO_SOCK] = 0;	}	/* This is not a transitional state */	this->_next_state = this;	}static void headsetConnectedHandleApplConnReq(struct State *this){	struct sockaddr_un client_addr;	unsigned int client_addr_len = sizeof(client_addr);	/* Per default stay in same state */	this->_next_state = this;		/* Connect Appli to us */	int _appl_sock = accept(hspd_sockets[IDX_PCM_APPL_SRV_SOCK], (struct sockaddr *)&client_addr, &client_addr_len);	if(_appl_sock != -1) {		fcntl(_appl_sock, F_SETFL, O_NONBLOCK);		if(recv_cfg(_appl_sock, 0, 0) >= 0) {			hspd_sockets[IDX_PCM_APPL_SOCK] = _appl_sock;			/* Go to HeadsetReady state */			this->_next_state = &HeadsetReadyState;		}		else {			/* else : stay where we are */			close(_appl_sock);		}	}	else {		syslog(LOG_ERR, "unable to accept local application connection, %s", strerror(errno));	}}struct State HeadsetConnectedState = {	.name = "Connected",	.pollEvents = {		[IDX_PCM_APPL_SRV_SOCK] = POLLIN,		[IDX_CTL_APPL_SRV_SOCK] = POLLIN,		[IDX_RFCOMM_SOCK] = POLLIN	 },	.enter             = headsetConnectedEnter,	.handleApplConnReq = headsetConnectedHandleApplConnReq,	.readRfcomm        = genericReadRfcomm,	.readCtlAppl       = unconnectedReadCtlAppl,	.getNextState      = genericGetNextState,};/* Ready State */static void headsetReadyEnter(struct State *this){	/* Check if application socket is still there */	struct pollfd pfd = {.fd = hspd_sockets[IDX_PCM_APPL_SOCK], .events = POLLOUT};	int ret = poll(&pfd, 1, 0);	if((ret == 1) && !(pfd.revents & (POLLHUP | POLLERR))) {		/* Application still there : go go go !!! */		/* Launch SCO connection */		int _sco_sock = scoConnectAsync(&hs_bdaddr);		if(_sco_sock >= 0) {			hspd_sockets[IDX_SCO_SOCK] = _sco_sock;			/* Go to HeadsetOpeningState state */			this->_next_state = &HeadsetOpeningState;		}		else {			appl_send_error_pkt(errno, hspd_sockets[IDX_PCM_APPL_SOCK]);			syslog(LOG_ERR, "unable to open bluetooth SCO socket");			close(_sco_sock);			this->_next_state = &HeadsetConnectedState;		}	}	else {		/* Application closed connection : keep headset connection */		this->_next_state = &HeadsetConnectedState;	}}struct State HeadsetReadyState = {	.name          = "Ready",	.pollEvents    = {}, /* Empty pollEvents : this state is purely transitionnal */	.enter         = headsetReadyEnter,	.readCtlAppl   = unconnectedReadCtlAppl,	.getNextState  = genericGetNextState,};/* Opening State */static void headsetOpeningReadSco(struct State *this, short revents){	/* Fetching result code */	int errcode;	unsigned int opt_size = sizeof(int);	/* default next state is back to ZombieAppl */	this->_next_state = &HeadsetZombieApplState;	if(getsockopt(hspd_sockets[IDX_SCO_SOCK], SOL_SOCKET, SO_ERROR, &errcode, &opt_size) == 0) {		if(errcode == 0) {			struct sco_conninfo conn;			struct sco_options opts;			unsigned int size;			size = sizeof(conn);			if (getsockopt(hspd_sockets[IDX_SCO_SOCK], SOL_SCO, SCO_CONNINFO, &conn, &size) == 0) {				size = sizeof(opts);				if (getsockopt(hspd_sockets[IDX_SCO_SOCK], SOL_SCO, SCO_OPTIONS, &opts, &size) == 0) {					/* Make sure we will block per default - clear 0_NONBLOCK flag */					fcntl(hspd_sockets[IDX_SCO_SOCK], F_SETFL, 0);					syslog(LOG_INFO, "SCO channel opened handle=0x%04x mtu=%d", conn.hci_handle, opts.mtu);					this->_next_state = &HeadsetStreamingState;				}				else {					appl_send_error_pkt(errno, hspd_sockets[IDX_PCM_APPL_SOCK]);					syslog(LOG_ERR, "unable to query SCO channel info: %s", strerror(errno));					/* go to default state : ZombieAppl */				}			}			else {				appl_send_error_pkt(errno, hspd_sockets[IDX_PCM_APPL_SOCK]);				syslog(LOG_ERR, "unable to query SCO channel info: %s", strerror(errno));				/* go to default state : ZombieAppl */			}		}		else {			appl_send_error_pkt(errcode, hspd_sockets[IDX_PCM_APPL_SOCK]);			syslog(LOG_ERR, "unable to open SCO channel to headset: %s", strerror(errcode));			/* go to default state : ZombieAppl */		}	}	else {		appl_send_error_pkt(errno, hspd_sockets[IDX_PCM_APPL_SOCK]);	}}struct State HeadsetOpeningState = {	.name = "Opening",	.pollEvents = {		[IDX_CTL_APPL_SRV_SOCK] = POLLIN,		[IDX_RFCOMM_SOCK] = POLLIN,		[IDX_SCO_SOCK]    = POLLOUT,	 },	.readSco       = headsetOpeningReadSco,	.readRfcomm    = genericReadRfcomm,	.readCtlAppl   = unconnectedReadCtlAppl,	.getNextState  = genericGetNextState,};/* Streaming State */static void headsetStreamingEnter(struct State *this){	/* Send sco socket to application using ancilliary data - see man 7 unix*/        char cmsg_b[CMSG_SPACE(sizeof(int))];  /* ancillary data buffer */	struct cmsghdr *cmsg;	ipc_packet_t pkt = {.type = PKT_TYPE_STREAMING_IND};	struct iovec iov =  {              .iov_base = &pkt,        /* Starting address */              .iov_len  = sizeof(pkt)   /* Number of bytes */        };	struct msghdr msgh = {		.msg_name       = 0,		.msg_namelen    = 0,		.msg_iov        = &iov,		.msg_iovlen     = 1,		.msg_control    = &cmsg_b,		.msg_controllen = CMSG_LEN(sizeof(int)),		.msg_flags      = 0	};	cmsg = CMSG_FIRSTHDR(&msgh);	cmsg->cmsg_level = SOL_SOCKET;	cmsg->cmsg_type  = SCM_RIGHTS;	cmsg->cmsg_len   = CMSG_LEN(sizeof(int));	/* Initialize the payload */        (*(int *)CMSG_DATA(cmsg)) = hspd_sockets[IDX_SCO_SOCK];	/* finally send it -we ignore PIPE signal & return code, as any errors will be caught later */	int ret = sendmsg(hspd_sockets[IDX_PCM_APPL_SOCK], &msgh, MSG_NOSIGNAL);	if(ret == -1) {		syslog(LOG_ERR, "Unable to send SCO socket to appl: %s", strerror(errno));	}	/* This is not a transitional state */	this->_next_state = this;	}static void headsetStreamingReadAppl(struct State *this, short revents){	if((revents & (POLLHUP | POLLERR)) == 0) {		/* Should not happen, treat as error */		this->_next_state = &HeadsetConnectedState;	}	else {		syslog(LOG_INFO, "Appli closed socket");		/* go to Zombie state */		this->_next_state = &HeadsetZombieState;	}}static void headsetStreamingReadRfcomm(struct State *this, short revents){	if((revents & (POLLHUP | POLLERR)) == 0) {		char buffer[32];		int size;		if((size = recv(hspd_sockets[IDX_RFCOMM_SOCK], buffer, sizeof(buffer) - 1, 0)) > 0) {			buffer[size] = 0;			process_at_command(buffer, size);		}		this->_next_state = this;	}	else {		syslog(LOG_NOTICE, "Headset disconnected as RFCOMM socket died");		this->_next_state = &HeadsetZombieApplState;	}}static void headsetStreamingReadSco(struct State *this, short revents){	if((revents & (POLLHUP | POLLERR)) == 0) {		this->_next_state = this;	}	else {		syslog(LOG_NOTICE, "Headset disconnected as SCO socket died");		this->_next_state = &HeadsetZombieApplState;	}}struct State HeadsetStreamingState = {	.name = "Streaming",	.pollEvents = {		[IDX_CTL_APPL_SRV_SOCK] = POLLIN,		[IDX_PCM_APPL_SOCK]   = POLLIN,		[IDX_RFCOMM_SOCK] = POLLIN,		[IDX_SCO_SOCK]    = POLLERR, /* We are interested in nothing but errors */	 },	.enter         = headsetStreamingEnter,	.readRfcomm    = headsetStreamingReadRfcomm,	.readPcmAppl   = headsetStreamingReadAppl,	.readSco       = headsetStreamingReadSco,	.readCtlAppl   = connectedReadCtlAppl,	.getNextState  = genericGetNextState,};/* Zombie State */static void headsetZombieEnter(struct State *this){	if(hspd_sockets[IDX_PCM_APPL_SOCK] != 0) {		close(hspd_sockets[IDX_PCM_APPL_SOCK]);		hspd_sockets[IDX_PCM_APPL_SOCK] = 0;	}	/* This is not a transitional state */	this->_next_state = this;	}static void headsetZombieHandleApplConnReq(struct State *this){	struct sockaddr_un client_addr;	unsigned int client_addr_len = sizeof(client_addr);	/* Per default stay in same state */	this->_next_state = this;		/* Connect Appli to us */	int _appl_sock = accept(hspd_sockets[IDX_PCM_APPL_SRV_SOCK], (struct sockaddr *)&client_addr, &client_addr_len);	if(_appl_sock != -1) {		fcntl(_appl_sock, F_SETFL, O_NONBLOCK);		if((recv_cfg(_appl_sock, 0, 0) >= 0)) { 			hspd_sockets[IDX_PCM_APPL_SOCK] = _appl_sock;			this->_next_state = &HeadsetStreamingState;		}		else {			/* else : stay where we are */			close(_appl_sock);		}	}	else {		syslog(LOG_ERR, "unable to accept local application connection");	}}void headsetZombieTimedout(struct State *this){	appl_send_error_pkt(EHOSTUNREACH, hspd_sockets[IDX_PCM_APPL_SOCK]);	syslog(LOG_NOTICE, "Nobody uses SCO channel anymore, closing it.");	this->_next_state = &HeadsetConnectedState;}int headsetZombieGetTimeout(struct State *this){	return 4000;}struct State HeadsetZombieState = {	.name = "Zombie",	.pollEvents = {		[IDX_PCM_APPL_SRV_SOCK] = POLLIN,		[IDX_CTL_APPL_SRV_SOCK] = POLLIN,		[IDX_RFCOMM_SOCK]   = POLLIN,		[IDX_SCO_SOCK]      = POLLERR,	 },	.enter             = headsetZombieEnter,	.readRfcomm        = genericReadRfcomm,	.readSco           = genericReadSco,	.handleApplConnReq = headsetZombieHandleApplConnReq,	.timedout          = headsetZombieTimedout,	.getTimeout        = headsetZombieGetTimeout,	.readCtlAppl       = connectedReadCtlAppl,	.getNextState      = genericGetNextState,};/* ZombieAppl State */static void headsetZombieApplEnter(struct State *this){	if(hs_connected) {		signalHeadsetDisconnected(&hs_bdaddr);	}	hs_connected = 0;	/* killing bluetooth sockets */	if(hspd_sockets[IDX_SCO_SOCK] != 0) {		close(hspd_sockets[IDX_SCO_SOCK]);		hspd_sockets[IDX_SCO_SOCK] = 0;	}	if(hspd_sockets[IDX_RFCOMM_SOCK] != 0) {		close(hspd_sockets[IDX_RFCOMM_SOCK]);		hspd_sockets[IDX_RFCOMM_SOCK] = 0;	}	memset(&hs_bdaddr, 0, sizeof(bdaddr_t));	/* This is not a transitional state */	this->_next_state = this;	}static void headsetZombieApplReadAppl(struct State *this, short revents){	if((revents & (POLLHUP | POLLERR)) == 0) {		/* Should not happen, treat as error */		this->_next_state = &HeadsetIdleState;	}	else {		syslog(LOG_INFO, "Appli closed socket");		/* go to Idle state */		this->_next_state = &HeadsetIdleState;	}}static void headsetZombieApplHandleRfcommConnReq(struct State *this){	struct sockaddr_rc client_addr;	unsigned int client_addr_len = sizeof(client_addr);	/* Per default stay in same state */	this->_next_state = this;		/* Connect Appli to us */	int _rfcomm_sock = accept(hspd_sockets[IDX_RFCOMM_SRV_SOCK], (struct sockaddr *)&client_addr, &client_addr_len);	if(_rfcomm_sock != -1) {		char remoteaddr[32];		ba2str(&client_addr.rc_bdaddr, remoteaddr);		syslog(LOG_INFO, "Incoming RFCOMM hs connection from %s accepted",				remoteaddr);		hspd_sockets[IDX_RFCOMM_SOCK] = _rfcomm_sock;		bacpy(&hs_bdaddr, &client_addr.rc_bdaddr);		hs_connected = 1;		signalHeadsetConnected(&hs_bdaddr);		this->_next_state = &HeadsetReadyState;	}	else {		syslog(LOG_ERR, "unable to accept bluetooth RFCOMM socket : %s", strerror(errno));		close(_rfcomm_sock);	}}struct State HeadsetZombieApplState = {	.name = "ZombieAppl",	.pollEvents = {		[IDX_PCM_APPL_SOCK]     = POLLIN | POLLERR,		[IDX_RFCOMM_SRV_SOCK]   = POLLIN	 },	.enter               = headsetZombieApplEnter,	.handleRfcommConnReq = headsetZombieApplHandleRfcommConnReq,	.readPcmAppl         = headsetZombieApplReadAppl,	.getNextState        = genericGetNextState};/* AT commands processing */struct commands_table {	const char * command;	int (*process_func)(const char *cmd);};static void respOK(){	const char resp_ok[] = "\r\nOK\r\n";	send(hspd_sockets[IDX_RFCOMM_SOCK], resp_ok, sizeof(resp_ok) - 1, MSG_NOSIGNAL);}static void respError(){	const char resp_error[] = "\r\nERROR\r\n";	send(hspd_sockets[IDX_RFCOMM_SOCK], resp_error, sizeof(resp_error) - 1, MSG_NOSIGNAL);}static int doVolChanged(const char * cmd){	return volctl_write_fromhs(cmd);}static int doBtnPushed(const char * cmd){	signalHeadsetButtonPushed(&hs_bdaddr);	return 0;}static void process_at_command(const char* buffer, unsigned int datalen){	int i;	int answered = 0;	const struct commands_table tbl[] = {		{"AT+CKPD=200", doBtnPushed },		{"AT+VGS=",     doVolChanged },		{"AT+VGM=",     doVolChanged },		{0,             0 },	};	#ifndef NDEBUG	fprintf(stderr, "Received from HS: %s\n", buffer);	#endif		for(i = 0; tbl[i].command != 0; i++) {		if(strncmp(buffer, tbl[i].command, strlen(tbl[i].command)) == 0) {			if(tbl[i].process_func(buffer) != 0) {				/* Error happened while processing */				respError();			}			else {				/* Everything's fine */				respOK();			}			answered = 1;			break;		}	}	if(!answered) {		/* command not found in list */		respError();	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -