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 00050 #include <stdio.h> 00051 #include "ltkcpp.h" 00052 #include "impinj_ltkcpp.h" 00053 #include "time.h" 00054 00055 using namespace LLRP; 00056 00057 /* 00058 ** Sorry, we use this linux safe method 00059 ** to print buffers. WIndows has the same 00060 ** method, but by a different name 00061 */ 00062 #if (WIN32) 00063 #define snprintf _snprintf 00064 #endif 00065 00066 class CMyApplication 00067 { 00068 private: 00069 00070 unsigned int m_PowerLevelIndex; 00071 unsigned int m_messageID; 00072 00073 public: 00075 int m_Verbose; 00076 00078 CConnection * m_pConnectionToReader; 00079 00080 inline 00081 CMyApplication (void) 00082 : m_Verbose(0), m_pConnectionToReader(NULL) 00083 { 00084 m_messageID = 0; 00085 } 00086 00087 int 00088 run ( 00089 char * pReaderHostName); 00090 00091 int 00092 checkConnectionStatus (void); 00093 00094 int 00095 enableImpinjExtensions (void); 00096 00097 int 00098 resetConfigurationToFactoryDefaults (void); 00099 00100 int 00101 getReaderCapabilities(void); 00102 00103 int 00104 setImpinjReaderConfig(void); 00105 00106 int 00107 addROSpec (void); 00108 00109 int 00110 enableROSpec (void); 00111 00112 int 00113 startROSpec (void); 00114 00115 int 00116 stopROSpec (void); 00117 00118 int 00119 addAccessSpec(void); 00120 00121 int 00122 enableAccessSpec(void); 00123 00124 int 00125 awaitAndPrintReport (int timeoutSec); 00126 00127 void 00128 printTagReportData ( 00129 CRO_ACCESS_REPORT * pRO_ACCESS_REPORT); 00130 00131 void 00132 printOneTagReportData ( 00133 CTagReportData * pTagReportData); 00134 00135 void 00136 formatOneEPC ( 00137 CParameter * pEpcParameter, 00138 char * buf, 00139 int buflen); 00140 00141 void 00142 formatOneReadResult ( 00143 CParameter * pEpcParameter, 00144 char * buf, 00145 int buflen); 00146 00147 void 00148 handleReaderEventNotification ( 00149 CReaderEventNotificationData *pNtfData); 00150 00151 void 00152 handleAntennaEvent ( 00153 CAntennaEvent * pAntennaEvent); 00154 00155 void 00156 handleReaderExceptionEvent ( 00157 CReaderExceptionEvent * pReaderExceptionEvent); 00158 00159 int 00160 checkLLRPStatus ( 00161 CLLRPStatus * pLLRPStatus, 00162 char * pWhatStr); 00163 00164 CMessage * 00165 transact ( 00166 CMessage * pSendMsg); 00167 00168 CMessage * 00169 recvMessage ( 00170 int nMaxMS); 00171 00172 int 00173 sendMessage ( 00174 CMessage * pSendMsg); 00175 00176 void 00177 printXMLMessage ( 00178 CMessage * pMessage); 00179 }; 00180 00181 00182 /* BEGIN forward declarations */ 00183 int 00184 main ( 00185 int ac, 00186 char * av[]); 00187 00188 void 00189 usage ( 00190 char * pProgName); 00191 /* END forward declarations */ 00192 00193 00209 int 00210 main ( 00211 int ac, 00212 char * av[]) 00213 { 00214 CMyApplication myApp; 00215 char * pReaderHostName; 00216 int rc; 00217 00218 /* 00219 * Process comand arguments, determine reader name 00220 * and verbosity level. 00221 */ 00222 if(ac == 2) 00223 { 00224 pReaderHostName = av[1]; 00225 } 00226 else if(ac == 3) 00227 { 00228 char * p = av[1]; 00229 00230 while(*p) 00231 { 00232 switch(*p++) 00233 { 00234 case '-': /* linux conventional option warn char */ 00235 case '/': /* Windows/DOS conventional option warn char */ 00236 break; 00237 00238 case 'v': 00239 case 'V': 00240 myApp.m_Verbose++; 00241 break; 00242 00243 default: 00244 usage(av[0]); 00245 /* no return */ 00246 break; 00247 } 00248 } 00249 00250 pReaderHostName = av[2]; 00251 } 00252 else 00253 { 00254 usage(av[0]); 00255 /* no return */ 00256 } 00257 00258 /* 00259 * Run application, capture return value for exit status 00260 */ 00261 rc = myApp.run(pReaderHostName); 00262 00263 printf("INFO: Done\n"); 00264 00265 /* 00266 * Exit with the right status. 00267 */ 00268 if(0 == rc) 00269 { 00270 exit(0); 00271 } 00272 else 00273 { 00274 exit(2); 00275 } 00276 /*NOTREACHED*/ 00277 } 00278 00279 00291 void 00292 usage ( 00293 char * pProgName) 00294 { 00295 #ifdef linux 00296 printf("Usage: %s [-v[v]] READERHOSTNAME\n", pProgName); 00297 printf("\n"); 00298 printf("Each -v increases verbosity level\n"); 00299 #endif /* linux */ 00300 #ifdef WIN32 00301 printf("Usage: %s [/v[v]] READERHOSTNAME\n", pProgName); 00302 printf("\n"); 00303 printf("Each /v increases verbosity level\n"); 00304 #endif /* WIN32 */ 00305 exit(1); 00306 } 00307 00308 00353 int 00354 CMyApplication::run ( 00355 char * pReaderHostName) 00356 { 00357 CTypeRegistry * pTypeRegistry; 00358 CConnection * pConn; 00359 int rc; 00360 00361 /* 00362 * Allocate the type registry. This is needed 00363 * by the connection to decode. 00364 */ 00365 pTypeRegistry = getTheTypeRegistry(); 00366 if(NULL == pTypeRegistry) 00367 { 00368 printf("ERROR: getTheTypeRegistry failed\n"); 00369 return -1; 00370 } 00371 00372 /* 00373 * Enroll impinj extension types into the 00374 * type registry, in preparation for using 00375 * Impinj extension params. 00376 */ 00377 LLRP::enrollImpinjTypesIntoRegistry(pTypeRegistry); 00378 00379 /* 00380 * Construct a connection (LLRP::CConnection). 00381 * Using a 32kb max frame size for send/recv. 00382 * The connection object is ready for business 00383 * but not actually connected to the reader yet. 00384 */ 00385 pConn = new CConnection(pTypeRegistry, 32u*1024u); 00386 if(NULL == pConn) 00387 { 00388 printf("ERROR: new CConnection failed\n"); 00389 return -2; 00390 } 00391 00392 /* 00393 * Open the connection to the reader 00394 */ 00395 if(m_Verbose) 00396 { 00397 printf("INFO: Connecting to %s....\n", pReaderHostName); 00398 } 00399 00400 rc = pConn->openConnectionToReader(pReaderHostName); 00401 if(0 != rc) 00402 { 00403 printf("ERROR: connect: %s (%d)\n", pConn->getConnectError(), rc); 00404 delete pConn; 00405 return -3; 00406 } 00407 00408 /* 00409 * Record the pointer to the connection object so other 00410 * routines can use it. 00411 */ 00412 m_pConnectionToReader = pConn; 00413 00414 if(m_Verbose) 00415 { 00416 printf("INFO: Connected, checking status....\n"); 00417 } 00418 00419 /* 00420 * Commence the sequence and check for errors as we go. 00421 * See comments for each routine for details. 00422 * Each routine prints messages. 00423 */ 00424 rc = 1; 00425 if(0 == checkConnectionStatus()) 00426 { 00427 rc = 2; 00428 if(0 == enableImpinjExtensions()) 00429 { 00430 rc = 3; 00431 if(0 == resetConfigurationToFactoryDefaults()) 00432 { 00433 rc = 4; 00434 if(0 == getReaderCapabilities()) 00435 { 00436 rc = 5; 00437 if(0 == setImpinjReaderConfig()) 00438 { 00439 rc = 6; 00440 if(0 == addROSpec()) 00441 { 00442 rc = 7; 00443 if(0 == addAccessSpec()) 00444 { 00445 rc = 8; 00446 if(0 == enableAccessSpec()) 00447 { 00448 rc = 9; 00449 if(0 == enableROSpec()) 00450 { 00451 rc = 10; 00452 if(0 == startROSpec()) 00453 { 00454 rc = 11; 00455 if(0 == awaitAndPrintReport(60)) 00456 { 00457 rc = 12; 00458 if(0 == stopROSpec()) 00459 { 00460 rc = 0; 00461 } 00462 } 00463 } 00464 } 00465 } 00466 } 00467 } 00468 } 00469 } 00470 } 00471 00472 /* 00473 * After we're done, try to leave the reader 00474 * in a clean state for next use. This is best 00475 * effort and no checking of the result is done. 00476 */ 00477 if(m_Verbose) 00478 { 00479 printf("INFO: Clean up reader configuration...\n"); 00480 } 00481 resetConfigurationToFactoryDefaults(); 00482 } 00483 } 00484 00485 if(m_Verbose) 00486 { 00487 printf("INFO: Finished\n"); 00488 } 00489 00490 /* 00491 * Close the connection and release its resources 00492 */ 00493 pConn->closeConnectionToReader(); 00494 delete pConn; 00495 00496 /* 00497 * Done with the registry. 00498 */ 00499 delete pTypeRegistry; 00500 00501 /* 00502 * When we get here all allocated memory should have been deallocated. 00503 */ 00504 00505 return rc; 00506 } 00507 00508 00539 int 00540 CMyApplication::checkConnectionStatus (void) 00541 { 00542 CMessage * pMessage; 00543 CREADER_EVENT_NOTIFICATION *pNtf; 00544 CReaderEventNotificationData *pNtfData; 00545 CConnectionAttemptEvent * pEvent; 00546 00547 /* 00548 * Expect the notification within 10 seconds. 00549 * It is suppose to be the very first message sent. 00550 */ 00551 pMessage = recvMessage(10000); 00552 00553 /* 00554 * recvMessage() returns NULL if something went wrong. 00555 */ 00556 if(NULL == pMessage) 00557 { 00558 /* recvMessage already tattled */ 00559 goto fail; 00560 } 00561 00562 /* 00563 * Check to make sure the message is of the right type. 00564 * The type label (pointer) in the message should be 00565 * the type descriptor for READER_EVENT_NOTIFICATION. 00566 */ 00567 if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor != pMessage->m_pType) 00568 { 00569 goto fail; 00570 } 00571 00572 /* 00573 * Now that we are sure it is a READER_EVENT_NOTIFICATION, 00574 * traverse to the ReaderEventNotificationData parameter. 00575 */ 00576 pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage; 00577 pNtfData = pNtf->getReaderEventNotificationData(); 00578 if(NULL == pNtfData) 00579 { 00580 goto fail; 00581 } 00582 00583 /* 00584 * The ConnectionAttemptEvent parameter must be present. 00585 */ 00586 pEvent = pNtfData->getConnectionAttemptEvent(); 00587 if(NULL == pEvent) 00588 { 00589 goto fail; 00590 } 00591 00592 /* 00593 * The status in the ConnectionAttemptEvent parameter 00594 * must indicate connection success. 00595 */ 00596 if(ConnectionAttemptStatusType_Success != pEvent->getStatus()) 00597 { 00598 goto fail; 00599 } 00600 00601 /* 00602 * Done with the message 00603 */ 00604 delete pMessage; 00605 00606 if(m_Verbose) 00607 { 00608 printf("INFO: Connection status OK\n"); 00609 } 00610 00611 /* 00612 * Victory. 00613 */ 00614 return 0; 00615 00616 fail: 00617 /* 00618 * Something went wrong. Tattle. Clean up. Return error. 00619 */ 00620 printf("ERROR: checkConnectionStatus failed\n"); 00621 delete pMessage; 00622 return -1; 00623 } 00624 00642 int 00643 CMyApplication::enableImpinjExtensions (void) 00644 { 00645 CIMPINJ_ENABLE_EXTENSIONS * pCmd; 00646 CMessage * pRspMsg; 00647 CIMPINJ_ENABLE_EXTENSIONS_RESPONSE *pRsp; 00648 00649 /* 00650 * Compose the command message 00651 */ 00652 pCmd = new CIMPINJ_ENABLE_EXTENSIONS(); 00653 pCmd->setMessageID(m_messageID++); 00654 /* 00655 * Send the message, expect the response of certain type 00656 */ 00657 pRspMsg = transact(pCmd); 00658 00659 /* 00660 * Done with the command message 00661 */ 00662 delete pCmd; 00663 00664 /* 00665 * transact() returns NULL if something went wrong. 00666 */ 00667 if(NULL == pRspMsg) 00668 { 00669 /* transact already tattled */ 00670 return -1; 00671 } 00672 00673 /* 00674 * Cast to a CIMPINJ_ENABLE_EXTENSIONS_RESPONSE message. 00675 */ 00676 pRsp = (CIMPINJ_ENABLE_EXTENSIONS_RESPONSE *) pRspMsg; 00677 00678 /* 00679 * Check the LLRPStatus parameter. 00680 */ 00681 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), 00682 "enableImpinjExtensions")) 00683 { 00684 /* checkLLRPStatus already tattled */ 00685 delete pRspMsg; 00686 return -1; 00687 } 00688 00689 /* 00690 * Done with the response message. 00691 */ 00692 delete pRspMsg; 00693 00694 /* 00695 * Tattle progress, maybe 00696 */ 00697 if(m_Verbose) 00698 { 00699 printf("INFO: Impinj Extensions are enabled\n"); 00700 } 00701 00702 /* 00703 * Victory. 00704 */ 00705 return 0; 00706 } 00707 00728 int 00729 CMyApplication::resetConfigurationToFactoryDefaults (void) 00730 { 00731 CSET_READER_CONFIG * pCmd; 00732 CMessage * pRspMsg; 00733 CSET_READER_CONFIG_RESPONSE *pRsp; 00734 00735 /* 00736 * Compose the command message 00737 */ 00738 pCmd = new CSET_READER_CONFIG(); 00739 pCmd->setMessageID(m_messageID++); 00740 pCmd->setResetToFactoryDefault(1); 00741 00742 /* 00743 * Send the message, expect the response of certain type 00744 */ 00745 pRspMsg = transact(pCmd); 00746 00747 /* 00748 * Done with the command message 00749 */ 00750 delete pCmd; 00751 00752 /* 00753 * transact() returns NULL if something went wrong. 00754 */ 00755 if(NULL == pRspMsg) 00756 { 00757 /* transact already tattled */ 00758 return -1; 00759 } 00760 00761 /* 00762 * Cast to a SET_READER_CONFIG_RESPONSE message. 00763 */ 00764 pRsp = (CSET_READER_CONFIG_RESPONSE *) pRspMsg; 00765 00766 /* 00767 * Check the LLRPStatus parameter. 00768 */ 00769 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), 00770 "resetConfigurationToFactoryDefaults")) 00771 { 00772 /* checkLLRPStatus already tattled */ 00773 delete pRspMsg; 00774 return -1; 00775 } 00776 00777 /* 00778 * Done with the response message. 00779 */ 00780 delete pRspMsg; 00781 00782 /* 00783 * Tattle progress, maybe 00784 */ 00785 if(m_Verbose) 00786 { 00787 printf("INFO: Configuration reset to factory defaults\n"); 00788 } 00789 00790 /* 00791 * Victory. 00792 */ 00793 return 0; 00794 } 00795 00796 00810 int 00811 CMyApplication::getReaderCapabilities(void) 00812 { 00813 CGET_READER_CAPABILITIES *pCmd; 00814 CMessage * pRspMsg; 00815 CGET_READER_CAPABILITIES_RESPONSE *pRsp; 00816 CGeneralDeviceCapabilities *pDevCap; 00817 00818 00819 /* 00820 * Compose the command message 00821 */ 00822 pCmd = new CGET_READER_CAPABILITIES(); 00823 pCmd->setMessageID(m_messageID++); 00824 pCmd->setRequestedData(GetReaderCapabilitiesRequestedData_All); 00825 00826 /* 00827 * Send the message, expect the response of certain type 00828 */ 00829 pRspMsg = transact(pCmd); 00830 00831 /* 00832 * Done with the command message 00833 */ 00834 delete pCmd; 00835 00836 /* 00837 * transact() returns NULL if something went wrong. 00838 */ 00839 if(NULL == pRspMsg) 00840 { 00841 /* transact already tattled */ 00842 return -1; 00843 } 00844 00845 /* 00846 * Cast to a CGET_READER_CAPABILITIES_RESPONSE message. 00847 */ 00848 pRsp = (CGET_READER_CAPABILITIES_RESPONSE *) pRspMsg; 00849 00850 /* 00851 * Check the LLRPStatus parameter. 00852 */ 00853 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), 00854 "getReaderCapabilities")) 00855 { 00856 /* checkLLRPStatus already tattled */ 00857 delete pRspMsg; 00858 return -1; 00859 } 00860 00861 /* 00862 ** Get out the general device capabilities 00863 */ 00864 if(NULL == (pDevCap = pRsp->getGeneralDeviceCapabilities())) 00865 { 00866 delete pRspMsg; 00867 return -1; 00868 } 00869 /* if this parameter is missing, or if this is not an Impinj 00870 ** reader, we can't determine its capabilities so we exit 00871 ** Impinj Private Enterprise NUmber is 25882 */ 00872 if( (NULL == (pDevCap = pRsp->getGeneralDeviceCapabilities())) || 00873 (25882 != pDevCap->getDeviceManufacturerName())) 00874 { 00875 delete pRspMsg; 00876 return -1; 00877 } 00878 00879 /* 00880 * Done with the response message. 00881 */ 00882 delete pRspMsg; 00883 00884 /* 00885 * Tattle progress, maybe 00886 */ 00887 if(m_Verbose) 00888 { 00889 printf("INFO: Found LLRP Capabilities \n"); 00890 } 00891 00892 /* 00893 * Victory. 00894 */ 00895 return 0; 00896 } 00897 00898 00975 int 00976 CMyApplication::setImpinjReaderConfig(void) 00977 { 00978 CSET_READER_CONFIG *pCmd; 00979 CMessage * pRspMsg; 00980 CSET_READER_CONFIG_RESPONSE *pRsp; 00981 00982 /* 00983 * Compose the command message 00984 */ 00985 pCmd = new CSET_READER_CONFIG(); 00986 pCmd->setMessageID(m_messageID++); 00987 00988 CAntennaConfiguration *pAnt = new(CAntennaConfiguration); 00989 00990 /* 00991 ** Apply this configuration to all antennas 00992 */ 00993 pAnt->setAntennaID(0); 00994 00995 /* 00996 ** Create the container Inventory command to hold all the parameters 00997 */ 00998 CC1G2InventoryCommand *pC1G2Inv = new CC1G2InventoryCommand(); 00999 01000 /* 01001 ** set the Impinj Low Duty Cycle mode as per the use case 01002 */ 01003 CImpinjLowDutyCycle *pImpLdc = new CImpinjLowDutyCycle(); 01004 pImpLdc->setEmptyFieldTimeout(10000); 01005 pImpLdc->setFieldPingInterval(200); 01006 pImpLdc->setLowDutyCycleMode(ImpinjLowDutyCycleMode_Enabled); 01007 pC1G2Inv->addCustom(pImpLdc); 01008 01009 /* 01010 ** Don't forget to add the InventoryCommand to the antenna 01011 ** configuration, and then add the antenna configuration to the 01012 ** config message 01013 */ 01014 pAnt->addAirProtocolInventoryCommandSettings(pC1G2Inv); 01015 pCmd->addAntennaConfiguration(pAnt); 01016 01017 /* 01018 ** Don't generate reports automatically, wait until the host 01019 ** asks for a report 01020 */ 01021 CROReportSpec *pROrs = new CROReportSpec(); 01022 pROrs->setROReportTrigger(ROReportTriggerType_None); 01023 pROrs->setN(0); 01024 01025 /* 01026 ** Turn off off report data that we don't need since our use 01027 ** case suggests we are bandwidth constrained 01028 */ 01029 CTagReportContentSelector *pROcontent = new CTagReportContentSelector(); 01030 pROcontent->setEnableAccessSpecID(false); 01031 pROcontent->setEnableAntennaID(false); 01032 pROcontent->setEnableChannelIndex(false); 01033 pROcontent->setEnableFirstSeenTimestamp(true); 01034 pROcontent->setEnableInventoryParameterSpecID(false); 01035 pROcontent->setEnableLastSeenTimestamp(false); 01036 pROcontent->setEnablePeakRSSI(false); 01037 pROcontent->setEnableROSpecID(false); 01038 pROcontent->setEnableSpecIndex(false); 01039 pROcontent->setEnableTagSeenCount(false); 01040 CC1G2EPCMemorySelector *pC1G2Mem = new CC1G2EPCMemorySelector(); 01041 pC1G2Mem->setEnableCRC(false); 01042 pC1G2Mem->setEnablePCBits(false); 01043 pROcontent->addAirProtocolEPCMemorySelector(pC1G2Mem); 01044 01045 pROrs->setTagReportContentSelector(pROcontent); 01046 pCmd->setROReportSpec(pROrs); 01047 01048 /* 01049 * Send the message, expect the response of certain type 01050 */ 01051 pRspMsg = transact(pCmd); 01052 01053 /* 01054 * Done with the command message 01055 */ 01056 delete pCmd; 01057 01058 /* 01059 * transact() returns NULL if something went wrong. 01060 */ 01061 if(NULL == pRspMsg) 01062 { 01063 /* transact already tattled */ 01064 return -1; 01065 } 01066 01067 /* 01068 * Cast to a CSET_READER_CONFIG_RESPONSE message. 01069 */ 01070 pRsp = (CSET_READER_CONFIG_RESPONSE *) pRspMsg; 01071 01072 /* 01073 * Check the LLRPStatus parameter. 01074 */ 01075 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), 01076 "setImpinjReaderConfig")) 01077 { 01078 /* checkLLRPStatus already tattled */ 01079 delete pRspMsg; 01080 return -1; 01081 } 01082 01083 /* 01084 * Done with the response message. 01085 */ 01086 delete pRspMsg; 01087 01088 /* 01089 * Tattle progress, maybe 01090 */ 01091 if(m_Verbose) 01092 { 01093 printf("INFO: Set Impinj Reader Configuration \n"); 01094 } 01095 01096 /* 01097 * Victory. 01098 */ 01099 return 0; 01100 } 01101 01179 int 01180 CMyApplication::addROSpec (void) 01181 { 01182 CROSpecStartTrigger * pROSpecStartTrigger = 01183 new CROSpecStartTrigger(); 01184 pROSpecStartTrigger->setROSpecStartTriggerType( 01185 ROSpecStartTriggerType_Null); 01186 01187 CROSpecStopTrigger * pROSpecStopTrigger = new CROSpecStopTrigger(); 01188 pROSpecStopTrigger->setROSpecStopTriggerType(ROSpecStopTriggerType_Null); 01189 pROSpecStopTrigger->setDurationTriggerValue(0); /* n/a */ 01190 01191 CROBoundarySpec * pROBoundarySpec = new CROBoundarySpec(); 01192 pROBoundarySpec->setROSpecStartTrigger(pROSpecStartTrigger); 01193 pROBoundarySpec->setROSpecStopTrigger(pROSpecStopTrigger); 01194 01195 CAISpecStopTrigger * pAISpecStopTrigger = new CAISpecStopTrigger(); 01196 pAISpecStopTrigger->setAISpecStopTriggerType( 01197 AISpecStopTriggerType_Null); 01198 pAISpecStopTrigger->setDurationTrigger(0); 01199 01200 CInventoryParameterSpec * pInventoryParameterSpec = 01201 new CInventoryParameterSpec(); 01202 pInventoryParameterSpec->setInventoryParameterSpecID(1234); 01203 pInventoryParameterSpec->setProtocolID(AirProtocols_EPCGlobalClass1Gen2); 01204 01205 /* make the bit pattern for the GID mask */ 01206 llrp_u1v_t gidMask = llrp_u1v_t(8); 01207 gidMask.m_nBit = 8; 01208 gidMask.m_pValue[0] = 0x33; 01209 01210 /* build the mask for the GID */ 01211 CC1G2TagInventoryMask *pMaskGID = new(CC1G2TagInventoryMask); 01212 pMaskGID->setMB(1); 01213 pMaskGID->setPointer(32); 01214 pMaskGID->setTagMask(gidMask); 01215 01216 /* build the inventory action for the GID filter */ 01217 CC1G2TagInventoryStateUnawareFilterAction *pActionGID= 01218 new CC1G2TagInventoryStateUnawareFilterAction(); 01219 pActionGID->setAction(C1G2StateUnawareAction_Select_Unselect); 01220 01221 /* Build the filter for the GID */ 01222 CC1G2Filter *pFilterGID = new CC1G2Filter(); 01223 pFilterGID->setC1G2TagInventoryStateUnawareFilterAction(pActionGID); 01224 pFilterGID->setC1G2TagInventoryMask(pMaskGID); 01225 pFilterGID->setT(C1G2TruncateAction_Do_Not_Truncate); 01226 01227 /* make the bit pattern for the GRAI mask */ 01228 llrp_u1v_t graiMask = llrp_u1v_t(8); 01229 graiMask.m_nBit = 8; 01230 graiMask.m_pValue[0] = 0x35; 01231 01232 /* build the mask for the GRAI */ 01233 CC1G2TagInventoryMask *pMaskGRAI = new(CC1G2TagInventoryMask); 01234 pMaskGRAI->setMB(1); 01235 pMaskGRAI->setPointer(32); 01236 pMaskGRAI->setTagMask(graiMask); 01237 01238 /* build the inventory action for the FRAI filter */ 01239 CC1G2TagInventoryStateUnawareFilterAction *pActionGRAI= 01240 new CC1G2TagInventoryStateUnawareFilterAction(); 01241 pActionGRAI->setAction(C1G2StateUnawareAction_Select_DoNothing); 01242 01243 /* Build the filter for the GRAI */ 01244 CC1G2Filter *pFilterGRAI = new CC1G2Filter(); 01245 pFilterGRAI->setC1G2TagInventoryStateUnawareFilterAction(pActionGRAI); 01246 pFilterGRAI->setC1G2TagInventoryMask(pMaskGRAI); 01247 pFilterGRAI->setT(C1G2TruncateAction_Do_Not_Truncate); 01248 01249 /* build the inventory command and add both filters */ 01250 CC1G2InventoryCommand *pInvCmd = new CC1G2InventoryCommand(); 01251 pInvCmd->setTagInventoryStateAware(false); 01252 pInvCmd->addC1G2Filter(pFilterGID); 01253 pInvCmd->addC1G2Filter(pFilterGRAI); 01254 01255 /* Build the antennaConfiguration to Contain this */ 01256 CAntennaConfiguration * pAntennaConfiguration = 01257 new CAntennaConfiguration(); 01258 pAntennaConfiguration->setAntennaID(0); 01259 pAntennaConfiguration->addAirProtocolInventoryCommandSettings(pInvCmd); 01260 01261 /* don't forget to add this to the INventory Parameter Spec above */ 01262 pInventoryParameterSpec->addAntennaConfiguration(pAntennaConfiguration); 01263 01264 /* 01265 ** Use all Antennas 01266 */ 01267 llrp_u16v_t AntennaIDs = llrp_u16v_t(1); 01268 AntennaIDs.m_pValue[0] = 0; 01269 01270 CAISpec * pAISpec = new CAISpec(); 01271 pAISpec->setAntennaIDs(AntennaIDs); 01272 pAISpec->setAISpecStopTrigger(pAISpecStopTrigger); 01273 pAISpec->addInventoryParameterSpec(pInventoryParameterSpec); 01274 01275 CROSpec * pROSpec = new CROSpec(); 01276 pROSpec->setROSpecID(1111); 01277 pROSpec->setPriority(0); 01278 pROSpec->setCurrentState(ROSpecState_Disabled); 01279 pROSpec->setROBoundarySpec(pROBoundarySpec); 01280 pROSpec->addSpecParameter(pAISpec); 01281 01282 CADD_ROSPEC * pCmd; 01283 CMessage * pRspMsg; 01284 CADD_ROSPEC_RESPONSE * pRsp; 01285 01286 /* 01287 * Compose the command message. 01288 * N.B.: After the message is composed, all the parameters 01289 * constructed, immediately above, are considered "owned" 01290 * by the command message. When it is destructed so 01291 * too will the parameters be. 01292 */ 01293 pCmd = new CADD_ROSPEC(); 01294 pCmd->setMessageID(m_messageID++); 01295 pCmd->setROSpec(pROSpec); 01296 01297 /* 01298 * Send the message, expect the response of certain type 01299 */ 01300 pRspMsg = transact(pCmd); 01301 01302 /* 01303 * Done with the command message. 01304 * N.B.: And the parameters 01305 */ 01306 delete pCmd; 01307 01308 /* 01309 * transact() returns NULL if something went wrong. 01310 */ 01311 if(NULL == pRspMsg) 01312 { 01313 /* transact already tattled */ 01314 return -1; 01315 } 01316 01317 /* 01318 * Cast to a ADD_ROSPEC_RESPONSE message. 01319 */ 01320 pRsp = (CADD_ROSPEC_RESPONSE *) pRspMsg; 01321 01322 /* 01323 * Check the LLRPStatus parameter. 01324 */ 01325 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "addROSpec")) 01326 { 01327 /* checkLLRPStatus already tattled */ 01328 delete pRspMsg; 01329 return -1; 01330 } 01331 01332 /* 01333 * Done with the response message. 01334 */ 01335 delete pRspMsg; 01336 01337 /* 01338 * Tattle progress, maybe 01339 */ 01340 if(m_Verbose) 01341 { 01342 printf("INFO: ROSpec added\n"); 01343 } 01344 01345 /* 01346 * Victory. 01347 */ 01348 return 0; 01349 } 01350 01351 01369 int 01370 CMyApplication::enableROSpec (void) 01371 { 01372 CENABLE_ROSPEC * pCmd; 01373 CMessage * pRspMsg; 01374 CENABLE_ROSPEC_RESPONSE * pRsp; 01375 01376 /* 01377 * Compose the command message 01378 */ 01379 pCmd = new CENABLE_ROSPEC(); 01380 pCmd->setMessageID(m_messageID++); 01381 pCmd->setROSpecID(1111); 01382 01383 /* 01384 * Send the message, expect the response of certain type 01385 */ 01386 pRspMsg = transact(pCmd); 01387 01388 /* 01389 * Done with the command message 01390 */ 01391 delete pCmd; 01392 01393 /* 01394 * transact() returns NULL if something went wrong. 01395 */ 01396 if(NULL == pRspMsg) 01397 { 01398 /* transact already tattled */ 01399 return -1; 01400 } 01401 01402 /* 01403 * Cast to a ENABLE_ROSPEC_RESPONSE message. 01404 */ 01405 pRsp = (CENABLE_ROSPEC_RESPONSE *) pRspMsg; 01406 01407 /* 01408 * Check the LLRPStatus parameter. 01409 */ 01410 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "enableROSpec")) 01411 { 01412 /* checkLLRPStatus already tattled */ 01413 delete pRspMsg; 01414 return -1; 01415 } 01416 01417 /* 01418 * Done with the response message. 01419 */ 01420 delete pRspMsg; 01421 01422 /* 01423 * Tattle progress, maybe 01424 */ 01425 if(m_Verbose) 01426 { 01427 printf("INFO: ROSpec enabled\n"); 01428 } 01429 01430 /* 01431 * Victory. 01432 */ 01433 return 0; 01434 } 01435 01436 01454 int 01455 CMyApplication::startROSpec (void) 01456 { 01457 CSTART_ROSPEC * pCmd; 01458 CMessage * pRspMsg; 01459 CSTART_ROSPEC_RESPONSE * pRsp; 01460 01461 /* 01462 * Compose the command message 01463 */ 01464 pCmd = new CSTART_ROSPEC(); 01465 pCmd->setMessageID(m_messageID++); 01466 pCmd->setROSpecID(1111); 01467 01468 /* 01469 * Send the message, expect the response of certain type 01470 */ 01471 pRspMsg = transact(pCmd); 01472 01473 /* 01474 * Done with the command message 01475 */ 01476 delete pCmd; 01477 01478 /* 01479 * transact() returns NULL if something went wrong. 01480 */ 01481 if(NULL == pRspMsg) 01482 { 01483 /* transact already tattled */ 01484 return -1; 01485 } 01486 01487 /* 01488 * Cast to a START_ROSPEC_RESPONSE message. 01489 */ 01490 pRsp = (CSTART_ROSPEC_RESPONSE *) pRspMsg; 01491 01492 /* 01493 * Check the LLRPStatus parameter. 01494 */ 01495 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "startROSpec")) 01496 { 01497 /* checkLLRPStatus already tattled */ 01498 delete pRspMsg; 01499 return -1; 01500 } 01501 01502 /* 01503 * Done with the response message. 01504 */ 01505 delete pRspMsg; 01506 01507 /* 01508 * Tattle progress 01509 */ 01510 if(m_Verbose) 01511 { 01512 printf("INFO: ROSpec started\n"); 01513 } 01514 01515 /* 01516 * Victory. 01517 */ 01518 return 0; 01519 } 01520 01538 int 01539 CMyApplication::stopROSpec (void) 01540 { 01541 CSTOP_ROSPEC * pCmd; 01542 CMessage * pRspMsg; 01543 CSTOP_ROSPEC_RESPONSE * pRsp; 01544 01545 /* 01546 * Compose the command message 01547 */ 01548 pCmd = new CSTOP_ROSPEC(); 01549 pCmd->setMessageID(m_messageID++); 01550 pCmd->setROSpecID(1111); 01551 01552 /* 01553 * Send the message, expect the response of certain type 01554 */ 01555 pRspMsg = transact(pCmd); 01556 01557 /* 01558 * Done with the command message 01559 */ 01560 delete pCmd; 01561 01562 /* 01563 * transact() returns NULL if something went wrong. 01564 */ 01565 if(NULL == pRspMsg) 01566 { 01567 /* transact already tattled */ 01568 return -1; 01569 } 01570 01571 /* 01572 * Cast to a STOP_ROSPEC_RESPONSE message. 01573 */ 01574 pRsp = (CSTOP_ROSPEC_RESPONSE *) pRspMsg; 01575 01576 /* 01577 * Check the LLRPStatus parameter. 01578 */ 01579 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "stopROSpec")) 01580 { 01581 /* checkLLRPStatus already tattled */ 01582 delete pRspMsg; 01583 return -1; 01584 } 01585 01586 /* 01587 * Done with the response message. 01588 */ 01589 delete pRspMsg; 01590 01591 /* 01592 * Tattle progress 01593 */ 01594 if(m_Verbose) 01595 { 01596 printf("INFO: ROSpec stopped\n"); 01597 } 01598 01599 /* 01600 * Victory. 01601 */ 01602 return 0; 01603 } 01604 01660 int 01661 CMyApplication::addAccessSpec (void) 01662 { 01663 CADD_ACCESSSPEC * pCmd; 01664 CMessage * pRspMsg; 01665 CADD_ACCESSSPEC_RESPONSE * pRsp; 01666 01667 pCmd = new CADD_ACCESSSPEC(); 01668 pCmd->setMessageID(m_messageID++); 01669 01670 /* build the C1G2Target Tag with the AccessSpec filter */ 01671 CC1G2TargetTag *ptargetTag = new CC1G2TargetTag(); 01672 ptargetTag->setMatch(true); 01673 ptargetTag->setMB(1); 01674 ptargetTag->setPointer(16); 01675 01676 llrp_u1v_t tagData = llrp_u1v_t(24); 01677 tagData.m_nBit = 24; 01678 tagData.m_pValue[0] = 0x30; 01679 tagData.m_pValue[1] = 0x00; 01680 tagData.m_pValue[2] = 0x35; 01681 ptargetTag->setTagData(tagData); 01682 01683 llrp_u1v_t tagMask = llrp_u1v_t(24); 01684 tagMask.m_nBit = 24; 01685 tagMask.m_pValue[0] = 0xf8; 01686 tagMask.m_pValue[1] = 0x00; 01687 tagMask.m_pValue[2] = 0xff; 01688 ptargetTag->setTagMask(tagMask); 01689 01690 /* build the AirProtocolTagSpec Add the filter */ 01691 CC1G2TagSpec *ptagSpec = new CC1G2TagSpec(); 01692 ptagSpec->addC1G2TargetTag(ptargetTag); 01693 01694 /* Build the read Op Spec */ 01695 CC1G2Read *pread = new CC1G2Read(); 01696 pread->setAccessPassword(0); 01697 pread->setMB(3); 01698 pread->setOpSpecID(1); 01699 pread->setWordCount(2); 01700 pread->setWordPointer(0); 01701 01702 /* Create the AccessCommand. Add the TagSpec and the OpSpec */ 01703 CAccessCommand *pAccessCommand = new CAccessCommand(); 01704 pAccessCommand->setAirProtocolTagSpec(ptagSpec); 01705 pAccessCommand->addAccessCommandOpSpec(pread); 01706 01707 /* set up the Access Report Spec rule to report only with ROSpecs */ 01708 CAccessReportSpec *pAccessReportSpec = new CAccessReportSpec(); 01709 pAccessReportSpec->setAccessReportTrigger( 01710 AccessReportTriggerType_Whenever_ROReport_Is_Generated); 01711 01712 /* set up the stop trigger for the access spec. Do not stop */ 01713 CAccessSpecStopTrigger *pAccessStopTrigger = new CAccessSpecStopTrigger(); 01714 pAccessStopTrigger->setAccessSpecStopTrigger( 01715 AccessSpecStopTriggerType_Null); 01716 pAccessStopTrigger->setOperationCountValue(0); /* ignored */ 01717 01718 /* Create and configure the AccessSpec */ 01719 CAccessSpec *pAccessSpec = new CAccessSpec(); 01720 pAccessSpec->setAccessSpecID(23); 01721 pAccessSpec->setAntennaID(0); /* valid for all antennas */ 01722 pAccessSpec->setCurrentState(AccessSpecState_Disabled); 01723 pAccessSpec->setProtocolID(AirProtocols_EPCGlobalClass1Gen2); 01724 pAccessSpec->setROSpecID(0); /* valid for All RoSpecs */ 01725 pAccessSpec->setAccessSpecStopTrigger(pAccessStopTrigger); 01726 pAccessSpec->setAccessReportSpec(pAccessReportSpec); 01727 pAccessSpec->setAccessCommand(pAccessCommand); 01728 01729 /* Add the AccessSpec to the ADD_ACCESS_SPEC message */ 01730 pCmd->setAccessSpec(pAccessSpec); 01731 01732 /* 01733 * Send the message, expect the response of certain type 01734 */ 01735 pRspMsg = transact(pCmd); 01736 01737 /* 01738 * Done with the command message 01739 */ 01740 delete pCmd; 01741 01742 /* 01743 * transact() returns NULL if something went wrong. 01744 */ 01745 if(NULL == pRspMsg) 01746 { 01747 /* transact already tattled */ 01748 return -1; 01749 } 01750 01751 /* 01752 * Cast to a ADD_ACCESSSPEC_RESPONSE message. 01753 */ 01754 pRsp = (CADD_ACCESSSPEC_RESPONSE *) pRspMsg; 01755 01756 /* 01757 * Check the LLRPStatus parameter. 01758 */ 01759 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "addAccessSpec")) 01760 { 01761 /* checkLLRPStatus already tattled */ 01762 delete pRspMsg; 01763 return -1; 01764 } 01765 01766 /* 01767 * Done with the response message. 01768 */ 01769 delete pRspMsg; 01770 01771 /* 01772 * Tattle progress, maybe 01773 */ 01774 if(m_Verbose) 01775 { 01776 printf("INFO: AccessSpec added\n"); 01777 } 01778 01779 /* 01780 * Victory. 01781 */ 01782 return 0; 01783 } 01784 01785 01799 int 01800 CMyApplication::enableAccessSpec (void) 01801 { 01802 CENABLE_ACCESSSPEC * pCmd; 01803 CMessage * pRspMsg; 01804 CENABLE_ACCESSSPEC_RESPONSE * pRsp; 01805 01806 /* 01807 * Compose the command message 01808 */ 01809 pCmd = new CENABLE_ACCESSSPEC(); 01810 pCmd->setMessageID(m_messageID++); 01811 pCmd->setAccessSpecID(23); 01812 01813 /* 01814 * Send the message, expect the response of certain type 01815 */ 01816 pRspMsg = transact(pCmd); 01817 01818 /* 01819 * Done with the command message 01820 */ 01821 delete pCmd; 01822 01823 /* 01824 * transact() returns NULL if something went wrong. 01825 */ 01826 if(NULL == pRspMsg) 01827 { 01828 /* transact already tattled */ 01829 return -1; 01830 } 01831 01832 /* 01833 * Cast to a ENABLE_ACCESSSPEC_RESPONSE message. 01834 */ 01835 pRsp = (CENABLE_ACCESSSPEC_RESPONSE *) pRspMsg; 01836 01837 /* 01838 * Check the LLRPStatus parameter. 01839 */ 01840 if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "enableAccessSpec")) 01841 { 01842 /* checkLLRPStatus already tattled */ 01843 delete pRspMsg; 01844 return -1; 01845 } 01846 01847 /* 01848 * Done with the response message. 01849 */ 01850 delete pRspMsg; 01851 01852 /* 01853 * Tattle progress, maybe 01854 */ 01855 if(m_Verbose) 01856 { 01857 printf("INFO: AccessSpec enabled\n"); 01858 } 01859 01860 /* 01861 * Victory. 01862 */ 01863 return 0; 01864 } 01865 01866 01886 int 01887 CMyApplication::awaitAndPrintReport (int timeout) 01888 { 01889 int bDone = 0; 01890 int retVal = 0; 01891 time_t startTime = time(NULL); 01892 time_t tempTime; 01893 time_t pollTime = time(NULL); 01894 /* 01895 * Keep receiving messages until done or until 01896 * something bad happens. 01897 */ 01898 while(!bDone) 01899 { 01900 CMessage * pMessage; 01901 const CTypeDescriptor * pType; 01902 01903 /* 01904 * Wait up to 1 second for a report. Check 01905 * That way, we can check the timestamp even if 01906 * there are no reports coming in 01907 */ 01908 pMessage = recvMessage(1000); 01909 01910 /* validate the timestamp */ 01911 tempTime = time(NULL); 01912 if(difftime(tempTime, startTime) > timeout) 01913 { 01914 bDone=1; 01915 } 01916 01917 if(difftime(tempTime, pollTime) > 10) 01918 { 01919 /* poll the reader for its report data */ 01920 CGET_REPORT *preport = new CGET_REPORT(); 01921 sendMessage(preport); 01922 delete preport; 01923 pollTime = tempTime; 01924 } 01925 01926 if(NULL == pMessage) 01927 { 01928 continue; 01929 } 01930 01931 /* 01932 * What happens depends on what kind of message 01933 * received. Use the type label (m_pType) to 01934 * discriminate message types. 01935 */ 01936 pType = pMessage->m_pType; 01937 01938 /* 01939 * Is it a tag report? If so, print it out. 01940 */ 01941 if(&CRO_ACCESS_REPORT::s_typeDescriptor == pType) 01942 { 01943 CRO_ACCESS_REPORT * pNtf; 01944 01945 pNtf = (CRO_ACCESS_REPORT *) pMessage; 01946 01947 printTagReportData(pNtf); 01948 } 01949 01950 /* 01951 * Is it a reader event? This example only recognizes 01952 * AntennaEvents. 01953 */ 01954 else if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor == pType) 01955 { 01956 CREADER_EVENT_NOTIFICATION *pNtf; 01957 CReaderEventNotificationData *pNtfData; 01958 01959 pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage; 01960 01961 pNtfData = pNtf->getReaderEventNotificationData(); 01962 if(NULL != pNtfData) 01963 { 01964 handleReaderEventNotification(pNtfData); 01965 } 01966 else 01967 { 01968 /* 01969 * This should never happen. Using continue 01970 * to keep indent depth down. 01971 */ 01972 printf("WARNING: READER_EVENT_NOTIFICATION without data\n"); 01973 } 01974 } 01975 01976 /* 01977 * Hmmm. Something unexpected. Just tattle and keep going. 01978 */ 01979 else 01980 { 01981 printf("WARNING: Ignored unexpected message during monitor: %s\n", 01982 pType->m_pName); 01983 } 01984 01985 /* 01986 * Done with the received message 01987 */ 01988 delete pMessage; 01989 } 01990 01991 return retVal; 01992 } 01993 01994 02009 void 02010 CMyApplication::printTagReportData ( 02011 CRO_ACCESS_REPORT * pRO_ACCESS_REPORT) 02012 { 02013 std::list<CTagReportData *>::iterator Cur; 02014 02015 unsigned int nEntry = 0; 02016 02017 /* 02018 * Loop through and count the number of entries 02019 */ 02020 for( 02021 Cur = pRO_ACCESS_REPORT->beginTagReportData(); 02022 Cur != pRO_ACCESS_REPORT->endTagReportData(); 02023 Cur++) 02024 { 02025 nEntry++; 02026 } 02027 02028 if(m_Verbose) 02029 { 02030 printf("INFO: %u tag report entries\n", nEntry); 02031 } 02032 02033 /* 02034 * Loop through again and print each entry. 02035 */ 02036 for( 02037 Cur = pRO_ACCESS_REPORT->beginTagReportData(); 02038 Cur != pRO_ACCESS_REPORT->endTagReportData(); 02039 Cur++) 02040 { 02041 printOneTagReportData(*Cur); 02042 } 02043 } 02044 02045 02054 void 02055 CMyApplication::formatOneEPC ( 02056 CParameter *pEPCParameter, 02057 char *buf, 02058 int buflen) 02059 { 02060 char * p = buf; 02061 int bufsize = buflen; 02062 int written = 0; 02063 02064 if(NULL != pEPCParameter) 02065 { 02066 const CTypeDescriptor * pType; 02067 llrp_u96_t my_u96; 02068 llrp_u1v_t my_u1v; 02069 llrp_u8_t * pValue = NULL; 02070 unsigned int n, i; 02071 02072 pType = pEPCParameter->m_pType; 02073 if(&CEPC_96::s_typeDescriptor == pType) 02074 { 02075 CEPC_96 *pEPC_96; 02076 02077 pEPC_96 = (CEPC_96 *) pEPCParameter; 02078 my_u96 = pEPC_96->getEPC(); 02079 pValue = my_u96.m_aValue; 02080 n = 12u; 02081 } 02082 else if(&CEPCData::s_typeDescriptor == pType) 02083 { 02084 CEPCData * pEPCData; 02085 02086 pEPCData = (CEPCData *) pEPCParameter; 02087 my_u1v = pEPCData->getEPC(); 02088 pValue = my_u1v.m_pValue; 02089 n = (my_u1v.m_nBit + 7u) / 8u; 02090 } 02091 02092 if(NULL != pValue) 02093 { 02094 for(i = 0; i < n; i++) 02095 { 02096 if(0 < i && i%2 == 0 && 1 < bufsize) 02097 { 02098 *p++ = '-'; 02099 bufsize--; 02100 } 02101 if(bufsize > 2) 02102 { 02103 written = snprintf(p, bufsize, "%02X", pValue[i]); 02104 bufsize -= written; 02105 p+= written; 02106 } 02107 } 02108 } 02109 else 02110 { 02111 written = snprintf(p, bufsize, "%s", "---unknown-epc-data-type---"); 02112 bufsize -= written; 02113 p += written; 02114 } 02115 } 02116 else 02117 { 02118 written = snprintf(p, bufsize, "%s", "--null epc---"); 02119 bufsize -= written; 02120 p += written; 02121 } 02122 02123 // null terminate this for good practice 02124 buf[buflen-1] = '\0'; 02125 } 02126 02127 02136 void 02137 CMyApplication::formatOneReadResult ( 02138 CParameter *pOpSpecReadResult, 02139 char *buf, 02140 int buflen) 02141 { 02142 EC1G2ReadResultType result; 02143 char * p = buf; 02144 int written = 0; 02145 int bufsize = buflen; 02146 int i; 02147 llrp_u16v_t readData; 02148 CC1G2ReadOpSpecResult *pread = (CC1G2ReadOpSpecResult*) pOpSpecReadResult; 02149 02150 result = pread->getResult(); 02151 02152 written = snprintf(p, bufsize, "ReadResult %d", result); 02153 p+= written; 02154 bufsize -= written; 02155 02156 if(result == C1G2ReadResultType_Success) 02157 { 02158 readData = pread->getReadData(); 02159 02160 written = snprintf(p, bufsize, ": Data "); 02161 p+= written; 02162 bufsize -= written; 02163 02164 for(i = 0; i < readData.m_nValue - 1 ; i++) 02165 { 02166 written =snprintf(p, bufsize, "%04x-", readData.m_pValue[i]); 02167 p+= written; 02168 bufsize -= written; 02169 } 02170 if(readData.m_nValue) 02171 { 02172 written =snprintf(p, bufsize, "%04x", readData.m_pValue[i]); 02173 p+= written; 02174 bufsize -= written; 02175 } 02176 } 02177 buf[buflen-1] = '\0'; 02178 } 02179 02188 void 02189 CMyApplication::printOneTagReportData ( 02190 CTagReportData * pTagReportData) 02191 { 02192 char aBuf[64]; 02193 char bBuf[64]; 02194 std::list<CParameter *>::iterator OpSpecResults; 02195 02196 /* 02197 * Print the EPC. It could be an 96-bit EPC_96 parameter 02198 * or an variable length EPCData parameter. 02199 */ 02200 02201 CParameter * pEPCParameter = 02202 pTagReportData->getEPCParameter(); 02203 02204 formatOneEPC(pEPCParameter, aBuf, 64); 02205 02206 /* 02207 ** This section only handles ReadResults. It can be extended in a 02208 ** similar fashion to handle all OpSpecResults 02209 */ 02210 bBuf[0] = '\0'; 02211 for ( 02212 OpSpecResults = pTagReportData->beginAccessCommandOpSpecResult(); 02213 OpSpecResults != pTagReportData->endAccessCommandOpSpecResult(); 02214 OpSpecResults++) 02215 { 02216 if( (*OpSpecResults)->m_pType == &CC1G2ReadOpSpecResult::s_typeDescriptor) 02217 { 02218 formatOneReadResult(*OpSpecResults, bBuf, 64); 02219 } 02220 } 02221 02222 /* 02223 * End of line 02224 */ 02225 printf("EPC: %s %s\n", aBuf, bBuf); 02226 } 02227 02228 02242 void 02243 CMyApplication::handleReaderEventNotification ( 02244 CReaderEventNotificationData *pNtfData) 02245 { 02246 CAntennaEvent * pAntennaEvent; 02247 CReaderExceptionEvent * pReaderExceptionEvent; 02248 int nReported = 0; 02249 02250 pAntennaEvent = pNtfData->getAntennaEvent(); 02251 if(NULL != pAntennaEvent) 02252 { 02253 handleAntennaEvent(pAntennaEvent); 02254 nReported++; 02255 } 02256 02257 pReaderExceptionEvent = pNtfData->getReaderExceptionEvent(); 02258 if(NULL != pReaderExceptionEvent) 02259 { 02260 handleReaderExceptionEvent(pReaderExceptionEvent); 02261 nReported++; 02262 } 02263 02264 /* 02265 * Similarly handle other events here: 02266 * HoppingEvent 02267 * GPIEvent 02268 * ROSpecEvent 02269 * ReportBufferLevelWarningEvent 02270 * ReportBufferOverflowErrorEvent 02271 * RFSurveyEvent 02272 * AISpecEvent 02273 * ConnectionAttemptEvent 02274 * ConnectionCloseEvent 02275 * Custom 02276 */ 02277 02278 if(0 == nReported) 02279 { 02280 printf("NOTICE: Unexpected (unhandled) ReaderEvent\n"); 02281 } 02282 } 02283 02284 02296 void 02297 CMyApplication::handleAntennaEvent ( 02298 CAntennaEvent * pAntennaEvent) 02299 { 02300 EAntennaEventType eEventType; 02301 llrp_u16_t AntennaID; 02302 char * pStateStr; 02303 02304 eEventType = pAntennaEvent->getEventType(); 02305 AntennaID = pAntennaEvent->getAntennaID(); 02306 02307 switch(eEventType) 02308 { 02309 case AntennaEventType_Antenna_Disconnected: 02310 pStateStr = "disconnected"; 02311 break; 02312 02313 case AntennaEventType_Antenna_Connected: 02314 pStateStr = "connected"; 02315 break; 02316 02317 default: 02318 pStateStr = "?unknown-event?"; 02319 break; 02320 } 02321 02322 printf("NOTICE: Antenna %d is %s\n", AntennaID, pStateStr); 02323 } 02324 02325 02338 void 02339 CMyApplication::handleReaderExceptionEvent ( 02340 CReaderExceptionEvent * pReaderExceptionEvent) 02341 { 02342 llrp_utf8v_t Message; 02343 02344 Message = pReaderExceptionEvent->getMessage(); 02345 02346 if(0 < Message.m_nValue && NULL != Message.m_pValue) 02347 { 02348 printf("NOTICE: ReaderException '%.*s'\n", 02349 Message.m_nValue, Message.m_pValue); 02350 } 02351 else 02352 { 02353 printf("NOTICE: ReaderException but no message\n"); 02354 } 02355 } 02356 02357 02376 int 02377 CMyApplication::checkLLRPStatus ( 02378 CLLRPStatus * pLLRPStatus, 02379 char * pWhatStr) 02380 { 02381 /* 02382 * The LLRPStatus parameter is mandatory in all responses. 02383 * If it is missing there should have been a decode error. 02384 * This just makes sure (remember, this program is a 02385 * diagnostic and suppose to catch LTKC mistakes). 02386 */ 02387 if(NULL == pLLRPStatus) 02388 { 02389 printf("ERROR: %s missing LLRP status\n", pWhatStr); 02390 return -1; 02391 } 02392 02393 /* 02394 * Make sure the status is M_Success. 02395 * If it isn't, print the error string if one. 02396 * This does not try to pretty-print the status 02397 * code. To get that, run this program with -vv 02398 * and examine the XML output. 02399 */ 02400 if(StatusCode_M_Success != pLLRPStatus->getStatusCode()) 02401 { 02402 llrp_utf8v_t ErrorDesc; 02403 02404 ErrorDesc = pLLRPStatus->getErrorDescription(); 02405 02406 if(0 == ErrorDesc.m_nValue) 02407 { 02408 printf("ERROR: %s failed, no error description given\n", 02409 pWhatStr); 02410 } 02411 else 02412 { 02413 printf("ERROR: %s failed, %.*s\n", 02414 pWhatStr, ErrorDesc.m_nValue, ErrorDesc.m_pValue); 02415 } 02416 return -2; 02417 } 02418 02419 /* 02420 * Victory. Everything is fine. 02421 */ 02422 return 0; 02423 } 02424 02425 02449 CMessage * 02450 CMyApplication::transact ( 02451 CMessage * pSendMsg) 02452 { 02453 CConnection * pConn = m_pConnectionToReader; 02454 CMessage * pRspMsg; 02455 02456 /* 02457 * Print the XML text for the outbound message if 02458 * verbosity is 2 or higher. 02459 */ 02460 if(1 < m_Verbose) 02461 { 02462 printf("\n===================================\n"); 02463 printf("INFO: Transact sending\n"); 02464 printXMLMessage(pSendMsg); 02465 } 02466 02467 /* 02468 * Send the message, expect the response of certain type. 02469 * If LLRP::CConnection::transact() returns NULL then there was 02470 * an error. In that case we try to print the error details. 02471 */ 02472 pRspMsg = pConn->transact(pSendMsg, 5000); 02473 02474 if(NULL == pRspMsg) 02475 { 02476 const CErrorDetails * pError = pConn->getTransactError(); 02477 02478 printf("ERROR: %s transact failed, %s\n", 02479 pSendMsg->m_pType->m_pName, 02480 pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given"); 02481 02482 if(NULL != pError->m_pRefType) 02483 { 02484 printf("ERROR: ... reference type %s\n", 02485 pError->m_pRefType->m_pName); 02486 } 02487 02488 if(NULL != pError->m_pRefField) 02489 { 02490 printf("ERROR: ... reference field %s\n", 02491 pError->m_pRefField->m_pName); 02492 } 02493 02494 return NULL; 02495 } 02496 02497 /* 02498 * Print the XML text for the inbound message if 02499 * verbosity is 2 or higher. 02500 */ 02501 if(1 < m_Verbose) 02502 { 02503 printf("\n- - - - - - - - - - - - - - - - - -\n"); 02504 printf("INFO: Transact received response\n"); 02505 printXMLMessage(pRspMsg); 02506 } 02507 02508 /* 02509 * If it is an ERROR_MESSAGE (response from reader 02510 * when it can't understand the request), tattle 02511 * and declare defeat. 02512 */ 02513 if(&CERROR_MESSAGE::s_typeDescriptor == pRspMsg->m_pType) 02514 { 02515 const CTypeDescriptor * pResponseType; 02516 02517 pResponseType = pSendMsg->m_pType->m_pResponseType; 02518 02519 printf("ERROR: Received ERROR_MESSAGE instead of %s\n", 02520 pResponseType->m_pName); 02521 delete pRspMsg; 02522 pRspMsg = NULL; 02523 } 02524 02525 return pRspMsg; 02526 } 02527 02528 02553 CMessage * 02554 CMyApplication::recvMessage ( 02555 int nMaxMS) 02556 { 02557 CConnection * pConn = m_pConnectionToReader; 02558 CMessage * pMessage; 02559 02560 /* 02561 * Receive the message subject to a time limit 02562 */ 02563 pMessage = pConn->recvMessage(nMaxMS); 02564 02565 /* 02566 * If LLRP::CConnection::recvMessage() returns NULL then there was 02567 * an error. In that case we try to print the error details. 02568 */ 02569 if(NULL == pMessage) 02570 { 02571 const CErrorDetails * pError = pConn->getRecvError(); 02572 02573 /* don't warn on timeout since this is a polling example */ 02574 if(pError->m_eResultCode != RC_RecvTimeout) 02575 { 02576 printf("ERROR: recvMessage failed, %s\n", 02577 pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given"); 02578 } 02579 02580 if(NULL != pError->m_pRefType) 02581 { 02582 printf("ERROR: ... reference type %s\n", 02583 pError->m_pRefType->m_pName); 02584 } 02585 02586 if(NULL != pError->m_pRefField) 02587 { 02588 printf("ERROR: ... reference field %s\n", 02589 pError->m_pRefField->m_pName); 02590 } 02591 02592 return NULL; 02593 } 02594 02595 /* 02596 * Print the XML text for the inbound message if 02597 * verbosity is 2 or higher. 02598 */ 02599 if(1 < m_Verbose) 02600 { 02601 printf("\n===================================\n"); 02602 printf("INFO: Message received\n"); 02603 printXMLMessage(pMessage); 02604 } 02605 02606 return pMessage; 02607 } 02608 02609 02627 int 02628 CMyApplication::sendMessage ( 02629 CMessage * pSendMsg) 02630 { 02631 CConnection * pConn = m_pConnectionToReader; 02632 02633 /* 02634 * Print the XML text for the outbound message if 02635 * verbosity is 2 or higher. 02636 */ 02637 if(1 < m_Verbose) 02638 { 02639 printf("\n===================================\n"); 02640 printf("INFO: Sending\n"); 02641 printXMLMessage(pSendMsg); 02642 } 02643 02644 /* 02645 * If LLRP::CConnection::sendMessage() returns other than RC_OK 02646 * then there was an error. In that case we try to print 02647 * the error details. 02648 */ 02649 if(RC_OK != pConn->sendMessage(pSendMsg)) 02650 { 02651 const CErrorDetails * pError = pConn->getSendError(); 02652 02653 printf("ERROR: %s sendMessage failed, %s\n", 02654 pSendMsg->m_pType->m_pName, 02655 pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given"); 02656 02657 if(NULL != pError->m_pRefType) 02658 { 02659 printf("ERROR: ... reference type %s\n", 02660 pError->m_pRefType->m_pName); 02661 } 02662 02663 if(NULL != pError->m_pRefField) 02664 { 02665 printf("ERROR: ... reference field %s\n", 02666 pError->m_pRefField->m_pName); 02667 } 02668 02669 return -1; 02670 } 02671 02672 /* 02673 * Victory 02674 */ 02675 return 0; 02676 } 02677 02678 02692 void 02693 CMyApplication::printXMLMessage ( 02694 CMessage * pMessage) 02695 { 02696 char aBuf[100*1024]; 02697 02698 /* 02699 * Convert the message to an XML string. 02700 * This fills the buffer with either the XML string 02701 * or an error message. The return value could 02702 * be checked. 02703 */ 02704 02705 pMessage->toXMLString(aBuf, sizeof aBuf); 02706 02707 /* 02708 * Print the XML Text to the standard output. 02709 */ 02710 printf("%s", aBuf); 02711 }