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,2008. All rights reserved. * 00012 * * 00013 *****************************************************************************/ 00014 00045 #include <stdio.h> 00046 00047 #include "ltkcpp.h" 00048 00049 using namespace LLRP; 00050 00051 00052 class CMyApplication 00053 { 00054 public: 00056 int m_Verbose; 00057 00059 CConnection * m_pConnectionToReader; 00060 00061 inline 00062 CMyApplication (void) 00063 : m_Verbose(0), m_pConnectionToReader(NULL) 00064 {} 00065 00066 int 00067 run ( 00068 char * pReaderHostName); 00069 00070 int 00071 checkConnectionStatus (void); 00072 00073 int 00074 scrubConfiguration (void); 00075 00076 int 00077 resetConfigurationToFactoryDefaults (void); 00078 00079 int 00080 deleteAllROSpecs (void); 00081 00082 int 00083 addROSpec (void); 00084 00085 int 00086 enableROSpec (void); 00087 00088 int 00089 startROSpec (void); 00090 00091 int 00092 awaitAndPrintReport (void); 00093 00094 void 00095 printTagReportData ( 00096 CRO_ACCESS_REPORT * pRO_ACCESS_REPORT); 00097 00098 void 00099 printOneTagReportData ( 00100 CTagReportData * pTagReportData); 00101 00102 void 00103 handleReaderEventNotification ( 00104 CReaderEventNotificationData *pNtfData); 00105 00106 void 00107 handleAntennaEvent ( 00108 CAntennaEvent * pAntennaEvent); 00109 00110 void 00111 handleReaderExceptionEvent ( 00112 CReaderExceptionEvent * pReaderExceptionEvent); 00113 00114 int 00115 checkLLRPStatus ( 00116 CLLRPStatus * pLLRPStatus, 00117 char * pWhatStr); 00118 00119 CMessage * 00120 transact ( 00121 CMessage * pSendMsg); 00122 00123 CMessage * 00124 recvMessage ( 00125 int nMaxMS); 00126 00127 int 00128 sendMessage ( 00129 CMessage * pSendMsg); 00130 00131 void 00132 printXMLMessage ( 00133 CMessage * pMessage); 00134 }; 00135 00136 00137 /* BEGIN forward declarations */ 00138 int 00139 main ( 00140 int ac, 00141 char * av[]); 00142 00143 void 00144 usage ( 00145 char * pProgName); 00146 /* END forward declarations */ 00147 00148 00164 int 00165 main ( 00166 int ac, 00167 char * av[]) 00168 { 00169 CMyApplication myApp; 00170 char * pReaderHostName; 00171 int rc; 00172 00173 /* 00174 * Process comand arguments, determine reader name 00175 * and verbosity level. 00176 */ 00177 if(ac == 2) 00178 { 00179 pReaderHostName = av[1]; 00180 } 00181 else if(ac == 3) 00182 { 00183 char * p = av[1]; 00184 00185 while(*p) 00186 { 00187 switch(*p++) 00188 { 00189 case '-': /* linux conventional option warn char */ 00190 case '/': /* Windows/DOS conventional option warn char */ 00191 break; 00192 00193 case 'v': 00194 case 'V': 00195 myApp.m_Verbose++; 00196 break; 00197 00198 default: 00199 usage(av[0]); 00200 /* no return */ 00201 break; 00202 } 00203 } 00204 00205 pReaderHostName = av[2]; 00206 } 00207 else 00208 { 00209 usage(av[0]); 00210 /* no return */ 00211 } 00212 00213 /* 00214 * Run application, capture return value for exit status 00215 */ 00216 rc = myApp.run(pReaderHostName); 00217 00218 printf("INFO: Done\n"); 00219 00220 /* 00221 * Exit with the right status. 00222 */ 00223 if(0 == rc) 00224 { 00225 exit(0); 00226 } 00227 else 00228 { 00229 exit(2); 00230 } 00231 /*NOTREACHED*/ 00232 } 00233 00234 00246 void 00247 usage ( 00248 char * pProgName) 00249 { 00250 #ifdef linux 00251 printf("Usage: %s [-v[v]] READERHOSTNAME\n", pProgName); 00252 printf("\n"); 00253 printf("Each -v increases verbosity level\n"); 00254 #endif /* linux */ 00255 #ifdef WIN32 00256 printf("Usage: %s [/v[v]] READERHOSTNAME\n", pProgName); 00257 printf("\n"); 00258 printf("Each /v increases verbosity level\n"); 00259 #endif /* WIN32 */ 00260 exit(1); 00261 } 00262 00263 00294 int 00295 CMyApplication::run ( 00296 char * pReaderHostName) 00297 { 00298 CTypeRegistry * pTypeRegistry; 00299 CConnection * pConn; 00300 int rc; 00301 00302 /* 00303 * Allocate the type registry. This is needed 00304 * by the connection to decode. 00305 */ 00306 pTypeRegistry = getTheTypeRegistry(); 00307 if(NULL == pTypeRegistry) 00308 { 00309 printf("ERROR: getTheTypeRegistry failed\n"); 00310 return -1; 00311 } 00312 00313 /* 00314 * Construct a connection (LLRP::CConnection). 00315 * Using a 32kb max frame size for send/recv. 00316 * The connection object is ready for business 00317 * but not actually connected to the reader yet. 00318 */ 00319 pConn = new CConnection(pTypeRegistry, 32u*1024u); 00320 if(NULL == pConn) 00321 { 00322 printf("ERROR: new CConnection failed\n"); 00323 return -2; 00324 } 00325 00326 /* 00327 * Open the connection to the reader 00328 */ 00329 if(m_Verbose) 00330 { 00331 printf("INFO: Connecting to %s....\n", pReaderHostName); 00332 } 00333 00334 rc = pConn->openConnectionToReader(pReaderHostName); 00335 if(0 != rc) 00336 { 00337 printf("ERROR: connect: %s (%d)\n", pConn->getConnectError(), rc); 00338 delete pConn; 00339 return -3; 00340 } 00341 00342 /* 00343 * Record the pointer to the connection object so other 00344 * routines can use it. 00345 */ 00346 m_pConnectionToReader = pConn; 00347 00348 if(m_Verbose) 00349 { 00350 printf("INFO: Connected, checking status....\n"); 00351 } 00352 00353 /* 00354 * Commence the sequence and check for errors as we go. 00355 * See comments for each routine for details. 00356 * Each routine prints messages. 00357 */ 00358 rc = 1; 00359 if(0 == checkConnectionStatus()) 00360 { 00361 rc = 2; 00362 if(0 == scrubConfiguration()) 00363 { 00364 rc = 3; 00365 if(0 == addROSpec()) 00366 { 00367 rc = 4; 00368 if(0 == enableROSpec()) 00369 { 00370 int i; 00371 00372 rc = 5; 00373 00374 for(i = 1; i <= 5; i++) 00375 { 00376 printf("INFO: Starting run %d ================\n", i); 00377 if(0 != startROSpec()) 00378 { 00379 /* already tattled */ 00380 break; 00381 } 00382 if(0 != awaitAndPrintReport()) 00383 { 00384 /* already tattled */ 00385 break; 00386 } 00387 } 00388 00389 if(5 == i) 00390 { 00391 rc = 0; 00392 } 00393 } 00394 } 00395 00396 /* 00397 * After we're done, try to leave the reader 00398 * in a clean state for next use. This is best 00399 * effort and no checking of the result is done. 00400 */ 00401 if(m_Verbose) 00402 { 00403 printf("INFO: Clean up reader configuration...\n"); 00404 } 00405 scrubConfiguration(); 00406 } 00407 } 00408 00409 if(m_Verbose) 00410 { 00411 printf("INFO: Finished\n"); 00412 } 00413 00414 /* 00415 * Close the connection and release its resources 00416 */ 00417 pConn->closeConnectionToReader(); 00418 delete pConn; 00419 00420 /* 00421 * Done with the registry. 00422 */ 00423 delete pTypeRegistry; 00424 00425 /* 00426 * When we get here all allocated memory should have been deallocated. 00427 */ 00428 00429 return rc; 00430 } 00431 00432 00463 int 00464 CMyApplication::checkConnectionStatus (void) 00465 { 00466 CMessage * pMessage; 00467 CREADER_EVENT_NOTIFICATION *pNtf; 00468 CReaderEventNotificationData *pNtfData; 00469 CConnectionAttemptEvent * pEvent; 00470 00471 /* 00472 * Expect the notification within 10 seconds. 00473 * It is suppose to be the very first message sent. 00474 */ 00475 pMessage = recvMessage(10000); 00476 00477 /* 00478 * recvMessage() returns NULL if something went wrong. 00479 */ 00480 if(NULL == pMessage) 00481 { 00482 /* recvMessage already tattled */ 00483 goto fail; 00484 } 00485 00486 /* 00487 * Check to make sure the message is of the right type. 00488 * The type label (pointer) in the message should be 00489 * the type descriptor for READER_EVENT_NOTIFICATION. 00490 */ 00491 if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor != pMessage->m_pType) 00492 { 00493 goto fail; 00494 } 00495 00496 /* 00497 * Now that we are sure it is a READER_EVENT_NOTIFICATION, 00498 * traverse to the ReaderEventNotificationData parameter. 00499 */ 00500 pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage; 00501 pNtfData = pNtf->getReaderEventNotificationData(); 00502 if(NULL == pNtfData) 00503 { 00504 goto fail; 00505 } 00506 00507 /* 00508 * The ConnectionAttemptEvent parameter must be present. 00509 */ 00510 pEvent = pNtfData->getConnectionAttemptEvent(); 00511 if(NULL == pEvent) 00512 { 00513 goto fail; 00514 } 00515 00516 /* 00517 * The status in the ConnectionAttemptEvent parameter 00518 * must indicate connection success. 00519 */ 00520 if(ConnectionAttemptStatusType_Success != pEvent->getStatus()) 00521 { 00522 goto fail; 00523 } 00524 00525 /* 00526 * Done with the message 00527 */ 00528 delete pMessage; 00529 00530 if(m_Verbose) 00531 { 00532 printf("INFO: Connection status OK\n"); 00533 } 00534 00535 /* 00536 * Victory. 00537 */ 00538 return 0; 00539 00540 fail: 00541 /* 00542 * Something went wrong. Tattle. Clean up. Return error. 00543 */ 00544 printf("ERROR: checkConnectionStatus failed\n"); 00545 delete pMessage; 00546 return -1; 00547 } 00548 00549 00566 int 00567 CMyApplication::scrubConfiguration (void) 00568 { 00569 if(0 != resetConfigurationToFactoryDefaults()) 00570 { 00571 return -1; 00572 } 00573 00574 if(0 != deleteAllROSpecs()) 00575 { 00576 return -2; 00577 } 00578 00579 return 0; 00580 } 00581 00582 00603 int 00604 CMyApplication::resetConfigurationToFactoryDefaults (void) 00605 { 00606 CSET_READER_CONFIG * pCmd; 00607 CMessage * pRspMsg; 00608 CSET_READER_CONFIG_RESPONSE *pRsp; 00609 00610 /* 00611 * Compose the command message 00612 */ 00613 pCmd = new CSET_READER_CONFIG(); 00614 pCmd->setMessageID(101); 00615 pCmd->setResetToFactoryDefault(1); 00616 00617 /* 00618 * Send the message, expect the response of certain type 00619 */ 00620 pRspMsg = transact(pCmd); 00621 00622 /* 00623 * Done with the command message 00624 */ 00625 delete pCmd; 00626 00627 /* 00628 * transact() returns NULL if something went wrong. 00629 */ 00630 if(NULL == pRspMsg) 00631 { 00632 /* transact already tattled */ 00633 return -1; 00634 } 00635 00636 /* 00637 * Cast to a SET_READER_CONFIG_RESPONSE message. 00638 */ 00639 pRsp = (CSET_READER_CONFIG_RESPONSE *) pRspMsg; 00640 00641 /* 00642 * Check the LLRPStatus parameter. 00643 */ 00644 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), 00645 "resetConfigurationToFactoryDefaults")) 00646 { 00647 /* checkLLRPStatus already tattled */ 00648 delete pRspMsg; 00649 return -1; 00650 } 00651 00652 /* 00653 * Done with the response message. 00654 */ 00655 delete pRspMsg; 00656 00657 /* 00658 * Tattle progress, maybe 00659 */ 00660 if(m_Verbose) 00661 { 00662 printf("INFO: Configuration reset to factory defaults\n"); 00663 } 00664 00665 /* 00666 * Victory. 00667 */ 00668 return 0; 00669 } 00670 00671 00691 int 00692 CMyApplication::deleteAllROSpecs (void) 00693 { 00694 CDELETE_ROSPEC * pCmd; 00695 CMessage * pRspMsg; 00696 CDELETE_ROSPEC_RESPONSE * pRsp; 00697 00698 /* 00699 * Compose the command message 00700 */ 00701 pCmd = new CDELETE_ROSPEC(); 00702 pCmd->setMessageID(102); 00703 pCmd->setROSpecID(0); /* All */ 00704 00705 /* 00706 * Send the message, expect the response of certain type 00707 */ 00708 pRspMsg = transact(pCmd); 00709 00710 /* 00711 * Done with the command message 00712 */ 00713 delete pCmd; 00714 00715 /* 00716 * transact() returns NULL if something went wrong. 00717 */ 00718 if(NULL == pRspMsg) 00719 { 00720 /* transact already tattled */ 00721 return -1; 00722 } 00723 00724 /* 00725 * Cast to a DELETE_ROSPEC_RESPONSE message. 00726 */ 00727 pRsp = (CDELETE_ROSPEC_RESPONSE *) pRspMsg; 00728 00729 /* 00730 * Check the LLRPStatus parameter. 00731 */ 00732 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "deleteAllROSpecs")) 00733 { 00734 /* checkLLRPStatus already tattled */ 00735 delete pRspMsg; 00736 return -1; 00737 } 00738 00739 /* 00740 * Done with the response message. 00741 */ 00742 delete pRspMsg; 00743 00744 /* 00745 * Tattle progress, maybe 00746 */ 00747 if(m_Verbose) 00748 { 00749 printf("INFO: All ROSpecs are deleted\n"); 00750 } 00751 00752 /* 00753 * Victory. 00754 */ 00755 return 0; 00756 } 00757 00758 00830 int 00831 CMyApplication::addROSpec (void) 00832 { 00833 CROSpecStartTrigger * pROSpecStartTrigger = 00834 new CROSpecStartTrigger(); 00835 pROSpecStartTrigger->setROSpecStartTriggerType( 00836 ROSpecStartTriggerType_Null); 00837 00838 CROSpecStopTrigger * pROSpecStopTrigger = new CROSpecStopTrigger(); 00839 pROSpecStopTrigger->setROSpecStopTriggerType(ROSpecStopTriggerType_Null); 00840 pROSpecStopTrigger->setDurationTriggerValue(0); /* n/a */ 00841 00842 CROBoundarySpec * pROBoundarySpec = new CROBoundarySpec(); 00843 pROBoundarySpec->setROSpecStartTrigger(pROSpecStartTrigger); 00844 pROBoundarySpec->setROSpecStopTrigger(pROSpecStopTrigger); 00845 00846 CAISpecStopTrigger * pAISpecStopTrigger = new CAISpecStopTrigger(); 00847 pAISpecStopTrigger->setAISpecStopTriggerType( 00848 AISpecStopTriggerType_Duration); 00849 pAISpecStopTrigger->setDurationTrigger(5000); 00850 00851 CInventoryParameterSpec * pInventoryParameterSpec = 00852 new CInventoryParameterSpec(); 00853 pInventoryParameterSpec->setInventoryParameterSpecID(1234); 00854 pInventoryParameterSpec->setProtocolID(AirProtocols_EPCGlobalClass1Gen2); 00855 00856 llrp_u16v_t AntennaIDs = llrp_u16v_t(1); 00857 AntennaIDs.m_pValue[0] = 0; /* All */ 00858 00859 CAISpec * pAISpec = new CAISpec(); 00860 pAISpec->setAntennaIDs(AntennaIDs); 00861 pAISpec->setAISpecStopTrigger(pAISpecStopTrigger); 00862 pAISpec->addInventoryParameterSpec(pInventoryParameterSpec); 00863 00864 CTagReportContentSelector * pTagReportContentSelector = 00865 new CTagReportContentSelector(); 00866 pTagReportContentSelector->setEnableROSpecID(FALSE); 00867 pTagReportContentSelector->setEnableSpecIndex(FALSE); 00868 pTagReportContentSelector->setEnableInventoryParameterSpecID(FALSE); 00869 pTagReportContentSelector->setEnableAntennaID(FALSE); 00870 pTagReportContentSelector->setEnableChannelIndex(FALSE); 00871 pTagReportContentSelector->setEnablePeakRSSI(FALSE); 00872 pTagReportContentSelector->setEnableFirstSeenTimestamp(FALSE); 00873 pTagReportContentSelector->setEnableLastSeenTimestamp(FALSE); 00874 pTagReportContentSelector->setEnableTagSeenCount(FALSE); 00875 pTagReportContentSelector->setEnableAccessSpecID(FALSE); 00876 00877 CROReportSpec * pROReportSpec = new CROReportSpec(); 00878 pROReportSpec->setROReportTrigger( 00879 ROReportTriggerType_Upon_N_Tags_Or_End_Of_ROSpec); 00880 pROReportSpec->setN(0); /* Unlimited */ 00881 pROReportSpec->setTagReportContentSelector(pTagReportContentSelector); 00882 00883 CROSpec * pROSpec = new CROSpec(); 00884 pROSpec->setROSpecID(123); 00885 pROSpec->setPriority(0); 00886 pROSpec->setCurrentState(ROSpecState_Disabled); 00887 pROSpec->setROBoundarySpec(pROBoundarySpec); 00888 pROSpec->addSpecParameter(pAISpec); 00889 pROSpec->setROReportSpec(pROReportSpec); 00890 00891 CADD_ROSPEC * pCmd; 00892 CMessage * pRspMsg; 00893 CADD_ROSPEC_RESPONSE * pRsp; 00894 00895 /* 00896 * Compose the command message. 00897 * N.B.: After the message is composed, all the parameters 00898 * constructed, immediately above, are considered "owned" 00899 * by the command message. When it is destructed so 00900 * too will the parameters be. 00901 */ 00902 pCmd = new CADD_ROSPEC(); 00903 pCmd->setMessageID(201); 00904 pCmd->setROSpec(pROSpec); 00905 00906 /* 00907 * Send the message, expect the response of certain type 00908 */ 00909 pRspMsg = transact(pCmd); 00910 00911 /* 00912 * Done with the command message. 00913 * N.B.: And the parameters 00914 */ 00915 delete pCmd; 00916 00917 /* 00918 * transact() returns NULL if something went wrong. 00919 */ 00920 if(NULL == pRspMsg) 00921 { 00922 /* transact already tattled */ 00923 return -1; 00924 } 00925 00926 /* 00927 * Cast to a ADD_ROSPEC_RESPONSE message. 00928 */ 00929 pRsp = (CADD_ROSPEC_RESPONSE *) pRspMsg; 00930 00931 /* 00932 * Check the LLRPStatus parameter. 00933 */ 00934 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "addROSpec")) 00935 { 00936 /* checkLLRPStatus already tattled */ 00937 delete pRspMsg; 00938 return -1; 00939 } 00940 00941 /* 00942 * Done with the response message. 00943 */ 00944 delete pRspMsg; 00945 00946 /* 00947 * Tattle progress, maybe 00948 */ 00949 if(m_Verbose) 00950 { 00951 printf("INFO: ROSpec added\n"); 00952 } 00953 00954 /* 00955 * Victory. 00956 */ 00957 return 0; 00958 } 00959 00960 00978 int 00979 CMyApplication::enableROSpec (void) 00980 { 00981 CENABLE_ROSPEC * pCmd; 00982 CMessage * pRspMsg; 00983 CENABLE_ROSPEC_RESPONSE * pRsp; 00984 00985 /* 00986 * Compose the command message 00987 */ 00988 pCmd = new CENABLE_ROSPEC(); 00989 pCmd->setMessageID(202); 00990 pCmd->setROSpecID(123); 00991 00992 /* 00993 * Send the message, expect the response of certain type 00994 */ 00995 pRspMsg = transact(pCmd); 00996 00997 /* 00998 * Done with the command message 00999 */ 01000 delete pCmd; 01001 01002 /* 01003 * transact() returns NULL if something went wrong. 01004 */ 01005 if(NULL == pRspMsg) 01006 { 01007 /* transact already tattled */ 01008 return -1; 01009 } 01010 01011 /* 01012 * Cast to a ENABLE_ROSPEC_RESPONSE message. 01013 */ 01014 pRsp = (CENABLE_ROSPEC_RESPONSE *) pRspMsg; 01015 01016 /* 01017 * Check the LLRPStatus parameter. 01018 */ 01019 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "enableROSpec")) 01020 { 01021 /* checkLLRPStatus already tattled */ 01022 delete pRspMsg; 01023 return -1; 01024 } 01025 01026 /* 01027 * Done with the response message. 01028 */ 01029 delete pRspMsg; 01030 01031 /* 01032 * Tattle progress, maybe 01033 */ 01034 if(m_Verbose) 01035 { 01036 printf("INFO: ROSpec enabled\n"); 01037 } 01038 01039 /* 01040 * Victory. 01041 */ 01042 return 0; 01043 } 01044 01045 01063 int 01064 CMyApplication::startROSpec (void) 01065 { 01066 CSTART_ROSPEC * pCmd; 01067 CMessage * pRspMsg; 01068 CSTART_ROSPEC_RESPONSE * pRsp; 01069 01070 /* 01071 * Compose the command message 01072 */ 01073 pCmd = new CSTART_ROSPEC(); 01074 pCmd->setMessageID(202); 01075 pCmd->setROSpecID(123); 01076 01077 /* 01078 * Send the message, expect the response of certain type 01079 */ 01080 pRspMsg = transact(pCmd); 01081 01082 /* 01083 * Done with the command message 01084 */ 01085 delete pCmd; 01086 01087 /* 01088 * transact() returns NULL if something went wrong. 01089 */ 01090 if(NULL == pRspMsg) 01091 { 01092 /* transact already tattled */ 01093 return -1; 01094 } 01095 01096 /* 01097 * Cast to a START_ROSPEC_RESPONSE message. 01098 */ 01099 pRsp = (CSTART_ROSPEC_RESPONSE *) pRspMsg; 01100 01101 /* 01102 * Check the LLRPStatus parameter. 01103 */ 01104 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "startROSpec")) 01105 { 01106 /* checkLLRPStatus already tattled */ 01107 delete pRspMsg; 01108 return -1; 01109 } 01110 01111 /* 01112 * Done with the response message. 01113 */ 01114 delete pRspMsg; 01115 01116 /* 01117 * Tattle progress 01118 */ 01119 if(m_Verbose) 01120 { 01121 printf("INFO: ROSpec started\n"); 01122 } 01123 01124 /* 01125 * Victory. 01126 */ 01127 return 0; 01128 } 01129 01130 01146 int 01147 CMyApplication::awaitAndPrintReport (void) 01148 { 01149 int bDone = 0; 01150 int retVal = 0; 01151 01152 /* 01153 * Keep receiving messages until done or until 01154 * something bad happens. 01155 */ 01156 while(!bDone) 01157 { 01158 CMessage * pMessage; 01159 const CTypeDescriptor * pType; 01160 01161 /* 01162 * Wait up to 7 seconds for a message. The report 01163 * should occur within 5 seconds. 01164 */ 01165 pMessage = recvMessage(7000); 01166 if(NULL == pMessage) 01167 { 01168 /* 01169 * Did not receive a message within a reasonable 01170 * amount of time. recvMessage() already tattled 01171 */ 01172 retVal = -2; 01173 bDone = 1; 01174 continue; 01175 } 01176 01177 /* 01178 * What happens depends on what kind of message 01179 * received. Use the type label (m_pType) to 01180 * discriminate message types. 01181 */ 01182 pType = pMessage->m_pType; 01183 01184 /* 01185 * Is it a tag report? If so, print it out. 01186 */ 01187 if(&CRO_ACCESS_REPORT::s_typeDescriptor == pType) 01188 { 01189 CRO_ACCESS_REPORT * pNtf; 01190 01191 pNtf = (CRO_ACCESS_REPORT *) pMessage; 01192 01193 printTagReportData(pNtf); 01194 bDone = 1; 01195 retVal = 0; 01196 } 01197 01198 /* 01199 * Is it a reader event? This example only recognizes 01200 * AntennaEvents. 01201 */ 01202 else if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor == pType) 01203 { 01204 CREADER_EVENT_NOTIFICATION *pNtf; 01205 CReaderEventNotificationData *pNtfData; 01206 01207 pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage; 01208 01209 pNtfData = pNtf->getReaderEventNotificationData(); 01210 if(NULL != pNtfData) 01211 { 01212 handleReaderEventNotification(pNtfData); 01213 } 01214 else 01215 { 01216 /* 01217 * This should never happen. Using continue 01218 * to keep indent depth down. 01219 */ 01220 printf("WARNING: READER_EVENT_NOTIFICATION without data\n"); 01221 } 01222 } 01223 01224 /* 01225 * Hmmm. Something unexpected. Just tattle and keep going. 01226 */ 01227 else 01228 { 01229 printf("WARNING: Ignored unexpected message during monitor: %s\n", 01230 pType->m_pName); 01231 } 01232 01233 /* 01234 * Done with the received message 01235 */ 01236 delete pMessage; 01237 } 01238 01239 return retVal; 01240 } 01241 01242 01257 void 01258 CMyApplication::printTagReportData ( 01259 CRO_ACCESS_REPORT * pRO_ACCESS_REPORT) 01260 { 01261 std::list<CTagReportData *>::iterator Cur; 01262 unsigned int nEntry = 0; 01263 01264 /* 01265 * Loop through and count the number of entries 01266 */ 01267 for( 01268 Cur = pRO_ACCESS_REPORT->beginTagReportData(); 01269 Cur != pRO_ACCESS_REPORT->endTagReportData(); 01270 Cur++) 01271 { 01272 nEntry++; 01273 } 01274 01275 printf("INFO: %u tag report entries\n", nEntry); 01276 01277 /* 01278 * Loop through again and print each entry. 01279 */ 01280 for( 01281 Cur = pRO_ACCESS_REPORT->beginTagReportData(); 01282 Cur != pRO_ACCESS_REPORT->endTagReportData(); 01283 Cur++) 01284 { 01285 printOneTagReportData(*Cur); 01286 } 01287 } 01288 01289 01299 void 01300 CMyApplication::printOneTagReportData ( 01301 CTagReportData * pTagReportData) 01302 { 01303 const CTypeDescriptor * pType; 01304 char aBuf[100*1024]; 01305 01306 /* 01307 * Print the EPC. It could be an 96-bit EPC_96 parameter 01308 * or an variable length EPCData parameter. 01309 */ 01310 01311 CParameter * pEPCParameter = 01312 pTagReportData->getEPCParameter(); 01313 01314 if(NULL != pEPCParameter) 01315 { 01316 char * p = aBuf; 01317 llrp_u96_t my_u96; 01318 llrp_u1v_t my_u1v; 01319 llrp_u8_t * pValue = NULL; 01320 unsigned int n, i; 01321 01322 pType = pEPCParameter->m_pType; 01323 if(&CEPC_96::s_typeDescriptor == pType) 01324 { 01325 CEPC_96 *pEPC_96; 01326 01327 pEPC_96 = (CEPC_96 *) pEPCParameter; 01328 my_u96 = pEPC_96->getEPC(); 01329 pValue = my_u96.m_aValue; 01330 n = 12u; 01331 } 01332 else if(&CEPCData::s_typeDescriptor == pType) 01333 { 01334 CEPCData * pEPCData; 01335 01336 pEPCData = (CEPCData *) pEPCParameter; 01337 my_u1v = pEPCData->getEPC(); 01338 pValue = my_u1v.m_pValue; 01339 n = (my_u1v.m_nBit + 7u) / 8u; 01340 } 01341 01342 if(NULL != pValue) 01343 { 01344 for(i = 0; i < n; i++) 01345 { 01346 if(0 < i && i%2 == 0) 01347 { 01348 *p++ = '-'; 01349 } 01350 sprintf(p, "%02X", pValue[i]); 01351 while(*p) p++; 01352 } 01353 } 01354 else 01355 { 01356 strcpy(aBuf, "---unknown-epc-data-type---"); 01357 } 01358 } 01359 else 01360 { 01361 strcpy(aBuf, "---missing-epc-data---"); 01362 } 01363 printf("%-32s", aBuf); 01364 01365 /* 01366 * End of line 01367 */ 01368 printf("\n"); 01369 } 01370 01371 01385 void 01386 CMyApplication::handleReaderEventNotification ( 01387 CReaderEventNotificationData *pNtfData) 01388 { 01389 CAntennaEvent * pAntennaEvent; 01390 CReaderExceptionEvent * pReaderExceptionEvent; 01391 int nReported = 0; 01392 01393 pAntennaEvent = pNtfData->getAntennaEvent(); 01394 if(NULL != pAntennaEvent) 01395 { 01396 handleAntennaEvent(pAntennaEvent); 01397 nReported++; 01398 } 01399 01400 pReaderExceptionEvent = pNtfData->getReaderExceptionEvent(); 01401 if(NULL != pReaderExceptionEvent) 01402 { 01403 handleReaderExceptionEvent(pReaderExceptionEvent); 01404 nReported++; 01405 } 01406 01407 /* 01408 * Similarly handle other events here: 01409 * HoppingEvent 01410 * GPIEvent 01411 * ROSpecEvent 01412 * ReportBufferLevelWarningEvent 01413 * ReportBufferOverflowErrorEvent 01414 * RFSurveyEvent 01415 * AISpecEvent 01416 * ConnectionAttemptEvent 01417 * ConnectionCloseEvent 01418 * Custom 01419 */ 01420 01421 if(0 == nReported) 01422 { 01423 printf("NOTICE: Unexpected (unhandled) ReaderEvent\n"); 01424 } 01425 } 01426 01427 01439 void 01440 CMyApplication::handleAntennaEvent ( 01441 CAntennaEvent * pAntennaEvent) 01442 { 01443 EAntennaEventType eEventType; 01444 llrp_u16_t AntennaID; 01445 char * pStateStr; 01446 01447 eEventType = pAntennaEvent->getEventType(); 01448 AntennaID = pAntennaEvent->getAntennaID(); 01449 01450 switch(eEventType) 01451 { 01452 case AntennaEventType_Antenna_Disconnected: 01453 pStateStr = "disconnected"; 01454 break; 01455 01456 case AntennaEventType_Antenna_Connected: 01457 pStateStr = "connected"; 01458 break; 01459 01460 default: 01461 pStateStr = "?unknown-event?"; 01462 break; 01463 } 01464 01465 printf("NOTICE: Antenna %d is %s\n", AntennaID, pStateStr); 01466 } 01467 01468 01481 void 01482 CMyApplication::handleReaderExceptionEvent ( 01483 CReaderExceptionEvent * pReaderExceptionEvent) 01484 { 01485 llrp_utf8v_t Message; 01486 01487 Message = pReaderExceptionEvent->getMessage(); 01488 01489 if(0 < Message.m_nValue && NULL != Message.m_pValue) 01490 { 01491 printf("NOTICE: ReaderException '%.*s'\n", 01492 Message.m_nValue, Message.m_pValue); 01493 } 01494 else 01495 { 01496 printf("NOTICE: ReaderException but no message\n"); 01497 } 01498 } 01499 01500 01519 int 01520 CMyApplication::checkLLRPStatus ( 01521 CLLRPStatus * pLLRPStatus, 01522 char * pWhatStr) 01523 { 01524 /* 01525 * The LLRPStatus parameter is mandatory in all responses. 01526 * If it is missing there should have been a decode error. 01527 * This just makes sure (remember, this program is a 01528 * diagnostic and suppose to catch LTKC mistakes). 01529 */ 01530 if(NULL == pLLRPStatus) 01531 { 01532 printf("ERROR: %s missing LLRP status\n", pWhatStr); 01533 return -1; 01534 } 01535 01536 /* 01537 * Make sure the status is M_Success. 01538 * If it isn't, print the error string if one. 01539 * This does not try to pretty-print the status 01540 * code. To get that, run this program with -vv 01541 * and examine the XML output. 01542 */ 01543 if(StatusCode_M_Success != pLLRPStatus->getStatusCode()) 01544 { 01545 llrp_utf8v_t ErrorDesc; 01546 01547 ErrorDesc = pLLRPStatus->getErrorDescription(); 01548 01549 if(0 == ErrorDesc.m_nValue) 01550 { 01551 printf("ERROR: %s failed, no error description given\n", 01552 pWhatStr); 01553 } 01554 else 01555 { 01556 printf("ERROR: %s failed, %.*s\n", 01557 pWhatStr, ErrorDesc.m_nValue, ErrorDesc.m_pValue); 01558 } 01559 return -2; 01560 } 01561 01562 /* 01563 * Victory. Everything is fine. 01564 */ 01565 return 0; 01566 } 01567 01568 01592 CMessage * 01593 CMyApplication::transact ( 01594 CMessage * pSendMsg) 01595 { 01596 CConnection * pConn = m_pConnectionToReader; 01597 CMessage * pRspMsg; 01598 01599 /* 01600 * Print the XML text for the outbound message if 01601 * verbosity is 2 or higher. 01602 */ 01603 if(1 < m_Verbose) 01604 { 01605 printf("\n===================================\n"); 01606 printf("INFO: Transact sending\n"); 01607 printXMLMessage(pSendMsg); 01608 } 01609 01610 /* 01611 * Send the message, expect the response of certain type. 01612 * If LLRP::CConnection::transact() returns NULL then there was 01613 * an error. In that case we try to print the error details. 01614 */ 01615 pRspMsg = pConn->transact(pSendMsg, 5000); 01616 01617 if(NULL == pRspMsg) 01618 { 01619 const CErrorDetails * pError = pConn->getTransactError(); 01620 01621 printf("ERROR: %s transact failed, %s\n", 01622 pSendMsg->m_pType->m_pName, 01623 pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given"); 01624 01625 if(NULL != pError->m_pRefType) 01626 { 01627 printf("ERROR: ... reference type %s\n", 01628 pError->m_pRefType->m_pName); 01629 } 01630 01631 if(NULL != pError->m_pRefField) 01632 { 01633 printf("ERROR: ... reference field %s\n", 01634 pError->m_pRefField->m_pName); 01635 } 01636 01637 return NULL; 01638 } 01639 01640 /* 01641 * Print the XML text for the inbound message if 01642 * verbosity is 2 or higher. 01643 */ 01644 if(1 < m_Verbose) 01645 { 01646 printf("\n- - - - - - - - - - - - - - - - - -\n"); 01647 printf("INFO: Transact received response\n"); 01648 printXMLMessage(pRspMsg); 01649 } 01650 01651 /* 01652 * If it is an ERROR_MESSAGE (response from reader 01653 * when it can't understand the request), tattle 01654 * and declare defeat. 01655 */ 01656 if(&CERROR_MESSAGE::s_typeDescriptor == pRspMsg->m_pType) 01657 { 01658 const CTypeDescriptor * pResponseType; 01659 01660 pResponseType = pSendMsg->m_pType->m_pResponseType; 01661 01662 printf("ERROR: Received ERROR_MESSAGE instead of %s\n", 01663 pResponseType->m_pName); 01664 delete pRspMsg; 01665 pRspMsg = NULL; 01666 } 01667 01668 return pRspMsg; 01669 } 01670 01671 01696 CMessage * 01697 CMyApplication::recvMessage ( 01698 int nMaxMS) 01699 { 01700 CConnection * pConn = m_pConnectionToReader; 01701 CMessage * pMessage; 01702 01703 /* 01704 * Receive the message subject to a time limit 01705 */ 01706 pMessage = pConn->recvMessage(nMaxMS); 01707 01708 /* 01709 * If LLRP::CConnection::recvMessage() returns NULL then there was 01710 * an error. In that case we try to print the error details. 01711 */ 01712 if(NULL == pMessage) 01713 { 01714 const CErrorDetails * pError = pConn->getRecvError(); 01715 01716 printf("ERROR: recvMessage failed, %s\n", 01717 pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given"); 01718 01719 if(NULL != pError->m_pRefType) 01720 { 01721 printf("ERROR: ... reference type %s\n", 01722 pError->m_pRefType->m_pName); 01723 } 01724 01725 if(NULL != pError->m_pRefField) 01726 { 01727 printf("ERROR: ... reference field %s\n", 01728 pError->m_pRefField->m_pName); 01729 } 01730 01731 return NULL; 01732 } 01733 01734 /* 01735 * Print the XML text for the inbound message if 01736 * verbosity is 2 or higher. 01737 */ 01738 if(1 < m_Verbose) 01739 { 01740 printf("\n===================================\n"); 01741 printf("INFO: Message received\n"); 01742 printXMLMessage(pMessage); 01743 } 01744 01745 return pMessage; 01746 } 01747 01748 01766 int 01767 CMyApplication::sendMessage ( 01768 CMessage * pSendMsg) 01769 { 01770 CConnection * pConn = m_pConnectionToReader; 01771 01772 /* 01773 * Print the XML text for the outbound message if 01774 * verbosity is 2 or higher. 01775 */ 01776 if(1 < m_Verbose) 01777 { 01778 printf("\n===================================\n"); 01779 printf("INFO: Sending\n"); 01780 printXMLMessage(pSendMsg); 01781 } 01782 01783 /* 01784 * If LLRP::CConnection::sendMessage() returns other than RC_OK 01785 * then there was an error. In that case we try to print 01786 * the error details. 01787 */ 01788 if(RC_OK != pConn->sendMessage(pSendMsg)) 01789 { 01790 const CErrorDetails * pError = pConn->getSendError(); 01791 01792 printf("ERROR: %s sendMessage failed, %s\n", 01793 pSendMsg->m_pType->m_pName, 01794 pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given"); 01795 01796 if(NULL != pError->m_pRefType) 01797 { 01798 printf("ERROR: ... reference type %s\n", 01799 pError->m_pRefType->m_pName); 01800 } 01801 01802 if(NULL != pError->m_pRefField) 01803 { 01804 printf("ERROR: ... reference field %s\n", 01805 pError->m_pRefField->m_pName); 01806 } 01807 01808 return -1; 01809 } 01810 01811 /* 01812 * Victory 01813 */ 01814 return 0; 01815 } 01816 01817 01831 void 01832 CMyApplication::printXMLMessage ( 01833 CMessage * pMessage) 01834 { 01835 char aBuf[100*1024]; 01836 01837 /* 01838 * Convert the message to an XML string. 01839 * This fills the buffer with either the XML string 01840 * or an error message. The return value could 01841 * be checked. 01842 */ 01843 01844 pMessage->toXMLString(aBuf, sizeof aBuf); 01845 01846 /* 01847 * Print the XML Text to the standard output. 01848 */ 01849 printf("%s", aBuf); 01850 }