📄 states.c
字号:
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 + -