LTKCPP-- LLRP Toolkit C Plus Plus Library
|
00001 00002 /* 00003 ***************************************************************************** 00004 * * 00005 * IMPINJ CONFIDENTIAL AND PROPRIETARY * 00006 * * 00007 * This source code is the sole property of Impinj, Inc. Reproduction or * 00008 * utilization of this source code in whole or in part is forbidden without * 00009 * the prior written consent of Impinj, Inc. * 00010 * * 00011 * (c) Copyright Impinj, Inc. 2007,2009. All rights reserved. * 00012 * * 00013 *****************************************************************************/ 00014 00051 #include <stdio.h> 00052 #include "ltkcpp.h" 00053 #include "impinj_ltkcpp.h" 00054 #include "time.h" 00055 00056 using namespace LLRP; 00057 00058 /* 00059 ** Sorry, we use this linux safe method 00060 ** to print buffers. WIndows has the same 00061 ** method, but by a different name 00062 */ 00063 #if (WIN32) 00064 #define snprintf _snprintf 00065 #endif 00066 00067 class CMyApplication 00068 { 00069 private: 00070 00071 unsigned int m_PowerLevelIndex; 00072 unsigned int m_hopTableID; 00073 unsigned int m_channelIndex; 00074 unsigned int m_modelNumber; 00075 unsigned int m_messageID; 00076 00077 public: 00079 int m_Verbose; 00080 00082 CConnection * m_pConnectionToReader; 00083 CTypeRegistry * m_pTypeRegistry; 00084 00085 inline 00086 CMyApplication (void) 00087 : m_Verbose(0), m_pConnectionToReader(NULL) 00088 { 00089 m_messageID = 0; 00090 } 00091 00092 int 00093 run ( 00094 char * pReaderHostName); 00095 00096 int 00097 checkConnectionStatus (void); 00098 00099 int 00100 enableImpinjExtensions (void); 00101 00102 int 00103 resetConfigurationToFactoryDefaults (void); 00104 00105 int 00106 getReaderCapabilities(void); 00107 00108 int 00109 getReaderConfig(void); 00110 00111 int 00112 setImpinjReaderConfig(void); 00113 00114 int 00115 addROSpec (void); 00116 00117 int 00118 enableROSpec (void); 00119 00120 int 00121 startROSpec (void); 00122 00123 int 00124 stopROSpec (void); 00125 00126 int 00127 awaitAndPrintReport (int timeoutSec); 00128 00129 void 00130 printTagReportData ( 00131 CRO_ACCESS_REPORT * pRO_ACCESS_REPORT); 00132 00133 void 00134 printOneTagReportData ( 00135 CTagReportData * pTagReportData); 00136 00137 void 00138 formatOneEPC ( 00139 CParameter * pEpcParameter, 00140 char * buf, 00141 int buflen); 00142 00143 void 00144 handleReaderEventNotification ( 00145 CReaderEventNotificationData *pNtfData); 00146 00147 void 00148 handleAntennaEvent ( 00149 CAntennaEvent * pAntennaEvent); 00150 00151 void 00152 handleReaderExceptionEvent ( 00153 CReaderExceptionEvent * pReaderExceptionEvent); 00154 00155 int 00156 checkLLRPStatus ( 00157 CLLRPStatus * pLLRPStatus, 00158 char * pWhatStr); 00159 00160 CMessage * 00161 transact ( 00162 CMessage * pSendMsg); 00163 00164 CMessage * 00165 recvMessage ( 00166 int nMaxMS); 00167 00168 int 00169 sendMessage ( 00170 CMessage * pSendMsg); 00171 00172 void 00173 printXMLMessage ( 00174 CMessage * pMessage); 00175 }; 00176 00177 00178 /* BEGIN forward declarations */ 00179 int 00180 main ( 00181 int ac, 00182 char * av[]); 00183 00184 void 00185 usage ( 00186 char * pProgName); 00187 /* END forward declarations */ 00188 00189 00205 int 00206 main ( 00207 int ac, 00208 char * av[]) 00209 { 00210 CMyApplication myApp; 00211 char * pReaderHostName; 00212 int rc; 00213 00214 /* 00215 * Process comand arguments, determine reader name 00216 * and verbosity level. 00217 */ 00218 if(ac == 2) 00219 { 00220 pReaderHostName = av[1]; 00221 } 00222 else if(ac == 3) 00223 { 00224 char * p = av[1]; 00225 00226 while(*p) 00227 { 00228 switch(*p++) 00229 { 00230 case '-': /* linux conventional option warn char */ 00231 case '/': /* Windows/DOS conventional option warn char */ 00232 break; 00233 00234 case 'v': 00235 case 'V': 00236 myApp.m_Verbose++; 00237 break; 00238 00239 default: 00240 usage(av[0]); 00241 /* no return */ 00242 break; 00243 } 00244 } 00245 00246 pReaderHostName = av[2]; 00247 } 00248 else 00249 { 00250 usage(av[0]); 00251 /* no return */ 00252 } 00253 00254 /* 00255 * Run application, capture return value for exit status 00256 */ 00257 rc = myApp.run(pReaderHostName); 00258 00259 printf("INFO: Done\n"); 00260 00261 /* 00262 * Exit with the right status. 00263 */ 00264 if(0 == rc) 00265 { 00266 exit(0); 00267 } 00268 else 00269 { 00270 exit(2); 00271 } 00272 /*NOTREACHED*/ 00273 } 00274 00275 00287 void 00288 usage ( 00289 char * pProgName) 00290 { 00291 #ifdef linux 00292 printf("Usage: %s [-v[v]] READERHOSTNAME\n", pProgName); 00293 printf("\n"); 00294 printf("Each -v increases verbosity level\n"); 00295 #endif /* linux */ 00296 #ifdef WIN32 00297 printf("Usage: %s [/v[v]] READERHOSTNAME\n", pProgName); 00298 printf("\n"); 00299 printf("Each /v increases verbosity level\n"); 00300 #endif /* WIN32 */ 00301 exit(1); 00302 } 00303 00304 00346 int 00347 CMyApplication::run ( 00348 char * pReaderHostName) 00349 { 00350 CConnection * pConn; 00351 int rc; 00352 00353 /* 00354 * Allocate the type registry. This is needed 00355 * by the connection to decode. 00356 */ 00357 m_pTypeRegistry = getTheTypeRegistry(); 00358 if(NULL == m_pTypeRegistry) 00359 { 00360 printf("ERROR: getTheTypeRegistry failed\n"); 00361 return -1; 00362 } 00363 00364 /* 00365 * Enroll impinj extension types into the 00366 * type registry, in preparation for using 00367 * Impinj extension params. 00368 */ 00369 LLRP::enrollImpinjTypesIntoRegistry(m_pTypeRegistry); 00370 00371 /* 00372 * Construct a connection (LLRP::CConnection). 00373 * Using a 32kb max frame size for send/recv. 00374 * The connection object is ready for business 00375 * but not actually connected to the reader yet. 00376 */ 00377 pConn = new CConnection(m_pTypeRegistry, 32u*1024u); 00378 if(NULL == pConn) 00379 { 00380 printf("ERROR: new CConnection failed\n"); 00381 return -2; 00382 } 00383 00384 /* 00385 * Open the connection to the reader 00386 */ 00387 if(m_Verbose) 00388 { 00389 printf("INFO: Connecting to %s....\n", pReaderHostName); 00390 } 00391 00392 rc = pConn->openConnectionToReader(pReaderHostName); 00393 if(0 != rc) 00394 { 00395 printf("ERROR: connect: %s (%d)\n", pConn->getConnectError(), rc); 00396 delete pConn; 00397 return -3; 00398 } 00399 00400 /* 00401 * Record the pointer to the connection object so other 00402 * routines can use it. 00403 */ 00404 m_pConnectionToReader = pConn; 00405 00406 if(m_Verbose) 00407 { 00408 printf("INFO: Connected, checking status....\n"); 00409 } 00410 00411 /* 00412 * Commence the sequence and check for errors as we go. 00413 * See comments for each routine for details. 00414 * Each routine prints messages. 00415 */ 00416 rc = 1; 00417 if(0 == checkConnectionStatus()) 00418 { 00419 rc = 2; 00420 if(0 == enableImpinjExtensions()) 00421 { 00422 rc = 3; 00423 if(0 == resetConfigurationToFactoryDefaults()) 00424 { 00425 rc = 4; 00426 if(0 == getReaderCapabilities()) 00427 { 00428 rc = 5; 00429 if(0 == getReaderConfig()) 00430 { 00431 rc = 6; 00432 if(0 == setImpinjReaderConfig()) 00433 { 00434 rc = 7; 00435 if(0 == addROSpec()) 00436 { 00437 rc = 8; 00438 if(0 == enableROSpec()) 00439 { 00440 rc = 9; 00441 if(0 == startROSpec()) 00442 { 00443 rc = 10; 00444 if(0 == awaitAndPrintReport(60)) 00445 { 00446 rc = 11; 00447 if(0 == stopROSpec()) 00448 { 00449 rc = 0; 00450 } 00451 } 00452 } 00453 } 00454 } 00455 } 00456 } 00457 } 00458 } 00459 00460 /* 00461 * After we're done, try to leave the reader 00462 * in a clean state for next use. This is best 00463 * effort and no checking of the result is done. 00464 */ 00465 if(m_Verbose) 00466 { 00467 printf("INFO: Clean up reader configuration...\n"); 00468 } 00469 resetConfigurationToFactoryDefaults(); 00470 } 00471 } 00472 00473 if(m_Verbose) 00474 { 00475 printf("INFO: Finished\n"); 00476 } 00477 00478 /* 00479 * Close the connection and release its resources 00480 */ 00481 pConn->closeConnectionToReader(); 00482 delete pConn; 00483 00484 /* 00485 * Done with the registry. 00486 */ 00487 delete m_pTypeRegistry; 00488 00489 /* 00490 * When we get here all allocated memory should have been deallocated. 00491 */ 00492 CXMLTextDecoder::cleanupParser(); 00493 00494 return rc; 00495 } 00496 00497 00528 int 00529 CMyApplication::checkConnectionStatus (void) 00530 { 00531 CMessage * pMessage; 00532 CREADER_EVENT_NOTIFICATION *pNtf; 00533 CReaderEventNotificationData *pNtfData; 00534 CConnectionAttemptEvent * pEvent; 00535 00536 /* 00537 * Expect the notification within 10 seconds. 00538 * It is suppose to be the very first message sent. 00539 */ 00540 pMessage = recvMessage(10000); 00541 00542 /* 00543 * recvMessage() returns NULL if something went wrong. 00544 */ 00545 if(NULL == pMessage) 00546 { 00547 /* recvMessage already tattled */ 00548 goto fail; 00549 } 00550 00551 /* 00552 * Check to make sure the message is of the right type. 00553 * The type label (pointer) in the message should be 00554 * the type descriptor for READER_EVENT_NOTIFICATION. 00555 */ 00556 if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor != pMessage->m_pType) 00557 { 00558 goto fail; 00559 } 00560 00561 /* 00562 * Now that we are sure it is a READER_EVENT_NOTIFICATION, 00563 * traverse to the ReaderEventNotificationData parameter. 00564 */ 00565 pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage; 00566 pNtfData = pNtf->getReaderEventNotificationData(); 00567 if(NULL == pNtfData) 00568 { 00569 goto fail; 00570 } 00571 00572 /* 00573 * The ConnectionAttemptEvent parameter must be present. 00574 */ 00575 pEvent = pNtfData->getConnectionAttemptEvent(); 00576 if(NULL == pEvent) 00577 { 00578 goto fail; 00579 } 00580 00581 /* 00582 * The status in the ConnectionAttemptEvent parameter 00583 * must indicate connection success. 00584 */ 00585 if(ConnectionAttemptStatusType_Success != pEvent->getStatus()) 00586 { 00587 goto fail; 00588 } 00589 00590 /* 00591 * Done with the message 00592 */ 00593 delete pMessage; 00594 00595 if(m_Verbose) 00596 { 00597 printf("INFO: Connection status OK\n"); 00598 } 00599 00600 /* 00601 * Victory. 00602 */ 00603 return 0; 00604 00605 fail: 00606 /* 00607 * Something went wrong. Tattle. Clean up. Return error. 00608 */ 00609 printf("ERROR: checkConnectionStatus failed\n"); 00610 delete pMessage; 00611 return -1; 00612 } 00613 00631 int 00632 CMyApplication::enableImpinjExtensions (void) 00633 { 00634 CIMPINJ_ENABLE_EXTENSIONS * pCmd; 00635 CMessage * pRspMsg; 00636 CIMPINJ_ENABLE_EXTENSIONS_RESPONSE *pRsp; 00637 00638 /* 00639 * Compose the command message 00640 */ 00641 pCmd = new CIMPINJ_ENABLE_EXTENSIONS(); 00642 pCmd->setMessageID(m_messageID++); 00643 /* 00644 * Send the message, expect the response of certain type 00645 */ 00646 pRspMsg = transact(pCmd); 00647 00648 /* 00649 * Done with the command message 00650 */ 00651 delete pCmd; 00652 00653 /* 00654 * transact() returns NULL if something went wrong. 00655 */ 00656 if(NULL == pRspMsg) 00657 { 00658 /* transact already tattled */ 00659 return -1; 00660 } 00661 00662 /* 00663 * Cast to a CIMPINJ_ENABLE_EXTENSIONS_RESPONSE message. 00664 */ 00665 pRsp = (CIMPINJ_ENABLE_EXTENSIONS_RESPONSE *) pRspMsg; 00666 00667 /* 00668 * Check the LLRPStatus parameter. 00669 */ 00670 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), 00671 "enableImpinjExtensions")) 00672 { 00673 /* checkLLRPStatus already tattled */ 00674 delete pRspMsg; 00675 return -1; 00676 } 00677 00678 /* 00679 * Done with the response message. 00680 */ 00681 delete pRspMsg; 00682 00683 /* 00684 * Tattle progress, maybe 00685 */ 00686 if(m_Verbose) 00687 { 00688 printf("INFO: Impinj Extensions are enabled\n"); 00689 } 00690 00691 /* 00692 * Victory. 00693 */ 00694 return 0; 00695 } 00696 00717 int 00718 CMyApplication::resetConfigurationToFactoryDefaults (void) 00719 { 00720 CSET_READER_CONFIG * pCmd; 00721 CMessage * pRspMsg; 00722 CSET_READER_CONFIG_RESPONSE *pRsp; 00723 00724 /* 00725 * Compose the command message 00726 */ 00727 pCmd = new CSET_READER_CONFIG(); 00728 pCmd->setMessageID(m_messageID++); 00729 pCmd->setResetToFactoryDefault(1); 00730 00731 /* 00732 * Send the message, expect the response of certain type 00733 */ 00734 pRspMsg = transact(pCmd); 00735 00736 /* 00737 * Done with the command message 00738 */ 00739 delete pCmd; 00740 00741 /* 00742 * transact() returns NULL if something went wrong. 00743 */ 00744 if(NULL == pRspMsg) 00745 { 00746 /* transact already tattled */ 00747 return -1; 00748 } 00749 00750 /* 00751 * Cast to a SET_READER_CONFIG_RESPONSE message. 00752 */ 00753 pRsp = (CSET_READER_CONFIG_RESPONSE *) pRspMsg; 00754 00755 /* 00756 * Check the LLRPStatus parameter. 00757 */ 00758 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), 00759 "resetConfigurationToFactoryDefaults")) 00760 { 00761 /* checkLLRPStatus already tattled */ 00762 delete pRspMsg; 00763 return -1; 00764 } 00765 00766 /* 00767 * Done with the response message. 00768 */ 00769 delete pRspMsg; 00770 00771 /* 00772 * Tattle progress, maybe 00773 */ 00774 if(m_Verbose) 00775 { 00776 printf("INFO: Configuration reset to factory defaults\n"); 00777 } 00778 00779 /* 00780 * Victory. 00781 */ 00782 return 0; 00783 } 00784 00802 int 00803 CMyApplication::getReaderCapabilities(void) 00804 { 00805 CGET_READER_CAPABILITIES *pCmd; 00806 CMessage * pRspMsg; 00807 CGET_READER_CAPABILITIES_RESPONSE *pRsp; 00808 CRegulatoryCapabilities *pReg; 00809 CUHFBandCapabilities *pUhf; 00810 CTransmitPowerLevelTableEntry *pPwrLvl; 00811 CGeneralDeviceCapabilities *pDeviceCap; 00812 std::list<CTransmitPowerLevelTableEntry *>::iterator PwrLvl; 00813 00814 /* 00815 * Compose the command message 00816 */ 00817 pCmd = new CGET_READER_CAPABILITIES(); 00818 pCmd->setMessageID(m_messageID++); 00819 pCmd->setRequestedData(GetReaderCapabilitiesRequestedData_All); 00820 00821 /* 00822 * Send the message, expect the response of certain type 00823 */ 00824 pRspMsg = transact(pCmd); 00825 00826 /* 00827 * Done with the command message 00828 */ 00829 delete pCmd; 00830 00831 /* 00832 * transact() returns NULL if something went wrong. 00833 */ 00834 if(NULL == pRspMsg) 00835 { 00836 /* transact already tattled */ 00837 return -1; 00838 } 00839 00840 /* 00841 * Cast to a CGET_READER_CAPABILITIES_RESPONSE message. 00842 */ 00843 pRsp = (CGET_READER_CAPABILITIES_RESPONSE *) pRspMsg; 00844 00845 /* 00846 * Check the LLRPStatus parameter. 00847 */ 00848 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), 00849 "getReaderCapabilities")) 00850 { 00851 /* checkLLRPStatus already tattled */ 00852 delete pRspMsg; 00853 return -1; 00854 } 00855 00856 /* 00857 ** Get out the Regulatory Capabilities element 00858 */ 00859 if(NULL == (pReg = pRsp->getRegulatoryCapabilities())) 00860 { 00861 delete pRspMsg; 00862 return -1; 00863 } 00864 00865 /* 00866 ** Get out the UHF Band Capabilities element 00867 */ 00868 if(NULL == (pUhf = pReg->getUHFBandCapabilities())) 00869 { 00870 delete pRspMsg; 00871 return -1; 00872 } 00873 00874 /* get the last power level in the table */ 00875 PwrLvl = pUhf->endTransmitPowerLevelTableEntry(); 00876 PwrLvl--; 00877 00878 // store the index for use int the ROSpec. 00879 pPwrLvl = *PwrLvl; 00880 m_PowerLevelIndex = pPwrLvl->getIndex(); 00881 00882 if(1 < m_Verbose) 00883 { 00884 printf("INFO: Reader Max Power index %u, power %f\n", 00885 pPwrLvl->getIndex(), (float)(float) pPwrLvl->getTransmitPowerValue()/100); 00886 } 00887 00888 /* if this parameter is missing, or if this is not an Impinj 00889 ** reader, we can't determine its capabilities so we exit 00890 ** Impinj Private Enterprise NUmber is 25882 */ 00891 if( (NULL == (pDeviceCap = pRsp->getGeneralDeviceCapabilities())) || 00892 (25882 != pDeviceCap->getDeviceManufacturerName())) 00893 { 00894 delete pRspMsg; 00895 return -1; 00896 } 00897 00898 m_modelNumber = pDeviceCap->getModelName(); 00899 00900 if(1 < m_Verbose) 00901 { 00902 printf("INFO: Reader Model Name %u\n", m_modelNumber); 00903 } 00904 00905 /* 00906 * Done with the response message. 00907 */ 00908 delete pRspMsg; 00909 00910 /* 00911 * Tattle progress, maybe 00912 */ 00913 if(m_Verbose) 00914 { 00915 printf("INFO: Found LLRP Capabilities \n"); 00916 } 00917 00918 /* 00919 * Victory. 00920 */ 00921 return 0; 00922 } 00923 00924 00939 int 00940 CMyApplication::getReaderConfig(void) 00941 { 00942 CGET_READER_CONFIG *pCmd; 00943 CMessage * pRspMsg; 00944 CGET_READER_CONFIG_RESPONSE *pRsp; 00945 std::list<CAntennaConfiguration*>::iterator pAntCfg; 00946 /* 00947 * Compose the command message 00948 */ 00949 pCmd = new CGET_READER_CONFIG(); 00950 pCmd->setMessageID(m_messageID++); 00951 pCmd->setRequestedData(GetReaderConfigRequestedData_All); 00952 00953 /* 00954 * Send the message, expect the response of certain type 00955 */ 00956 pRspMsg = transact(pCmd); 00957 00958 /* 00959 * Done with the command message 00960 */ 00961 delete pCmd; 00962 00963 /* 00964 * transact() returns NULL if something went wrong. 00965 */ 00966 if(NULL == pRspMsg) 00967 { 00968 /* transact already tattled */ 00969 return -1; 00970 } 00971 00972 /* 00973 * Cast to a CGET_READER_CONFIG_RESPONSE message. 00974 */ 00975 pRsp = (CGET_READER_CONFIG_RESPONSE *) pRspMsg; 00976 00977 /* 00978 * Check the LLRPStatus parameter. 00979 */ 00980 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), 00981 "getReaderConfig")) 00982 { 00983 /* checkLLRPStatus already tattled */ 00984 delete pRspMsg; 00985 return -1; 00986 } 00987 00988 /* just get the hop table and channel index out of 00989 ** the first antenna configuration since they must all 00990 ** be the same */ 00991 pAntCfg = pRsp->beginAntennaConfiguration(); 00992 if(pAntCfg != pRsp->endAntennaConfiguration()) 00993 { 00994 CRFTransmitter *prfTx; 00995 prfTx = (*pAntCfg)->getRFTransmitter(); 00996 m_hopTableID = prfTx->getHopTableID(); 00997 m_channelIndex = prfTx->getChannelIndex(); 00998 } 00999 else 01000 { 01001 delete pRspMsg; 01002 return -1; 01003 } 01004 01005 if(1 < m_Verbose) 01006 { 01007 printf("INFO: Reader hopTableID %u, ChannelIndex %u\n", 01008 m_hopTableID, m_channelIndex); 01009 } 01010 01011 /* 01012 * Done with the response message. 01013 */ 01014 delete pRspMsg; 01015 01016 /* 01017 * Tattle progress, maybe 01018 */ 01019 if(m_Verbose) 01020 { 01021 printf("INFO: Found LLRP Configuration \n"); 01022 } 01023 01024 /* 01025 * Victory. 01026 */ 01027 return 0; 01028 } 01029 01044 int 01045 CMyApplication::setImpinjReaderConfig(void) 01046 { 01047 CMessage * pCmdMsg; 01048 CSET_READER_CONFIG *pCmd; 01049 CMessage * pRspMsg; 01050 CSET_READER_CONFIG_RESPONSE *pRsp; 01051 CXMLTextDecoder * pDecoder; 01052 std::list<CAntennaConfiguration *>::iterator Cur; 01053 01054 01055 /* Build a decoder to extract the message from XML */ 01056 pDecoder = new CXMLTextDecoder(m_pTypeRegistry, "setReaderConfig.xml"); 01057 01058 if(NULL == pDecoder) 01059 { 01060 return -1; 01061 } 01062 01063 pCmdMsg = pDecoder->decodeMessage(); 01064 01065 delete pDecoder; 01066 01067 if(NULL == pCmdMsg) 01068 { 01069 return -2; 01070 } 01071 01072 if(&CSET_READER_CONFIG::s_typeDescriptor != pCmdMsg->m_pType) 01073 { 01074 return -3; 01075 } 01076 01077 /* get the message as a SET_READER_CONFIG */ 01078 pCmd = (CSET_READER_CONFIG *) pCmdMsg; 01079 01080 01081 /* It's always a good idea to give it a unique message ID */ 01082 pCmd->setMessageID(m_messageID++); 01083 01084 /* at this point,we would be ready to send the message, but we need 01085 * to make a change to the transmit power for each enabled antenna. 01086 * Loop through */ 01087 for( 01088 Cur = pCmd->beginAntennaConfiguration(); 01089 Cur != pCmd->endAntennaConfiguration(); 01090 Cur++) 01091 { 01092 CRFTransmitter *pRfTx = (*Cur)->getRFTransmitter(); 01093 01094 /* we already have this element in our sample XML file, but 01095 * we check here to create one if it doesn't exist to show 01096 * a more general usage */ 01097 if(NULL == pRfTx) 01098 { 01099 pRfTx = new CRFTransmitter(); 01100 (*Cur)->setRFTransmitter(pRfTx); 01101 } 01102 /* 01103 ** Set the max power that we retreived from the capabilities 01104 ** and the hopTableID and Channel index we got from the config 01105 */ 01106 pRfTx->setChannelIndex(m_channelIndex); 01107 pRfTx->setHopTableID(m_hopTableID); 01108 pRfTx->setTransmitPower(m_PowerLevelIndex); 01109 } 01110 01111 /* 01112 * Send the message, expect the response of certain type 01113 */ 01114 pRspMsg = transact(pCmd); 01115 01116 /* 01117 * Done with the command message 01118 */ 01119 delete pCmd; 01120 01121 /* 01122 * transact() returns NULL if something went wrong. 01123 */ 01124 if(NULL == pRspMsg) 01125 { 01126 /* transact already tattled */ 01127 return -1; 01128 } 01129 01130 /* 01131 * Cast to a CSET_READER_CONFIG_RESPONSE message. 01132 */ 01133 pRsp = (CSET_READER_CONFIG_RESPONSE *) pRspMsg; 01134 01135 /* 01136 * Check the LLRPStatus parameter. 01137 */ 01138 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), 01139 "setImpinjReaderConfig")) 01140 { 01141 /* checkLLRPStatus already tattled */ 01142 delete pRspMsg; 01143 return -1; 01144 } 01145 01146 /* 01147 * Done with the response message. 01148 */ 01149 delete pRspMsg; 01150 01151 /* 01152 * Tattle progress, maybe 01153 */ 01154 if(m_Verbose) 01155 { 01156 printf("INFO: Set Impinj Reader Configuration \n"); 01157 } 01158 01159 /* 01160 * Victory. 01161 */ 01162 return 0; 01163 } 01164 01213 int 01214 CMyApplication::addROSpec (void) 01215 { 01216 CROSpecStartTrigger * pROSpecStartTrigger = 01217 new CROSpecStartTrigger(); 01218 pROSpecStartTrigger->setROSpecStartTriggerType( 01219 ROSpecStartTriggerType_Null); 01220 01221 CROSpecStopTrigger * pROSpecStopTrigger = new CROSpecStopTrigger(); 01222 pROSpecStopTrigger->setROSpecStopTriggerType(ROSpecStopTriggerType_Null); 01223 pROSpecStopTrigger->setDurationTriggerValue(0); /* n/a */ 01224 01225 CROBoundarySpec * pROBoundarySpec = new CROBoundarySpec(); 01226 pROBoundarySpec->setROSpecStartTrigger(pROSpecStartTrigger); 01227 pROBoundarySpec->setROSpecStopTrigger(pROSpecStopTrigger); 01228 01229 CAISpecStopTrigger * pAISpecStopTrigger = new CAISpecStopTrigger(); 01230 pAISpecStopTrigger->setAISpecStopTriggerType( 01231 AISpecStopTriggerType_Null); 01232 pAISpecStopTrigger->setDurationTrigger(0); 01233 01234 CInventoryParameterSpec * pInventoryParameterSpec = 01235 new CInventoryParameterSpec(); 01236 pInventoryParameterSpec->setInventoryParameterSpecID(1234); 01237 pInventoryParameterSpec->setProtocolID(AirProtocols_EPCGlobalClass1Gen2); 01238 01239 /* 01240 ** configure to use two antennas 01241 */ 01242 llrp_u16v_t AntennaIDs = llrp_u16v_t(2); 01243 AntennaIDs.m_pValue[0] = 1; 01244 AntennaIDs.m_pValue[1] = 2; 01245 01246 CAISpec * pAISpec = new CAISpec(); 01247 pAISpec->setAntennaIDs(AntennaIDs); 01248 pAISpec->setAISpecStopTrigger(pAISpecStopTrigger); 01249 pAISpec->addInventoryParameterSpec(pInventoryParameterSpec); 01250 01251 CROSpec * pROSpec = new CROSpec(); 01252 pROSpec->setROSpecID(1111); 01253 pROSpec->setPriority(0); 01254 pROSpec->setCurrentState(ROSpecState_Disabled); 01255 pROSpec->setROBoundarySpec(pROBoundarySpec); 01256 pROSpec->addSpecParameter(pAISpec); 01257 01258 CADD_ROSPEC * pCmd; 01259 CMessage * pRspMsg; 01260 CADD_ROSPEC_RESPONSE * pRsp; 01261 01262 /* 01263 * Compose the command message. 01264 * N.B.: After the message is composed, all the parameters 01265 * constructed, immediately above, are considered "owned" 01266 * by the command message. When it is destructed so 01267 * too will the parameters be. 01268 */ 01269 pCmd = new CADD_ROSPEC(); 01270 pCmd->setMessageID(m_messageID++); 01271 pCmd->setROSpec(pROSpec); 01272 01273 /* 01274 * Send the message, expect the response of certain type 01275 */ 01276 pRspMsg = transact(pCmd); 01277 01278 /* 01279 * Done with the command message. 01280 * N.B.: And the parameters 01281 */ 01282 delete pCmd; 01283 01284 /* 01285 * transact() returns NULL if something went wrong. 01286 */ 01287 if(NULL == pRspMsg) 01288 { 01289 /* transact already tattled */ 01290 return -1; 01291 } 01292 01293 /* 01294 * Cast to a ADD_ROSPEC_RESPONSE message. 01295 */ 01296 pRsp = (CADD_ROSPEC_RESPONSE *) pRspMsg; 01297 01298 /* 01299 * Check the LLRPStatus parameter. 01300 */ 01301 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "addROSpec")) 01302 { 01303 /* checkLLRPStatus already tattled */ 01304 delete pRspMsg; 01305 return -1; 01306 } 01307 01308 /* 01309 * Done with the response message. 01310 */ 01311 delete pRspMsg; 01312 01313 /* 01314 * Tattle progress, maybe 01315 */ 01316 if(m_Verbose) 01317 { 01318 printf("INFO: ROSpec added\n"); 01319 } 01320 01321 /* 01322 * Victory. 01323 */ 01324 return 0; 01325 } 01326 01327 01345 int 01346 CMyApplication::enableROSpec (void) 01347 { 01348 CENABLE_ROSPEC * pCmd; 01349 CMessage * pRspMsg; 01350 CENABLE_ROSPEC_RESPONSE * pRsp; 01351 01352 /* 01353 * Compose the command message 01354 */ 01355 pCmd = new CENABLE_ROSPEC(); 01356 pCmd->setMessageID(m_messageID++); 01357 pCmd->setROSpecID(1111); 01358 01359 /* 01360 * Send the message, expect the response of certain type 01361 */ 01362 pRspMsg = transact(pCmd); 01363 01364 /* 01365 * Done with the command message 01366 */ 01367 delete pCmd; 01368 01369 /* 01370 * transact() returns NULL if something went wrong. 01371 */ 01372 if(NULL == pRspMsg) 01373 { 01374 /* transact already tattled */ 01375 return -1; 01376 } 01377 01378 /* 01379 * Cast to a ENABLE_ROSPEC_RESPONSE message. 01380 */ 01381 pRsp = (CENABLE_ROSPEC_RESPONSE *) pRspMsg; 01382 01383 /* 01384 * Check the LLRPStatus parameter. 01385 */ 01386 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "enableROSpec")) 01387 { 01388 /* checkLLRPStatus already tattled */ 01389 delete pRspMsg; 01390 return -1; 01391 } 01392 01393 /* 01394 * Done with the response message. 01395 */ 01396 delete pRspMsg; 01397 01398 /* 01399 * Tattle progress, maybe 01400 */ 01401 if(m_Verbose) 01402 { 01403 printf("INFO: ROSpec enabled\n"); 01404 } 01405 01406 /* 01407 * Victory. 01408 */ 01409 return 0; 01410 } 01411 01412 01430 int 01431 CMyApplication::startROSpec (void) 01432 { 01433 CSTART_ROSPEC * pCmd; 01434 CMessage * pRspMsg; 01435 CSTART_ROSPEC_RESPONSE * pRsp; 01436 01437 /* 01438 * Compose the command message 01439 */ 01440 pCmd = new CSTART_ROSPEC(); 01441 pCmd->setMessageID(m_messageID++); 01442 pCmd->setROSpecID(1111); 01443 01444 /* 01445 * Send the message, expect the response of certain type 01446 */ 01447 pRspMsg = transact(pCmd); 01448 01449 /* 01450 * Done with the command message 01451 */ 01452 delete pCmd; 01453 01454 /* 01455 * transact() returns NULL if something went wrong. 01456 */ 01457 if(NULL == pRspMsg) 01458 { 01459 /* transact already tattled */ 01460 return -1; 01461 } 01462 01463 /* 01464 * Cast to a START_ROSPEC_RESPONSE message. 01465 */ 01466 pRsp = (CSTART_ROSPEC_RESPONSE *) pRspMsg; 01467 01468 /* 01469 * Check the LLRPStatus parameter. 01470 */ 01471 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "startROSpec")) 01472 { 01473 /* checkLLRPStatus already tattled */ 01474 delete pRspMsg; 01475 return -1; 01476 } 01477 01478 /* 01479 * Done with the response message. 01480 */ 01481 delete pRspMsg; 01482 01483 /* 01484 * Tattle progress 01485 */ 01486 if(m_Verbose) 01487 { 01488 printf("INFO: ROSpec started\n"); 01489 } 01490 01491 /* 01492 * Victory. 01493 */ 01494 return 0; 01495 } 01496 01514 int 01515 CMyApplication::stopROSpec (void) 01516 { 01517 CSTOP_ROSPEC * pCmd; 01518 CMessage * pRspMsg; 01519 CSTOP_ROSPEC_RESPONSE * pRsp; 01520 01521 /* 01522 * Compose the command message 01523 */ 01524 pCmd = new CSTOP_ROSPEC(); 01525 pCmd->setMessageID(m_messageID++); 01526 pCmd->setROSpecID(1111); 01527 01528 /* 01529 * Send the message, expect the response of certain type 01530 */ 01531 pRspMsg = transact(pCmd); 01532 01533 /* 01534 * Done with the command message 01535 */ 01536 delete pCmd; 01537 01538 /* 01539 * transact() returns NULL if something went wrong. 01540 */ 01541 if(NULL == pRspMsg) 01542 { 01543 /* transact already tattled */ 01544 return -1; 01545 } 01546 01547 /* 01548 * Cast to a STOP_ROSPEC_RESPONSE message. 01549 */ 01550 pRsp = (CSTOP_ROSPEC_RESPONSE *) pRspMsg; 01551 01552 /* 01553 * Check the LLRPStatus parameter. 01554 */ 01555 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "stopROSpec")) 01556 { 01557 /* checkLLRPStatus already tattled */ 01558 delete pRspMsg; 01559 return -1; 01560 } 01561 01562 /* 01563 * Done with the response message. 01564 */ 01565 delete pRspMsg; 01566 01567 /* 01568 * Tattle progress 01569 */ 01570 if(m_Verbose) 01571 { 01572 printf("INFO: ROSpec stopped\n"); 01573 } 01574 01575 /* 01576 * Victory. 01577 */ 01578 return 0; 01579 } 01580 01581 01601 int 01602 CMyApplication::awaitAndPrintReport (int timeout) 01603 { 01604 int bDone = 0; 01605 int retVal = 0; 01606 time_t startTime = time(NULL); 01607 time_t tempTime; 01608 /* 01609 * Keep receiving messages until done or until 01610 * something bad happens. 01611 */ 01612 while(!bDone) 01613 { 01614 CMessage * pMessage; 01615 const CTypeDescriptor * pType; 01616 01617 /* 01618 * Wait up to 1 second for a report. Check 01619 * That way, we can check the timestamp even if 01620 * there are no reports coming in 01621 */ 01622 pMessage = recvMessage(1000); 01623 01624 /* validate the timestamp */ 01625 tempTime = time(NULL); 01626 if(difftime(tempTime, startTime) > timeout) 01627 { 01628 bDone=1; 01629 } 01630 01631 if(NULL == pMessage) 01632 { 01633 continue; 01634 } 01635 01636 /* 01637 * What happens depends on what kind of message 01638 * received. Use the type label (m_pType) to 01639 * discriminate message types. 01640 */ 01641 pType = pMessage->m_pType; 01642 01643 /* 01644 * Is it a tag report? If so, print it out. 01645 */ 01646 if(&CRO_ACCESS_REPORT::s_typeDescriptor == pType) 01647 { 01648 CRO_ACCESS_REPORT * pNtf; 01649 01650 pNtf = (CRO_ACCESS_REPORT *) pMessage; 01651 01652 printTagReportData(pNtf); 01653 } 01654 01655 /* 01656 * Is it a reader event? This example only recognizes 01657 * AntennaEvents. 01658 */ 01659 else if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor == pType) 01660 { 01661 CREADER_EVENT_NOTIFICATION *pNtf; 01662 CReaderEventNotificationData *pNtfData; 01663 01664 pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage; 01665 01666 pNtfData = pNtf->getReaderEventNotificationData(); 01667 if(NULL != pNtfData) 01668 { 01669 handleReaderEventNotification(pNtfData); 01670 } 01671 else 01672 { 01673 /* 01674 * This should never happen. Using continue 01675 * to keep indent depth down. 01676 */ 01677 printf("WARNING: READER_EVENT_NOTIFICATION without data\n"); 01678 } 01679 } 01680 01681 /* 01682 * Hmmm. Something unexpected. Just tattle and keep going. 01683 */ 01684 else 01685 { 01686 printf("WARNING: Ignored unexpected message during monitor: %s\n", 01687 pType->m_pName); 01688 } 01689 01690 /* 01691 * Done with the received message 01692 */ 01693 delete pMessage; 01694 } 01695 01696 return retVal; 01697 } 01698 01699 01714 void 01715 CMyApplication::printTagReportData ( 01716 CRO_ACCESS_REPORT * pRO_ACCESS_REPORT) 01717 { 01718 std::list<CTagReportData *>::iterator Cur; 01719 std::list<CParameter *>::iterator CustCur; 01720 01721 unsigned int nEntry = 0; 01722 01723 /* 01724 * Loop through and count the number of entries 01725 */ 01726 for( 01727 Cur = pRO_ACCESS_REPORT->beginTagReportData(); 01728 Cur != pRO_ACCESS_REPORT->endTagReportData(); 01729 Cur++) 01730 { 01731 nEntry++; 01732 } 01733 01734 if(m_Verbose) 01735 { 01736 printf("INFO: %u tag report entries\n", nEntry); 01737 } 01738 01739 /* 01740 * Loop through again and print each entry. 01741 */ 01742 for( 01743 Cur = pRO_ACCESS_REPORT->beginTagReportData(); 01744 Cur != pRO_ACCESS_REPORT->endTagReportData(); 01745 Cur++) 01746 { 01747 printOneTagReportData(*Cur); 01748 } 01749 } 01750 01759 void 01760 CMyApplication::formatOneEPC ( 01761 CParameter *pEPCParameter, 01762 char *buf, 01763 int buflen) 01764 { 01765 char * p = buf; 01766 int bufsize = buflen; 01767 int written = 0; 01768 01769 if(NULL != pEPCParameter) 01770 { 01771 const CTypeDescriptor * pType; 01772 llrp_u96_t my_u96; 01773 llrp_u1v_t my_u1v; 01774 llrp_u8_t * pValue = NULL; 01775 unsigned int n, i; 01776 01777 pType = pEPCParameter->m_pType; 01778 if(&CEPC_96::s_typeDescriptor == pType) 01779 { 01780 CEPC_96 *pEPC_96; 01781 01782 pEPC_96 = (CEPC_96 *) pEPCParameter; 01783 my_u96 = pEPC_96->getEPC(); 01784 pValue = my_u96.m_aValue; 01785 n = 12u; 01786 } 01787 else if(&CEPCData::s_typeDescriptor == pType) 01788 { 01789 CEPCData * pEPCData; 01790 01791 pEPCData = (CEPCData *) pEPCParameter; 01792 my_u1v = pEPCData->getEPC(); 01793 pValue = my_u1v.m_pValue; 01794 n = (my_u1v.m_nBit + 7u) / 8u; 01795 } 01796 01797 if(NULL != pValue) 01798 { 01799 for(i = 0; i < n; i++) 01800 { 01801 if(0 < i && i%2 == 0 && 1 < bufsize) 01802 { 01803 *p++ = '-'; 01804 bufsize--; 01805 } 01806 if(bufsize > 2) 01807 { 01808 written = snprintf(p, bufsize, "%02X", pValue[i]); 01809 bufsize -= written; 01810 p+= written; 01811 } 01812 } 01813 } 01814 else 01815 { 01816 written = snprintf(p, bufsize, "%s", "---unknown-epc-data-type---"); 01817 bufsize -= written; 01818 p += written; 01819 } 01820 } 01821 else 01822 { 01823 written = snprintf(p, bufsize, "%s", "--null epc---"); 01824 bufsize -= written; 01825 p += written; 01826 } 01827 01828 // null terminate this for good practice 01829 buf[buflen-1] = '\0'; 01830 01831 } 01832 01841 void 01842 CMyApplication::printOneTagReportData ( 01843 CTagReportData * pTagReportData) 01844 { 01845 char aBuf[64]; 01846 01847 /* 01848 * Print the EPC. It could be an 96-bit EPC_96 parameter 01849 * or an variable length EPCData parameter. 01850 */ 01851 01852 CParameter * pEPCParameter = 01853 pTagReportData->getEPCParameter(); 01854 01855 formatOneEPC(pEPCParameter, aBuf, 64); 01856 01857 /* 01858 * End of line 01859 */ 01860 printf("EPC: %s\n", aBuf); 01861 } 01862 01863 01877 void 01878 CMyApplication::handleReaderEventNotification ( 01879 CReaderEventNotificationData *pNtfData) 01880 { 01881 CAntennaEvent * pAntennaEvent; 01882 CReaderExceptionEvent * pReaderExceptionEvent; 01883 int nReported = 0; 01884 01885 pAntennaEvent = pNtfData->getAntennaEvent(); 01886 if(NULL != pAntennaEvent) 01887 { 01888 handleAntennaEvent(pAntennaEvent); 01889 nReported++; 01890 } 01891 01892 pReaderExceptionEvent = pNtfData->getReaderExceptionEvent(); 01893 if(NULL != pReaderExceptionEvent) 01894 { 01895 handleReaderExceptionEvent(pReaderExceptionEvent); 01896 nReported++; 01897 } 01898 01899 /* 01900 * Similarly handle other events here: 01901 * HoppingEvent 01902 * GPIEvent 01903 * ROSpecEvent 01904 * ReportBufferLevelWarningEvent 01905 * ReportBufferOverflowErrorEvent 01906 * RFSurveyEvent 01907 * AISpecEvent 01908 * ConnectionAttemptEvent 01909 * ConnectionCloseEvent 01910 * Custom 01911 */ 01912 01913 if(0 == nReported) 01914 { 01915 printf("NOTICE: Unexpected (unhandled) ReaderEvent\n"); 01916 } 01917 } 01918 01919 01931 void 01932 CMyApplication::handleAntennaEvent ( 01933 CAntennaEvent * pAntennaEvent) 01934 { 01935 EAntennaEventType eEventType; 01936 llrp_u16_t AntennaID; 01937 char * pStateStr; 01938 01939 eEventType = pAntennaEvent->getEventType(); 01940 AntennaID = pAntennaEvent->getAntennaID(); 01941 01942 switch(eEventType) 01943 { 01944 case AntennaEventType_Antenna_Disconnected: 01945 pStateStr = "disconnected"; 01946 break; 01947 01948 case AntennaEventType_Antenna_Connected: 01949 pStateStr = "connected"; 01950 break; 01951 01952 default: 01953 pStateStr = "?unknown-event?"; 01954 break; 01955 } 01956 01957 printf("NOTICE: Antenna %d is %s\n", AntennaID, pStateStr); 01958 } 01959 01960 01973 void 01974 CMyApplication::handleReaderExceptionEvent ( 01975 CReaderExceptionEvent * pReaderExceptionEvent) 01976 { 01977 llrp_utf8v_t Message; 01978 01979 Message = pReaderExceptionEvent->getMessage(); 01980 01981 if(0 < Message.m_nValue && NULL != Message.m_pValue) 01982 { 01983 printf("NOTICE: ReaderException '%.*s'\n", 01984 Message.m_nValue, Message.m_pValue); 01985 } 01986 else 01987 { 01988 printf("NOTICE: ReaderException but no message\n"); 01989 } 01990 } 01991 01992 02011 int 02012 CMyApplication::checkLLRPStatus ( 02013 CLLRPStatus * pLLRPStatus, 02014 char * pWhatStr) 02015 { 02016 /* 02017 * The LLRPStatus parameter is mandatory in all responses. 02018 * If it is missing there should have been a decode error. 02019 * This just makes sure (remember, this program is a 02020 * diagnostic and suppose to catch LTKC mistakes). 02021 */ 02022 if(NULL == pLLRPStatus) 02023 { 02024 printf("ERROR: %s missing LLRP status\n", pWhatStr); 02025 return -1; 02026 } 02027 02028 /* 02029 * Make sure the status is M_Success. 02030 * If it isn't, print the error string if one. 02031 * This does not try to pretty-print the status 02032 * code. To get that, run this program with -vv 02033 * and examine the XML output. 02034 */ 02035 if(StatusCode_M_Success != pLLRPStatus->getStatusCode()) 02036 { 02037 llrp_utf8v_t ErrorDesc; 02038 02039 ErrorDesc = pLLRPStatus->getErrorDescription(); 02040 02041 if(0 == ErrorDesc.m_nValue) 02042 { 02043 printf("ERROR: %s failed, no error description given\n", 02044 pWhatStr); 02045 } 02046 else 02047 { 02048 printf("ERROR: %s failed, %.*s\n", 02049 pWhatStr, ErrorDesc.m_nValue, ErrorDesc.m_pValue); 02050 } 02051 return -2; 02052 } 02053 02054 /* 02055 * Victory. Everything is fine. 02056 */ 02057 return 0; 02058 } 02059 02060 02084 CMessage * 02085 CMyApplication::transact ( 02086 CMessage * pSendMsg) 02087 { 02088 CConnection * pConn = m_pConnectionToReader; 02089 CMessage * pRspMsg; 02090 02091 /* 02092 * Print the XML text for the outbound message if 02093 * verbosity is 2 or higher. 02094 */ 02095 if(1 < m_Verbose) 02096 { 02097 printf("\n===================================\n"); 02098 printf("INFO: Transact sending\n"); 02099 printXMLMessage(pSendMsg); 02100 } 02101 02102 /* 02103 * Send the message, expect the response of certain type. 02104 * If LLRP::CConnection::transact() returns NULL then there was 02105 * an error. In that case we try to print the error details. 02106 */ 02107 pRspMsg = pConn->transact(pSendMsg, 5000); 02108 02109 if(NULL == pRspMsg) 02110 { 02111 const CErrorDetails * pError = pConn->getTransactError(); 02112 02113 printf("ERROR: %s transact failed, %s\n", 02114 pSendMsg->m_pType->m_pName, 02115 pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given"); 02116 02117 if(NULL != pError->m_pRefType) 02118 { 02119 printf("ERROR: ... reference type %s\n", 02120 pError->m_pRefType->m_pName); 02121 } 02122 02123 if(NULL != pError->m_pRefField) 02124 { 02125 printf("ERROR: ... reference field %s\n", 02126 pError->m_pRefField->m_pName); 02127 } 02128 02129 return NULL; 02130 } 02131 02132 /* 02133 * Print the XML text for the inbound message if 02134 * verbosity is 2 or higher. 02135 */ 02136 if(1 < m_Verbose) 02137 { 02138 printf("\n- - - - - - - - - - - - - - - - - -\n"); 02139 printf("INFO: Transact received response\n"); 02140 printXMLMessage(pRspMsg); 02141 } 02142 02143 /* 02144 * If it is an ERROR_MESSAGE (response from reader 02145 * when it can't understand the request), tattle 02146 * and declare defeat. 02147 */ 02148 if(&CERROR_MESSAGE::s_typeDescriptor == pRspMsg->m_pType) 02149 { 02150 const CTypeDescriptor * pResponseType; 02151 02152 pResponseType = pSendMsg->m_pType->m_pResponseType; 02153 02154 printf("ERROR: Received ERROR_MESSAGE instead of %s\n", 02155 pResponseType->m_pName); 02156 delete pRspMsg; 02157 pRspMsg = NULL; 02158 } 02159 02160 return pRspMsg; 02161 } 02162 02163 02188 CMessage * 02189 CMyApplication::recvMessage ( 02190 int nMaxMS) 02191 { 02192 CConnection * pConn = m_pConnectionToReader; 02193 CMessage * pMessage; 02194 02195 /* 02196 * Receive the message subject to a time limit 02197 */ 02198 pMessage = pConn->recvMessage(nMaxMS); 02199 02200 /* 02201 * If LLRP::CConnection::recvMessage() returns NULL then there was 02202 * an error. In that case we try to print the error details. 02203 */ 02204 if(NULL == pMessage) 02205 { 02206 const CErrorDetails * pError = pConn->getRecvError(); 02207 02208 /* don't warn on timeout since this is a polling example */ 02209 if(pError->m_eResultCode != RC_RecvTimeout) 02210 { 02211 printf("ERROR: recvMessage failed, %s\n", 02212 pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given"); 02213 } 02214 02215 if(NULL != pError->m_pRefType) 02216 { 02217 printf("ERROR: ... reference type %s\n", 02218 pError->m_pRefType->m_pName); 02219 } 02220 02221 if(NULL != pError->m_pRefField) 02222 { 02223 printf("ERROR: ... reference field %s\n", 02224 pError->m_pRefField->m_pName); 02225 } 02226 02227 return NULL; 02228 } 02229 02230 /* 02231 * Print the XML text for the inbound message if 02232 * verbosity is 2 or higher. 02233 */ 02234 if(1 < m_Verbose) 02235 { 02236 printf("\n===================================\n"); 02237 printf("INFO: Message received\n"); 02238 printXMLMessage(pMessage); 02239 } 02240 02241 return pMessage; 02242 } 02243 02244 02262 int 02263 CMyApplication::sendMessage ( 02264 CMessage * pSendMsg) 02265 { 02266 CConnection * pConn = m_pConnectionToReader; 02267 02268 /* 02269 * Print the XML text for the outbound message if 02270 * verbosity is 2 or higher. 02271 */ 02272 if(1 < m_Verbose) 02273 { 02274 printf("\n===================================\n"); 02275 printf("INFO: Sending\n"); 02276 printXMLMessage(pSendMsg); 02277 } 02278 02279 /* 02280 * If LLRP::CConnection::sendMessage() returns other than RC_OK 02281 * then there was an error. In that case we try to print 02282 * the error details. 02283 */ 02284 if(RC_OK != pConn->sendMessage(pSendMsg)) 02285 { 02286 const CErrorDetails * pError = pConn->getSendError(); 02287 02288 printf("ERROR: %s sendMessage failed, %s\n", 02289 pSendMsg->m_pType->m_pName, 02290 pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given"); 02291 02292 if(NULL != pError->m_pRefType) 02293 { 02294 printf("ERROR: ... reference type %s\n", 02295 pError->m_pRefType->m_pName); 02296 } 02297 02298 if(NULL != pError->m_pRefField) 02299 { 02300 printf("ERROR: ... reference field %s\n", 02301 pError->m_pRefField->m_pName); 02302 } 02303 02304 return -1; 02305 } 02306 02307 /* 02308 * Victory 02309 */ 02310 return 0; 02311 } 02312 02313 02327 void 02328 CMyApplication::printXMLMessage ( 02329 CMessage * pMessage) 02330 { 02331 char aBuf[100*1024]; 02332 02333 /* 02334 * Convert the message to an XML string. 02335 * This fills the buffer with either the XML string 02336 * or an error message. The return value could 02337 * be checked. 02338 */ 02339 02340 pMessage->toXMLString(aBuf, sizeof aBuf); 02341 02342 /* 02343 * Print the XML Text to the standard output. 02344 */ 02345 printf("%s", aBuf); 02346 }