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