LTKCPP-- LLRP Toolkit C Plus Plus Library
target/sdk/libltkcpp-win/docsample3/docsample3.cpp
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 }