LTKCPP-- LLRP Toolkit C Plus Plus Library
target/sdk/libltkcpp-win/docsample5/docsample5.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,2010. All rights reserved.                *
00012  *                                                                           *
00013  *****************************************************************************/
00014 
00048 #include <stdio.h>
00049 #include "ltkcpp.h"
00050 #include "impinj_ltkcpp.h"
00051 #include "time.h"
00052 
00053 using namespace LLRP;
00054 
00055 /*
00056 ** Sorry, we use this linux safe method
00057 ** to print buffers.  WIndows has the same
00058 ** method, but by a different name
00059 */
00060 #if (WIN32)
00061 #define snprintf _snprintf
00062 #endif
00063 
00064 class CMyApplication
00065 {
00066 private:
00067 
00068     unsigned int m_PowerLevelIndex;
00069     unsigned int m_messageID;
00070 
00071   public:
00072     /* Store the command line parsing here */ 
00073     /* Verbose level, incremented by each -v on command line */
00074     int                         m_Verbose;
00075     unsigned int                m_password;
00076     unsigned short int          m_qtmode;
00077     unsigned short int          m_tid;
00078     EImpinjQTAccessRange        m_shortRange;
00079     unsigned int                m_newPassword;
00080 
00082     CConnection *               m_pConnectionToReader;
00083 
00084     inline
00085     CMyApplication (void)
00086      : m_Verbose(0), m_pConnectionToReader(NULL)
00087     {
00088         m_messageID = 0;
00089         m_shortRange=ImpinjQTAccessRange_Normal_Range;
00090         m_password = 0;
00091         m_qtmode = 0;
00092         m_tid = 0;
00093         m_Verbose = 0;        
00094     }
00095 
00096     int
00097     run (
00098       char *                    pReaderHostName);
00099 
00100     int
00101     checkConnectionStatus (void);
00102 
00103     int
00104     enableImpinjExtensions (void);
00105 
00106     int
00107     resetConfigurationToFactoryDefaults (void);
00108 
00109     int 
00110     getReaderCapabilities(void);
00111 
00112     int
00113     setImpinjReaderConfig(void);
00114 
00115     int
00116     addROSpec (void);
00117 
00118     int
00119     enableROSpec (void);
00120 
00121     int
00122     startROSpec (void);
00123 
00124     int
00125     stopROSpec (void);
00126 
00127     int 
00128     addAccessSpec(void);
00129 
00130     int
00131     enableAccessSpec(void);
00132 
00133     int
00134     awaitAndPrintReport (int timeoutSec);
00135 
00136     void
00137     printTagReportData (
00138       CRO_ACCESS_REPORT *       pRO_ACCESS_REPORT);
00139 
00140     void
00141     printOneTagReportData (
00142       CTagReportData *          pTagReportData);
00143 
00144     int
00145     formatOneEPC (
00146       CParameter           *pEPCParameter, 
00147       char *                buf, 
00148       int                   buflen,
00149       char *                startStr);
00150 
00151     int
00152     formatOneWriteResult (
00153       CParameter *          pWriteResilt,
00154       char *                buf,
00155       int                   buflen,
00156       char *                startStr);
00157     int
00158     formatOneSetQTConfigResult (
00159       CParameter *          pQTResilt,
00160       char *                buf,
00161       int                   buflen,
00162       char *                startStr);
00163 
00164     int
00165     formatOneGetQTConfigResult (
00166       CParameter *          pQTResilt,
00167       char *                buf,
00168       int                   buflen,
00169       char *                startStr);
00170 
00171     int
00172     formatOneSerializedTID (
00173       CParameter *          pTID,
00174       char *                buf,
00175       int                   buflen,
00176       char *                startStr);
00177 
00178     int
00179     formatOneReadResult (
00180       CParameter *          pReadResult,
00181       char *                buf,
00182       int                   buflen,
00183       char *                startStr);
00184 
00185     void
00186     handleReaderEventNotification (
00187       CReaderEventNotificationData *pNtfData);
00188 
00189     void
00190     handleAntennaEvent (
00191       CAntennaEvent *           pAntennaEvent);
00192 
00193     void
00194     handleReaderExceptionEvent (
00195       CReaderExceptionEvent *   pReaderExceptionEvent);
00196 
00197     int
00198     checkLLRPStatus (
00199       CLLRPStatus *             pLLRPStatus,
00200       char *                    pWhatStr);
00201 
00202     CMessage *
00203     transact (
00204       CMessage *                pSendMsg);
00205 
00206     CMessage *
00207     recvMessage (
00208       int                       nMaxMS);
00209 
00210     int
00211     sendMessage (
00212       CMessage *                pSendMsg);
00213 
00214     void
00215     printXMLMessage (
00216       CMessage *                pMessage);
00217 };
00218 
00219 
00220 /* BEGIN forward declarations */
00221 int
00222 main (
00223   int                           ac,
00224   char *                        av[]);
00225 
00226 void
00227 usage (
00228   char *                        pProgName);
00229 /* END forward declarations */
00230 
00231 
00247 int
00248 main (
00249   int                           ac,
00250   char *                        av[])
00251 {
00252     CMyApplication              myApp;
00253     char *                      pReaderHostName;
00254     int                         rc;
00255     int                         i;
00256 
00257     /*
00258      * Process comand arguments, determine reader name
00259      * and verbosity level.
00260      */
00261 
00262     if( ac < 2)
00263     {
00264         usage(av[0]);
00265         return -1;
00266     }
00267 
00268     srand((unsigned int) time(NULL));
00269 
00270 
00271     /* get the options. Skip the last one as its the hostname */
00272     for( i = 1; i < ac-1; i++)
00273     {
00274         if((0 == strcmp(av[i],"-p")) && (i < (ac-1)))
00275         {
00276             i++;
00277             myApp.m_password = atoi(av[i]);    
00278         }
00279         else if((0 == strcmp(av[i],"-n")) && (i < (ac-1)))
00280         {
00281             i++;
00282             myApp.m_newPassword = atoi(av[i]);    
00283         }        
00284         else if(0==strcmp(av[i], "-t"))
00285         {
00286             myApp.m_tid=1;
00287         }
00288         else if(0==strcmp(av[i], "-s"))
00289         {
00290             myApp.m_shortRange=ImpinjQTAccessRange_Short_Range ;
00291         }
00292         else if((0 == strcmp(av[i],"-v")) && (i < (ac-1)))
00293         {
00294             i++;
00295             myApp.m_Verbose = atoi(av[i]);    
00296         }
00297         else if((0 == strcmp(av[i],"-q")) && (i < (ac-1)))
00298         {
00299             i++;
00300             myApp.m_qtmode = atoi(av[i]);  
00301         }
00302         else
00303         {
00304             usage(av[0]);
00305             return -1;
00306         }
00307     }
00308 
00309     pReaderHostName = av[i];
00310 
00311     /*
00312      * Run application, capture return value for exit status
00313      */
00314     rc = myApp.run(pReaderHostName );
00315 
00316     printf("INFO: Done\n");
00317 
00318     /*
00319      * Exit with the right status.
00320      */
00321     if(0 == rc)
00322     {
00323         exit(0);
00324     }
00325     else
00326     {
00327         exit(2);
00328     }
00329     /*NOTREACHED*/
00330 }
00331 
00332 
00344 void
00345 usage (
00346   char *                        pProgName)
00347 {
00348     printf("Usage: %s [options] READERHOSTNAME\n", pProgName);
00349     printf("     -p <password> -- specify an optional password for operations\n");
00350     printf("     -n <password> -- specifies a new password for the set password command\n");
00351     printf("     -t  -- specify to automatically backscatter the TID\n");
00352     printf("     -s  -- if setting QT config, -s will short range the tag\n");
00353     printf("     -q <n>  -- run QT scenario n where n is defined as \n");
00354     printf("         0 -- Read standard TID memory\n");
00355     printf("         1 -- set tag password (uses -p, -n )\n");
00356     printf("         2 -- Read private memory data without QT commands\n");
00357     printf("         3 -- read QT status of tag (uses -p)\n");
00358     printf("         4 -- set QT status of tag to private (uses -p, -s)\n");
00359     printf("         5 -- set QT status of tag to public (uses -p, -s)\n");
00360     printf("         6 -- Peek at private memory data with temporary QT command (uses -p)\n");   
00361     printf("         7 -- Write 32 words of user data to random values\n");
00362     printf("         8 -- Write 6 words of public EPC data to random values\n");
00363     printf("         9 -- Read Reserved memory\n");
00364     printf("\n");
00365 
00366     exit(1);
00367 }
00368 
00369 
00414 int
00415 CMyApplication::run (
00416   char *                        pReaderHostName)
00417 {
00418     CTypeRegistry *             pTypeRegistry;
00419     CConnection *               pConn;
00420     int                         rc;
00421 
00422     /*
00423      * Allocate the type registry. This is needed
00424      * by the connection to decode.
00425      */
00426     pTypeRegistry = getTheTypeRegistry();
00427     if(NULL == pTypeRegistry)
00428     {
00429         printf("ERROR: getTheTypeRegistry failed\n");
00430         return -1;
00431     }
00432 
00433     /*
00434      * Enroll impinj extension types into the 
00435      * type registry, in preparation for using 
00436      * Impinj extension params.
00437      */
00438     LLRP::enrollImpinjTypesIntoRegistry(pTypeRegistry);
00439 
00440     /*
00441      * Construct a connection (LLRP::CConnection).
00442      * Using a 32kb max frame size for send/recv.
00443      * The connection object is ready for business
00444      * but not actually connected to the reader yet.
00445      */
00446     pConn = new CConnection(pTypeRegistry, 32u*1024u);
00447     if(NULL == pConn)
00448     {
00449         printf("ERROR: new CConnection failed\n");
00450         return -2;
00451     }
00452 
00453     /*
00454      * Open the connection to the reader
00455      */
00456     if(m_Verbose)
00457     {
00458         printf("INFO: Connecting to %s....\n", pReaderHostName);
00459     }
00460 
00461     rc = pConn->openConnectionToReader(pReaderHostName);
00462     if(0 != rc)
00463     {
00464         printf("ERROR: connect: %s (%d)\n", pConn->getConnectError(), rc);
00465         delete pConn;
00466         return -3;
00467     }
00468 
00469     /*
00470      * Record the pointer to the connection object so other
00471      * routines can use it.
00472      */
00473     m_pConnectionToReader = pConn;
00474 
00475     if(m_Verbose)
00476     {
00477         printf("INFO: Connected, checking status....\n");
00478     }
00479 
00480     /*
00481      * Commence the sequence and check for errors as we go.
00482      * See comments for each routine for details.
00483      * Each routine prints messages.
00484      */
00485     rc = 1;
00486     if(0 == checkConnectionStatus())
00487     {
00488         rc = 2;
00489         if(0 == enableImpinjExtensions())
00490         {
00491             rc = 3;
00492             if(0 == resetConfigurationToFactoryDefaults())
00493             {
00494                 rc = 4;
00495                 if(0 == getReaderCapabilities())
00496                 {
00497                     rc = 5;
00498                     if(0 == setImpinjReaderConfig())
00499                     {
00500                         rc = 6;
00501                         if(0 == addROSpec())
00502                         {
00503                             rc = 7;
00504                             if(0 == addAccessSpec())
00505                             {
00506                                 rc = 8;
00507                                 if(0 == enableAccessSpec())
00508                                 {
00509                                     rc = 9;
00510                                     if(0 == enableROSpec())
00511                                     {
00512                                         rc = 10;
00513                                         if(0 == startROSpec())
00514                                         {
00515                                             rc = 11;
00516                                             if(0 == awaitAndPrintReport(1))
00517                                             {
00518                                                 rc = 12;
00519                                                 if(0 == stopROSpec())
00520                                                 {
00521                                                     rc = 0;
00522                                                 }
00523                                             }
00524                                         }
00525                                     }
00526                                 }
00527                             }
00528                         }
00529                     }
00530                 }
00531             }
00532 
00533             /*
00534              * After we're done, try to leave the reader
00535              * in a clean state for next use. This is best
00536              * effort and no checking of the result is done.
00537              */
00538             if(m_Verbose)
00539             {
00540                 printf("INFO: Clean up reader configuration...\n");
00541             }
00542             resetConfigurationToFactoryDefaults();
00543         }
00544     }
00545 
00546     if(m_Verbose)
00547     {
00548         printf("INFO: Finished\n");
00549     }
00550 
00551     /*
00552      * Close the connection and release its resources
00553      */
00554     pConn->closeConnectionToReader();
00555     delete pConn;
00556 
00557     /*
00558      * Done with the registry.
00559      */
00560     delete pTypeRegistry;
00561 
00562     /*
00563      * When we get here all allocated memory should have been deallocated.
00564      */
00565 
00566     return rc;
00567 }
00568 
00569 
00600 int
00601 CMyApplication::checkConnectionStatus (void)
00602 {
00603     CMessage *                  pMessage;
00604     CREADER_EVENT_NOTIFICATION *pNtf;
00605     CReaderEventNotificationData *pNtfData;
00606     CConnectionAttemptEvent *   pEvent;
00607 
00608     /*
00609      * Expect the notification within 10 seconds.
00610      * It is suppose to be the very first message sent.
00611      */
00612     pMessage = recvMessage(10000);
00613 
00614     /*
00615      * recvMessage() returns NULL if something went wrong.
00616      */
00617     if(NULL == pMessage)
00618     {
00619         /* recvMessage already tattled */
00620         goto fail;
00621     }
00622 
00623     /*
00624      * Check to make sure the message is of the right type.
00625      * The type label (pointer) in the message should be
00626      * the type descriptor for READER_EVENT_NOTIFICATION.
00627      */
00628     if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor != pMessage->m_pType)
00629     {
00630         goto fail;
00631     }
00632 
00633     /*
00634      * Now that we are sure it is a READER_EVENT_NOTIFICATION,
00635      * traverse to the ReaderEventNotificationData parameter.
00636      */
00637     pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage;
00638     pNtfData = pNtf->getReaderEventNotificationData();
00639     if(NULL == pNtfData)
00640     {
00641         goto fail;
00642     }
00643 
00644     /*
00645      * The ConnectionAttemptEvent parameter must be present.
00646      */
00647     pEvent = pNtfData->getConnectionAttemptEvent();
00648     if(NULL == pEvent)
00649     {
00650         goto fail;
00651     }
00652 
00653     /*
00654      * The status in the ConnectionAttemptEvent parameter
00655      * must indicate connection success.
00656      */
00657     if(ConnectionAttemptStatusType_Success != pEvent->getStatus())
00658     {
00659         goto fail;
00660     }
00661 
00662     /*
00663      * Done with the message
00664      */
00665     delete pMessage;
00666 
00667     if(m_Verbose)
00668     {
00669         printf("INFO: Connection status OK\n");
00670     }
00671 
00672     /*
00673      * Victory.
00674      */
00675     return 0;
00676 
00677   fail:
00678     /*
00679      * Something went wrong. Tattle. Clean up. Return error.
00680      */
00681     printf("ERROR: checkConnectionStatus failed\n");
00682     delete pMessage;
00683     return -1;
00684 }
00685 
00703 int
00704 CMyApplication::enableImpinjExtensions (void)
00705 {
00706     CIMPINJ_ENABLE_EXTENSIONS *        pCmd;
00707     CMessage *                         pRspMsg;
00708     CIMPINJ_ENABLE_EXTENSIONS_RESPONSE *pRsp;
00709 
00710     /*
00711      * Compose the command message
00712      */
00713     pCmd = new CIMPINJ_ENABLE_EXTENSIONS();
00714     pCmd->setMessageID(m_messageID++);
00715     /*
00716      * Send the message, expect the response of certain type
00717      */
00718     pRspMsg = transact(pCmd);
00719 
00720     /*
00721      * Done with the command message
00722      */
00723     delete pCmd;
00724 
00725     /*
00726      * transact() returns NULL if something went wrong.
00727      */
00728     if(NULL == pRspMsg)
00729     {
00730         /* transact already tattled */
00731         return -1;
00732     }
00733 
00734     /*
00735      * Cast to a CIMPINJ_ENABLE_EXTENSIONS_RESPONSE message.
00736      */
00737     pRsp = (CIMPINJ_ENABLE_EXTENSIONS_RESPONSE *) pRspMsg;
00738 
00739     /*
00740      * Check the LLRPStatus parameter.
00741      */
00742     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(),
00743                         "enableImpinjExtensions"))
00744     {
00745         /* checkLLRPStatus already tattled */
00746         delete pRspMsg;
00747         return -1;
00748     }
00749 
00750     /*
00751      * Done with the response message.
00752      */
00753     delete pRspMsg;
00754 
00755     /*
00756      * Tattle progress, maybe
00757      */
00758     if(m_Verbose)
00759     {
00760         printf("INFO: Impinj Extensions are enabled\n");
00761     }
00762 
00763     /*
00764      * Victory.
00765      */
00766     return 0;
00767 }
00768 
00789 int
00790 CMyApplication::resetConfigurationToFactoryDefaults (void)
00791 {
00792     CSET_READER_CONFIG *        pCmd;
00793     CMessage *                  pRspMsg;
00794     CSET_READER_CONFIG_RESPONSE *pRsp;
00795 
00796     /*
00797      * Compose the command message
00798      */
00799     pCmd = new CSET_READER_CONFIG();
00800     pCmd->setMessageID(m_messageID++);
00801     pCmd->setResetToFactoryDefault(1);
00802 
00803     /*
00804      * Send the message, expect the response of certain type
00805      */
00806     pRspMsg = transact(pCmd);
00807 
00808     /*
00809      * Done with the command message
00810      */
00811     delete pCmd;
00812 
00813     /*
00814      * transact() returns NULL if something went wrong.
00815      */
00816     if(NULL == pRspMsg)
00817     {
00818         /* transact already tattled */
00819         return -1;
00820     }
00821 
00822     /*
00823      * Cast to a SET_READER_CONFIG_RESPONSE message.
00824      */
00825     pRsp = (CSET_READER_CONFIG_RESPONSE *) pRspMsg;
00826 
00827     /*
00828      * Check the LLRPStatus parameter.
00829      */
00830     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(),
00831                         "resetConfigurationToFactoryDefaults"))
00832     {
00833         /* checkLLRPStatus already tattled */
00834         delete pRspMsg;
00835         return -1;
00836     }
00837 
00838     /*
00839      * Done with the response message.
00840      */
00841     delete pRspMsg;
00842 
00843     /*
00844      * Tattle progress, maybe
00845      */
00846     if(m_Verbose)
00847     {
00848         printf("INFO: Configuration reset to factory defaults\n");
00849     }
00850 
00851     /*
00852      * Victory.
00853      */
00854     return 0;
00855 }
00856 
00857 
00871 int
00872 CMyApplication::getReaderCapabilities(void)
00873 {
00874     CGET_READER_CAPABILITIES          *pCmd;
00875     CMessage *                         pRspMsg;
00876     CGET_READER_CAPABILITIES_RESPONSE *pRsp;
00877       CGeneralDeviceCapabilities          *pDevCap;
00878     unsigned int bMajorVersion, bMinorVersion, bDevVersion, bBuildVersion = 0;
00879 
00880 
00881     /*
00882      * Compose the command message
00883      */
00884     pCmd = new CGET_READER_CAPABILITIES();
00885     pCmd->setMessageID(m_messageID++);
00886     pCmd->setRequestedData(GetReaderCapabilitiesRequestedData_All);
00887 
00888     /*
00889      * Send the message, expect the response of certain type
00890      */
00891     pRspMsg = transact(pCmd);
00892 
00893     /*
00894      * Done with the command message
00895      */
00896     delete pCmd;
00897 
00898     /*
00899      * transact() returns NULL if something went wrong.
00900      */
00901     if(NULL == pRspMsg)
00902     {
00903         /* transact already tattled */
00904         return -1;
00905     }
00906 
00907     /*
00908      * Cast to a CGET_READER_CAPABILITIES_RESPONSE message.
00909      */
00910     pRsp = (CGET_READER_CAPABILITIES_RESPONSE *) pRspMsg;
00911 
00912     /*
00913      * Check the LLRPStatus parameter.
00914      */
00915     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(),
00916                         "getReaderCapabilities"))
00917     {
00918         /* checkLLRPStatus already tattled */
00919         delete pRspMsg;
00920         return -1;
00921     }
00922 
00923     /*
00924     ** Get out the general device capabilities
00925     */
00926     if(NULL == (pDevCap = pRsp->getGeneralDeviceCapabilities()))
00927     {
00928         delete pRspMsg;
00929         return -1;
00930     }
00931 
00932 
00933     /* if this parameter is missing, or if this is not an Impinj
00934     ** reader, we can't determine its capabilities so we exit
00935     ** Impinj Private Enterprise NUmber is 25882 */
00936     if( (NULL == (pDevCap = pRsp->getGeneralDeviceCapabilities())) || 
00937         (25882 != pDevCap->getDeviceManufacturerName()))
00938     {
00939         delete pRspMsg;
00940         return -1;
00941     }
00942 
00943 
00944   /*
00945    * Get the version information from the reader and make sure we are 4.4 or better.
00946    */
00947   if  ( pDevCap->getReaderFirmwareVersion().m_nValue < 3)
00948   {
00949         printf("ERROR: Must have Firmware 4.4 or later for low level data example \n");
00950         delete pRspMsg;
00951         return -1;
00952   }
00953 
00954   /*
00955    * Parse to make sure it is really 4.4 or better
00956    */
00957   sscanf((char *) pDevCap->getReaderFirmwareVersion().m_pValue, "%u.%u.%u.%u", &bMajorVersion, &bMinorVersion, &bDevVersion, &bBuildVersion);
00958 
00959     if( (bMajorVersion < 4) && (bMinorVersion < 4) )
00960     {
00961         printf("ERROR: Must have Firmware 4.4 or later for low level data example \n");
00962         delete pRspMsg;
00963         return -1;
00964     }
00965 
00966     /*
00967      * Done with the response message.
00968      */
00969     delete pRspMsg;
00970 
00971     /*
00972      * Tattle progress, maybe
00973      */
00974     if(m_Verbose)
00975     {
00976         printf("INFO: Found LLRP Capabilities \n");
00977     }
00978 
00979     /*
00980      * Victory.
00981      */
00982     return 0;
00983 }
00984 
00985 
01000 int
01001 CMyApplication::setImpinjReaderConfig(void)
01002 {
01003     CSET_READER_CONFIG          *pCmd;
01004     CMessage *                  pRspMsg;
01005     CSET_READER_CONFIG_RESPONSE *pRsp;
01006 
01007     /*
01008      * Compose the command message
01009      */
01010     pCmd = new CSET_READER_CONFIG();
01011     pCmd->setMessageID(m_messageID++);
01012 
01013     CAntennaConfiguration *pAnt = new(CAntennaConfiguration);
01014 
01015     /*
01016     ** Apply this configuration to all antennas 
01017     */
01018     pAnt->setAntennaID(0);
01019 
01020     /*
01021     ** Create the container Inventory command to hold all the parameters 
01022     */
01023     CC1G2InventoryCommand *pC1G2Inv = new CC1G2InventoryCommand();
01024     
01025     /* set the mode to auto-set max throughput */
01026     CC1G2RFControl *pC1G2Rf = new CC1G2RFControl();
01027     pC1G2Rf->setModeIndex(2); /* DRM M=4 */
01028     pC1G2Rf->setTari(0);        /* tari is ignored by the reader */
01029     pC1G2Inv->setC1G2RFControl(pC1G2Rf);
01030 
01031     CC1G2SingulationControl *pC1G2Sing = new CC1G2SingulationControl();    
01032     pC1G2Sing->setSession(1);
01033     pC1G2Sing->setTagPopulation(1);
01034     pC1G2Sing->setTagTransitTime(0);
01035     pC1G2Inv->setC1G2SingulationControl(pC1G2Sing);
01036 
01037     pC1G2Inv->setTagInventoryStateAware(false);
01038 
01039     /* set the Impinj Inventory search mode as per the use case */
01040     CImpinjInventorySearchMode *pImpIsm = new CImpinjInventorySearchMode();
01041     pImpIsm->setInventorySearchMode(ImpinjInventorySearchType_Single_Target);
01042     pC1G2Inv->addCustom(pImpIsm);
01043 
01044     /* 
01045     ** set the Impinj Low Duty Cycle mode as per the use case 
01046     */
01047     CImpinjLowDutyCycle *pImpLdc = new CImpinjLowDutyCycle();
01048     pImpLdc->setEmptyFieldTimeout(10000);
01049     pImpLdc->setFieldPingInterval(200);
01050     pImpLdc->setLowDutyCycleMode(ImpinjLowDutyCycleMode_Enabled);
01051     pC1G2Inv->addCustom(pImpLdc);
01052 
01053     /*
01054     ** Don't forget to add the InventoryCommand to the antenna
01055     ** configuration, and then add the antenna configuration to the
01056     ** config message
01057     */
01058     pAnt->addAirProtocolInventoryCommandSettings(pC1G2Inv);
01059     pCmd->addAntennaConfiguration(pAnt);
01060 
01061     /* 
01062     ** report every tag (N=1) since that is required for tag direction 
01063     */
01064     CROReportSpec *pROrs = new CROReportSpec();
01065     pROrs->setROReportTrigger(ROReportTriggerType_Upon_N_Tags_Or_End_Of_ROSpec);
01066     pROrs->setN(1);
01067 
01068     /* 
01069     ** Turn off off report data that we don't need since our use 
01070     ** case suggests we are bandwidth constrained 
01071     */
01072     CTagReportContentSelector *pROcontent = new CTagReportContentSelector();
01073     pROcontent->setEnableAccessSpecID(false);
01074     pROcontent->setEnableAntennaID(false);
01075     pROcontent->setEnableChannelIndex(false);
01076     pROcontent->setEnableFirstSeenTimestamp(true);
01077     pROcontent->setEnableInventoryParameterSpecID(false);
01078     pROcontent->setEnableLastSeenTimestamp(false);
01079     pROcontent->setEnablePeakRSSI(false);
01080     pROcontent->setEnableROSpecID(false);
01081     pROcontent->setEnableSpecIndex(false);
01082     pROcontent->setEnableTagSeenCount(false);
01083     CC1G2EPCMemorySelector *pC1G2Mem = new CC1G2EPCMemorySelector();
01084     pC1G2Mem->setEnableCRC(false);
01085     pC1G2Mem->setEnablePCBits(false);
01086     pROcontent->addAirProtocolEPCMemorySelector(pC1G2Mem);
01087     pROrs->setTagReportContentSelector(pROcontent);
01088 
01089     /* Optionally turn on EPC/TID backscatter. leave the others off as
01090     ** low level data is another example */
01091     CImpinjTagReportContentSelector * pImpTagCnt = new CImpinjTagReportContentSelector();
01092     
01093     CImpinjEnableRFPhaseAngle       * pEnableRfPhase = new CImpinjEnableRFPhaseAngle();
01094     pEnableRfPhase->setRFPhaseAngleMode(ImpinjRFPhaseAngleMode_Disabled);
01095     pImpTagCnt->setImpinjEnableRFPhaseAngle(pEnableRfPhase);
01096 
01097     CImpinjEnablePeakRSSI       * pEnablePeakRssi = new CImpinjEnablePeakRSSI();
01098     pEnablePeakRssi->setPeakRSSIMode(ImpinjPeakRSSIMode_Disabled);
01099     pImpTagCnt->setImpinjEnablePeakRSSI(pEnablePeakRssi);
01100 
01101     CImpinjEnableSerializedTID  * pEnableSerializedTID = new CImpinjEnableSerializedTID();
01102 
01103     /* Here's where we set the backscatter of the TID */
01104     if(m_tid)
01105         pEnableSerializedTID->setSerializedTIDMode(ImpinjSerializedTIDMode_Enabled);
01106     else
01107         pEnableSerializedTID->setSerializedTIDMode(ImpinjSerializedTIDMode_Disabled);
01108 
01109     pImpTagCnt->setImpinjEnableSerializedTID(pEnableSerializedTID);   
01110 
01111     pROrs->addCustom(pImpTagCnt);    
01112 
01113     pCmd->setROReportSpec(pROrs);
01114 
01115     /*
01116      * Send the message, expect the response of certain type
01117      */
01118     pRspMsg = transact(pCmd);
01119 
01120     /*
01121      * Done with the command message
01122      */
01123     delete pCmd;
01124 
01125     /*
01126      * transact() returns NULL if something went wrong.
01127      */
01128     if(NULL == pRspMsg)
01129     {
01130         /* transact already tattled */
01131         return -1;
01132     }
01133 
01134     /*
01135      * Cast to a CSET_READER_CONFIG_RESPONSE message.
01136      */
01137     pRsp = (CSET_READER_CONFIG_RESPONSE *) pRspMsg;
01138 
01139     /*
01140      * Check the LLRPStatus parameter.
01141      */
01142     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(),
01143                         "setImpinjReaderConfig"))
01144     {
01145         /* checkLLRPStatus already tattled */
01146         delete pRspMsg;
01147         return -1;
01148     }
01149 
01150     /*
01151      * Done with the response message.
01152      */
01153     delete pRspMsg;
01154 
01155     /*
01156      * Tattle progress, maybe
01157      */
01158     if(m_Verbose)
01159     {
01160         printf("INFO: Set Impinj Reader Configuration \n");
01161     }
01162 
01163     /*
01164      * Victory.
01165      */
01166     return 0;
01167 }
01168 
01246 int
01247 CMyApplication::addROSpec (void)
01248 {
01249     CROSpecStartTrigger *       pROSpecStartTrigger =
01250                                     new CROSpecStartTrigger();
01251     pROSpecStartTrigger->setROSpecStartTriggerType(
01252                                 ROSpecStartTriggerType_Null);
01253 
01254     CROSpecStopTrigger *        pROSpecStopTrigger = new CROSpecStopTrigger();
01255     pROSpecStopTrigger->setROSpecStopTriggerType(ROSpecStopTriggerType_Null);
01256     pROSpecStopTrigger->setDurationTriggerValue(0);     /* n/a */
01257 
01258     CROBoundarySpec *           pROBoundarySpec = new CROBoundarySpec();
01259     pROBoundarySpec->setROSpecStartTrigger(pROSpecStartTrigger);
01260     pROBoundarySpec->setROSpecStopTrigger(pROSpecStopTrigger);
01261 
01262     CAISpecStopTrigger *        pAISpecStopTrigger = new CAISpecStopTrigger();
01263     pAISpecStopTrigger->setAISpecStopTriggerType(
01264             AISpecStopTriggerType_Null);
01265     pAISpecStopTrigger->setDurationTrigger(0);
01266 
01267     CInventoryParameterSpec *   pInventoryParameterSpec =
01268                                     new CInventoryParameterSpec();
01269     pInventoryParameterSpec->setInventoryParameterSpecID(1234);
01270     pInventoryParameterSpec->setProtocolID(AirProtocols_EPCGlobalClass1Gen2);
01271 
01272     /* Build the antennaConfiguration to Contain this */
01273     CAntennaConfiguration * pAntennaConfiguration = 
01274                                     new CAntennaConfiguration();
01275     pAntennaConfiguration->setAntennaID(0);
01276 
01277     /* don't forget to add this to the INventory Parameter Spec above */
01278     pInventoryParameterSpec->addAntennaConfiguration(pAntennaConfiguration);
01279 
01280     /* 
01281     ** Use all Antennas
01282     */
01283     llrp_u16v_t                 AntennaIDs = llrp_u16v_t(1);
01284     AntennaIDs.m_pValue[0] = 0;
01285 
01286     CAISpec *                   pAISpec = new CAISpec();
01287     pAISpec->setAntennaIDs(AntennaIDs);
01288     pAISpec->setAISpecStopTrigger(pAISpecStopTrigger);
01289     pAISpec->addInventoryParameterSpec(pInventoryParameterSpec);
01290 
01291     CROSpec *                   pROSpec = new CROSpec();
01292     pROSpec->setROSpecID(1111);
01293     pROSpec->setPriority(0);
01294     pROSpec->setCurrentState(ROSpecState_Disabled);
01295     pROSpec->setROBoundarySpec(pROBoundarySpec);
01296     pROSpec->addSpecParameter(pAISpec);
01297 
01298     CADD_ROSPEC *               pCmd;
01299     CMessage *                  pRspMsg;
01300     CADD_ROSPEC_RESPONSE *      pRsp;
01301 
01302     /*
01303      * Compose the command message.
01304      * N.B.: After the message is composed, all the parameters
01305      *       constructed, immediately above, are considered "owned"
01306      *       by the command message. When it is destructed so
01307      *       too will the parameters be.
01308      */
01309     pCmd = new CADD_ROSPEC();
01310     pCmd->setMessageID(m_messageID++);
01311     pCmd->setROSpec(pROSpec);
01312 
01313     /*
01314      * Send the message, expect the response of certain type
01315      */
01316     pRspMsg = transact(pCmd);
01317 
01318     /*
01319      * Done with the command message.
01320      * N.B.: And the parameters
01321      */
01322     delete pCmd;
01323 
01324     /*
01325      * transact() returns NULL if something went wrong.
01326      */
01327     if(NULL == pRspMsg)
01328     {
01329         /* transact already tattled */
01330         return -1;
01331     }
01332 
01333     /*
01334      * Cast to a ADD_ROSPEC_RESPONSE message.
01335      */
01336     pRsp = (CADD_ROSPEC_RESPONSE *) pRspMsg;
01337 
01338     /*
01339      * Check the LLRPStatus parameter.
01340      */
01341     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "addROSpec"))
01342     {
01343         /* checkLLRPStatus already tattled */
01344         delete pRspMsg;
01345         return -1;
01346     }
01347 
01348     /*
01349      * Done with the response message.
01350      */
01351     delete pRspMsg;
01352 
01353     /*
01354      * Tattle progress, maybe
01355      */
01356     if(m_Verbose)
01357     {
01358         printf("INFO: ROSpec added\n");
01359     }
01360 
01361     /*
01362      * Victory.
01363      */
01364     return 0;
01365 }
01366 
01367 
01385 int
01386 CMyApplication::enableROSpec (void)
01387 {
01388     CENABLE_ROSPEC *            pCmd;
01389     CMessage *                  pRspMsg;
01390     CENABLE_ROSPEC_RESPONSE *   pRsp;
01391 
01392     /*
01393      * Compose the command message
01394      */
01395     pCmd = new CENABLE_ROSPEC();
01396     pCmd->setMessageID(m_messageID++);
01397     pCmd->setROSpecID(1111);
01398 
01399     /*
01400      * Send the message, expect the response of certain type
01401      */
01402     pRspMsg = transact(pCmd);
01403 
01404     /*
01405      * Done with the command message
01406      */
01407     delete pCmd;
01408 
01409     /*
01410      * transact() returns NULL if something went wrong.
01411      */
01412     if(NULL == pRspMsg)
01413     {
01414         /* transact already tattled */
01415         return -1;
01416     }
01417 
01418     /*
01419      * Cast to a ENABLE_ROSPEC_RESPONSE message.
01420      */
01421     pRsp = (CENABLE_ROSPEC_RESPONSE *) pRspMsg;
01422 
01423     /*
01424      * Check the LLRPStatus parameter.
01425      */
01426     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "enableROSpec"))
01427     {
01428         /* checkLLRPStatus already tattled */
01429         delete pRspMsg;
01430         return -1;
01431     }
01432 
01433     /*
01434      * Done with the response message.
01435      */
01436     delete pRspMsg;
01437 
01438     /*
01439      * Tattle progress, maybe
01440      */
01441     if(m_Verbose)
01442     {
01443         printf("INFO: ROSpec enabled\n");
01444     }
01445 
01446     /*
01447      * Victory.
01448      */
01449     return 0;
01450 }
01451 
01452 
01470 int
01471 CMyApplication::startROSpec (void)
01472 {
01473     CSTART_ROSPEC *             pCmd;
01474     CMessage *                  pRspMsg;
01475     CSTART_ROSPEC_RESPONSE *    pRsp;
01476 
01477     /*
01478      * Compose the command message
01479      */
01480     pCmd = new CSTART_ROSPEC();
01481     pCmd->setMessageID(m_messageID++);
01482     pCmd->setROSpecID(1111);
01483 
01484     /*
01485      * Send the message, expect the response of certain type
01486      */
01487     pRspMsg = transact(pCmd);
01488 
01489     /*
01490      * Done with the command message
01491      */
01492     delete pCmd;
01493 
01494     /*
01495      * transact() returns NULL if something went wrong.
01496      */
01497     if(NULL == pRspMsg)
01498     {
01499         /* transact already tattled */
01500         return -1;
01501     }
01502 
01503     /*
01504      * Cast to a START_ROSPEC_RESPONSE message.
01505      */
01506     pRsp = (CSTART_ROSPEC_RESPONSE *) pRspMsg;
01507 
01508     /*
01509      * Check the LLRPStatus parameter.
01510      */
01511     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "startROSpec"))
01512     {
01513         /* checkLLRPStatus already tattled */
01514         delete pRspMsg;
01515         return -1;
01516     }
01517 
01518     /*
01519      * Done with the response message.
01520      */
01521     delete pRspMsg;
01522 
01523     /*
01524      * Tattle progress
01525      */
01526     if(m_Verbose)
01527     {
01528         printf("INFO: ROSpec started\n");
01529     }
01530 
01531     /*
01532      * Victory.
01533      */
01534     return 0;
01535 }
01536 
01554 int
01555 CMyApplication::stopROSpec (void)
01556 {
01557     CSTOP_ROSPEC *             pCmd;
01558     CMessage *                  pRspMsg;
01559     CSTOP_ROSPEC_RESPONSE *    pRsp;
01560 
01561     /*
01562      * Compose the command message
01563      */
01564     pCmd = new CSTOP_ROSPEC();
01565     pCmd->setMessageID(m_messageID++);
01566     pCmd->setROSpecID(1111);
01567 
01568     /*
01569      * Send the message, expect the response of certain type
01570      */
01571     pRspMsg = transact(pCmd);
01572 
01573     /*
01574      * Done with the command message
01575      */
01576     delete pCmd;
01577 
01578     /*
01579      * transact() returns NULL if something went wrong.
01580      */
01581     if(NULL == pRspMsg)
01582     {
01583         /* transact already tattled */
01584         return -1;
01585     }
01586 
01587     /*
01588      * Cast to a STOP_ROSPEC_RESPONSE message.
01589      */
01590     pRsp = (CSTOP_ROSPEC_RESPONSE *) pRspMsg;
01591 
01592     /*
01593      * Check the LLRPStatus parameter.
01594      */
01595     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "stopROSpec"))
01596     {
01597         /* checkLLRPStatus already tattled */
01598         delete pRspMsg;
01599         return -1;
01600     }
01601 
01602     /*
01603      * Done with the response message.
01604      */
01605     delete pRspMsg;
01606 
01607     /*
01608      * Tattle progress
01609      */
01610     if(m_Verbose)
01611     {
01612         printf("INFO: ROSpec stopped\n");
01613     }
01614 
01615     /*
01616      * Victory.
01617      */
01618     return 0;
01619 }
01620 
01633 int
01634 CMyApplication::addAccessSpec (void)
01635 {
01636     CADD_ACCESSSPEC *            pCmd;
01637     CMessage *                   pRspMsg;
01638     CADD_ACCESSSPEC_RESPONSE *   pRsp;
01639 
01640     pCmd = new CADD_ACCESSSPEC();
01641     pCmd->setMessageID(m_messageID++);
01642 
01643     /* build the C1G2Target Tag with the AccessSpec filter */
01644     CC1G2TargetTag *ptargetTag = new CC1G2TargetTag();
01645     ptargetTag->setMatch(true);
01646     ptargetTag->setMB(1);
01647     ptargetTag->setPointer(16);
01648     
01649     /* match any tag */
01650     llrp_u1v_t tagData = llrp_u1v_t(0);
01651     tagData.m_nBit = 0;
01652     ptargetTag->setTagData(tagData);
01653     llrp_u1v_t tagMask = llrp_u1v_t(0);
01654     tagMask.m_nBit = 0;
01655     ptargetTag->setTagMask(tagMask);
01656 
01657     /* build the AirProtocolTagSpec Add the filter */
01658     CC1G2TagSpec *ptagSpec = new CC1G2TagSpec();
01659     ptagSpec->addC1G2TargetTag(ptargetTag);
01660 
01661     /* Create the AccessCommand.  Add the TagSpec and the OpSpec */
01662     CAccessCommand *pAccessCommand = new CAccessCommand();
01663     pAccessCommand->setAirProtocolTagSpec(ptagSpec);
01664 
01665     /* Build the read Op Spec and add to the access command */
01666     /*
01667      **     -q <n>  -- run QT scenario n where n is defined as 
01668      **         0 -- Read standard TID memory
01669      **         1 -- set tag password (uses -p, -n)
01670      **         2 -- Read private memory data without QT commands
01671      **         3 -- read QT status of tag (uses -p)
01672      **         4 -- set QT status of tag to private (uses -p, -s)
01673      **         5 -- set QT status of tag to public (uses -p, -s)
01674      **         6 -- Peek at private memory data with temporary QT command (uses -p)
01675      **         7 -- write random data to user memory
01676      **         8 -- write random data to the public EPC space
01677     */
01678 
01679     switch(m_qtmode)
01680     {
01681     case 0:
01682         {
01683             CC1G2Read *preadStdTID = new CC1G2Read();
01684             preadStdTID->setAccessPassword(0);     /* no access required to read */
01685             preadStdTID->setMB(2);
01686             preadStdTID->setOpSpecID(1);
01687             preadStdTID->setWordCount(2);      /* standard TID */
01688             preadStdTID->setWordPointer(0);
01689             pAccessCommand->addAccessCommandOpSpec(preadStdTID);
01690         }
01691         break;
01692     case 1:
01693         {
01694             llrp_u16v_t Data = llrp_u16v_t(2);
01695             Data.m_pValue[0] = ((m_newPassword >> 16) & 0x0000ffff);
01696             Data.m_pValue[1] = (m_newPassword & 0x0000ffff);
01697 
01698             CC1G2Write *pwrite = new CC1G2Write();
01699             pwrite->setOpSpecID(10);
01700             pwrite->setMB(0);
01701             pwrite->setAccessPassword(m_password);
01702             pwrite->setWordPointer(2);
01703             pwrite->setWriteData(Data);
01704             pAccessCommand->addAccessCommandOpSpec(pwrite);
01705         }
01706         break;
01707     case 2:
01708         {
01709             CC1G2Read *preadSTID = new CC1G2Read();
01710             preadSTID->setAccessPassword(0);     /* no access required to read */
01711             preadSTID->setMB(2);
01712             preadSTID->setOpSpecID(2);
01713             preadSTID->setWordCount(6);      /* standard TID plus 48 bit STID */
01714             preadSTID->setWordPointer(0);
01715             pAccessCommand->addAccessCommandOpSpec(preadSTID);
01716 
01717             CC1G2Read *preadPEPC = new CC1G2Read();
01718             preadPEPC->setAccessPassword(0);     /* no access required to read */
01719             preadPEPC->setMB(2);
01720             preadPEPC->setOpSpecID(2);
01721             preadPEPC->setWordCount(6);      /* Public EPC memory */
01722             preadPEPC->setWordPointer(6);
01723             pAccessCommand->addAccessCommandOpSpec(preadPEPC);
01724 
01725             CC1G2Read *preadUser = new CC1G2Read();
01726             preadUser->setAccessPassword(0);     /* no access required to read */
01727             preadUser->setMB(3);
01728             preadUser->setOpSpecID(3);
01729             preadUser->setWordCount(32);        /* 512 bits of user memory */
01730             preadUser->setWordPointer(0);
01731             pAccessCommand->addAccessCommandOpSpec(preadUser);
01732         }
01733         break;
01734     default:
01735         /* for unknown, just try to read QT status */
01736     case 3:
01737         {
01738             CImpinjGetQTConfig *pgetQT = new CImpinjGetQTConfig();
01739             pgetQT->setAccessPassword(m_password);  /* use password if provided */
01740             pgetQT->setOpSpecID(4);
01741             pAccessCommand->addAccessCommandOpSpec(pgetQT);
01742         }
01743         break;
01744     case 4:
01745         {
01746             CImpinjSetQTConfig *psetQT = new CImpinjSetQTConfig();
01747             psetQT->setAccessPassword(m_password);
01748             psetQT->setOpSpecID(5);
01749             psetQT->setAccessRange(m_shortRange);
01750             psetQT->setDataProfile(ImpinjQTDataProfile_Private);
01751             psetQT->setPersistence(ImpinjQTPersistence_Permanent);
01752             pAccessCommand->addAccessCommandOpSpec(psetQT);
01753         }
01754         break;
01755     case 5:
01756         {
01757             CImpinjSetQTConfig *psetQT = new CImpinjSetQTConfig();
01758             psetQT->setAccessPassword(m_password);
01759             psetQT->setOpSpecID(6);
01760             psetQT->setAccessRange(m_shortRange);
01761             psetQT->setDataProfile(ImpinjQTDataProfile_Public);
01762             psetQT->setPersistence(ImpinjQTPersistence_Permanent);
01763             pAccessCommand->addAccessCommandOpSpec(psetQT);
01764         }
01765         break;
01766     case 6:
01767         {
01768             CImpinjSetQTConfig *psetQT = new CImpinjSetQTConfig();
01769             psetQT->setAccessPassword(m_password);
01770             psetQT->setOpSpecID(6);
01771             psetQT->setAccessRange(ImpinjQTAccessRange_Normal_Range );
01772             psetQT->setDataProfile(ImpinjQTDataProfile_Private);
01773             psetQT->setPersistence(ImpinjQTPersistence_Temporary );
01774             pAccessCommand->addAccessCommandOpSpec(psetQT);
01775 
01776             CC1G2Read *preadPrivEPC = new CC1G2Read();
01777             preadPrivEPC->setAccessPassword(0);     /* no access required to read */
01778             preadPrivEPC->setMB(1);
01779             preadPrivEPC->setOpSpecID(7);
01780             preadPrivEPC->setWordCount(8);      /* assume 128-bit */
01781             preadPrivEPC->setWordPointer(2);
01782             pAccessCommand->addAccessCommandOpSpec(preadPrivEPC);
01783 
01784             CC1G2Read *preadSTID = new CC1G2Read();
01785             preadSTID->setAccessPassword(0);     /* no access required to read */
01786             preadSTID->setMB(2);
01787             preadSTID->setOpSpecID(8);
01788             preadSTID->setWordCount(6);      /* standard TID plus 48 bit STID */
01789             preadSTID->setWordPointer(0);
01790             pAccessCommand->addAccessCommandOpSpec(preadSTID);
01791 
01792             CC1G2Read *preadUser = new CC1G2Read();
01793             preadUser->setAccessPassword(0);     /* no access required to read */
01794             preadUser->setMB(3);
01795             preadUser->setOpSpecID(9);
01796             preadUser->setWordCount(32);
01797             preadUser->setWordPointer(0);
01798             pAccessCommand->addAccessCommandOpSpec(preadUser);
01799         }
01800         break;
01801     case 7:
01802         {
01803             llrp_u16v_t Data = llrp_u16v_t(32);
01804 
01805             for(int x = 0; x < 32; x++)
01806             {
01807                 Data.m_pValue[x] = rand();
01808             }
01809             
01810             CC1G2Write *pwrite = new CC1G2Write();
01811             pwrite->setOpSpecID(10);
01812             pwrite->setMB(3);
01813             pwrite->setAccessPassword(m_password);
01814             pwrite->setWordPointer(0);
01815             pwrite->setWriteData(Data);
01816             pAccessCommand->addAccessCommandOpSpec(pwrite);
01817         }
01818         break;
01819     case 8:
01820         {
01821             llrp_u16v_t Data = llrp_u16v_t(6);
01822 
01823             for(int x = 0; x < 6; x++)
01824             {
01825                 Data.m_pValue[x] = rand();
01826             }
01827             
01828             CC1G2Write *pwrite = new CC1G2Write();
01829             pwrite->setOpSpecID(11);
01830             pwrite->setMB(2);
01831             pwrite->setAccessPassword(m_password);
01832             pwrite->setWordPointer(6);
01833             pwrite->setWriteData(Data);
01834             pAccessCommand->addAccessCommandOpSpec(pwrite);
01835         }
01836         break;
01837     case 9:
01838         {
01839             CC1G2Read *preadRsvd = new CC1G2Read();
01840             preadRsvd->setAccessPassword(0);     /* no access required to read */
01841             preadRsvd->setMB(0);
01842             preadRsvd->setOpSpecID(12);
01843             preadRsvd->setWordCount(4);      /* Access and Kill */
01844             preadRsvd->setWordPointer(0);
01845             pAccessCommand->addAccessCommandOpSpec(preadRsvd);
01846         }
01847         break;
01848     }
01849     
01850     /* set up the Access Report Spec rule to report only with ROSpecs */
01851     CAccessReportSpec *pAccessReportSpec = new CAccessReportSpec();
01852     pAccessReportSpec->setAccessReportTrigger(
01853             AccessReportTriggerType_Whenever_ROReport_Is_Generated);
01854 
01855     /* set up the stop trigger for the access spec. Do not stop */
01856     CAccessSpecStopTrigger *pAccessStopTrigger = new CAccessSpecStopTrigger();
01857     pAccessStopTrigger->setAccessSpecStopTrigger(
01858         AccessSpecStopTriggerType_Null);
01859     pAccessStopTrigger->setOperationCountValue(0);      /* ignored */
01860 
01861     /* Create and configure the AccessSpec */
01862     CAccessSpec *pAccessSpec = new CAccessSpec();
01863     pAccessSpec->setAccessSpecID(23);
01864     pAccessSpec->setAntennaID(0);       /* valid for all antennas */
01865     pAccessSpec->setCurrentState(AccessSpecState_Disabled);
01866     pAccessSpec->setProtocolID(AirProtocols_EPCGlobalClass1Gen2);
01867     pAccessSpec->setROSpecID(0);        /* valid for All RoSpecs */
01868     pAccessSpec->setAccessSpecStopTrigger(pAccessStopTrigger);
01869     pAccessSpec->setAccessReportSpec(pAccessReportSpec);
01870     pAccessSpec->setAccessCommand(pAccessCommand);
01871 
01872     /* Add the AccessSpec to the ADD_ACCESS_SPEC message */
01873     pCmd->setAccessSpec(pAccessSpec);
01874 
01875     /*
01876      * Send the message, expect the response of certain type
01877      */
01878     pRspMsg = transact(pCmd);
01879 
01880     /*
01881      * Done with the command message
01882      */
01883     delete pCmd;
01884 
01885     /*
01886      * transact() returns NULL if something went wrong.
01887      */
01888     if(NULL == pRspMsg)
01889     {
01890         /* transact already tattled */
01891         return -1;
01892     }
01893 
01894     /*
01895      * Cast to a ADD_ACCESSSPEC_RESPONSE message.
01896      */
01897     pRsp = (CADD_ACCESSSPEC_RESPONSE *) pRspMsg;
01898 
01899     /*
01900      * Check the LLRPStatus parameter.
01901      */
01902     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "addAccessSpec"))
01903     {
01904         /* checkLLRPStatus already tattled */
01905         delete pRspMsg;
01906         return -1;
01907     }
01908 
01909     /*
01910      * Done with the response message.
01911      */
01912     delete pRspMsg;
01913 
01914     /*
01915      * Tattle progress, maybe
01916      */
01917     if(m_Verbose)
01918     {
01919         printf("INFO: AccessSpec added\n");
01920     }
01921 
01922     /*
01923      * Victory.
01924      */
01925     return 0;
01926 }
01927 
01928 
01942 int
01943 CMyApplication::enableAccessSpec (void)
01944 {
01945     CENABLE_ACCESSSPEC *            pCmd;
01946     CMessage *                      pRspMsg;
01947     CENABLE_ACCESSSPEC_RESPONSE *   pRsp;
01948 
01949     /*
01950      * Compose the command message
01951      */
01952     pCmd = new CENABLE_ACCESSSPEC();
01953     pCmd->setMessageID(m_messageID++);
01954     pCmd->setAccessSpecID(23);
01955 
01956     /*
01957      * Send the message, expect the response of certain type
01958      */
01959     pRspMsg = transact(pCmd);
01960 
01961     /*
01962      * Done with the command message
01963      */
01964     delete pCmd;
01965 
01966     /*
01967      * transact() returns NULL if something went wrong.
01968      */
01969     if(NULL == pRspMsg)
01970     {
01971         /* transact already tattled */
01972         return -1;
01973     }
01974 
01975     /*
01976      * Cast to a ENABLE_ACCESSSPEC_RESPONSE message.
01977      */
01978     pRsp = (CENABLE_ACCESSSPEC_RESPONSE *) pRspMsg;
01979 
01980     /*
01981      * Check the LLRPStatus parameter.
01982      */
01983     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "enableAccessSpec"))
01984     {
01985         /* checkLLRPStatus already tattled */
01986         delete pRspMsg;
01987         return -1;
01988     }
01989 
01990     /*
01991      * Done with the response message.
01992      */
01993     delete pRspMsg;
01994 
01995     /*
01996      * Tattle progress, maybe
01997      */
01998     if(m_Verbose)
01999     {
02000         printf("INFO: AccessSpec enabled\n");
02001     }
02002 
02003     /*
02004      * Victory.
02005      */
02006     return 0;
02007 }
02008 
02009 
02029 int
02030 CMyApplication::awaitAndPrintReport (int timeout)
02031 {
02032     int                         bDone = 0;
02033     int                         retVal = 0;
02034     time_t                      startTime = time(NULL);
02035     time_t                      tempTime;
02036     /*
02037      * Keep receiving messages until done or until
02038      * something bad happens.
02039      */
02040     while(!bDone)
02041     {
02042         CMessage *              pMessage;
02043         const CTypeDescriptor * pType;
02044 
02045         /*
02046          * Wait up to 1 second for a report.  Check
02047          * That way, we can check the timestamp even if 
02048          * there are no reports coming in
02049          */
02050         pMessage = recvMessage(1000);
02051 
02052         /* validate the timestamp */
02053         tempTime = time(NULL);
02054         if(difftime(tempTime, startTime) > timeout)
02055         {
02056             bDone=1;
02057         }
02058 
02059         if(NULL == pMessage)
02060         {
02061             continue;
02062         }
02063 
02064         /*
02065          * What happens depends on what kind of message
02066          * received. Use the type label (m_pType) to
02067          * discriminate message types.
02068          */
02069         pType = pMessage->m_pType;
02070 
02071         /*
02072          * Is it a tag report? If so, print it out.
02073          */
02074         if(&CRO_ACCESS_REPORT::s_typeDescriptor == pType)
02075         {
02076             CRO_ACCESS_REPORT * pNtf;
02077 
02078             pNtf = (CRO_ACCESS_REPORT *) pMessage;
02079 
02080             printTagReportData(pNtf);
02081         }
02082 
02083         /*
02084          * Is it a reader event? This example only recognizes
02085          * AntennaEvents.
02086          */
02087         else if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor == pType)
02088         {
02089             CREADER_EVENT_NOTIFICATION *pNtf;
02090             CReaderEventNotificationData *pNtfData;
02091 
02092             pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage;
02093 
02094             pNtfData = pNtf->getReaderEventNotificationData();
02095             if(NULL != pNtfData)
02096             {
02097                 handleReaderEventNotification(pNtfData);
02098             }
02099             else
02100             {
02101                 /*
02102                  * This should never happen. Using continue
02103                  * to keep indent depth down.
02104                  */
02105                 printf("WARNING: READER_EVENT_NOTIFICATION without data\n");
02106             }
02107         }
02108 
02109         /*
02110          * Hmmm. Something unexpected. Just tattle and keep going.
02111          */
02112         else
02113         {
02114             printf("WARNING: Ignored unexpected message during monitor: %s\n",
02115                 pType->m_pName);
02116         }
02117 
02118         /*
02119          * Done with the received message
02120          */
02121         delete pMessage;
02122     }
02123 
02124     return retVal;
02125 }
02126 
02127 
02142 void
02143 CMyApplication::printTagReportData (
02144   CRO_ACCESS_REPORT *           pRO_ACCESS_REPORT)
02145 {
02146     std::list<CTagReportData *>::iterator Cur;
02147 
02148     unsigned int                nEntry = 0;
02149     
02150     /*
02151      * Loop through and count the number of entries
02152      */
02153     for(
02154         Cur = pRO_ACCESS_REPORT->beginTagReportData();
02155         Cur != pRO_ACCESS_REPORT->endTagReportData();
02156         Cur++)
02157     {
02158         nEntry++;
02159     }
02160 
02161     if(m_Verbose)
02162     {
02163         printf("INFO: %u tag report entries\n", nEntry);
02164     }
02165 
02166     /*
02167      * Loop through again and print each entry.
02168      */
02169     for(
02170         Cur = pRO_ACCESS_REPORT->beginTagReportData();
02171         Cur != pRO_ACCESS_REPORT->endTagReportData();
02172         Cur++)
02173     {
02174         printOneTagReportData(*Cur);
02175     }
02176 }
02177 
02178 
02187 int
02188 CMyApplication::formatOneEPC (
02189   CParameter *pEPCParameter, 
02190   char *buf, 
02191   int buflen,
02192   char * startStr)
02193 {
02194     char *              p = buf;
02195     int                 bufsize = buflen;
02196     int                 written = 0;
02197 
02198     written = snprintf(p, bufsize, "%s", startStr); 
02199     bufsize -= written;
02200     p += written;
02201 
02202     if(NULL != pEPCParameter)
02203     {
02204         const CTypeDescriptor *     pType;
02205         llrp_u96_t          my_u96;
02206         llrp_u1v_t          my_u1v;
02207         llrp_u8_t *         pValue = NULL;
02208         unsigned int        n, i;
02209 
02210         pType = pEPCParameter->m_pType;
02211         if(&CEPC_96::s_typeDescriptor == pType)
02212         {
02213             CEPC_96             *pEPC_96;
02214 
02215             pEPC_96 = (CEPC_96 *) pEPCParameter;
02216             my_u96 = pEPC_96->getEPC();
02217             pValue = my_u96.m_aValue;
02218             n = 12u;
02219         }
02220         else if(&CEPCData::s_typeDescriptor == pType)
02221         {
02222             CEPCData *          pEPCData;
02223 
02224             pEPCData = (CEPCData *) pEPCParameter;
02225             my_u1v = pEPCData->getEPC();
02226             pValue = my_u1v.m_pValue;
02227             n = (my_u1v.m_nBit + 7u) / 8u;
02228         }
02229 
02230         if(NULL != pValue)
02231         {
02232             for(i = 0; i < n; i++)
02233             {
02234                 if(0 < i && i%2 == 0 && 1 < bufsize)
02235                 {
02236                     *p++ = '-';
02237                     bufsize--;
02238                 }
02239                 if(bufsize > 2)
02240                 {
02241                     written = snprintf(p, bufsize, "%02X", pValue[i]);
02242                     bufsize -= written;
02243                     p+= written;
02244                 }
02245             }
02246         }
02247         else
02248         {
02249             written = snprintf(p, bufsize, "%s", "---unknown-epc-data-type---");
02250             bufsize -= written;
02251             p += written;
02252         }
02253     }
02254     else
02255     {
02256         written = snprintf(p, bufsize, "%s", "--null epc---");
02257         bufsize -= written;
02258         p += written;
02259     }
02260 
02261     // null terminate this for good practice
02262     buf[buflen-1] = '\0';
02263 
02264     return buflen - bufsize;
02265 }
02266 
02275 int
02276 CMyApplication::formatOneReadResult (
02277   CParameter *pOpSpecReadResult, 
02278   char *buf, 
02279   int buflen,
02280   char * startStr)
02281 {
02282     EC1G2ReadResultType result;
02283     char *              p = buf;
02284     int written = 0; 
02285     int bufsize = buflen;
02286     int i;
02287     llrp_u16v_t  readData;
02288     CC1G2ReadOpSpecResult *pread = (CC1G2ReadOpSpecResult*) pOpSpecReadResult;
02289 
02290     written = snprintf(p, bufsize, "%s", startStr); 
02291     bufsize -= written;
02292     p += written;
02293 
02294     result = pread->getResult();
02295     written = snprintf(p, bufsize, "result=%d", result);
02296     p+= written;
02297     bufsize -= written;
02298 
02299     if(result == C1G2ReadResultType_Success)
02300     {
02301         readData = pread->getReadData();
02302         
02303         written = snprintf(p, bufsize, " Data=");
02304         p+= written;
02305         bufsize -= written;
02306 
02307         for(i = 0; i < readData.m_nValue - 1 ; i++)
02308         {
02309             written =snprintf(p, bufsize, "%04x-", readData.m_pValue[i]);
02310             p+= written;
02311             bufsize -= written;
02312         }
02313         if(readData.m_nValue)
02314         {
02315             written =snprintf(p, bufsize, "%04x", readData.m_pValue[i]);
02316             p+= written;
02317             bufsize -= written;
02318         }
02319     }
02320     buf[buflen-1] = '\0';
02321     return buflen - bufsize;
02322 }
02323 
02332 int
02333 CMyApplication::formatOneWriteResult (
02334   CParameter *pOpSpecReadResult, 
02335   char *buf, 
02336   int buflen,
02337   char * startStr)
02338 {
02339     EC1G2WriteResultType result;
02340     char *              p = buf;
02341     int written = 0; 
02342     int bufsize = buflen;
02343     llrp_u16v_t  readData;
02344     CC1G2WriteOpSpecResult *pwrite = (CC1G2WriteOpSpecResult*) pOpSpecReadResult;
02345 
02346     written = snprintf(p, bufsize, "%s", startStr); 
02347     bufsize -= written;
02348     p += written;
02349 
02350     result = pwrite->getResult();
02351     written = snprintf(p, bufsize, "result=%d", result);
02352     p+= written;
02353     bufsize -= written;
02354 
02355     buf[buflen-1] = '\0';
02356     return buflen - bufsize;
02357 }
02358 
02367 int
02368 CMyApplication::formatOneSetQTConfigResult (
02369   CParameter *pSetQTConfig, 
02370   char *buf, 
02371   int buflen,
02372   char * startStr)
02373 {
02374     EImpinjSetQTConfigResultType  result;
02375     char *              p = buf;
02376 
02377     int written = 0; 
02378     int bufsize = buflen;
02379     llrp_u16v_t  readData;
02380     CImpinjSetQTConfigOpSpecResult *pset = (CImpinjSetQTConfigOpSpecResult*) pSetQTConfig;
02381 
02382     written = snprintf(p, bufsize, "%s", startStr); 
02383     bufsize -= written;
02384     p += written;
02385 
02386     result = pset->getResult();
02387 
02388     written = snprintf(p, bufsize, "result=%d", result);
02389     p+= written;
02390     bufsize -= written;
02391 
02392     buf[buflen-1] = '\0';
02393     return buflen - bufsize;
02394 }
02395 
02404 int
02405 CMyApplication::formatOneGetQTConfigResult (
02406   CParameter *pSetQTConfig, 
02407   char *buf, 
02408   int buflen,
02409   char * startStr)
02410 {
02411     EImpinjGetQTConfigResultType  result;
02412     char *              p = buf;
02413     int written = 0; 
02414     int bufsize = buflen;
02415     llrp_u16v_t  readData;
02416     const char * dataStrings[3] = {  "Unknown",    
02417                                      "Private",   
02418                                      "Public"};  
02419 
02420     const char * rangeStrings[3] = { "Unknown",
02421                                      "Normal",
02422                                      "Short"};
02423 
02424     CImpinjGetQTConfigOpSpecResult *pset = (CImpinjGetQTConfigOpSpecResult*) pSetQTConfig;
02425 
02426     written = snprintf(p, bufsize, "%s", startStr); 
02427     bufsize -= written;
02428     p += written;
02429 
02430     result = pset->getResult();
02431     written = snprintf(p, bufsize, "result=%d ", result);
02432     p+= written;
02433     bufsize -= written;
02434 
02435     if(ImpinjGetQTConfigResultType_Success  == result)
02436     {
02437         written = snprintf(p, bufsize, "data=%s range=%s\n",
02438             dataStrings[pset->getDataProfile()],
02439             rangeStrings[pset->getAccessRange()]);
02440         p+= written;
02441         bufsize -= written;
02442     }
02443 
02444     buf[buflen-1] = '\0';
02445     return buflen - bufsize;
02446 }
02447 
02448 
02457 int
02458 CMyApplication::formatOneSerializedTID (
02459   CParameter *pSerializedTID, 
02460   char *buf, 
02461   int buflen,
02462   char * startStr)
02463 {
02464     char *              p = buf;
02465     int written = 0; 
02466     int bufsize = buflen;
02467 
02468     CImpinjSerializedTID *pTID = (CImpinjSerializedTID*) pSerializedTID;
02469 
02470     written = snprintf(p, bufsize, "%s", startStr); 
02471     bufsize -= written;
02472     p += written;
02473 
02474     llrp_u16v_t tid = pTID->getTID();
02475 
02476     for(int i = 0; i < tid.m_nValue; i++)
02477     {
02478         if(0 < i && i%2 == 0 && 1 < bufsize)
02479         {
02480             *p++ = '-';
02481             bufsize--;
02482         }
02483         if(bufsize > 2)
02484         {
02485             written = snprintf(p, bufsize, "%02X", tid.m_pValue[i]);
02486             bufsize -= written;
02487             p+= written;
02488         }
02489     }
02490 
02491     buf[buflen-1] = '\0';
02492     return buflen - bufsize;
02493 }
02494 
02503 void
02504 CMyApplication::printOneTagReportData (
02505   CTagReportData *              pTagReportData)
02506 {
02507     const int                   bufSize = 1024;
02508     char                        aBuf[bufSize];
02509     char                       *ptr = aBuf;
02510     int                         written = 0;
02511     int                         bufLimit = bufSize;
02512 
02513     std::list<CParameter *>::iterator OpSpecResults;
02514     std::list<CParameter *>::iterator Cur;
02515 
02516     /*
02517      * Print the EPC. It could be an 96-bit EPC_96 parameter
02518      * or an variable length EPCData parameter.
02519      */
02520 
02521     CParameter *                pEPCParameter =
02522                                     pTagReportData->getEPCParameter();
02523 
02524     written = formatOneEPC(pEPCParameter, ptr, bufLimit, "epc=");
02525     ptr += written;
02526     bufLimit-=written;
02527     
02528     aBuf[bufSize-1] = '\0';
02529     /*
02530     ** Handle a few of the op Spec result types 
02531     */
02532     for (
02533         OpSpecResults = pTagReportData->beginAccessCommandOpSpecResult();
02534         OpSpecResults != pTagReportData->endAccessCommandOpSpecResult();
02535         OpSpecResults++)
02536         {
02537             if( (*OpSpecResults)->m_pType == &CC1G2ReadOpSpecResult::s_typeDescriptor)
02538             {
02539                 written = formatOneReadResult(*OpSpecResults, ptr, bufLimit, "\n    READ ");
02540                 ptr += written;
02541                 bufLimit-=written;
02542             }
02543             else if( (*OpSpecResults)->m_pType == &CC1G2WriteOpSpecResult::s_typeDescriptor)
02544             {
02545                 written = formatOneWriteResult(*OpSpecResults, ptr, bufLimit, "\n    WRITE ");
02546                 ptr += written;
02547                 bufLimit-=written;
02548             }
02549             else if( (*OpSpecResults)->m_pType == &CImpinjSetQTConfigOpSpecResult::s_typeDescriptor)
02550             {
02551                 written = formatOneSetQTConfigResult(*OpSpecResults, ptr, bufLimit, "\n    SETQT ");
02552                 ptr += written;
02553                 bufLimit-=written;
02554             }
02555             else if( (*OpSpecResults)->m_pType == &CImpinjGetQTConfigOpSpecResult::s_typeDescriptor)
02556             {
02557                 written = formatOneGetQTConfigResult(*OpSpecResults, ptr, bufLimit, "\n    GETQT ");
02558                 ptr += written;
02559                 bufLimit-=written;
02560             } 
02561         }
02562 
02563     /* look for custom parameters like TID */
02564     for(
02565         Cur = pTagReportData->beginCustom();
02566         Cur != pTagReportData->endCustom();
02567         Cur++)
02568     {
02569         /* look for our special Impinj Tag Report Data */
02570         if(&CImpinjSerializedTID ::s_typeDescriptor == (*Cur)->m_pType)
02571         {
02572             written = formatOneSerializedTID(*Cur, ptr, bufLimit, "\n    SERIAL-TID ");
02573             ptr += written;
02574             bufLimit -= written;
02575         } 
02576     }
02577 
02578     /*
02579      * End of line
02580      */
02581     printf("%s\n", aBuf);
02582 }
02583 
02584 
02598 void
02599 CMyApplication::handleReaderEventNotification (
02600   CReaderEventNotificationData *pNtfData)
02601 {
02602     CAntennaEvent *             pAntennaEvent;
02603     CReaderExceptionEvent *     pReaderExceptionEvent;
02604     int                         nReported = 0;
02605 
02606     pAntennaEvent = pNtfData->getAntennaEvent();
02607     if(NULL != pAntennaEvent)
02608     {
02609         handleAntennaEvent(pAntennaEvent);
02610         nReported++;
02611     }
02612 
02613     pReaderExceptionEvent = pNtfData->getReaderExceptionEvent();
02614     if(NULL != pReaderExceptionEvent)
02615     {
02616         handleReaderExceptionEvent(pReaderExceptionEvent);
02617         nReported++;
02618     }
02619 
02620     /*
02621      * Similarly handle other events here:
02622      *      HoppingEvent
02623      *      GPIEvent
02624      *      ROSpecEvent
02625      *      ReportBufferLevelWarningEvent
02626      *      ReportBufferOverflowErrorEvent
02627      *      RFSurveyEvent
02628      *      AISpecEvent
02629      *      ConnectionAttemptEvent
02630      *      ConnectionCloseEvent
02631      *      Custom
02632      */
02633 
02634     if(0 == nReported)
02635     {
02636         printf("NOTICE: Unexpected (unhandled) ReaderEvent\n");
02637     }
02638 }
02639 
02640 
02652 void
02653 CMyApplication::handleAntennaEvent (
02654   CAntennaEvent *               pAntennaEvent)
02655 {
02656     EAntennaEventType           eEventType;
02657     llrp_u16_t                  AntennaID;
02658     char *                      pStateStr;
02659 
02660     eEventType = pAntennaEvent->getEventType();
02661     AntennaID = pAntennaEvent->getAntennaID();
02662 
02663     switch(eEventType)
02664     {
02665     case AntennaEventType_Antenna_Disconnected:
02666         pStateStr = "disconnected";
02667         break;
02668 
02669     case AntennaEventType_Antenna_Connected:
02670         pStateStr = "connected";
02671         break;
02672 
02673     default:
02674         pStateStr = "?unknown-event?";
02675         break;
02676     }
02677 
02678     printf("NOTICE: Antenna %d is %s\n", AntennaID, pStateStr);
02679 }
02680 
02681 
02694 void
02695 CMyApplication::handleReaderExceptionEvent (
02696   CReaderExceptionEvent *       pReaderExceptionEvent)
02697 {
02698     llrp_utf8v_t                Message;
02699 
02700     Message = pReaderExceptionEvent->getMessage();
02701 
02702     if(0 < Message.m_nValue && NULL != Message.m_pValue)
02703     {
02704         printf("NOTICE: ReaderException '%.*s'\n",
02705              Message.m_nValue, Message.m_pValue);
02706     }
02707     else
02708     {
02709         printf("NOTICE: ReaderException but no message\n");
02710     }
02711 }
02712 
02713 
02732 int
02733 CMyApplication::checkLLRPStatus (
02734   CLLRPStatus *                 pLLRPStatus,
02735   char *                        pWhatStr)
02736 {
02737     /*
02738      * The LLRPStatus parameter is mandatory in all responses.
02739      * If it is missing there should have been a decode error.
02740      * This just makes sure (remember, this program is a
02741      * diagnostic and suppose to catch LTKC mistakes).
02742      */
02743     if(NULL == pLLRPStatus)
02744     {
02745         printf("ERROR: %s missing LLRP status\n", pWhatStr);
02746         return -1;
02747     }
02748 
02749     /*
02750      * Make sure the status is M_Success.
02751      * If it isn't, print the error string if one.
02752      * This does not try to pretty-print the status
02753      * code. To get that, run this program with -vv
02754      * and examine the XML output.
02755      */
02756     if(StatusCode_M_Success != pLLRPStatus->getStatusCode())
02757     {
02758         llrp_utf8v_t            ErrorDesc;
02759 
02760         ErrorDesc = pLLRPStatus->getErrorDescription();
02761 
02762         if(0 == ErrorDesc.m_nValue)
02763         {
02764             printf("ERROR: %s failed, no error description given\n",
02765                 pWhatStr);
02766         }
02767         else
02768         {
02769             printf("ERROR: %s failed, %.*s\n",
02770                 pWhatStr, ErrorDesc.m_nValue, ErrorDesc.m_pValue);
02771         }
02772         return -2;
02773     }
02774 
02775     /*
02776      * Victory. Everything is fine.
02777      */
02778     return 0;
02779 }
02780 
02781 
02805 CMessage *
02806 CMyApplication::transact (
02807   CMessage *                    pSendMsg)
02808 {
02809     CConnection *               pConn = m_pConnectionToReader;
02810     CMessage *                  pRspMsg;
02811 
02812     /*
02813      * Print the XML text for the outbound message if
02814      * verbosity is 2 or higher.
02815      */
02816     if(1 < m_Verbose)
02817     {
02818         printf("\n===================================\n");
02819         printf("INFO: Transact sending\n");
02820         printXMLMessage(pSendMsg);
02821     }
02822 
02823     /*
02824      * Send the message, expect the response of certain type.
02825      * If LLRP::CConnection::transact() returns NULL then there was
02826      * an error. In that case we try to print the error details.
02827      */
02828     pRspMsg = pConn->transact(pSendMsg, 5000);
02829 
02830     if(NULL == pRspMsg)
02831     {
02832         const CErrorDetails *   pError = pConn->getTransactError();
02833 
02834         printf("ERROR: %s transact failed, %s\n",
02835             pSendMsg->m_pType->m_pName,
02836             pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given");
02837 
02838         if(NULL != pError->m_pRefType)
02839         {
02840             printf("ERROR: ... reference type %s\n",
02841                 pError->m_pRefType->m_pName);
02842         }
02843 
02844         if(NULL != pError->m_pRefField)
02845         {
02846             printf("ERROR: ... reference field %s\n",
02847                 pError->m_pRefField->m_pName);
02848         }
02849 
02850         return NULL;
02851     }
02852 
02853     /*
02854      * Print the XML text for the inbound message if
02855      * verbosity is 2 or higher.
02856      */
02857     if(1 < m_Verbose)
02858     {
02859         printf("\n- - - - - - - - - - - - - - - - - -\n");
02860         printf("INFO: Transact received response\n");
02861         printXMLMessage(pRspMsg);
02862     }
02863 
02864     /*
02865      * If it is an ERROR_MESSAGE (response from reader
02866      * when it can't understand the request), tattle
02867      * and declare defeat.
02868      */
02869     if(&CERROR_MESSAGE::s_typeDescriptor == pRspMsg->m_pType)
02870     {
02871         const CTypeDescriptor * pResponseType;
02872 
02873         pResponseType = pSendMsg->m_pType->m_pResponseType;
02874 
02875         printf("ERROR: Received ERROR_MESSAGE instead of %s\n",
02876             pResponseType->m_pName);
02877         delete pRspMsg;
02878         pRspMsg = NULL;
02879     }
02880 
02881     return pRspMsg;
02882 }
02883 
02884 
02909 CMessage *
02910 CMyApplication::recvMessage (
02911   int                           nMaxMS)
02912 {
02913     CConnection *               pConn = m_pConnectionToReader;
02914     CMessage *                  pMessage;
02915 
02916     /*
02917      * Receive the message subject to a time limit
02918      */
02919     pMessage = pConn->recvMessage(nMaxMS);
02920 
02921     /*
02922      * If LLRP::CConnection::recvMessage() returns NULL then there was
02923      * an error. In that case we try to print the error details.
02924      */
02925     if(NULL == pMessage)
02926     {
02927         const CErrorDetails *   pError = pConn->getRecvError();
02928 
02929         /* don't warn on timeout since this is a polling example */
02930         if(pError->m_eResultCode != RC_RecvTimeout)
02931         {
02932             printf("ERROR: recvMessage failed, %s\n",
02933                 pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given");
02934         }
02935 
02936         if(NULL != pError->m_pRefType)
02937         {
02938             printf("ERROR: ... reference type %s\n",
02939                 pError->m_pRefType->m_pName);
02940         }
02941 
02942         if(NULL != pError->m_pRefField)
02943         {
02944             printf("ERROR: ... reference field %s\n",
02945                 pError->m_pRefField->m_pName);
02946         }
02947 
02948         return NULL;
02949     }
02950 
02951     /*
02952      * Print the XML text for the inbound message if
02953      * verbosity is 2 or higher.
02954      */
02955     if(1 < m_Verbose)
02956     {
02957         printf("\n===================================\n");
02958         printf("INFO: Message received\n");
02959         printXMLMessage(pMessage);
02960     }
02961 
02962     return pMessage;
02963 }
02964 
02965 
02983 int
02984 CMyApplication::sendMessage (
02985   CMessage *                    pSendMsg)
02986 {
02987     CConnection *               pConn = m_pConnectionToReader;
02988 
02989     /*
02990      * Print the XML text for the outbound message if
02991      * verbosity is 2 or higher.
02992      */
02993     if(1 < m_Verbose)
02994     {
02995         printf("\n===================================\n");
02996         printf("INFO: Sending\n");
02997         printXMLMessage(pSendMsg);
02998     }
02999 
03000     /*
03001      * If LLRP::CConnection::sendMessage() returns other than RC_OK
03002      * then there was an error. In that case we try to print
03003      * the error details.
03004      */
03005     if(RC_OK != pConn->sendMessage(pSendMsg))
03006     {
03007         const CErrorDetails *   pError = pConn->getSendError();
03008 
03009         printf("ERROR: %s sendMessage failed, %s\n",
03010             pSendMsg->m_pType->m_pName,
03011             pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given");
03012 
03013         if(NULL != pError->m_pRefType)
03014         {
03015             printf("ERROR: ... reference type %s\n",
03016                 pError->m_pRefType->m_pName);
03017         }
03018 
03019         if(NULL != pError->m_pRefField)
03020         {
03021             printf("ERROR: ... reference field %s\n",
03022                 pError->m_pRefField->m_pName);
03023         }
03024 
03025         return -1;
03026     }
03027 
03028     /*
03029      * Victory
03030      */
03031     return 0;
03032 }
03033 
03034 
03048 void
03049 CMyApplication::printXMLMessage (
03050   CMessage *                    pMessage)
03051 {
03052     char                        aBuf[100*1024];
03053 
03054     /*
03055      * Convert the message to an XML string.
03056      * This fills the buffer with either the XML string
03057      * or an error message. The return value could
03058      * be checked.
03059      */
03060 
03061     pMessage->toXMLString(aBuf, sizeof aBuf);
03062 
03063     /*
03064      * Print the XML Text to the standard output.
03065      */
03066     printf("%s", aBuf);
03067 }