CADT SPO4025c Pseudo code for receiving generic protocol ------------------------------------------ #define MarkChar (char)0xFF #define QuoteChar (char)0xFE #define AckChar (char)0xFD #define NakChar (char)0xFC #define EventChar (char)0xFB class COximeter { // USB device handle FT_HANDLE ftHandle; // RS232 serial port device handle HANDLE hSerial; char cPacket[128]; // packet buffer int iPacketType,iPacketSize; .. public: .. int OnRxPacket(); .. friend unsigned long _stdcall PacketProtocol(void *pParameters); } static unsigned long _stdcall PacketProtocol(void *pParameters) { COximeter *pOx; bool bQuote; short iSequence,iPhase; short sChecksum; char cRxBuffer[256]; char cChecksum; DWORD dwLenReceived; iPhase=99; while (true) { .. fetch USB or COM input data // read chunk of received bytes from buffer for (unsigned int ic=0; iciPacketType=c1 & 0x07F; sChecksum+=pOx->iPacketType; iPhase++; } else if (iPhase==2) { // get packet size number pOx->iPacketSize=c1 & 0x0FF; sChecksum+=pOx->iPacketSize; iPhase++; } else if (iPhase==3) { // get packet data if (bQuote) { c1|=(char)0x80; bQuote=false; } pOx->cPacket[iRxWrite++]=c1; sChecksum+=c1 & 0x0FF; if (iRxWrite==pOx->iPacketSize) iPhase++; } else if (iPhase==4) { // get checksum and check cChecksum=0x7F & (sChecksum ^ (sChecksum >> 7) ^ (sChecksum >> 14)); char cAck[3]; if (cChecksum==c1) { // send the ack sequence cAck[0]=AckChar; pOx->iNRxAck++; } else { // send the nak sequence cAck[0]=NakChar; pOx->iNRxNak++; #ifdef _DEBUG sprintf(cDebug,"Oximeter NAK sent.\n"); OutputDebugString(cDebug); #endif // _DEBUG } cAck[1]=iSequence; cAck[2]=EventChar; if (pOx->hSerial) { iStatus=WriteFile(pOx->hSerial,cAck,3,&dwLenWritten,NULL); if (!iStatus) { iStatus=GetLastError(); goto x99; } } else { iStatus=FT_Write(pOx->ftHandle,cAck,3,&dwLenWritten); if (iStatus!=FT_OK) goto x99; } if (cChecksum==c1) { #ifdef _DEBUG // if (!iSequence) { char *pcWrite=cDebug+sprintf(cDebug,"PacketProtocol(): %02X %02X type=%02X size=%02X -", 0x00FF,iSequence & 0x00FF,pOx->iPacketType & 0x00FF, pOx->iPacketSize & 0x00FF); // data bytes for (int i1=0; i1iPacketSize; i1++) pcWrite+=sprintf(pcWrite," %02X",pOx->cPacket[i1] & 0x00FF); // checksum pcWrite+=sprintf(pcWrite," - %02X\n",cChecksum); // OutputDebugString(cDebug); // } #endif // _DEBUG pOx->OnRxPacket(); } iPhase++; } // phase 5 is dropping after complete packet else if (iPhase==6) { // waiting for Ack sequence character if (c1!=pOx->cTxSequ) // treat bad packet sequence number like Nak goto x98; pOx->iNTxAck++; // disable transmitter pOx->lTxTicks=0xFFFFFFFFL; pOx->OnTxPacket(); iPhase++; } // phase 7 is dropping after Ack packet else if (iPhase==8) { // waiting for Nak sequence character pOx->iNTxNak++; x98: if (5iNTxRepeat) { // immediate repeat packet transmission pOx->lTxTicks=GetTickCount(); if (pOx->hEvents[1]!=INVALID_HANDLE_VALUE) SetEvent(pOx->hEvents[1]); } else { // give up on this packet pOx->iNTxFailed++; pOx->lTxTicks=0xFFFFFFFFL; pOx->OnTxFailed(); } iPhase++; } // phase 9 is dropping after Nak packet } // received character loop } // characters available in queue and received The packet receiver routine looks like this #define IBOK 0x00 #define IBSensorDisconnected 0x01 #define IBNoFingerInProbe 0x02 #define IBLowPerfusion 0x03 #define IBSelftestError 0x45 int COximeter::OnRxPacket() { // sSample is lower half of 32 bit sample number // 300 samples per second (runs in steps of 6) // use sSample or the packet iSequence number to detect missing // packets unsigned short sSample=(cPacket[0] & 0x0FF)+(cPacket[1]<<8); unsigned short sIR=(cPacket[2] & 0x0FF)+(cPacket[3]<<8); short sIR2=(cPacket[4] & 0x0FF)+(cPacket[5]<<8); short sCurIR=(cPacket[6] & 0x0FF)+(cPacket[7]<<8); short sLEDIR=255-(unsigned char)cPacket[28]; unsigned short sRed=(cPacket[8] & 0x0FF)+(cPacket[9]<<8) /* + short(double(sIR)/7.9 ) */; short sRed2=(cPacket[10] & 0x0FF)+(cPacket[11]<<8) /* + short(double(sIR)/7.9 ) */; short sCurRed=(cPacket[12] & 0x0FF)+(cPacket[13]<<8); short sLEDRed=255-(unsigned char)cPacket[29]; unsigned short sOra=(cPacket[14] & 0x0FF)+(cPacket[15]<<8); short sOra2=(cPacket[16] & 0x0FF)+(cPacket[17]<<8); short sCurOra=(cPacket[18] & 0x0FF)+(cPacket[19]<<8); short sLEDOra=255-(unsigned char)cPacket[30]; unsigned short sGain=cPacket[31] & 0x00FF; HCRTOS=(unsigned char)cPacket[32]; short HCFlags=cPacket[33] & 0x0FF; // pChildView is an object showing the plethysmogram curves VisPleth(pChildView,(double(8*4095-sIR)*double(255-sGain))/double(sLEDIR)); VisPleth(pChildView,(double(8*4095-sRed)*double(255-sGain))/double(sLEDRed)); short sSensorR=(cPacket[20] & 0x0FF)+(cPacket[21]<<8); short sAmbient=(cPacket[22] & 0x0FF)+(cPacket[23]<<8); short sGenerator=(cPacket[24] & 0x0FF)+(cPacket[25]<<8); short sTemperature=(cPacket[26] & 0x0FF)+(cPacket[27]<<8); if (iPacketType==36) { // extended packet with oximetry results short HCInfoByte=cPacket[34] & 0x0FF; char *pc1=NULL; if (HCInfoByte==IBOK) pc1="OK"; else if (HCInfoByte==IBSensorDisconnected) pc1="Sensor?"; else if (HCInfoByte==IBNoFingerInProbe) pc1="Finger?"; else if (HCInfoByte==IBLowPerfusion) pc1="Perfusion?"; else if (HCInfoByte==IBSelftestError) pc1="Selftest?"; short HCPCount=(cPacket[36] & 0x0FF)+(cPacket[37]<<8); short HCPerf=(cPacket[38] & 0x0FF)+(cPacket[39]<<8); short HCPuls=(cPacket[40] & 0x0FF)+(cPacket[41]<<8); short HCRise=(cPacket[42] & 0x0FF)+(cPacket[43]<<8); short HCJitter=(cPacket[44] & 0x0FF)+(cPacket[45]<<8); short HCSPO2=(cPacket[46] & 0x0FF)+(cPacket[47]<<8); short HCHBCO=(cPacket[48] & 0x0FF)+(cPacket[49]<<8); } }