📄 blue.cpp
字号:
int ritorno=0; int optL=hciEvts[index].resL; unsigned char* ubuf = (unsigned char*)buf; /* 1) see if msg is our response. */ if ((len-2)==ubuf[1]) { if (hciEvts[index].evt==ANY_EVT || (buf[0]==hciEvts[index].evt && (optL==ubuf[1]))) { ritorno=HciReqRes::readRes(buf,ubuf[1]+2); scanRes(buf,2); if (hciEvts[index].evt==ANY_EVT) evtComplete(); /* 2) If interesting verify correctness (status=0).*/ if (log) { int l; Dprintf("> %s(%02x)",hciEvts[index].des,buf[0]); for (l=0; l<ubuf[1]; l++) Dprintf("%02x",(unsigned char)res[2+l]); switch (hciEvts[index].evt) { case DISCONN_COMPLETE: Dprintf(" reason(%s)",blueErrDes(res[5])); case CONNECT_COMPLETE: Dprintf(" status(%s)",blueErrDes(res[2])); ritorno=res[2]?blue2linuxErr(res[2]):ritorno; default: break; } } } } return ritorno;}enum L2capCode { NO_CODE=0, COMMAND_REJ=1, CONNECT_REQ, CONNECT_RES, CONFIG_REQ, CONFIG_RES, DISCONN_REQ, DISCONN_RES, ECHO_REQ, ECHO_RES, INFO_REQ, INFO_RES,};struct L2capCmdEvt{ L2capCode code; int len;};class HciL2cap: public HciReqRes { static char hciH; static L2capCmdEvt l2capCmdEvt[11]; static char req_ident; static char res_ident; L2capCode code; int remL;public: HciL2cap(char cid, L2capCode code, char* opt, int optl=-1); ~HciL2cap(); int readRes(char* des, int len); int writeReq(char* buf, int len); void copy(HciL2cap& ing) {memcpy(this,&ing,sizeof(*this));} static void setHciHandle(char newHhciH); static void setReqNumber(char reqn); static char getReqNumber();};char HciL2cap::hciH='\x0';char HciL2cap::req_ident=0;char HciL2cap::res_ident=0;L2capCmdEvt HciL2cap::l2capCmdEvt[]={ {COMMAND_REJ, 0}, {CONNECT_REQ, 4}, {CONNECT_RES, 8}, {CONFIG_REQ, 8}, {CONFIG_RES, 6}, {DISCONN_REQ, 4}, {DISCONN_RES, 4}, {ECHO_REQ, 0}, {ECHO_RES, 0}, {INFO_REQ, 0}, {INFO_RES, 0},};void HciL2cap::setHciHandle(char newHciH) { hciH=newHciH;}void HciL2cap::setReqNumber(char number) { req_ident=number;}char HciL2cap::getReqNumber() { return req_ident;}HciL2cap::~HciL2cap() {}HciL2cap::HciL2cap(char cid, L2capCode cod, char* opt, int optl): code(cod) { setProto(L2CAP); HciReqRes::compileReq(&hciH,1); HciReqRes::compileReq("\x20",1); remL=0; unsigned int l; int optL=optl; for (l=0; (l<sizeof(l2capCmdEvt)/sizeof(L2capCmdEvt)) && (optL==-1); l++) if (l2capCmdEvt[l].code==code) optL=l2capCmdEvt[l].len; if (optL!=-1) { char codechar=(char)code; char optLc=(char) optL + 4/*len,cid*/ + 4 /*code,ident,len*/; HciReqRes::compileReq(&optLc, 1); HciReqRes::compileReq("\x00", 1); optLc-=4; HciReqRes::compileReq(&optLc, 1); HciReqRes::compileReq("\x00", 1); HciReqRes::compileReq(&cid,1); HciReqRes::compileReq("\x00",1); if (codechar!=NO_CODE) { char ident; if (codechar%2) { res_ident++; ident=res_ident; } else { req_ident++; ident=req_ident; } HciReqRes::compileReq(&codechar,1); HciReqRes::compileReq(&ident,1); optLc-=4; HciReqRes::compileReq(&optLc, 1); HciReqRes::compileReq("\x00", 1); } if (opt && optL) HciReqRes::compileReq(opt, optL); } else if (code!=NO_CODE) Dprintf("L2cap::L2cap() code=%d !found.",code);}int HciL2cap::writeReq(char* buf, int len) { if (log) { Dprintf("< L2CAP:"); int l; for (l=0; (l<getReqC()); l++) Dprintf("%02x",(unsigned char)req[l]); } return HciReqRes::writeReq(buf,len);}/* * L2CAP ACL L2CAP * ACL 28 20 0C 00 08 00 01 00 ... * | | | len cid * (handle) | | * (flag) | * (len) * * When >1 packet is generated4anL2CAPmsg, we have this situation: * ACLlen=18 | L2CAPlen=14 * 28 20 11 00 | 0e 00 41 ... * 28 10 01 00 | aa * * Same packet sometimes is generated with 1 frame: * ACLlen=18 | L2CAPlen=14 * 28 20 12 00 | 0e 00 41 ... * * In first case, the second frame can be linked to first only thank to ACL level, so we expect that * every non first frame are related to last frame in same direction. * */ int HciL2cap::readRes(char* buf, int len) { int ritorno=0; unsigned char* ubuf=(unsigned char*) buf; if (buf[0]==hciH) { /* * If start frame, remain on, * middle frame, remain on, * end frame, turn off. */ ritorno=HciReqRes::readRes(buf,len); if (log) { int l; Dprintf("> L2CAP:"); for (l=0; l<len; l++) Dprintf("%02x",(unsigned char)res[l]); } if (remL==0) remL=ubuf[4]+(ubuf[5]<<8); remL-=(ritorno-8); if (remL>0) { Dprintf("(!complete packet,remain=%d)",remL); /*requestOn=true*/; } if (remL<0) Dprintf("(corrupted packet!remL=%d!)",remL); if (buf[8]==CONNECT_RES && buf[16]==1 && buf[18]==2) { Dprintf("(auth pending, reschedule same event)"); setDone(false); } } return ritorno;}HciBus::HciBus() { memset(this,0,sizeof(*this));#ifdef USE_PROC_FS fdCommand=open("/proc/USBDo/intr",O_WRONLY,0666); fdEvent =open("/proc/USBDo/intr",O_RDONLY,0666); fdDataAsync=open("/proc/USBDo/bulk",O_RDWR,0666);/* fdDataSync =open("/proc/USBDo/isoc",O_RDWR,0666);*/#else fdCommand=open("/dev/usu_intr",O_WRONLY,0666); fdEvent =open("/dev/usu_intr",O_RDONLY,0666); fdDataAsync=open("/dev/usu_bulk",O_RDWR,0666);#endif lastPduL=MAX_PDU_LEN; lastPduC=0; lastPdu = new char[MAX_PDU_LEN];}HciBus::~HciBus() { if (fdCommand>0) close(fdCommand); if (fdEvent>0) close(fdEvent); if (fdDataAsync>0) close(fdDataAsync); if (fdDataSync>0) close(fdDataSync); int l,ritorno=0; for (l=0; l<MAX_PENDING_CMD; l++) if (hcireqres[l]) { Dprintf("HciBus::clear() found obj!!!\n"); /*hcireqres[l].detach()~HciReqRes()*/; hcireqres[l]=NULL; ritorno++; } delete lastPdu;}void onMessageDestroy(void* hb, HciReqRes& hcirr) { ((HciBus*)hb)->clear(hcirr);}int HciBus::schedule(HciReqRes& hcirr,char classe) { int ritorno=-ENOSPC; int l,la,lb;// if (hcirr.done()) return -EBADMSG; la=(classe=='a')?0:MAX_PENDING_CMD_CLASSA; lb=(classe=='a')? MAX_PENDING_CMD_CLASSA:MAX_PENDING_CMD; for (l=la; (l<lb) && (ritorno<0); l++) if (hcireqres[l]==NULL || hcireqres[l]->done()) ritorno=l; if (ritorno>=0) { hcireqres[ritorno]=&hcirr;// fb=(void (*) (HciReqRes&)) &HciBus::onMessageDestroy; hcirr.atExit(this,onMessageDestroy); /* hcireqres[ritorno].detach(); hcireqres[ritorno].copy(hcirr); hcireqres[ritorno].attach(); */ ritorno=hcirr.writeReq(lastPdu, lastPduL); if (ritorno>0) { /* So event can pass through this function.*/ lastPduC=ritorno; ritorno=hcirr.getProto()==HciReqRes::HCI?writeHci(fdCommand):writeHci(fdDataAsync); } } if (log && ritorno!=0) Dprintf("\tscheduled(%s=%s)\n",ritorno>=0?"bytes":"err",linuxErrDes(ritorno)); return ritorno;}int HciBus::writeHci(char* cmddata,int cmddataLen) { if (cmddataLen>lastPduL) return -ENOSPC; memcpy(lastPdu,cmddata,cmddataLen); lastPduC=cmddataLen; return writeHci(fdCommand);}int HciBus::writeHci(int fd) { int ritorno=0; int nVolte=0; while (ritorno>=0 && lastPduC>0 && nVolte<10 && fd>=0) { ritorno=write(fd,lastPdu,lastPduC); if (ritorno>=0) lastPduC-=ritorno; if (nVolte) { struct timespec ts; ts.tv_sec=0; ts.tv_nsec=1000*100; /* 100 msec.*/ nanosleep(&ts,0); } nVolte++; } if (nVolte==10 || fd==-1) ritorno=-ENODEV; return ritorno;}/* In one cycle we read msg & deliver. * * Return 0 if 0 bytes was readed form hciFd, * >0 if wee read a valid msg & is being accepted, without error, by someone. * <0 (msg decode with error -EBADMSG) | (msg !accepted by so -ESRCH) | (msg accepted with error) */int HciBus::hci_readEvt() { return readHci(HciReqRes::HCI);}int HciBus::l2cap_readEvt() { return readHci(HciReqRes::L2CAP);}/* readMsg() read {hci,l2cap} pdu (so we found hci,l2cap header) * for l2cap put only header from first packet, so user level can recognize multipacket. */int HciBus::readMsg(HciReqRes::ProtoT proto) { int ritorno=0; bool done=false; int nPacket=0; int lastPduCkp1=0; unsigned char* ulastPdu = (unsigned char*)lastPdu; /* Header & msg.*/ int currFd =(proto==HciReqRes::HCI)?fdEvent:fdDataAsync;; int hdrLen =(proto==HciReqRes::HCI)?2:4; int pduLen; /* Overwrite lastPdu.*/ lastPduC=0; while (ritorno>=0 && !done) { /* HCI Event: L2CAP Event: * id len ACL | L2CAP * 13 0B ... 28 20 12 00 | 0e 00 41 ... * len len * hdrlen=2 hdrlen=4 * len@pdu[1] len@pdu[2:3] * * 1) Read header, */ if (proto==HciReqRes::L2CAP || (proto==HciReqRes::HCI && nPacket==0)) { ritorno=currFd!=-1?read(currFd,lastPdu+lastPduC,hdrLen):-ENODEV; if (proto==HciReqRes::HCI || (proto==HciReqRes::L2CAP && nPacket==0)) lastPduCkp1+=hdrLen; nPacket++; } /* 2) Read remaining bytes of protocol {HCI,ACL}. */ if (ritorno==hdrLen) { pduLen=ulastPdu[hdrLen>>1]; /* HCI len. */ if (proto==HciReqRes::L2CAP) pduLen+=ulastPdu[(hdrLen>>1)+1]<<8; /* ACL len. */ while (ritorno>=0 && pduLen>0) { ritorno=read(currFd,lastPdu+lastPduCkp1,pduLen); if (ritorno>0) { pduLen-=ritorno; lastPduCkp1+=ritorno; } if (ritorno==0) { static int nTime=0; if (nTime<100) { struct timespec ts; ts.tv_sec=0; ts.tv_nsec=1<<20; /* about 1ms.*/ nanosleep(&ts,0); nTime++; } else { ritorno = -ETIMEDOUT; if (log) Dprintf("> msg timedout while reconstruct msg of len(%d/%d)!",lastPduCkp1,pduLen+lastPduCkp1); } } } } else if (ritorno>0) { if (log) Dprintf("(ERR!: can't read atomically header)"); ritorno=-EBADMSG; } if (ritorno>=0) { done = true; if (ritorno>0 && proto==HciReqRes::L2CAP) { int l2capLen=ulastPdu[4]+(ulastPdu[5]<<8); Dprintf("l2cap (desLen,readedLen)=(%d,%d)",l2capLen,lastPduCkp1-8); if (l2capLen<4) { if (log) Dprintf("(ERR!:L2CAP msg have len<4 (len=%d))",l2capLen); } else if (l2capLen>lastPduCkp1-8) { done=false; if (log) Dprintf("(L2CAP msg have other %d bytes)",l2capLen-(lastPduCkp1-8)); } else if (l2capLen<lastPduCkp1-8) { if (log) Dprintf("(ERR!:bad L2CAP msg: ACL len > L2CAP len)"); ritorno = -EBADMSG; done = false; } } } } if (ritorno>0) { lastPduC=lastPduCkp1; ritorno =lastPduCkp1; } return ritorno;}/* If any pending message, we complete in this routine. * The problem is that if we have: * <- ReadA * <- ReadRemoteName * -> 16 bytes * -> 16 bytes * -> N bytes (ReadA) * -> 16 bytes * -> 16 bytes * It is difficult to recognize readRemoteName PDU against response (F 4 ...) * For now we serialize. */int HciBus::readHci(HciReqRes::ProtoT proto) { /* * Read entire msg. Hci seem to prefere serial beh.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -