LTKCPP-- LLRP Toolkit C Plus Plus Library
custom_select_2.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_Immediate);
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_Tag_Observation);
00809     pAISpecStopTrigger->setDurationTrigger(0);
00810 
00811     CTagObservationTrigger *    pAISpecTagObsvTrigger = new CTagObservationTrigger();
00812     pAISpecTagObsvTrigger->setTriggerType(TagObservationTriggerType_Upon_Seeing_N_Tags_Or_Timeout);
00813     pAISpecTagObsvTrigger->setNumberOfTags(100);
00814     pAISpecTagObsvTrigger->setNumberOfAttempts(0);
00815     pAISpecTagObsvTrigger->setT(0);
00816     pAISpecTagObsvTrigger->setTimeout(500);
00817 
00818     pAISpecStopTrigger->setTagObservationTrigger(pAISpecTagObsvTrigger);
00819 
00820 
00822 
00823 
00824     CInventoryParameterSpec *   pInventoryParameterSpec =
00825                                     new CInventoryParameterSpec();
00826     pInventoryParameterSpec->setInventoryParameterSpecID(1234);
00827     pInventoryParameterSpec->setProtocolID(AirProtocols_EPCGlobalClass1Gen2);
00828 
00829     CAntennaConfiguration *     pAntennaConfig = new CAntennaConfiguration();
00830     pAntennaConfig->setAntennaID(1);
00831 
00832     CRFTransmitter *               pRFTransmitter = new CRFTransmitter();
00833     pRFTransmitter->setHopTableID(1);
00834     pRFTransmitter->setChannelIndex(0);
00835     pRFTransmitter->setTransmitPower(81);
00836     pAntennaConfig->setRFTransmitter(pRFTransmitter);
00837 
00838     CC1G2InventoryCommand *        pC1G2InventoryCmd = new CC1G2InventoryCommand();
00839     pC1G2InventoryCmd->setTagInventoryStateAware(1);
00840 
00841 // Filter 1    
00842     CC1G2Filter *                  pC1G2Filter1 = new CC1G2Filter();
00843     pC1G2Filter1->setT(C1G2TruncateAction_Do_Not_Truncate);
00844 
00845     CC1G2TagInventoryMask *        pC1G2TagInvMask1 = new CC1G2TagInventoryMask();
00846     pC1G2TagInvMask1->setMB(2);
00847     pC1G2TagInvMask1->setPointer(0);
00848     
00849     llrp_u1v_t tagMask1 = llrp_u1v_t(15);
00850     tagMask1.m_nBit = 15;
00851     tagMask1.m_pValue[0] = 0xE2;
00852     tagMask1.m_pValue[1] = 0x00;
00853     pC1G2TagInvMask1->setTagMask(tagMask1);
00854 
00855     pC1G2Filter1->setC1G2TagInventoryMask(pC1G2TagInvMask1);
00856     
00857     CC1G2TagInventoryStateAwareFilterAction * pC1G2TagInvStateAwareFilterAction1 = new CC1G2TagInventoryStateAwareFilterAction();
00858     pC1G2TagInvStateAwareFilterAction1->setTarget(C1G2StateAwareTarget_Inventoried_State_For_Session_S3);
00859     pC1G2TagInvStateAwareFilterAction1->setAction(C1G2StateAwareAction_AssertSLOrA_DeassertSLOrB);
00860 
00861     pC1G2Filter1->setC1G2TagInventoryStateAwareFilterAction(pC1G2TagInvStateAwareFilterAction1);
00862 
00863     pC1G2InventoryCmd->addC1G2Filter(pC1G2Filter1);
00864 
00865  // Filter 2
00866     CC1G2Filter *                  pC1G2Filter2 = new CC1G2Filter();
00867     pC1G2Filter2->setT(C1G2TruncateAction_Do_Not_Truncate);
00868 
00869     CC1G2TagInventoryMask *        pC1G2TagInvMask2 = new CC1G2TagInventoryMask();
00870     pC1G2TagInvMask2->setMB(1);
00871     pC1G2TagInvMask2->setPointer(0);
00872 
00873     llrp_u1v_t tagMask2 = llrp_u1v_t(16);
00874     tagMask2.m_nBit = 16;
00875     tagMask2.m_pValue[0] = 0xE2;
00876     tagMask2.m_pValue[1] = 0x00;
00877     pC1G2TagInvMask2->setTagMask(tagMask2);
00878 
00879     pC1G2Filter2->setC1G2TagInventoryMask(pC1G2TagInvMask2);
00880     
00881     CC1G2TagInventoryStateAwareFilterAction * pC1G2TagInvStateAwareFilterAction2 = new CC1G2TagInventoryStateAwareFilterAction();
00882     pC1G2TagInvStateAwareFilterAction2->setTarget(C1G2StateAwareTarget_Inventoried_State_For_Session_S2);
00883     pC1G2TagInvStateAwareFilterAction2->setAction(C1G2StateAwareAction_AssertSLOrA_DeassertSLOrB);
00884 
00885     pC1G2Filter2->setC1G2TagInventoryStateAwareFilterAction(pC1G2TagInvStateAwareFilterAction2);
00886 
00887     pC1G2InventoryCmd->addC1G2Filter(pC1G2Filter2); 
00888 
00889 // Filter 3
00890     CC1G2Filter *                  pC1G2Filter3 = new CC1G2Filter();
00891     pC1G2Filter3->setT(C1G2TruncateAction_Do_Not_Truncate);
00892 
00893     CC1G2TagInventoryMask *        pC1G2TagInvMask3 = new CC1G2TagInventoryMask();
00894     pC1G2TagInvMask3->setMB(3);
00895     pC1G2TagInvMask3->setPointer(0);
00896 
00897     llrp_u1v_t tagMask3 = llrp_u1v_t(32);
00898     tagMask3.m_nBit = 32;
00899     tagMask3.m_pValue[0] = 0xFF;
00900     tagMask3.m_pValue[1] = 0xFF;
00901     tagMask3.m_pValue[2] = 0xE2;
00902     tagMask3.m_pValue[3] = 0x00;
00903     pC1G2TagInvMask3->setTagMask(tagMask3);
00904 
00905     pC1G2Filter3->setC1G2TagInventoryMask(pC1G2TagInvMask3);
00906     
00907     CC1G2TagInventoryStateAwareFilterAction * pC1G2TagInvStateAwareFilterAction3 = new CC1G2TagInventoryStateAwareFilterAction();
00908     pC1G2TagInvStateAwareFilterAction3->setTarget(C1G2StateAwareTarget_Inventoried_State_For_Session_S1);
00909     pC1G2TagInvStateAwareFilterAction3->setAction(C1G2StateAwareAction_AssertSLOrA_DeassertSLOrB);
00910 
00911     pC1G2Filter3->setC1G2TagInventoryStateAwareFilterAction(pC1G2TagInvStateAwareFilterAction3);
00912 
00913     pC1G2InventoryCmd->addC1G2Filter(pC1G2Filter3); 
00914 
00915 // Filter 4
00916     CC1G2Filter *                  pC1G2Filter4 = new CC1G2Filter();
00917     pC1G2Filter4->setT(C1G2TruncateAction_Do_Not_Truncate);
00918 
00919     CC1G2TagInventoryMask *        pC1G2TagInvMask4 = new CC1G2TagInventoryMask();
00920     pC1G2TagInvMask4->setMB(2);
00921     pC1G2TagInvMask4->setPointer(0);
00922 
00923     llrp_u1v_t tagMask4 = llrp_u1v_t(8);
00924     tagMask4.m_nBit = 8;
00925     tagMask4.m_pValue[0] = 0xAA;
00926     pC1G2TagInvMask4->setTagMask(tagMask4);
00927 
00928     pC1G2Filter4->setC1G2TagInventoryMask(pC1G2TagInvMask4);
00929     
00930     CC1G2TagInventoryStateAwareFilterAction * pC1G2TagInvStateAwareFilterAction4 = new CC1G2TagInventoryStateAwareFilterAction();
00931     pC1G2TagInvStateAwareFilterAction4->setTarget(C1G2StateAwareTarget_Inventoried_State_For_Session_S0);
00932     pC1G2TagInvStateAwareFilterAction4->setAction(C1G2StateAwareAction_AssertSLOrA_DeassertSLOrB);
00933 
00934     pC1G2Filter4->setC1G2TagInventoryStateAwareFilterAction(pC1G2TagInvStateAwareFilterAction4);
00935 
00936     pC1G2InventoryCmd->addC1G2Filter(pC1G2Filter4); 
00937 
00938 // Filter 5
00939     CC1G2Filter *                  pC1G2Filter5 = new CC1G2Filter();
00940     pC1G2Filter5->setT(C1G2TruncateAction_Do_Not_Truncate);
00941 
00942     CC1G2TagInventoryMask *        pC1G2TagInvMask5 = new CC1G2TagInventoryMask();
00943     pC1G2TagInvMask5->setMB(1);
00944     pC1G2TagInvMask5->setPointer(0);
00945 
00946     llrp_u1v_t tagMask5 = llrp_u1v_t(16);
00947     tagMask5.m_nBit = 16;
00948     tagMask5.m_pValue[0] = 0xFF;
00949     tagMask5.m_pValue[1] = 0xFF;
00950     pC1G2TagInvMask5->setTagMask(tagMask5);
00951 
00952     pC1G2Filter5->setC1G2TagInventoryMask(pC1G2TagInvMask5);
00953     
00954     CC1G2TagInventoryStateAwareFilterAction * pC1G2TagInvStateAwareFilterAction5 = new CC1G2TagInventoryStateAwareFilterAction();
00955     pC1G2TagInvStateAwareFilterAction5->setTarget(C1G2StateAwareTarget_SL);
00956     pC1G2TagInvStateAwareFilterAction5->setAction(C1G2StateAwareAction_AssertSLOrA_DeassertSLOrB);
00957 
00958     pC1G2Filter5->setC1G2TagInventoryStateAwareFilterAction(pC1G2TagInvStateAwareFilterAction5);
00959 
00960     pC1G2InventoryCmd->addC1G2Filter(pC1G2Filter5); 
00961 
00962 //
00963 
00964 
00965     CC1G2SingulationControl *               pC1G2SingulationControl = new CC1G2SingulationControl();
00966     pC1G2SingulationControl->setSession(1);
00967     pC1G2SingulationControl->setTagPopulation(32);
00968     pC1G2SingulationControl->setTagTransitTime(0);
00969 
00970     CC1G2TagInventoryStateAwareSingulationAction * pC1G2TagInvStateAwareSingAction = new CC1G2TagInventoryStateAwareSingulationAction();
00971     pC1G2TagInvStateAwareSingAction->setI(C1G2TagInventoryStateAwareI_State_B);
00972     pC1G2TagInvStateAwareSingAction->setS(C1G2TagInventoryStateAwareS_SL);
00973 
00974     pC1G2SingulationControl->setC1G2TagInventoryStateAwareSingulationAction(pC1G2TagInvStateAwareSingAction);
00975 
00976     pC1G2InventoryCmd->setC1G2SingulationControl(pC1G2SingulationControl);
00977 
00978     pAntennaConfig->addAirProtocolInventoryCommandSettings(pC1G2InventoryCmd);
00979 
00980     pInventoryParameterSpec->addAntennaConfiguration(pAntennaConfig);
00981 
00983     llrp_u16v_t AntennaIDs = llrp_u16v_t(1);
00984     AntennaIDs.m_pValue[0] = 1;
00985 
00986     CAISpec *                   pAISpec = new CAISpec();
00987     pAISpec->setAntennaIDs(AntennaIDs);
00988     pAISpec->setAISpecStopTrigger(pAISpecStopTrigger);
00989     pAISpec->addInventoryParameterSpec(pInventoryParameterSpec);
00990 
00991 
00993     CROReportSpec *             pROReportSpec = new CROReportSpec();
00994     pROReportSpec->setROReportTrigger(ROReportTriggerType_Upon_N_Tags_Or_End_Of_AISpec);
00995     pROReportSpec->setN(1000);
00996 
00997     CTagReportContentSelector * pTagRptContentSelector = new CTagReportContentSelector();
00998     pTagRptContentSelector->setEnableROSpecID(1);
00999     pTagRptContentSelector->setEnableSpecIndex(1);
01000     pTagRptContentSelector->setEnableInventoryParameterSpecID(1);
01001     pTagRptContentSelector->setEnableAntennaID(1);
01002     pTagRptContentSelector->setEnableChannelIndex(1);
01003     pTagRptContentSelector->setEnablePeakRSSI(1);
01004     pTagRptContentSelector->setEnableFirstSeenTimestamp(1);
01005     pTagRptContentSelector->setEnableLastSeenTimestamp(1);
01006     pTagRptContentSelector->setEnableTagSeenCount(1);
01007     pTagRptContentSelector->setEnableAccessSpecID(1);
01008 
01009     pROReportSpec->setTagReportContentSelector(pTagRptContentSelector);    
01011 
01012 
01013     CROSpec *                   pROSpec = new CROSpec();
01014     pROSpec->setROSpecID(1);
01015     pROSpec->setPriority(0);
01016     pROSpec->setCurrentState(ROSpecState_Disabled);
01017     pROSpec->setROBoundarySpec(pROBoundarySpec);
01018     pROSpec->addSpecParameter(pAISpec);
01019     pROSpec->setROReportSpec(pROReportSpec);
01020 
01021     CADD_ROSPEC *               pCmd;
01022     CMessage *                  pRspMsg;
01023     CADD_ROSPEC_RESPONSE *      pRsp;
01024 
01025     /*
01026      * Compose the command message.
01027      * N.B.: After the message is composed, all the parameters
01028      *       constructed, immediately above, are considered "owned"
01029      *       by the command message. When it is destructed so
01030      *       too will the parameters be.
01031      */
01032     pCmd = new CADD_ROSPEC();
01033     pCmd->setMessageID(m_messageID++);
01034     pCmd->setROSpec(pROSpec);
01035 
01036     /*
01037      * Send the message, expect the response of certain type
01038      */
01039     pRspMsg = transact(pCmd);
01040 
01041     /*
01042      * Done with the command message.
01043      * N.B.: And the parameters
01044      */
01045     delete pCmd;
01046 
01047     /*
01048      * transact() returns NULL if something went wrong.
01049      */
01050     if(NULL == pRspMsg)
01051     {
01052         /* transact already tattled */
01053         return -1;
01054     }
01055 
01056     /*
01057      * Cast to a ADD_ROSPEC_RESPONSE message.
01058      */
01059     pRsp = (CADD_ROSPEC_RESPONSE *) pRspMsg;
01060 
01061     /*
01062      * Check the LLRPStatus parameter.
01063      */
01064     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "addROSpec"))
01065     {
01066         /* checkLLRPStatus already tattled */
01067         delete pRspMsg;
01068         return -1;
01069     }
01070 
01071     /*
01072      * Done with the response message.
01073      */
01074     delete pRspMsg;
01075 
01076     /*
01077      * Tattle progress, maybe
01078      */
01079     if(m_Verbose)
01080     {
01081         printf("INFO: ROSpec added\n");
01082     }
01083 
01084     /*
01085      * Victory.
01086      */
01087     return 0;
01088 }
01089 
01090 
01108 int
01109 CMyApplication::enableROSpec (void)
01110 {
01111     CENABLE_ROSPEC *            pCmd;
01112     CMessage *                  pRspMsg;
01113     CENABLE_ROSPEC_RESPONSE *   pRsp;
01114 
01115     /*
01116      * Compose the command message
01117      */
01118     pCmd = new CENABLE_ROSPEC();
01119     pCmd->setMessageID(m_messageID++);
01120     pCmd->setROSpecID(1);
01121 
01122     /*
01123      * Send the message, expect the response of certain type
01124      */
01125     pRspMsg = transact(pCmd);
01126 
01127     /*
01128      * Done with the command message
01129      */
01130     delete pCmd;
01131 
01132     /*
01133      * transact() returns NULL if something went wrong.
01134      */
01135     if(NULL == pRspMsg)
01136     {
01137         /* transact already tattled */
01138         return -1;
01139     }
01140 
01141     /*
01142      * Cast to a ENABLE_ROSPEC_RESPONSE message.
01143      */
01144     pRsp = (CENABLE_ROSPEC_RESPONSE *) pRspMsg;
01145 
01146     /*
01147      * Check the LLRPStatus parameter.
01148      */
01149     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "enableROSpec"))
01150     {
01151         /* checkLLRPStatus already tattled */
01152         delete pRspMsg;
01153         return -1;
01154     }
01155 
01156     /*
01157      * Done with the response message.
01158      */
01159     delete pRspMsg;
01160 
01161     /*
01162      * Tattle progress, maybe
01163      */
01164     if(m_Verbose)
01165     {
01166         printf("INFO: ROSpec enabled\n");
01167     }
01168 
01169     /*
01170      * Victory.
01171      */
01172     return 0;
01173 }
01174 
01175 
01193 int
01194 CMyApplication::startROSpec (void)
01195 {
01196     CSTART_ROSPEC *             pCmd;
01197     CMessage *                  pRspMsg;
01198     CSTART_ROSPEC_RESPONSE *    pRsp;
01199 
01200     /*
01201      * Compose the command message
01202      */
01203     pCmd = new CSTART_ROSPEC();
01204     pCmd->setMessageID(m_messageID++);
01205     pCmd->setROSpecID(1);
01206 
01207     /*
01208      * Send the message, expect the response of certain type
01209      */
01210     pRspMsg = transact(pCmd);
01211 
01212     /*
01213      * Done with the command message
01214      */
01215     delete pCmd;
01216 
01217     /*
01218      * transact() returns NULL if something went wrong.
01219      */
01220     if(NULL == pRspMsg)
01221     {
01222         /* transact already tattled */
01223         return -1;
01224     }
01225 
01226     /*
01227      * Cast to a START_ROSPEC_RESPONSE message.
01228      */
01229     pRsp = (CSTART_ROSPEC_RESPONSE *) pRspMsg;
01230 
01231     /*
01232      * Check the LLRPStatus parameter.
01233      */
01234     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "startROSpec"))
01235     {
01236         /* checkLLRPStatus already tattled */
01237         delete pRspMsg;
01238         return -1;
01239     }
01240 
01241     /*
01242      * Done with the response message.
01243      */
01244     delete pRspMsg;
01245 
01246     /*
01247      * Tattle progress
01248      */
01249     if(m_Verbose)
01250     {
01251         printf("INFO: ROSpec started\n");
01252     }
01253 
01254     /*
01255      * Victory.
01256      */
01257     return 0;
01258 }
01259 
01277 int
01278 CMyApplication::stopROSpec (void)
01279 {
01280     CSTOP_ROSPEC *             pCmd;
01281     CMessage *                  pRspMsg;
01282     CSTOP_ROSPEC_RESPONSE *    pRsp;
01283 
01284     /*
01285      * Compose the command message
01286      */
01287     pCmd = new CSTOP_ROSPEC();
01288     pCmd->setMessageID(m_messageID++);
01289     pCmd->setROSpecID(1);
01290 
01291     /*
01292      * Send the message, expect the response of certain type
01293      */
01294     pRspMsg = transact(pCmd);
01295 
01296     /*
01297      * Done with the command message
01298      */
01299     delete pCmd;
01300 
01301     /*
01302      * transact() returns NULL if something went wrong.
01303      */
01304     if(NULL == pRspMsg)
01305     {
01306         /* transact already tattled */
01307         return -1;
01308     }
01309 
01310     /*
01311      * Cast to a STOP_ROSPEC_RESPONSE message.
01312      */
01313     pRsp = (CSTOP_ROSPEC_RESPONSE *) pRspMsg;
01314 
01315     /*
01316      * Check the LLRPStatus parameter.
01317      */
01318     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "stopROSpec"))
01319     {
01320         /* checkLLRPStatus already tattled */
01321         delete pRspMsg;
01322         return -1;
01323     }
01324 
01325     /*
01326      * Done with the response message.
01327      */
01328     delete pRspMsg;
01329 
01330     /*
01331      * Tattle progress
01332      */
01333     if(m_Verbose)
01334     {
01335         printf("INFO: ROSpec stopped\n");
01336     }
01337 
01338     /*
01339      * Victory.
01340      */
01341     return 0;
01342 }
01343 
01344 
01364 int
01365 CMyApplication::awaitAndPrintReport (int timeout)
01366 {
01367     int                         bDone = 0;
01368     int                         retVal = 0;
01369     time_t                      startTime = time(NULL);
01370     time_t                      tempTime;
01371     /*
01372      * Keep receiving messages until done or until
01373      * something bad happens.
01374      */
01375     while(!bDone)
01376     {
01377         CMessage *              pMessage;
01378         const CTypeDescriptor * pType;
01379 
01380         /*
01381          * Wait up to 1 second for a report.  Check
01382          * That way, we can check the timestamp even if 
01383          * there are no reports coming in
01384          */
01385         pMessage = recvMessage(1000);
01386 
01387         /* validate the timestamp */
01388         tempTime = time(NULL);
01389         if(difftime(tempTime, startTime) > timeout)
01390         {
01391             bDone=1;
01392         }
01393 
01394         if(NULL == pMessage)
01395         {
01396             continue;
01397         }
01398 
01399         /*
01400          * What happens depends on what kind of message
01401          * received. Use the type label (m_pType) to
01402          * discriminate message types.
01403          */
01404         pType = pMessage->m_pType;
01405 
01406         /*
01407          * Is it a tag report? If so, print it out.
01408          */
01409         if(&CRO_ACCESS_REPORT::s_typeDescriptor == pType)
01410         {
01411             CRO_ACCESS_REPORT * pNtf;
01412 
01413             pNtf = (CRO_ACCESS_REPORT *) pMessage;
01414 
01415             printTagReportData(pNtf);
01416         }
01417 
01418         /*
01419          * Is it a reader event? This example only recognizes
01420          * AntennaEvents.
01421          */
01422         else if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor == pType)
01423         {
01424             CREADER_EVENT_NOTIFICATION *pNtf;
01425             CReaderEventNotificationData *pNtfData;
01426 
01427             pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage;
01428 
01429             pNtfData = pNtf->getReaderEventNotificationData();
01430             if(NULL != pNtfData)
01431             {
01432                 handleReaderEventNotification(pNtfData);
01433             }
01434             else
01435             {
01436                 /*
01437                  * This should never happen. Using continue
01438                  * to keep indent depth down.
01439                  */
01440                 printf("WARNING: READER_EVENT_NOTIFICATION without data\n");
01441             }
01442         }
01443 
01444         /*
01445          * Hmmm. Something unexpected. Just tattle and keep going.
01446          */
01447         else
01448         {
01449             printf("WARNING: Ignored unexpected message during monitor: %s\n",
01450                 pType->m_pName);
01451         }
01452 
01453         /*
01454          * Done with the received message
01455          */
01456         delete pMessage;
01457     }
01458 
01459     return retVal;
01460 }
01461 
01462 
01477 void
01478 CMyApplication::printTagReportData (
01479   CRO_ACCESS_REPORT *           pRO_ACCESS_REPORT)
01480 {
01481     std::list<CTagReportData *>::iterator Cur;
01482 
01483     unsigned int                nEntry = 0;
01484 
01485     /*
01486      * Loop through and count the number of entries
01487      */
01488     for(
01489         Cur = pRO_ACCESS_REPORT->beginTagReportData();
01490         Cur != pRO_ACCESS_REPORT->endTagReportData();
01491         Cur++)
01492     {
01493         nEntry++;
01494     }
01495 
01496     if(m_Verbose)
01497     {
01498     printf("INFO: %u tag report entries\n", nEntry);
01499     }
01500 
01501     /*
01502      * Loop through again and print each entry.
01503      */
01504     for(
01505         Cur = pRO_ACCESS_REPORT->beginTagReportData();
01506         Cur != pRO_ACCESS_REPORT->endTagReportData();
01507         Cur++)
01508     {
01509         printOneTagReportData(*Cur);
01510     }
01511 }
01512 
01513 
01522 void
01523 CMyApplication::formatOneEPC (
01524   CParameter *pEPCParameter, 
01525   char *buf, 
01526   int buflen)
01527 {
01528     char *              p = buf;
01529     int                 bufsize = buflen;
01530     int                 written = 0;
01531 
01532     if(NULL != pEPCParameter)
01533     {
01534         const CTypeDescriptor *     pType;
01535         llrp_u96_t          my_u96;
01536         llrp_u1v_t          my_u1v;
01537         llrp_u8_t *         pValue = NULL;
01538         unsigned int        n, i;
01539 
01540         pType = pEPCParameter->m_pType;
01541         if(&CEPC_96::s_typeDescriptor == pType)
01542         {
01543             CEPC_96             *pEPC_96;
01544 
01545             pEPC_96 = (CEPC_96 *) pEPCParameter;
01546             my_u96 = pEPC_96->getEPC();
01547             pValue = my_u96.m_aValue;
01548             n = 12u;
01549         }
01550         else if(&CEPCData::s_typeDescriptor == pType)
01551         {
01552             CEPCData *          pEPCData;
01553 
01554             pEPCData = (CEPCData *) pEPCParameter;
01555             my_u1v = pEPCData->getEPC();
01556             pValue = my_u1v.m_pValue;
01557             n = (my_u1v.m_nBit + 7u) / 8u;
01558         }
01559 
01560         if(NULL != pValue)
01561         {
01562             for(i = 0; i < n; i++)
01563             {
01564                 if(0 < i && i%2 == 0 && 1 < bufsize)
01565                 {
01566                     *p++ = '-';
01567                     bufsize--;
01568                 }
01569                 if(bufsize > 2)
01570                 {
01571                     written = snprintf(p, bufsize, "%02X", pValue[i]);
01572                     bufsize -= written;
01573                     p+= written;
01574                 }
01575             }
01576         }
01577         else
01578         {
01579             written = snprintf(p, bufsize, "%s", "---unknown-epc-data-type---");
01580             bufsize -= written;
01581             p += written;
01582         }
01583     }
01584     else
01585     {
01586         written = snprintf(p, bufsize, "%s", "--null epc---");
01587         bufsize -= written;
01588         p += written;
01589     }
01590 
01591     // null terminate this for good practice
01592     buf[buflen-1] = '\0';
01593 
01594 }
01595 
01604 void
01605 CMyApplication::printOneTagReportData (
01606   CTagReportData *              pTagReportData)
01607 {
01608     char                        aBuf[64];
01609 
01610     /*
01611      * Print the EPC. It could be an 96-bit EPC_96 parameter
01612      * or an variable length EPCData parameter.
01613      */
01614 
01615     CParameter *                pEPCParameter =
01616                                     pTagReportData->getEPCParameter();
01617 
01618     formatOneEPC(pEPCParameter, aBuf, 64);
01619     
01620     /*
01621      * End of line
01622      */
01623     printf("EPC: %s\n", aBuf);
01624 }
01625 
01626 
01640 void
01641 CMyApplication::handleReaderEventNotification (
01642   CReaderEventNotificationData *pNtfData)
01643 {
01644     CAntennaEvent *             pAntennaEvent;
01645     CReaderExceptionEvent *     pReaderExceptionEvent;
01646     int                         nReported = 0;
01647 
01648     pAntennaEvent = pNtfData->getAntennaEvent();
01649     if(NULL != pAntennaEvent)
01650     {
01651         handleAntennaEvent(pAntennaEvent);
01652         nReported++;
01653     }
01654 
01655     pReaderExceptionEvent = pNtfData->getReaderExceptionEvent();
01656     if(NULL != pReaderExceptionEvent)
01657     {
01658         handleReaderExceptionEvent(pReaderExceptionEvent);
01659         nReported++;
01660     }
01661 
01662     /*
01663      * Similarly handle other events here:
01664      *      HoppingEvent
01665      *      GPIEvent
01666      *      ROSpecEvent
01667      *      ReportBufferLevelWarningEvent
01668      *      ReportBufferOverflowErrorEvent
01669      *      RFSurveyEvent
01670      *      AISpecEvent
01671      *      ConnectionAttemptEvent
01672      *      ConnectionCloseEvent
01673      *      Custom
01674      */
01675 
01676     if(0 == nReported)
01677     {
01678         printf("NOTICE: Unexpected (unhandled) ReaderEvent\n");
01679     }
01680 }
01681 
01682 
01694 void
01695 CMyApplication::handleAntennaEvent (
01696   CAntennaEvent *               pAntennaEvent)
01697 {
01698     EAntennaEventType           eEventType;
01699     llrp_u16_t                  AntennaID;
01700     char *                      pStateStr;
01701 
01702     eEventType = pAntennaEvent->getEventType();
01703     AntennaID = pAntennaEvent->getAntennaID();
01704 
01705     switch(eEventType)
01706     {
01707     case AntennaEventType_Antenna_Disconnected:
01708         pStateStr = "disconnected";
01709         break;
01710 
01711     case AntennaEventType_Antenna_Connected:
01712         pStateStr = "connected";
01713         break;
01714 
01715     default:
01716         pStateStr = "?unknown-event?";
01717         break;
01718     }
01719 
01720     printf("NOTICE: Antenna %d is %s\n", AntennaID, pStateStr);
01721 }
01722 
01723 
01736 void
01737 CMyApplication::handleReaderExceptionEvent (
01738   CReaderExceptionEvent *       pReaderExceptionEvent)
01739 {
01740     llrp_utf8v_t                Message;
01741 
01742     Message = pReaderExceptionEvent->getMessage();
01743 
01744     if(0 < Message.m_nValue && NULL != Message.m_pValue)
01745     {
01746         printf("NOTICE: ReaderException '%.*s'\n",
01747              Message.m_nValue, Message.m_pValue);
01748     }
01749     else
01750     {
01751         printf("NOTICE: ReaderException but no message\n");
01752     }
01753 }
01754 
01755 
01774 int
01775 CMyApplication::checkLLRPStatus (
01776   CLLRPStatus *                 pLLRPStatus,
01777   char *                        pWhatStr)
01778 {
01779     /*
01780      * The LLRPStatus parameter is mandatory in all responses.
01781      * If it is missing there should have been a decode error.
01782      * This just makes sure (remember, this program is a
01783      * diagnostic and suppose to catch LTKC mistakes).
01784      */
01785     if(NULL == pLLRPStatus)
01786     {
01787         printf("ERROR: %s missing LLRP status\n", pWhatStr);
01788         return -1;
01789     }
01790 
01791     /*
01792      * Make sure the status is M_Success.
01793      * If it isn't, print the error string if one.
01794      * This does not try to pretty-print the status
01795      * code. To get that, run this program with -vv
01796      * and examine the XML output.
01797      */
01798     if(StatusCode_M_Success != pLLRPStatus->getStatusCode())
01799     {
01800         llrp_utf8v_t            ErrorDesc;
01801 
01802         ErrorDesc = pLLRPStatus->getErrorDescription();
01803 
01804         if(0 == ErrorDesc.m_nValue)
01805         {
01806             printf("ERROR: %s failed, no error description given\n",
01807                 pWhatStr);
01808         }
01809         else
01810         {
01811             printf("ERROR: %s failed, %.*s\n",
01812                 pWhatStr, ErrorDesc.m_nValue, ErrorDesc.m_pValue);
01813         }
01814         return -2;
01815     }
01816 
01817     /*
01818      * Victory. Everything is fine.
01819      */
01820     return 0;
01821 }
01822 
01823 
01847 CMessage *
01848 CMyApplication::transact (
01849   CMessage *                    pSendMsg)
01850 {
01851     CConnection *               pConn = m_pConnectionToReader;
01852     CMessage *                  pRspMsg;
01853 
01854     /*
01855      * Print the XML text for the outbound message if
01856      * verbosity is 2 or higher.
01857      */
01858     if(1 < m_Verbose)
01859     {
01860         printf("\n===================================\n");
01861         printf("INFO: Transact sending\n");
01862         printXMLMessage(pSendMsg);
01863     }
01864 
01865     /*
01866      * Send the message, expect the response of certain type.
01867      * If LLRP::CConnection::transact() returns NULL then there was
01868      * an error. In that case we try to print the error details.
01869      */
01870     pRspMsg = pConn->transact(pSendMsg, 5000);
01871 
01872     if(NULL == pRspMsg)
01873     {
01874         const CErrorDetails *   pError = pConn->getTransactError();
01875 
01876         printf("ERROR: %s transact failed, %s\n",
01877             pSendMsg->m_pType->m_pName,
01878             pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given");
01879 
01880         if(NULL != pError->m_pRefType)
01881         {
01882             printf("ERROR: ... reference type %s\n",
01883                 pError->m_pRefType->m_pName);
01884         }
01885 
01886         if(NULL != pError->m_pRefField)
01887         {
01888             printf("ERROR: ... reference field %s\n",
01889                 pError->m_pRefField->m_pName);
01890         }
01891 
01892         return NULL;
01893     }
01894 
01895     /*
01896      * Print the XML text for the inbound message if
01897      * verbosity is 2 or higher.
01898      */
01899     if(1 < m_Verbose)
01900     {
01901         printf("\n- - - - - - - - - - - - - - - - - -\n");
01902         printf("INFO: Transact received response\n");
01903         printXMLMessage(pRspMsg);
01904     }
01905 
01906     /*
01907      * If it is an ERROR_MESSAGE (response from reader
01908      * when it can't understand the request), tattle
01909      * and declare defeat.
01910      */
01911     if(&CERROR_MESSAGE::s_typeDescriptor == pRspMsg->m_pType)
01912     {
01913         const CTypeDescriptor * pResponseType;
01914 
01915         pResponseType = pSendMsg->m_pType->m_pResponseType;
01916 
01917         printf("ERROR: Received ERROR_MESSAGE instead of %s\n",
01918             pResponseType->m_pName);
01919         delete pRspMsg;
01920         pRspMsg = NULL;
01921     }
01922 
01923     return pRspMsg;
01924 }
01925 
01926 
01951 CMessage *
01952 CMyApplication::recvMessage (
01953   int                           nMaxMS)
01954 {
01955     CConnection *               pConn = m_pConnectionToReader;
01956     CMessage *                  pMessage;
01957 
01958     /*
01959      * Receive the message subject to a time limit
01960      */
01961     pMessage = pConn->recvMessage(nMaxMS);
01962 
01963     /*
01964      * If LLRP::CConnection::recvMessage() returns NULL then there was
01965      * an error. In that case we try to print the error details.
01966      */
01967     if(NULL == pMessage)
01968     {
01969         const CErrorDetails *   pError = pConn->getRecvError();
01970 
01971         /* don't warn on timeout since this is a polling example */
01972         if(pError->m_eResultCode != RC_RecvTimeout)
01973         {
01974         printf("ERROR: recvMessage failed, %s\n",
01975             pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given");
01976         }
01977 
01978         if(NULL != pError->m_pRefType)
01979         {
01980             printf("ERROR: ... reference type %s\n",
01981                 pError->m_pRefType->m_pName);
01982         }
01983 
01984         if(NULL != pError->m_pRefField)
01985         {
01986             printf("ERROR: ... reference field %s\n",
01987                 pError->m_pRefField->m_pName);
01988         }
01989 
01990         return NULL;
01991     }
01992 
01993     /*
01994      * Print the XML text for the inbound message if
01995      * verbosity is 2 or higher.
01996      */
01997     if(1 < m_Verbose)
01998     {
01999         printf("\n===================================\n");
02000         printf("INFO: Message received\n");
02001         printXMLMessage(pMessage);
02002     }
02003 
02004     return pMessage;
02005 }
02006 
02007 
02025 int
02026 CMyApplication::sendMessage (
02027   CMessage *                    pSendMsg)
02028 {
02029     CConnection *               pConn = m_pConnectionToReader;
02030 
02031     /*
02032      * Print the XML text for the outbound message if
02033      * verbosity is 2 or higher.
02034      */
02035     if(1 < m_Verbose)
02036     {
02037         printf("\n===================================\n");
02038         printf("INFO: Sending\n");
02039         printXMLMessage(pSendMsg);
02040     }
02041 
02042     /*
02043      * If LLRP::CConnection::sendMessage() returns other than RC_OK
02044      * then there was an error. In that case we try to print
02045      * the error details.
02046      */
02047     if(RC_OK != pConn->sendMessage(pSendMsg))
02048     {
02049         const CErrorDetails *   pError = pConn->getSendError();
02050 
02051         printf("ERROR: %s sendMessage failed, %s\n",
02052             pSendMsg->m_pType->m_pName,
02053             pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given");
02054 
02055         if(NULL != pError->m_pRefType)
02056         {
02057             printf("ERROR: ... reference type %s\n",
02058                 pError->m_pRefType->m_pName);
02059         }
02060 
02061         if(NULL != pError->m_pRefField)
02062         {
02063             printf("ERROR: ... reference field %s\n",
02064                 pError->m_pRefField->m_pName);
02065         }
02066 
02067         return -1;
02068     }
02069 
02070     /*
02071      * Victory
02072      */
02073     return 0;
02074 }
02075 
02076 
02090 void
02091 CMyApplication::printXMLMessage (
02092   CMessage *                    pMessage)
02093 {
02094     char                        aBuf[100*1024];
02095 
02096     /*
02097      * Convert the message to an XML string.
02098      * This fills the buffer with either the XML string
02099      * or an error message. The return value could
02100      * be checked.
02101      */
02102 
02103     pMessage->toXMLString(aBuf, sizeof aBuf);
02104 
02105     /*
02106      * Print the XML Text to the standard output.
02107      */
02108     printf("%s", aBuf);
02109 }