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 00044 #include <stdio.h> 00045 #include "ltkcpp.h" 00046 #include "impinj_ltkcpp.h" 00047 #include "time.h" 00048 00049 using namespace LLRP; 00050 00051 /* 00052 ** Sorry, we use this linux safe method 00053 ** to print buffers. WIndows has the same 00054 ** method, but by a different name 00055 */ 00056 #if (WIN32) 00057 #define snprintf _snprintf 00058 #endif 00059 00060 class CMyApplication 00061 { 00062 unsigned int m_messageID; 00063 00064 public: 00066 int m_Verbose; 00067 00069 CConnection * m_pConnectionToReader; 00070 00071 inline 00072 CMyApplication (void) 00073 : m_Verbose(0), m_pConnectionToReader(NULL) 00074 { 00075 m_messageID = 0; 00076 } 00077 00078 int 00079 run ( 00080 char * pReaderHostName); 00081 00082 int 00083 checkConnectionStatus (void); 00084 00085 int 00086 enableImpinjExtensions (void); 00087 00088 int 00089 resetConfigurationToFactoryDefaults (void); 00090 00091 int 00092 addROSpec (void); 00093 00094 int 00095 enableROSpec (void); 00096 00097 int 00098 startROSpec (void); 00099 00100 int 00101 stopROSpec (void); 00102 00103 int 00104 awaitAndPrintReport (int timeoutSec); 00105 00106 void 00107 printTagReportData ( 00108 CRO_ACCESS_REPORT * pRO_ACCESS_REPORT); 00109 00110 void 00111 printOneTagReportData ( 00112 CTagReportData * pTagReportData); 00113 00114 void 00115 formatOneEPC ( 00116 CParameter * pEpcParameter, 00117 char * buf, 00118 int buflen); 00119 00120 void 00121 handleReaderEventNotification ( 00122 CReaderEventNotificationData *pNtfData); 00123 00124 void 00125 handleAntennaEvent ( 00126 CAntennaEvent * pAntennaEvent); 00127 00128 void 00129 handleReaderExceptionEvent ( 00130 CReaderExceptionEvent * pReaderExceptionEvent); 00131 00132 int 00133 checkLLRPStatus ( 00134 CLLRPStatus * pLLRPStatus, 00135 char * pWhatStr); 00136 00137 CMessage * 00138 transact ( 00139 CMessage * pSendMsg); 00140 00141 CMessage * 00142 recvMessage ( 00143 int nMaxMS); 00144 00145 int 00146 sendMessage ( 00147 CMessage * pSendMsg); 00148 00149 void 00150 printXMLMessage ( 00151 CMessage * pMessage); 00152 }; 00153 00154 00155 /* BEGIN forward declarations */ 00156 int 00157 main ( 00158 int ac, 00159 char * av[]); 00160 00161 void 00162 usage ( 00163 char * pProgName); 00164 /* END forward declarations */ 00165 00166 00182 int 00183 main ( 00184 int ac, 00185 char * av[]) 00186 { 00187 CMyApplication myApp; 00188 char * pReaderHostName; 00189 int rc; 00190 00191 /* 00192 * Process comand arguments, determine reader name 00193 * and verbosity level. 00194 */ 00195 if(ac == 2) 00196 { 00197 pReaderHostName = av[1]; 00198 } 00199 else if(ac == 3) 00200 { 00201 char * p = av[1]; 00202 00203 while(*p) 00204 { 00205 switch(*p++) 00206 { 00207 case '-': /* linux conventional option warn char */ 00208 case '/': /* Windows/DOS conventional option warn char */ 00209 break; 00210 00211 case 'v': 00212 case 'V': 00213 myApp.m_Verbose++; 00214 break; 00215 00216 default: 00217 usage(av[0]); 00218 /* no return */ 00219 break; 00220 } 00221 } 00222 00223 pReaderHostName = av[2]; 00224 } 00225 else 00226 { 00227 usage(av[0]); 00228 /* no return */ 00229 } 00230 00231 /* 00232 * Run application, capture return value for exit status 00233 */ 00234 rc = myApp.run(pReaderHostName); 00235 00236 printf("INFO: Done\n"); 00237 00238 /* 00239 * Exit with the right status. 00240 */ 00241 if(0 == rc) 00242 { 00243 exit(0); 00244 } 00245 else 00246 { 00247 exit(2); 00248 } 00249 /*NOTREACHED*/ 00250 } 00251 00252 00264 void 00265 usage ( 00266 char * pProgName) 00267 { 00268 #ifdef linux 00269 printf("Usage: %s [-v[v]] READERHOSTNAME\n", pProgName); 00270 printf("\n"); 00271 printf("Each -v increases verbosity level\n"); 00272 #endif /* linux */ 00273 #ifdef WIN32 00274 printf("Usage: %s [/v[v]] READERHOSTNAME\n", pProgName); 00275 printf("\n"); 00276 printf("Each /v increases verbosity level\n"); 00277 #endif /* WIN32 */ 00278 exit(1); 00279 } 00280 00281 00315 int 00316 CMyApplication::run ( 00317 char * pReaderHostName) 00318 { 00319 CTypeRegistry * pTypeRegistry; 00320 CConnection * pConn; 00321 int rc; 00322 00323 /* 00324 * Allocate the type registry. This is needed 00325 * by the connection to decode. 00326 */ 00327 pTypeRegistry = getTheTypeRegistry(); 00328 if(NULL == pTypeRegistry) 00329 { 00330 printf("ERROR: getTheTypeRegistry failed\n"); 00331 return -1; 00332 } 00333 00334 /* 00335 * Enroll impinj extension types into the 00336 * type registry, in preparation for using 00337 * Impinj extension params. 00338 */ 00339 LLRP::enrollImpinjTypesIntoRegistry(pTypeRegistry); 00340 00341 /* 00342 * Construct a connection (LLRP::CConnection). 00343 * Using a 32kb max frame size for send/recv. 00344 * The connection object is ready for business 00345 * but not actually connected to the reader yet. 00346 */ 00347 pConn = new CConnection(pTypeRegistry, 32u*1024u); 00348 if(NULL == pConn) 00349 { 00350 printf("ERROR: new CConnection failed\n"); 00351 return -2; 00352 } 00353 00354 /* 00355 * Open the connection to the reader 00356 */ 00357 if(m_Verbose) 00358 { 00359 printf("INFO: Connecting to %s....\n", pReaderHostName); 00360 } 00361 00362 rc = pConn->openConnectionToReader(pReaderHostName); 00363 if(0 != rc) 00364 { 00365 printf("ERROR: connect: %s (%d)\n", pConn->getConnectError(), rc); 00366 delete pConn; 00367 return -3; 00368 } 00369 00370 /* 00371 * Record the pointer to the connection object so other 00372 * routines can use it. 00373 */ 00374 m_pConnectionToReader = pConn; 00375 00376 if(m_Verbose) 00377 { 00378 printf("INFO: Connected, checking status....\n"); 00379 } 00380 00381 /* 00382 * Commence the sequence and check for errors as we go. 00383 * See comments for each routine for details. 00384 * Each routine prints messages. 00385 */ 00386 rc = 1; 00387 if(0 == checkConnectionStatus()) 00388 { 00389 rc = 2; 00390 if(0 == enableImpinjExtensions()) 00391 { 00392 rc = 3; 00393 if(0 == resetConfigurationToFactoryDefaults()) 00394 { 00395 rc = 4; 00396 if(0 == addROSpec()) 00397 { 00398 rc = 5; 00399 if(0 == enableROSpec()) 00400 { 00401 rc = 6; 00402 if(0 == startROSpec()) 00403 { 00404 rc = 7; 00405 if(0 == awaitAndPrintReport(10)) 00406 { 00407 rc = 8; 00408 if(0 == stopROSpec()) 00409 { 00410 rc = 0; 00411 } 00412 } 00413 } 00414 } 00415 } 00416 } 00417 00418 /* 00419 * After we're done, try to leave the reader 00420 * in a clean state for next use. This is best 00421 * effort and no checking of the result is done. 00422 */ 00423 if(m_Verbose) 00424 { 00425 printf("INFO: Clean up reader configuration...\n"); 00426 } 00427 resetConfigurationToFactoryDefaults(); 00428 } 00429 } 00430 00431 if(m_Verbose) 00432 { 00433 printf("INFO: Finished\n"); 00434 } 00435 00436 /* 00437 * Close the connection and release its resources 00438 */ 00439 pConn->closeConnectionToReader(); 00440 delete pConn; 00441 00442 /* 00443 * Done with the registry. 00444 */ 00445 delete pTypeRegistry; 00446 00447 /* 00448 * When we get here all allocated memory should have been deallocated. 00449 */ 00450 00451 return rc; 00452 } 00453 00454 00485 int 00486 CMyApplication::checkConnectionStatus (void) 00487 { 00488 CMessage * pMessage; 00489 CREADER_EVENT_NOTIFICATION *pNtf; 00490 CReaderEventNotificationData *pNtfData; 00491 CConnectionAttemptEvent * pEvent; 00492 00493 /* 00494 * Expect the notification within 10 seconds. 00495 * It is suppose to be the very first message sent. 00496 */ 00497 pMessage = recvMessage(10000); 00498 00499 /* 00500 * recvMessage() returns NULL if something went wrong. 00501 */ 00502 if(NULL == pMessage) 00503 { 00504 /* recvMessage already tattled */ 00505 goto fail; 00506 } 00507 00508 /* 00509 * Check to make sure the message is of the right type. 00510 * The type label (pointer) in the message should be 00511 * the type descriptor for READER_EVENT_NOTIFICATION. 00512 */ 00513 if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor != pMessage->m_pType) 00514 { 00515 goto fail; 00516 } 00517 00518 /* 00519 * Now that we are sure it is a READER_EVENT_NOTIFICATION, 00520 * traverse to the ReaderEventNotificationData parameter. 00521 */ 00522 pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage; 00523 pNtfData = pNtf->getReaderEventNotificationData(); 00524 if(NULL == pNtfData) 00525 { 00526 goto fail; 00527 } 00528 00529 /* 00530 * The ConnectionAttemptEvent parameter must be present. 00531 */ 00532 pEvent = pNtfData->getConnectionAttemptEvent(); 00533 if(NULL == pEvent) 00534 { 00535 goto fail; 00536 } 00537 00538 /* 00539 * The status in the ConnectionAttemptEvent parameter 00540 * must indicate connection success. 00541 */ 00542 if(ConnectionAttemptStatusType_Success != pEvent->getStatus()) 00543 { 00544 goto fail; 00545 } 00546 00547 /* 00548 * Done with the message 00549 */ 00550 delete pMessage; 00551 00552 if(m_Verbose) 00553 { 00554 printf("INFO: Connection status OK\n"); 00555 } 00556 00557 /* 00558 * Victory. 00559 */ 00560 return 0; 00561 00562 fail: 00563 /* 00564 * Something went wrong. Tattle. Clean up. Return error. 00565 */ 00566 printf("ERROR: checkConnectionStatus failed\n"); 00567 delete pMessage; 00568 return -1; 00569 } 00570 00588 int 00589 CMyApplication::enableImpinjExtensions (void) 00590 { 00591 CIMPINJ_ENABLE_EXTENSIONS * pCmd; 00592 CMessage * pRspMsg; 00593 CIMPINJ_ENABLE_EXTENSIONS_RESPONSE *pRsp; 00594 00595 /* 00596 * Compose the command message 00597 */ 00598 pCmd = new CIMPINJ_ENABLE_EXTENSIONS(); 00599 pCmd->setMessageID(m_messageID++); 00600 /* 00601 * Send the message, expect the response of certain type 00602 */ 00603 pRspMsg = transact(pCmd); 00604 00605 /* 00606 * Done with the command message 00607 */ 00608 delete pCmd; 00609 00610 /* 00611 * transact() returns NULL if something went wrong. 00612 */ 00613 if(NULL == pRspMsg) 00614 { 00615 /* transact already tattled */ 00616 return -1; 00617 } 00618 00619 /* 00620 * Cast to a CIMPINJ_ENABLE_EXTENSIONS_RESPONSE message. 00621 */ 00622 pRsp = (CIMPINJ_ENABLE_EXTENSIONS_RESPONSE *) pRspMsg; 00623 00624 /* 00625 * Check the LLRPStatus parameter. 00626 */ 00627 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), 00628 "enableImpinjExtensions")) 00629 { 00630 /* checkLLRPStatus already tattled */ 00631 delete pRspMsg; 00632 return -1; 00633 } 00634 00635 /* 00636 * Done with the response message. 00637 */ 00638 delete pRspMsg; 00639 00640 /* 00641 * Tattle progress, maybe 00642 */ 00643 if(m_Verbose) 00644 { 00645 printf("INFO: Impinj Extensions are enabled\n"); 00646 } 00647 00648 /* 00649 * Victory. 00650 */ 00651 return 0; 00652 } 00653 00674 int 00675 CMyApplication::resetConfigurationToFactoryDefaults (void) 00676 { 00677 CSET_READER_CONFIG * pCmd; 00678 CMessage * pRspMsg; 00679 CSET_READER_CONFIG_RESPONSE *pRsp; 00680 00681 /* 00682 * Compose the command message 00683 */ 00684 pCmd = new CSET_READER_CONFIG(); 00685 pCmd->setMessageID(m_messageID++); 00686 pCmd->setResetToFactoryDefault(1); 00687 00688 /* 00689 * Send the message, expect the response of certain type 00690 */ 00691 pRspMsg = transact(pCmd); 00692 00693 /* 00694 * Done with the command message 00695 */ 00696 delete pCmd; 00697 00698 /* 00699 * transact() returns NULL if something went wrong. 00700 */ 00701 if(NULL == pRspMsg) 00702 { 00703 /* transact already tattled */ 00704 return -1; 00705 } 00706 00707 /* 00708 * Cast to a SET_READER_CONFIG_RESPONSE message. 00709 */ 00710 pRsp = (CSET_READER_CONFIG_RESPONSE *) pRspMsg; 00711 00712 /* 00713 * Check the LLRPStatus parameter. 00714 */ 00715 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), 00716 "resetConfigurationToFactoryDefaults")) 00717 { 00718 /* checkLLRPStatus already tattled */ 00719 delete pRspMsg; 00720 return -1; 00721 } 00722 00723 /* 00724 * Done with the response message. 00725 */ 00726 delete pRspMsg; 00727 00728 /* 00729 * Tattle progress, maybe 00730 */ 00731 if(m_Verbose) 00732 { 00733 printf("INFO: Configuration reset to factory defaults\n"); 00734 } 00735 00736 /* 00737 * Victory. 00738 */ 00739 return 0; 00740 } 00741 00742 00790 int 00791 CMyApplication::addROSpec (void) 00792 { 00793 CROSpecStartTrigger * pROSpecStartTrigger = 00794 new CROSpecStartTrigger(); 00795 pROSpecStartTrigger->setROSpecStartTriggerType( 00796 ROSpecStartTriggerType_Null); 00797 00798 CROSpecStopTrigger * pROSpecStopTrigger = new CROSpecStopTrigger(); 00799 pROSpecStopTrigger->setROSpecStopTriggerType(ROSpecStopTriggerType_Null); 00800 pROSpecStopTrigger->setDurationTriggerValue(0); /* n/a */ 00801 00802 CROBoundarySpec * pROBoundarySpec = new CROBoundarySpec(); 00803 pROBoundarySpec->setROSpecStartTrigger(pROSpecStartTrigger); 00804 pROBoundarySpec->setROSpecStopTrigger(pROSpecStopTrigger); 00805 00806 CAISpecStopTrigger * pAISpecStopTrigger = new CAISpecStopTrigger(); 00807 pAISpecStopTrigger->setAISpecStopTriggerType( 00808 AISpecStopTriggerType_Null); 00809 pAISpecStopTrigger->setDurationTrigger(0); 00810 00811 CInventoryParameterSpec * pInventoryParameterSpec = 00812 new CInventoryParameterSpec(); 00813 pInventoryParameterSpec->setInventoryParameterSpecID(1234); 00814 pInventoryParameterSpec->setProtocolID(AirProtocols_EPCGlobalClass1Gen2); 00815 00816 llrp_u16v_t AntennaIDs = llrp_u16v_t(1); 00817 AntennaIDs.m_pValue[0] = 0; /* All */ 00818 00819 CAISpec * pAISpec = new CAISpec(); 00820 pAISpec->setAntennaIDs(AntennaIDs); 00821 pAISpec->setAISpecStopTrigger(pAISpecStopTrigger); 00822 pAISpec->addInventoryParameterSpec(pInventoryParameterSpec); 00823 00824 CROSpec * pROSpec = new CROSpec(); 00825 pROSpec->setROSpecID(1111); 00826 pROSpec->setPriority(0); 00827 pROSpec->setCurrentState(ROSpecState_Disabled); 00828 pROSpec->setROBoundarySpec(pROBoundarySpec); 00829 pROSpec->addSpecParameter(pAISpec); 00830 00831 CADD_ROSPEC * pCmd; 00832 CMessage * pRspMsg; 00833 CADD_ROSPEC_RESPONSE * pRsp; 00834 00835 /* 00836 * Compose the command message. 00837 * N.B.: After the message is composed, all the parameters 00838 * constructed, immediately above, are considered "owned" 00839 * by the command message. When it is destructed so 00840 * too will the parameters be. 00841 */ 00842 pCmd = new CADD_ROSPEC(); 00843 pCmd->setMessageID(m_messageID++); 00844 pCmd->setROSpec(pROSpec); 00845 00846 /* 00847 * Send the message, expect the response of certain type 00848 */ 00849 pRspMsg = transact(pCmd); 00850 00851 /* 00852 * Done with the command message. 00853 * N.B.: And the parameters 00854 */ 00855 delete pCmd; 00856 00857 /* 00858 * transact() returns NULL if something went wrong. 00859 */ 00860 if(NULL == pRspMsg) 00861 { 00862 /* transact already tattled */ 00863 return -1; 00864 } 00865 00866 /* 00867 * Cast to a ADD_ROSPEC_RESPONSE message. 00868 */ 00869 pRsp = (CADD_ROSPEC_RESPONSE *) pRspMsg; 00870 00871 /* 00872 * Check the LLRPStatus parameter. 00873 */ 00874 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "addROSpec")) 00875 { 00876 /* checkLLRPStatus already tattled */ 00877 delete pRspMsg; 00878 return -1; 00879 } 00880 00881 /* 00882 * Done with the response message. 00883 */ 00884 delete pRspMsg; 00885 00886 /* 00887 * Tattle progress, maybe 00888 */ 00889 if(m_Verbose) 00890 { 00891 printf("INFO: ROSpec added\n"); 00892 } 00893 00894 /* 00895 * Victory. 00896 */ 00897 return 0; 00898 } 00899 00900 00918 int 00919 CMyApplication::enableROSpec (void) 00920 { 00921 CENABLE_ROSPEC * pCmd; 00922 CMessage * pRspMsg; 00923 CENABLE_ROSPEC_RESPONSE * pRsp; 00924 00925 /* 00926 * Compose the command message 00927 */ 00928 pCmd = new CENABLE_ROSPEC(); 00929 pCmd->setMessageID(m_messageID++); 00930 pCmd->setROSpecID(1111); 00931 00932 /* 00933 * Send the message, expect the response of certain type 00934 */ 00935 pRspMsg = transact(pCmd); 00936 00937 /* 00938 * Done with the command message 00939 */ 00940 delete pCmd; 00941 00942 /* 00943 * transact() returns NULL if something went wrong. 00944 */ 00945 if(NULL == pRspMsg) 00946 { 00947 /* transact already tattled */ 00948 return -1; 00949 } 00950 00951 /* 00952 * Cast to a ENABLE_ROSPEC_RESPONSE message. 00953 */ 00954 pRsp = (CENABLE_ROSPEC_RESPONSE *) pRspMsg; 00955 00956 /* 00957 * Check the LLRPStatus parameter. 00958 */ 00959 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "enableROSpec")) 00960 { 00961 /* checkLLRPStatus already tattled */ 00962 delete pRspMsg; 00963 return -1; 00964 } 00965 00966 /* 00967 * Done with the response message. 00968 */ 00969 delete pRspMsg; 00970 00971 /* 00972 * Tattle progress, maybe 00973 */ 00974 if(m_Verbose) 00975 { 00976 printf("INFO: ROSpec enabled\n"); 00977 } 00978 00979 /* 00980 * Victory. 00981 */ 00982 return 0; 00983 } 00984 00985 01003 int 01004 CMyApplication::startROSpec (void) 01005 { 01006 CSTART_ROSPEC * pCmd; 01007 CMessage * pRspMsg; 01008 CSTART_ROSPEC_RESPONSE * pRsp; 01009 01010 /* 01011 * Compose the command message 01012 */ 01013 pCmd = new CSTART_ROSPEC(); 01014 pCmd->setMessageID(m_messageID++); 01015 pCmd->setROSpecID(1111); 01016 01017 /* 01018 * Send the message, expect the response of certain type 01019 */ 01020 pRspMsg = transact(pCmd); 01021 01022 /* 01023 * Done with the command message 01024 */ 01025 delete pCmd; 01026 01027 /* 01028 * transact() returns NULL if something went wrong. 01029 */ 01030 if(NULL == pRspMsg) 01031 { 01032 /* transact already tattled */ 01033 return -1; 01034 } 01035 01036 /* 01037 * Cast to a START_ROSPEC_RESPONSE message. 01038 */ 01039 pRsp = (CSTART_ROSPEC_RESPONSE *) pRspMsg; 01040 01041 /* 01042 * Check the LLRPStatus parameter. 01043 */ 01044 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "startROSpec")) 01045 { 01046 /* checkLLRPStatus already tattled */ 01047 delete pRspMsg; 01048 return -1; 01049 } 01050 01051 /* 01052 * Done with the response message. 01053 */ 01054 delete pRspMsg; 01055 01056 /* 01057 * Tattle progress 01058 */ 01059 if(m_Verbose) 01060 { 01061 printf("INFO: ROSpec started\n"); 01062 } 01063 01064 /* 01065 * Victory. 01066 */ 01067 return 0; 01068 } 01069 01087 int 01088 CMyApplication::stopROSpec (void) 01089 { 01090 CSTOP_ROSPEC * pCmd; 01091 CMessage * pRspMsg; 01092 CSTOP_ROSPEC_RESPONSE * pRsp; 01093 01094 /* 01095 * Compose the command message 01096 */ 01097 pCmd = new CSTOP_ROSPEC(); 01098 pCmd->setMessageID(m_messageID++); 01099 pCmd->setROSpecID(1111); 01100 01101 /* 01102 * Send the message, expect the response of certain type 01103 */ 01104 pRspMsg = transact(pCmd); 01105 01106 /* 01107 * Done with the command message 01108 */ 01109 delete pCmd; 01110 01111 /* 01112 * transact() returns NULL if something went wrong. 01113 */ 01114 if(NULL == pRspMsg) 01115 { 01116 /* transact already tattled */ 01117 return -1; 01118 } 01119 01120 /* 01121 * Cast to a STOP_ROSPEC_RESPONSE message. 01122 */ 01123 pRsp = (CSTOP_ROSPEC_RESPONSE *) pRspMsg; 01124 01125 /* 01126 * Check the LLRPStatus parameter. 01127 */ 01128 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "stopROSpec")) 01129 { 01130 /* checkLLRPStatus already tattled */ 01131 delete pRspMsg; 01132 return -1; 01133 } 01134 01135 /* 01136 * Done with the response message. 01137 */ 01138 delete pRspMsg; 01139 01140 /* 01141 * Tattle progress 01142 */ 01143 if(m_Verbose) 01144 { 01145 printf("INFO: ROSpec stopped\n"); 01146 } 01147 01148 /* 01149 * Victory. 01150 */ 01151 return 0; 01152 } 01153 01154 01174 int 01175 CMyApplication::awaitAndPrintReport (int timeout) 01176 { 01177 int bDone = 0; 01178 int retVal = 0; 01179 time_t startTime = time(NULL); 01180 time_t tempTime; 01181 /* 01182 * Keep receiving messages until done or until 01183 * something bad happens. 01184 */ 01185 while(!bDone) 01186 { 01187 CMessage * pMessage; 01188 const CTypeDescriptor * pType; 01189 01190 /* 01191 * Wait up to 1 second for a report. Check 01192 * That way, we can check the timestamp even if 01193 * there are no reports coming in 01194 */ 01195 pMessage = recvMessage(1000); 01196 01197 /* validate the timestamp */ 01198 tempTime = time(NULL); 01199 if(difftime(tempTime, startTime) > timeout) 01200 { 01201 bDone=1; 01202 } 01203 01204 if(NULL == pMessage) 01205 { 01206 continue; 01207 } 01208 01209 /* 01210 * What happens depends on what kind of message 01211 * received. Use the type label (m_pType) to 01212 * discriminate message types. 01213 */ 01214 pType = pMessage->m_pType; 01215 01216 /* 01217 * Is it a tag report? If so, print it out. 01218 */ 01219 if(&CRO_ACCESS_REPORT::s_typeDescriptor == pType) 01220 { 01221 CRO_ACCESS_REPORT * pNtf; 01222 01223 pNtf = (CRO_ACCESS_REPORT *) pMessage; 01224 01225 printTagReportData(pNtf); 01226 } 01227 01228 /* 01229 * Is it a reader event? This example only recognizes 01230 * AntennaEvents. 01231 */ 01232 else if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor == pType) 01233 { 01234 CREADER_EVENT_NOTIFICATION *pNtf; 01235 CReaderEventNotificationData *pNtfData; 01236 01237 pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage; 01238 01239 pNtfData = pNtf->getReaderEventNotificationData(); 01240 if(NULL != pNtfData) 01241 { 01242 handleReaderEventNotification(pNtfData); 01243 } 01244 else 01245 { 01246 /* 01247 * This should never happen. Using continue 01248 * to keep indent depth down. 01249 */ 01250 printf("WARNING: READER_EVENT_NOTIFICATION without data\n"); 01251 } 01252 } 01253 01254 /* 01255 * Hmmm. Something unexpected. Just tattle and keep going. 01256 */ 01257 else 01258 { 01259 printf("WARNING: Ignored unexpected message during monitor: %s\n", 01260 pType->m_pName); 01261 } 01262 01263 /* 01264 * Done with the received message 01265 */ 01266 delete pMessage; 01267 } 01268 01269 return retVal; 01270 } 01271 01272 01287 void 01288 CMyApplication::printTagReportData ( 01289 CRO_ACCESS_REPORT * pRO_ACCESS_REPORT) 01290 { 01291 std::list<CTagReportData *>::iterator Cur; 01292 01293 unsigned int nEntry = 0; 01294 01295 /* 01296 * Loop through and count the number of entries 01297 */ 01298 for( 01299 Cur = pRO_ACCESS_REPORT->beginTagReportData(); 01300 Cur != pRO_ACCESS_REPORT->endTagReportData(); 01301 Cur++) 01302 { 01303 nEntry++; 01304 } 01305 01306 if(m_Verbose) 01307 { 01308 printf("INFO: %u tag report entries\n", nEntry); 01309 } 01310 01311 /* 01312 * Loop through again and print each entry. 01313 */ 01314 for( 01315 Cur = pRO_ACCESS_REPORT->beginTagReportData(); 01316 Cur != pRO_ACCESS_REPORT->endTagReportData(); 01317 Cur++) 01318 { 01319 printOneTagReportData(*Cur); 01320 } 01321 } 01322 01323 01332 void 01333 CMyApplication::formatOneEPC ( 01334 CParameter *pEPCParameter, 01335 char *buf, 01336 int buflen) 01337 { 01338 char * p = buf; 01339 int bufsize = buflen; 01340 int written = 0; 01341 01342 if(NULL != pEPCParameter) 01343 { 01344 const CTypeDescriptor * pType; 01345 llrp_u96_t my_u96; 01346 llrp_u1v_t my_u1v; 01347 llrp_u8_t * pValue = NULL; 01348 unsigned int n, i; 01349 01350 pType = pEPCParameter->m_pType; 01351 if(&CEPC_96::s_typeDescriptor == pType) 01352 { 01353 CEPC_96 *pEPC_96; 01354 01355 pEPC_96 = (CEPC_96 *) pEPCParameter; 01356 my_u96 = pEPC_96->getEPC(); 01357 pValue = my_u96.m_aValue; 01358 n = 12u; 01359 } 01360 else if(&CEPCData::s_typeDescriptor == pType) 01361 { 01362 CEPCData * pEPCData; 01363 01364 pEPCData = (CEPCData *) pEPCParameter; 01365 my_u1v = pEPCData->getEPC(); 01366 pValue = my_u1v.m_pValue; 01367 n = (my_u1v.m_nBit + 7u) / 8u; 01368 } 01369 01370 if(NULL != pValue) 01371 { 01372 for(i = 0; i < n; i++) 01373 { 01374 if(0 < i && i%2 == 0 && 1 < bufsize) 01375 { 01376 *p++ = '-'; 01377 bufsize--; 01378 } 01379 if(bufsize > 2) 01380 { 01381 written = snprintf(p, bufsize, "%02X", pValue[i]); 01382 bufsize -= written; 01383 p+= written; 01384 } 01385 } 01386 } 01387 else 01388 { 01389 written = snprintf(p, bufsize, "%s", "---unknown-epc-data-type---"); 01390 bufsize -= written; 01391 p += written; 01392 } 01393 } 01394 else 01395 { 01396 written = snprintf(p, bufsize, "%s", "--null epc---"); 01397 bufsize -= written; 01398 p += written; 01399 } 01400 01401 // null terminate this for good practice 01402 buf[buflen-1] = '\0'; 01403 01404 } 01405 01414 void 01415 CMyApplication::printOneTagReportData ( 01416 CTagReportData * pTagReportData) 01417 { 01418 char aBuf[64]; 01419 01420 /* 01421 * Print the EPC. It could be an 96-bit EPC_96 parameter 01422 * or an variable length EPCData parameter. 01423 */ 01424 01425 CParameter * pEPCParameter = 01426 pTagReportData->getEPCParameter(); 01427 01428 formatOneEPC(pEPCParameter, aBuf, 64); 01429 01430 /* 01431 * End of line 01432 */ 01433 printf("EPC: %s\n", aBuf); 01434 } 01435 01436 01450 void 01451 CMyApplication::handleReaderEventNotification ( 01452 CReaderEventNotificationData *pNtfData) 01453 { 01454 CAntennaEvent * pAntennaEvent; 01455 CReaderExceptionEvent * pReaderExceptionEvent; 01456 int nReported = 0; 01457 01458 pAntennaEvent = pNtfData->getAntennaEvent(); 01459 if(NULL != pAntennaEvent) 01460 { 01461 handleAntennaEvent(pAntennaEvent); 01462 nReported++; 01463 } 01464 01465 pReaderExceptionEvent = pNtfData->getReaderExceptionEvent(); 01466 if(NULL != pReaderExceptionEvent) 01467 { 01468 handleReaderExceptionEvent(pReaderExceptionEvent); 01469 nReported++; 01470 } 01471 01472 /* 01473 * Similarly handle other events here: 01474 * HoppingEvent 01475 * GPIEvent 01476 * ROSpecEvent 01477 * ReportBufferLevelWarningEvent 01478 * ReportBufferOverflowErrorEvent 01479 * RFSurveyEvent 01480 * AISpecEvent 01481 * ConnectionAttemptEvent 01482 * ConnectionCloseEvent 01483 * Custom 01484 */ 01485 01486 if(0 == nReported) 01487 { 01488 printf("NOTICE: Unexpected (unhandled) ReaderEvent\n"); 01489 } 01490 } 01491 01492 01504 void 01505 CMyApplication::handleAntennaEvent ( 01506 CAntennaEvent * pAntennaEvent) 01507 { 01508 EAntennaEventType eEventType; 01509 llrp_u16_t AntennaID; 01510 char * pStateStr; 01511 01512 eEventType = pAntennaEvent->getEventType(); 01513 AntennaID = pAntennaEvent->getAntennaID(); 01514 01515 switch(eEventType) 01516 { 01517 case AntennaEventType_Antenna_Disconnected: 01518 pStateStr = "disconnected"; 01519 break; 01520 01521 case AntennaEventType_Antenna_Connected: 01522 pStateStr = "connected"; 01523 break; 01524 01525 default: 01526 pStateStr = "?unknown-event?"; 01527 break; 01528 } 01529 01530 printf("NOTICE: Antenna %d is %s\n", AntennaID, pStateStr); 01531 } 01532 01533 01546 void 01547 CMyApplication::handleReaderExceptionEvent ( 01548 CReaderExceptionEvent * pReaderExceptionEvent) 01549 { 01550 llrp_utf8v_t Message; 01551 01552 Message = pReaderExceptionEvent->getMessage(); 01553 01554 if(0 < Message.m_nValue && NULL != Message.m_pValue) 01555 { 01556 printf("NOTICE: ReaderException '%.*s'\n", 01557 Message.m_nValue, Message.m_pValue); 01558 } 01559 else 01560 { 01561 printf("NOTICE: ReaderException but no message\n"); 01562 } 01563 } 01564 01565 01584 int 01585 CMyApplication::checkLLRPStatus ( 01586 CLLRPStatus * pLLRPStatus, 01587 char * pWhatStr) 01588 { 01589 /* 01590 * The LLRPStatus parameter is mandatory in all responses. 01591 * If it is missing there should have been a decode error. 01592 * This just makes sure (remember, this program is a 01593 * diagnostic and suppose to catch LTKC mistakes). 01594 */ 01595 if(NULL == pLLRPStatus) 01596 { 01597 printf("ERROR: %s missing LLRP status\n", pWhatStr); 01598 return -1; 01599 } 01600 01601 /* 01602 * Make sure the status is M_Success. 01603 * If it isn't, print the error string if one. 01604 * This does not try to pretty-print the status 01605 * code. To get that, run this program with -vv 01606 * and examine the XML output. 01607 */ 01608 if(StatusCode_M_Success != pLLRPStatus->getStatusCode()) 01609 { 01610 llrp_utf8v_t ErrorDesc; 01611 01612 ErrorDesc = pLLRPStatus->getErrorDescription(); 01613 01614 if(0 == ErrorDesc.m_nValue) 01615 { 01616 printf("ERROR: %s failed, no error description given\n", 01617 pWhatStr); 01618 } 01619 else 01620 { 01621 printf("ERROR: %s failed, %.*s\n", 01622 pWhatStr, ErrorDesc.m_nValue, ErrorDesc.m_pValue); 01623 } 01624 return -2; 01625 } 01626 01627 /* 01628 * Victory. Everything is fine. 01629 */ 01630 return 0; 01631 } 01632 01633 01657 CMessage * 01658 CMyApplication::transact ( 01659 CMessage * pSendMsg) 01660 { 01661 CConnection * pConn = m_pConnectionToReader; 01662 CMessage * pRspMsg; 01663 01664 /* 01665 * Print the XML text for the outbound message if 01666 * verbosity is 2 or higher. 01667 */ 01668 if(1 < m_Verbose) 01669 { 01670 printf("\n===================================\n"); 01671 printf("INFO: Transact sending\n"); 01672 printXMLMessage(pSendMsg); 01673 } 01674 01675 /* 01676 * Send the message, expect the response of certain type. 01677 * If LLRP::CConnection::transact() returns NULL then there was 01678 * an error. In that case we try to print the error details. 01679 */ 01680 pRspMsg = pConn->transact(pSendMsg, 5000); 01681 01682 if(NULL == pRspMsg) 01683 { 01684 const CErrorDetails * pError = pConn->getTransactError(); 01685 01686 printf("ERROR: %s transact failed, %s\n", 01687 pSendMsg->m_pType->m_pName, 01688 pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given"); 01689 01690 if(NULL != pError->m_pRefType) 01691 { 01692 printf("ERROR: ... reference type %s\n", 01693 pError->m_pRefType->m_pName); 01694 } 01695 01696 if(NULL != pError->m_pRefField) 01697 { 01698 printf("ERROR: ... reference field %s\n", 01699 pError->m_pRefField->m_pName); 01700 } 01701 01702 return NULL; 01703 } 01704 01705 /* 01706 * Print the XML text for the inbound message if 01707 * verbosity is 2 or higher. 01708 */ 01709 if(1 < m_Verbose) 01710 { 01711 printf("\n- - - - - - - - - - - - - - - - - -\n"); 01712 printf("INFO: Transact received response\n"); 01713 printXMLMessage(pRspMsg); 01714 } 01715 01716 /* 01717 * If it is an ERROR_MESSAGE (response from reader 01718 * when it can't understand the request), tattle 01719 * and declare defeat. 01720 */ 01721 if(&CERROR_MESSAGE::s_typeDescriptor == pRspMsg->m_pType) 01722 { 01723 const CTypeDescriptor * pResponseType; 01724 01725 pResponseType = pSendMsg->m_pType->m_pResponseType; 01726 01727 printf("ERROR: Received ERROR_MESSAGE instead of %s\n", 01728 pResponseType->m_pName); 01729 delete pRspMsg; 01730 pRspMsg = NULL; 01731 } 01732 01733 return pRspMsg; 01734 } 01735 01736 01761 CMessage * 01762 CMyApplication::recvMessage ( 01763 int nMaxMS) 01764 { 01765 CConnection * pConn = m_pConnectionToReader; 01766 CMessage * pMessage; 01767 01768 /* 01769 * Receive the message subject to a time limit 01770 */ 01771 pMessage = pConn->recvMessage(nMaxMS); 01772 01773 /* 01774 * If LLRP::CConnection::recvMessage() returns NULL then there was 01775 * an error. In that case we try to print the error details. 01776 */ 01777 if(NULL == pMessage) 01778 { 01779 const CErrorDetails * pError = pConn->getRecvError(); 01780 01781 /* don't warn on timeout since this is a polling example */ 01782 if(pError->m_eResultCode != RC_RecvTimeout) 01783 { 01784 printf("ERROR: recvMessage failed, %s\n", 01785 pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given"); 01786 } 01787 01788 if(NULL != pError->m_pRefType) 01789 { 01790 printf("ERROR: ... reference type %s\n", 01791 pError->m_pRefType->m_pName); 01792 } 01793 01794 if(NULL != pError->m_pRefField) 01795 { 01796 printf("ERROR: ... reference field %s\n", 01797 pError->m_pRefField->m_pName); 01798 } 01799 01800 return NULL; 01801 } 01802 01803 /* 01804 * Print the XML text for the inbound message if 01805 * verbosity is 2 or higher. 01806 */ 01807 if(1 < m_Verbose) 01808 { 01809 printf("\n===================================\n"); 01810 printf("INFO: Message received\n"); 01811 printXMLMessage(pMessage); 01812 } 01813 01814 return pMessage; 01815 } 01816 01817 01835 int 01836 CMyApplication::sendMessage ( 01837 CMessage * pSendMsg) 01838 { 01839 CConnection * pConn = m_pConnectionToReader; 01840 01841 /* 01842 * Print the XML text for the outbound message if 01843 * verbosity is 2 or higher. 01844 */ 01845 if(1 < m_Verbose) 01846 { 01847 printf("\n===================================\n"); 01848 printf("INFO: Sending\n"); 01849 printXMLMessage(pSendMsg); 01850 } 01851 01852 /* 01853 * If LLRP::CConnection::sendMessage() returns other than RC_OK 01854 * then there was an error. In that case we try to print 01855 * the error details. 01856 */ 01857 if(RC_OK != pConn->sendMessage(pSendMsg)) 01858 { 01859 const CErrorDetails * pError = pConn->getSendError(); 01860 01861 printf("ERROR: %s sendMessage failed, %s\n", 01862 pSendMsg->m_pType->m_pName, 01863 pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given"); 01864 01865 if(NULL != pError->m_pRefType) 01866 { 01867 printf("ERROR: ... reference type %s\n", 01868 pError->m_pRefType->m_pName); 01869 } 01870 01871 if(NULL != pError->m_pRefField) 01872 { 01873 printf("ERROR: ... reference field %s\n", 01874 pError->m_pRefField->m_pName); 01875 } 01876 01877 return -1; 01878 } 01879 01880 /* 01881 * Victory 01882 */ 01883 return 0; 01884 } 01885 01886 01900 void 01901 CMyApplication::printXMLMessage ( 01902 CMessage * pMessage) 01903 { 01904 char aBuf[100*1024]; 01905 01906 /* 01907 * Convert the message to an XML string. 01908 * This fills the buffer with either the XML string 01909 * or an error message. The return value could 01910 * be checked. 01911 */ 01912 01913 pMessage->toXMLString(aBuf, sizeof aBuf); 01914 01915 /* 01916 * Print the XML Text to the standard output. 01917 */ 01918 printf("%s", aBuf); 01919 }