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