📄 blue.cpp
字号:
/* * blue.cpp * * Author : Lionetti Salvatore <salvatorelionetti@yahoo.it> * License: GPL * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include<stdio.h>#include<stdio.h>#include<fcntl.h> /* open().*/#include<unistd.h> /* read()/close().*/#if 0#ifdef LITTLE_ENDIAN#undef LITTLE_ENDIAN#include<linux/byteorder/little_endian.h>#elif defined BIG_ENDIAN#undef BIG_ENDIAN#include<linux/byteorder/big_endian.h>#endif#endif#include<string.h> /* memcpy().*/#include<linux/types.h> /* __u16 */#include<time.h> /* nanosleep(), timespec.*/#include<stdarg.h> /* va_start(), va_end().*/#include<errno.h>#include"blue.h"#include"../config_usu.h" /* To select fs to which interact.*/#undef USE_PROCFSchar* linuxErrDes(int errCode) { char* ritorno=0; switch (errCode) { case -ESRCH: {ritorno="-ESRCH";break;} case -ENOSPC:{ritorno="-ENOSPC";break;} case -EPROTO:{ritorno="-EPROTO";break;} case -ENODEV:{ritorno="-ENODEV";break;} case -EBADMSG:{ritorno="-EBADMSG";break;} case -EALREADY:{ritorno="-EALREADY";break;} case -EINVAL:{ritorno="-EINVAL";break;} case -ETIMEDOUT:{ritorno="-ETIMEDOUT";break;} case -EHOSTDOWN:{ritorno="-EHOSTDOWN";break;} case -EACCES:{ritorno="-EACCES";break;} case -ENOTCONN:{ritorno="-ENOTCONN";break;} case -ECONNRESET:{ritorno="-ECONNRESET";break;} case -EBUSY:{ritorno="-EBUSY";break;} case -ECONNABORTED:{ritorno="-ECONNABORTED";break;} default: { static char defaultErr[10]; snprintf(defaultErr,10,"%d",errCode); ritorno=defaultErr; break; } } return ritorno;}int blue2linuxErr(int errCode) { int ritorno=0; switch(errCode) { case '\xb': {ritorno=-EALREADY;break;} case '\x12': {ritorno=-EINVAL;break;} case '\x10': {ritorno=-ETIMEDOUT;break;} case '\x4': {ritorno=-EHOSTDOWN;break;} case '\x18': case '\x5': {ritorno=-EACCES;break;} case '\x2': {ritorno=-ENOTCONN;break;} case '\x13': {ritorno=-ECONNRESET;break;} case '\xc': {ritorno=-EBUSY;break;} case '\x9': case '\xa': {ritorno=-EMLINK;break;} /* Many link.*/ case '\x16': {ritorno=-ECONNABORTED;break;} /* Software cause connection abort.*//* case '\x22': {ritorno=-EPROTO;break;} UNKNOWN.*/ case '\x1f': {ritorno=-EIO;break;} /* affix report unk err.*/ default: {ritorno=errCode;break;} } return ritorno;}char* blueErrDes(int errCode) { return linuxErrDes(blue2linuxErr(errCode));}int log=1;FILE* fdlog=NULL;int Dprintf(const char* fmt,...) { int ritorno; { va_list va; va_start(va,fmt); ritorno=vfprintf(stdout,fmt,va); va_end(va); } if (fdlog==NULL) { fdlog=fopen("log.txt","a"); if (fdlog) fprintf(fdlog,"\n=========START PROGRAM============\n"); } if (fdlog) { va_list va; va_start(va,fmt); int ritorno; ritorno=vfprintf(fdlog,fmt,va); va_end(va); } return ritorno;}HciReqRes::HciReqRes() { req=new char[MAX_PDU_LEN*2]; res=req + MAX_PDU_LEN; reqL=resL=MAX_PDU_LEN; /* max len.*/ reqC=resC=0; /* cursors.*/ atExitF=NULL;}HciReqRes::~HciReqRes() { if (atExitF) atExitF(atExitP,*this); delete req;}void HciReqRes::atExit(void* ingP,atExitT ing) { atExitF=ing; atExitP=ingP;}/* Write only if all requested bytes are now available.*/int HciReqRes::compileReq(char* buf, int len) { int ritorno=0; if (len+reqC<=reqL) { memcpy(req+reqC,buf,len); ritorno=len; reqC+=len; } return ritorno;}int HciReqRes::scanRes(char* buf, int len) { int ritorno=len; if (ritorno>0) { memcpy(buf,res+resC,ritorno); resC+=ritorno; /*if (resC==0) requestOn=false; */ } return ritorno;}int HciReqRes::writeReq(char* buf, int len) { int ritorno=-ENOSPC; if (len>reqC) { if (reqC>0) memcpy(buf, req, reqC); ritorno=reqC; /*reqC=0; so multi read can be done.*/ requestOn=true; } return ritorno;}/* Read only if all bytes requested are now available.*/int HciReqRes::readRes(char* buf, int len) { int ritorno=0; /*if (len<=resC)*/ { /*resC-=len;*/ resC=0; memcpy(res+resC,buf,len); ritorno=len; requestOn=false; /*if (resC==0) requestOn=false; */ } return ritorno;}bool HciReqRes::done() {return !requestOn;}enum HciReqRes::ProtoT HciReqRes::getProto() {return proto;}void HciReqRes::setProto(enum HciReqRes::ProtoT pro) {proto=pro;}int HciReqRes::getReqC() {return reqC;}int HciReqRes::getResC() {return resC;}void HciReqRes::setDone(bool idone) {requestOn=!idone;}/*void HciReqRes::attach() {if (hcirr) hcirr->usecount++;}void HciReqRes::detach() {if (hcirr) hcirr->usecount--;}void HciReqRes::copy(HciReqRes& ing) {memcpy(this,&ing,sizeof(*this));}*/enum OgfOcfT { WRITE_VOICE_SETTING=0, WRITE_SCAN_ENABLE, WRITE_AUTH_ENABLE, WRITE_ENCR_MODE, WRITE_LOCAL_NAME, CREATE_CONNECTION, LINKKEY_REPLY, LINKKEY_NEG_REPLY, PINCODE_REPLY, DISCONNECT, WRITE_CLASS_OF_DEV, WRITE_LINK_POLICY, ADD_SCO_CONNECTION, ACCEPT_CONNECTION, READ_HOST_MAC, /* HOST mean the special bt device that let us2communicate with HciBus.*/ SEARCH_DEVICE, READ_REMOTE_NAME, WRITE_PAGESCAN_TIMEOUT, WRITE_INCONNECTION_TIMEOUT, SET_EVENT_FILTER, EVENT_WAITING,};/* All HCI Command end with EVT command complete: (also if err?) * class HciCmd capture this behavior.*//* Only deal with hci cmd and related response (e..., f...) * * AcceptConnection is only req (really is a response to device) * and have no response at all. Now we only schedule. * If wrong command, we a spurious hciEvent.*/class HciCmd: public HciReqRes {public: enum OgfT {NULL_OGF=0, LINK_CTL, LINK_POL, HOST_CTL, INFO_PAR, STATUS_PAR, TESTING_CMD=0x3E, VENDOR_CMD}; struct HciCmdT { char* des; enum OgfT ogf; __u16 ocf; __u8 reqL; __u8 resL; };#if 0 char* reqOptTypes; char* resOptTypes;#endifprivate: static HciCmdT hciCmds[21]; enum OgfOcfT index;public: HciCmd(enum OgfOcfT ind, char* reqopt=0); ~HciCmd(); int readRes(char* des, int len); int writeReq(char* buf, int len); /* Now we assume that only one parameter is present in req.*/ void setPar(char* reqopt); int getReqL() {return req[2];} void copy(HciCmd& ing) {memcpy(this,&ing,sizeof(*this));}};#if 0struct HciCmd::HciCmdT asd[]={ {"wrVoiceSetting", HciCmd::HOST_CTL, 0x26, 2, 0}, /* WRITE_VOICE_SETTING */ {"wrVoiceSetting", HciCmd::HOST_CTL, 0x26, 2, 0} /* WRITE_VOICE_SETTING */};#endifstruct HciCmd::HciCmdT HciCmd::hciCmds[]={ {"wrVoiceSetting", HOST_CTL, 0x26, 2, 0}, /* WRITE_VOICE_SETTING */ {"wrScanEnable", HOST_CTL, 0x1a, 1, 0}, /* WRITE_SCAN_ENABLE */ {"wrAuthEnable", HOST_CTL, 0x20, 1, 0}, /* WRITE_AUTH_ENABLE */ {"wrEncrMode", HOST_CTL, 0x22, 1, 0}, /* WRITE_ENCR_MODE */ {"wrLocalName", HOST_CTL, 0x13, 256, 0}, /* WRITE_LOCAL_NAME */ {"createConn", LINK_CTL, 0x05, 13, 0}, /* CREATE_CONNECTION */ {"linkKeyReply", LINK_CTL, 0x0b, 22, 6}, /* LINKKEY_REPLY */ {"linkKeyNegReply", LINK_CTL, 0x0c, 6, 6}, /* LINKKEY_NEG_REPLY */ {"pinCodeReply", LINK_CTL, 0x0d, /*12*/23, 6}, /* PINCODE_REPLY */ {"disconnect", LINK_CTL, 0x06, 3, 0}, /* DISCONNECT */ {"wrClassOfDev", HOST_CTL, 0x24, 3, 0}, /* WRITE_CLASS_OF_DEV */ {"wrLinkPolicy", LINK_POL, 0x0d, 4, 2}, /* WRITE_LINK_POLICY */ {"addScoConn", LINK_CTL, 0x07, 4, 0}, /* ADD_SCO_CONNECTION */ {"acceptConn", LINK_CTL, 0x09, 7, 0}, /* ACCEPT_CONNECTION */ {"rdHostMac", INFO_PAR, 0x09, 0, 6}, /* READ_HOST_MAC */ {"searchDev", LINK_CTL, 0x01, 5, 0}, /* SEARCH_DEVICE */ {"readRemoteName", LINK_CTL, 0x19, 10, 0}, /* READ_REMOTE_NAME */ {"wrPageScanTimeout", HOST_CTL, 0x18, 2, 0}, /* WRITE_PAGESCAN_TIMEOUT*/ {"wrIConnectionTimeout",HOST_CTL, 0x18, 2, 0}, /* WRITE_INCONNECTION_TIMEOUT*/ {"setEventFilter", HOST_CTL, 0x05, 2, 0}, /* SET_EVENT_FILTER */ {"eventWait", NULL_OGF, 0x00, 0,0} /* EVENT_WAITING */};HciCmd::HciCmd(enum OgfOcfT ind, char* reqopt) { setProto(HCI); index=ind; if (hciCmds[index].ogf!=NULL_OGF) { char tmp; tmp = hciCmds[index].ocf; compileReq(&tmp,1); tmp = (hciCmds[index].ocf>>8)&3 | hciCmds[index].ogf<<2; compileReq(&tmp,1); tmp = index==WRITE_LOCAL_NAME?strlen(reqopt):hciCmds[index].reqL; compileReq(&tmp,1); if (reqopt) compileReq(reqopt, index==WRITE_LOCAL_NAME?strlen(reqopt):req[2]); }}HciCmd::~HciCmd() {}int HciCmd::writeReq(char* buf, int len) { if (log && index!=EVENT_WAITING) { Dprintf("< %s(%x,%x) ",hciCmds[index].des, req[0],req[1]); int l; for (l=0; (l<hciCmds[index].reqL) && (l<getReqC()-3); l++) Dprintf(index==WRITE_LOCAL_NAME?"c":"%02x",(unsigned char)req[3+l]); } return HciReqRes::writeReq(buf,len);}int HciCmd::readRes(char* buf, int len) { int ritorno=0; int expL=6; /* Parameter correct for 0xf */ int ogfocfC=4; /* Parameter correct for oxf */ int statusC=2; /* Parameter correct for 0xf */ /* 1) see if msg is our response: * (0xe, len, nPendPct, ocf,ogf, status : check ocf,ogf,status,len=expected). * (0xf, len, status, nPendCmd, ocf, ogf: check ocf,ogf,status,len=expected). */ if (buf[0]=='\xe' || buf[0]=='\xf') { if (buf[0]=='\xe') { expL+=hciCmds[index].resL; ogfocfC=3; statusC=5; } if (len>=expL) { if (expL==(buf[1]+2) && memcmp(req,buf+ogfocfC,2)==0) { ritorno=HciReqRes::readRes(buf,expL); { /* skip common header: E len nPendCmd ocf ogf status(?)*/ char tmp[6]; HciReqRes::scanRes(tmp,6); } /* 2) If interesting verify correctness (status=0).*/ if (log) { int l; Dprintf("> cmd%s(%02x) (%x,%x) status(%s)",buf[0]=='\xe'?"Compl":"Stat",buf[0],buf[ogfocfC],buf[ogfocfC+1],blueErrDes(buf[statusC])); for (l=getResC(); l<expL; l++) Dprintf("%02x",(unsigned char)res[l]); } ritorno = buf[statusC]?blue2linuxErr(buf[statusC]):ritorno;/*-EPROTO*/; } } } return ritorno;}void HciCmd::setPar(char* reqopt) { memcpy(req+3,reqopt,hciCmds[index].reqL); }/* Hci bytes produced, so communication is started by device: * HciCmd < * HciCmd > * HciEvt > */enum EvtT { ANY_EVT=0, NUM_COMPL_PACKET=0x13, PINCODE_REQ=0x16, LINKKEY_REQ, LINKKEY_NOTIFY, CONNECT_COMPLETE=3, CONNECT_REQUEST, DISCONN_COMPLETE, SEARCH_DEVICE_END=1, SEARCH_DEVICE_FOUND, DEVICE_NAME=7};class HciEvt: public HciReqRes {public: struct HciEvtT { char* des; enum EvtT evt; __u8 resL; };private: int index; static HciEvtT hciEvts[11];public: HciEvt(enum EvtT ind); ~HciEvt(); int readRes(char* des, int len); int writeReq(char* buf, int len); virtual void evtComplete(); void copy(HciEvt& ing) {memcpy(this,&ing,sizeof(*this));}};struct HciEvt::HciEvtT HciEvt::hciEvts[]={ {"anyEvt", ANY_EVT, 0}, {"numComplPacket", NUM_COMPL_PACKET, 5}, {"pinCodeRequest", PINCODE_REQ, 6}, {"linkKeyRequest", LINKKEY_REQ, 6}, {"linkKeyNotify", LINKKEY_NOTIFY, 23}, {"connectComplete", CONNECT_COMPLETE, 11}, {"connectRequest", CONNECT_REQUEST, 10}, {"disconnComplete", DISCONN_COMPLETE, 4}, {"searchDevEnd", SEARCH_DEVICE_END, 1}, {"searchDevFound", SEARCH_DEVICE_FOUND, 15}, {"remoteDeviceName", DEVICE_NAME, 255},};HciEvt::HciEvt(enum EvtT ind) { unsigned int l; setProto(HCI); index=-1; for (l=0; l<sizeof(hciEvts)/sizeof(HciEvtT); l++) if (hciEvts[l].evt==ind) index=l; if (index==-1) Dprintf("\n INTERNAL ERROR! index %d !exist in hciEvts[].\n",(int)ind);// resC=hciEvts[index].resL+2;}HciEvt::~HciEvt() {}void HciEvt::evtComplete() {Dprintf("evtComplete!!!\n");}int HciEvt::writeReq(char* buf, int len) { return HciReqRes::writeReq(buf,len);}/* HciBus ensure that only one event@time is delivered.*/int HciEvt::readRes(char* buf, int len) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -