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