LTKCPP-- LLRP Toolkit C Plus Plus Library
docsample2.cpp
Go to the documentation of this file.
00001 
00002 /*
00003  *****************************************************************************
00004  *                                                                           *
00005  *                 IMPINJ CONFIDENTIAL AND PROPRIETARY                       *
00006  *                                                                           *
00007  * This source code is the sole property of Impinj, Inc.  Reproduction or    *
00008  * utilization of this source code in whole or in part is forbidden without  *
00009  * the prior written consent of Impinj, Inc.                                 *
00010  *                                                                           *
00011  * (c) Copyright Impinj, Inc. 2007,2009. All rights reserved.                *
00012  *                                                                           *
00013  *****************************************************************************/
00014 
00051 #include <stdio.h>
00052 #include "ltkcpp.h"
00053 #include "impinj_ltkcpp.h"
00054 #include "time.h"
00055 
00056 using namespace LLRP;
00057 
00058 /*
00059 ** Sorry, we use this linux safe method
00060 ** to print buffers.  WIndows has the same
00061 ** method, but by a different name
00062 */
00063 #if (WIN32)
00064 #define snprintf _snprintf
00065 #endif
00066 
00067 class CMyApplication
00068 {
00069 private:
00070 
00071     unsigned int m_PowerLevelIndex;
00072     unsigned int m_hopTableID;
00073     unsigned int m_channelIndex;
00074     unsigned int m_modelNumber;
00075     unsigned int m_messageID;
00076 
00077   public:
00079     int                         m_Verbose;
00080 
00082     CConnection *               m_pConnectionToReader;
00083     CTypeRegistry *             m_pTypeRegistry;
00084 
00085     inline
00086     CMyApplication (void)
00087      : m_Verbose(0), m_pConnectionToReader(NULL)
00088     {
00089         m_messageID = 0;
00090     }
00091 
00092     int
00093     run (
00094       char *                    pReaderHostName);
00095 
00096     int
00097     checkConnectionStatus (void);
00098 
00099     int
00100     enableImpinjExtensions (void);
00101 
00102     int
00103     resetConfigurationToFactoryDefaults (void);
00104 
00105     int 
00106     getReaderCapabilities(void);
00107 
00108     int
00109     getReaderConfig(void);
00110 
00111     int
00112     setImpinjReaderConfig(void);
00113 
00114     int
00115     addROSpec (void);
00116 
00117     int
00118     enableROSpec (void);
00119 
00120     int
00121     startROSpec (void);
00122 
00123     int
00124     stopROSpec (void);
00125 
00126     int
00127     awaitAndPrintReport (int timeoutSec);
00128 
00129     void
00130     printTagReportData (
00131       CRO_ACCESS_REPORT *       pRO_ACCESS_REPORT);
00132 
00133     void
00134     printOneTagReportData (
00135       CTagReportData *          pTagReportData);
00136 
00137     void
00138     formatOneEPC (
00139       CParameter *          pEpcParameter,
00140       char *                buf,
00141       int                   buflen);
00142 
00143     void
00144     handleReaderEventNotification (
00145       CReaderEventNotificationData *pNtfData);
00146 
00147     void
00148     handleAntennaEvent (
00149       CAntennaEvent *           pAntennaEvent);
00150 
00151     void
00152     handleReaderExceptionEvent (
00153       CReaderExceptionEvent *   pReaderExceptionEvent);
00154 
00155     int
00156     checkLLRPStatus (
00157       CLLRPStatus *             pLLRPStatus,
00158       char *                    pWhatStr);
00159 
00160     CMessage *
00161     transact (
00162       CMessage *                pSendMsg);
00163 
00164     CMessage *
00165     recvMessage (
00166       int                       nMaxMS);
00167 
00168     int
00169     sendMessage (
00170       CMessage *                pSendMsg);
00171 
00172     void
00173     printXMLMessage (
00174       CMessage *                pMessage);
00175 };
00176 
00177 
00178 /* BEGIN forward declarations */
00179 int
00180 main (
00181   int                           ac,
00182   char *                        av[]);
00183 
00184 void
00185 usage (
00186   char *                        pProgName);
00187 /* END forward declarations */
00188 
00189 
00205 int
00206 main (
00207   int                           ac,
00208   char *                        av[])
00209 {
00210     CMyApplication              myApp;
00211     char *                      pReaderHostName;
00212     int                         rc;
00213 
00214     /*
00215      * Process comand arguments, determine reader name
00216      * and verbosity level.
00217      */
00218     if(ac == 2)
00219     {
00220         pReaderHostName = av[1];
00221     }
00222     else if(ac == 3)
00223     {
00224         char *                  p = av[1];
00225 
00226         while(*p)
00227         {
00228             switch(*p++)
00229             {
00230             case '-':   /* linux conventional option warn char */
00231             case '/':   /* Windows/DOS conventional option warn char */
00232                 break;
00233 
00234             case 'v':
00235             case 'V':
00236                 myApp.m_Verbose++;
00237                 break;
00238 
00239             default:
00240                 usage(av[0]);
00241                 /* no return */
00242                 break;
00243             }
00244         }
00245 
00246         pReaderHostName = av[2];
00247     }
00248     else
00249     {
00250         usage(av[0]);
00251         /* no return */
00252     }
00253 
00254     /*
00255      * Run application, capture return value for exit status
00256      */
00257     rc = myApp.run(pReaderHostName);
00258 
00259     printf("INFO: Done\n");
00260 
00261     /*
00262      * Exit with the right status.
00263      */
00264     if(0 == rc)
00265     {
00266         exit(0);
00267     }
00268     else
00269     {
00270         exit(2);
00271     }
00272     /*NOTREACHED*/
00273 }
00274 
00275 
00287 void
00288 usage (
00289   char *                        pProgName)
00290 {
00291 #ifdef linux
00292     printf("Usage: %s [-v[v]] READERHOSTNAME\n", pProgName);
00293     printf("\n");
00294     printf("Each -v increases verbosity level\n");
00295 #endif /* linux */
00296 #ifdef WIN32
00297     printf("Usage: %s [/v[v]] READERHOSTNAME\n", pProgName);
00298     printf("\n");
00299     printf("Each /v increases verbosity level\n");
00300 #endif /* WIN32 */
00301     exit(1);
00302 }
00303 
00304 
00346 int
00347 CMyApplication::run (
00348   char *                        pReaderHostName)
00349 {
00350     CConnection *               pConn;
00351     int                         rc;
00352 
00353     /*
00354      * Allocate the type registry. This is needed
00355      * by the connection to decode.
00356      */
00357     m_pTypeRegistry = getTheTypeRegistry();
00358     if(NULL == m_pTypeRegistry)
00359     {
00360         printf("ERROR: getTheTypeRegistry failed\n");
00361         return -1;
00362     }
00363 
00364     /*
00365      * Enroll impinj extension types into the 
00366      * type registry, in preparation for using 
00367      * Impinj extension params.
00368      */
00369     LLRP::enrollImpinjTypesIntoRegistry(m_pTypeRegistry);
00370 
00371     /*
00372      * Construct a connection (LLRP::CConnection).
00373      * Using a 32kb max frame size for send/recv.
00374      * The connection object is ready for business
00375      * but not actually connected to the reader yet.
00376      */
00377     pConn = new CConnection(m_pTypeRegistry, 32u*1024u);
00378     if(NULL == pConn)
00379     {
00380         printf("ERROR: new CConnection failed\n");
00381         return -2;
00382     }
00383 
00384     /*
00385      * Open the connection to the reader
00386      */
00387     if(m_Verbose)
00388     {
00389         printf("INFO: Connecting to %s....\n", pReaderHostName);
00390     }
00391 
00392     rc = pConn->openConnectionToReader(pReaderHostName);
00393     if(0 != rc)
00394     {
00395         printf("ERROR: connect: %s (%d)\n", pConn->getConnectError(), rc);
00396         delete pConn;
00397         return -3;
00398     }
00399 
00400     /*
00401      * Record the pointer to the connection object so other
00402      * routines can use it.
00403      */
00404     m_pConnectionToReader = pConn;
00405 
00406     if(m_Verbose)
00407     {
00408         printf("INFO: Connected, checking status....\n");
00409     }
00410 
00411     /*
00412      * Commence the sequence and check for errors as we go.
00413      * See comments for each routine for details.
00414      * Each routine prints messages.
00415      */
00416     rc = 1;
00417     if(0 == checkConnectionStatus())
00418     {
00419         rc = 2;
00420         if(0 == enableImpinjExtensions())
00421         {
00422             rc = 3;
00423             if(0 == resetConfigurationToFactoryDefaults())
00424             {
00425                 rc = 4;
00426                 if(0 == getReaderCapabilities())
00427                 {
00428                     rc = 5;
00429                     if(0 == getReaderConfig())
00430                     {
00431                         rc = 6;
00432                         if(0 == setImpinjReaderConfig())
00433                         {
00434                             rc = 7;
00435                             if(0 == addROSpec())
00436                             {
00437                                 rc = 8;
00438                                 if(0 == enableROSpec())
00439                                 {
00440                                     rc = 9;
00441                                     if(0 == startROSpec())
00442                                     {
00443                                         rc = 10;
00444                                         if(0 == awaitAndPrintReport(60))
00445                                         {
00446                                             rc = 11;
00447                                             if(0 == stopROSpec())
00448                                             {
00449                                                 rc = 0;
00450                                             }
00451                                         }
00452                                     }
00453                                 }
00454                             }
00455                         }
00456                     }
00457                 }
00458             }
00459 
00460             /*
00461              * After we're done, try to leave the reader
00462              * in a clean state for next use. This is best
00463              * effort and no checking of the result is done.
00464              */
00465             if(m_Verbose)
00466             {
00467                 printf("INFO: Clean up reader configuration...\n");
00468             }
00469             resetConfigurationToFactoryDefaults();
00470         }
00471     }
00472 
00473     if(m_Verbose)
00474     {
00475         printf("INFO: Finished\n");
00476     }
00477 
00478     /*
00479      * Close the connection and release its resources
00480      */
00481     pConn->closeConnectionToReader();
00482     delete pConn;
00483 
00484     /*
00485      * Done with the registry.
00486      */
00487     delete m_pTypeRegistry;
00488 
00489     /*
00490      * When we get here all allocated memory should have been deallocated.
00491      */
00492     CXMLTextDecoder::cleanupParser();
00493 
00494     return rc;
00495 }
00496 
00497 
00528 int
00529 CMyApplication::checkConnectionStatus (void)
00530 {
00531     CMessage *                  pMessage;
00532     CREADER_EVENT_NOTIFICATION *pNtf;
00533     CReaderEventNotificationData *pNtfData;
00534     CConnectionAttemptEvent *   pEvent;
00535 
00536     /*
00537      * Expect the notification within 10 seconds.
00538      * It is suppose to be the very first message sent.
00539      */
00540     pMessage = recvMessage(10000);
00541 
00542     /*
00543      * recvMessage() returns NULL if something went wrong.
00544      */
00545     if(NULL == pMessage)
00546     {
00547         /* recvMessage already tattled */
00548         goto fail;
00549     }
00550 
00551     /*
00552      * Check to make sure the message is of the right type.
00553      * The type label (pointer) in the message should be
00554      * the type descriptor for READER_EVENT_NOTIFICATION.
00555      */
00556     if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor != pMessage->m_pType)
00557     {
00558         goto fail;
00559     }
00560 
00561     /*
00562      * Now that we are sure it is a READER_EVENT_NOTIFICATION,
00563      * traverse to the ReaderEventNotificationData parameter.
00564      */
00565     pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage;
00566     pNtfData = pNtf->getReaderEventNotificationData();
00567     if(NULL == pNtfData)
00568     {
00569         goto fail;
00570     }
00571 
00572     /*
00573      * The ConnectionAttemptEvent parameter must be present.
00574      */
00575     pEvent = pNtfData->getConnectionAttemptEvent();
00576     if(NULL == pEvent)
00577     {
00578         goto fail;
00579     }
00580 
00581     /*
00582      * The status in the ConnectionAttemptEvent parameter
00583      * must indicate connection success.
00584      */
00585     if(ConnectionAttemptStatusType_Success != pEvent->getStatus())
00586     {
00587         goto fail;
00588     }
00589 
00590     /*
00591      * Done with the message
00592      */
00593     delete pMessage;
00594 
00595     if(m_Verbose)
00596     {
00597         printf("INFO: Connection status OK\n");
00598     }
00599 
00600     /*
00601      * Victory.
00602      */
00603     return 0;
00604 
00605   fail:
00606     /*
00607      * Something went wrong. Tattle. Clean up. Return error.
00608      */
00609     printf("ERROR: checkConnectionStatus failed\n");
00610     delete pMessage;
00611     return -1;
00612 }
00613 
00631 int
00632 CMyApplication::enableImpinjExtensions (void)
00633 {
00634     CIMPINJ_ENABLE_EXTENSIONS *        pCmd;
00635     CMessage *                         pRspMsg;
00636     CIMPINJ_ENABLE_EXTENSIONS_RESPONSE *pRsp;
00637 
00638     /*
00639      * Compose the command message
00640      */
00641     pCmd = new CIMPINJ_ENABLE_EXTENSIONS();
00642     pCmd->setMessageID(m_messageID++);
00643     /*
00644      * Send the message, expect the response of certain type
00645      */
00646     pRspMsg = transact(pCmd);
00647 
00648     /*
00649      * Done with the command message
00650      */
00651     delete pCmd;
00652 
00653     /*
00654      * transact() returns NULL if something went wrong.
00655      */
00656     if(NULL == pRspMsg)
00657     {
00658         /* transact already tattled */
00659         return -1;
00660     }
00661 
00662     /*
00663      * Cast to a CIMPINJ_ENABLE_EXTENSIONS_RESPONSE message.
00664      */
00665     pRsp = (CIMPINJ_ENABLE_EXTENSIONS_RESPONSE *) pRspMsg;
00666 
00667     /*
00668      * Check the LLRPStatus parameter.
00669      */
00670     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(),
00671                         "enableImpinjExtensions"))
00672     {
00673         /* checkLLRPStatus already tattled */
00674         delete pRspMsg;
00675         return -1;
00676     }
00677 
00678     /*
00679      * Done with the response message.
00680      */
00681     delete pRspMsg;
00682 
00683     /*
00684      * Tattle progress, maybe
00685      */
00686     if(m_Verbose)
00687     {
00688         printf("INFO: Impinj Extensions are enabled\n");
00689     }
00690 
00691     /*
00692      * Victory.
00693      */
00694     return 0;
00695 }
00696 
00717 int
00718 CMyApplication::resetConfigurationToFactoryDefaults (void)
00719 {
00720     CSET_READER_CONFIG *        pCmd;
00721     CMessage *                  pRspMsg;
00722     CSET_READER_CONFIG_RESPONSE *pRsp;
00723 
00724     /*
00725      * Compose the command message
00726      */
00727     pCmd = new CSET_READER_CONFIG();
00728     pCmd->setMessageID(m_messageID++);
00729     pCmd->setResetToFactoryDefault(1);
00730 
00731     /*
00732      * Send the message, expect the response of certain type
00733      */
00734     pRspMsg = transact(pCmd);
00735 
00736     /*
00737      * Done with the command message
00738      */
00739     delete pCmd;
00740 
00741     /*
00742      * transact() returns NULL if something went wrong.
00743      */
00744     if(NULL == pRspMsg)
00745     {
00746         /* transact already tattled */
00747         return -1;
00748     }
00749 
00750     /*
00751      * Cast to a SET_READER_CONFIG_RESPONSE message.
00752      */
00753     pRsp = (CSET_READER_CONFIG_RESPONSE *) pRspMsg;
00754 
00755     /*
00756      * Check the LLRPStatus parameter.
00757      */
00758     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(),
00759                         "resetConfigurationToFactoryDefaults"))
00760     {
00761         /* checkLLRPStatus already tattled */
00762         delete pRspMsg;
00763         return -1;
00764     }
00765 
00766     /*
00767      * Done with the response message.
00768      */
00769     delete pRspMsg;
00770 
00771     /*
00772      * Tattle progress, maybe
00773      */
00774     if(m_Verbose)
00775     {
00776         printf("INFO: Configuration reset to factory defaults\n");
00777     }
00778 
00779     /*
00780      * Victory.
00781      */
00782     return 0;
00783 }
00784 
00802 int
00803 CMyApplication::getReaderCapabilities(void)
00804 {
00805     CGET_READER_CAPABILITIES          *pCmd;
00806     CMessage *                         pRspMsg;
00807     CGET_READER_CAPABILITIES_RESPONSE *pRsp;
00808     CRegulatoryCapabilities           *pReg;
00809     CUHFBandCapabilities              *pUhf;
00810     CTransmitPowerLevelTableEntry     *pPwrLvl;
00811     CGeneralDeviceCapabilities        *pDeviceCap;
00812     std::list<CTransmitPowerLevelTableEntry *>::iterator     PwrLvl;
00813 
00814     /*
00815      * Compose the command message
00816      */
00817     pCmd = new CGET_READER_CAPABILITIES();
00818     pCmd->setMessageID(m_messageID++);
00819     pCmd->setRequestedData(GetReaderCapabilitiesRequestedData_All);
00820 
00821     /*
00822      * Send the message, expect the response of certain type
00823      */
00824     pRspMsg = transact(pCmd);
00825 
00826     /*
00827      * Done with the command message
00828      */
00829     delete pCmd;
00830 
00831     /*
00832      * transact() returns NULL if something went wrong.
00833      */
00834     if(NULL == pRspMsg)
00835     {
00836         /* transact already tattled */
00837         return -1;
00838     }
00839 
00840     /*
00841      * Cast to a CGET_READER_CAPABILITIES_RESPONSE message.
00842      */
00843     pRsp = (CGET_READER_CAPABILITIES_RESPONSE *) pRspMsg;
00844 
00845     /*
00846      * Check the LLRPStatus parameter.
00847      */
00848     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(),
00849                         "getReaderCapabilities"))
00850     {
00851         /* checkLLRPStatus already tattled */
00852         delete pRspMsg;
00853         return -1;
00854     }
00855 
00856     /*
00857     ** Get out the Regulatory Capabilities element
00858     */
00859     if(NULL == (pReg = pRsp->getRegulatoryCapabilities()))
00860     {
00861         delete pRspMsg;
00862         return -1;
00863     }
00864 
00865     /*
00866     ** Get out the UHF Band Capabilities element
00867     */
00868     if(NULL == (pUhf = pReg->getUHFBandCapabilities()))
00869     {
00870         delete pRspMsg;
00871         return -1;
00872     }
00873 
00874     /* get the last power level in the table */
00875     PwrLvl = pUhf->endTransmitPowerLevelTableEntry();
00876     PwrLvl--;
00877 
00878     // store the index for use int the ROSpec.
00879     pPwrLvl = *PwrLvl;
00880     m_PowerLevelIndex = pPwrLvl->getIndex();
00881 
00882     if(1 < m_Verbose)
00883     {
00884         printf("INFO: Reader Max Power index %u, power %f\n", 
00885             pPwrLvl->getIndex(), (float)(float)  pPwrLvl->getTransmitPowerValue()/100);
00886     }
00887 
00888     /* if this parameter is missing, or if this is not an Impinj
00889     ** reader, we can't determine its capabilities so we exit
00890     ** Impinj Private Enterprise NUmber is 25882 */
00891     if( (NULL == (pDeviceCap = pRsp->getGeneralDeviceCapabilities())) || 
00892         (25882 != pDeviceCap->getDeviceManufacturerName()))
00893     {
00894         delete pRspMsg;
00895         return -1;
00896     }
00897 
00898     m_modelNumber = pDeviceCap->getModelName();
00899 
00900     if(1 < m_Verbose)
00901     {
00902         printf("INFO: Reader Model Name %u\n", m_modelNumber);
00903     }
00904 
00905     /*
00906      * Done with the response message.
00907      */
00908     delete pRspMsg;
00909 
00910     /*
00911      * Tattle progress, maybe
00912      */
00913     if(m_Verbose)
00914     {
00915         printf("INFO: Found LLRP Capabilities \n");
00916     }
00917 
00918     /*
00919      * Victory.
00920      */
00921     return 0;
00922 }
00923 
00924 
00939 int
00940 CMyApplication::getReaderConfig(void)
00941 {
00942     CGET_READER_CONFIG          *pCmd;
00943     CMessage *                   pRspMsg;
00944     CGET_READER_CONFIG_RESPONSE *pRsp;
00945     std::list<CAntennaConfiguration*>::iterator pAntCfg; 
00946     /*
00947      * Compose the command message
00948      */
00949     pCmd = new CGET_READER_CONFIG();
00950     pCmd->setMessageID(m_messageID++);
00951     pCmd->setRequestedData(GetReaderConfigRequestedData_All);
00952 
00953     /*
00954      * Send the message, expect the response of certain type
00955      */
00956     pRspMsg = transact(pCmd);
00957 
00958     /*
00959      * Done with the command message
00960      */
00961     delete pCmd;
00962 
00963     /*
00964      * transact() returns NULL if something went wrong.
00965      */
00966     if(NULL == pRspMsg)
00967     {
00968         /* transact already tattled */
00969         return -1;
00970     }
00971 
00972     /*
00973      * Cast to a CGET_READER_CONFIG_RESPONSE message.
00974      */
00975     pRsp = (CGET_READER_CONFIG_RESPONSE *) pRspMsg;
00976 
00977     /*
00978      * Check the LLRPStatus parameter.
00979      */
00980     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(),
00981                         "getReaderConfig"))
00982     {
00983         /* checkLLRPStatus already tattled */
00984         delete pRspMsg;
00985         return -1;
00986     }
00987 
00988     /* just get the hop table and channel index out of 
00989     ** the first antenna configuration since they must all
00990     ** be the same */
00991     pAntCfg = pRsp->beginAntennaConfiguration();
00992     if(pAntCfg != pRsp->endAntennaConfiguration())
00993     {
00994         CRFTransmitter *prfTx;
00995         prfTx = (*pAntCfg)->getRFTransmitter();
00996         m_hopTableID = prfTx->getHopTableID();
00997         m_channelIndex = prfTx->getChannelIndex();
00998     }
00999     else
01000     {
01001         delete pRspMsg;
01002         return -1;
01003     }
01004 
01005     if(1 < m_Verbose)
01006     {
01007         printf("INFO: Reader hopTableID  %u, ChannelIndex %u\n", 
01008             m_hopTableID, m_channelIndex);
01009     }
01010 
01011     /*
01012      * Done with the response message.
01013      */
01014     delete pRspMsg;
01015 
01016     /*
01017      * Tattle progress, maybe
01018      */
01019     if(m_Verbose)
01020     {
01021         printf("INFO: Found LLRP Configuration \n");
01022     }
01023 
01024     /*
01025      * Victory.
01026      */
01027     return 0;
01028 }
01029 
01044 int
01045 CMyApplication::setImpinjReaderConfig(void)
01046 {
01047     CMessage *                  pCmdMsg;
01048     CSET_READER_CONFIG          *pCmd;
01049     CMessage *                  pRspMsg;
01050     CSET_READER_CONFIG_RESPONSE *pRsp;
01051     CXMLTextDecoder *           pDecoder;
01052     std::list<CAntennaConfiguration *>::iterator Cur;
01053        
01054 
01055     /* Build a decoder to extract the message from XML */
01056     pDecoder = new CXMLTextDecoder(m_pTypeRegistry, "setReaderConfig.xml");
01057 
01058     if(NULL == pDecoder)
01059     {
01060         return -1;
01061     }
01062     
01063     pCmdMsg = pDecoder->decodeMessage();
01064 
01065     delete pDecoder;
01066 
01067     if(NULL == pCmdMsg)
01068     {
01069         return -2;   
01070     }
01071 
01072     if(&CSET_READER_CONFIG::s_typeDescriptor != pCmdMsg->m_pType)
01073     {
01074         return -3;
01075     }
01076 
01077     /* get the message as a SET_READER_CONFIG */
01078     pCmd = (CSET_READER_CONFIG *) pCmdMsg;
01079 
01080 
01081     /* It's always a good idea to give it a unique message ID */
01082     pCmd->setMessageID(m_messageID++);
01083 
01084     /* at this point,we would be ready to send the message, but we need
01085      * to make a change to the transmit power for each enabled antenna.
01086      * Loop through */
01087     for(
01088         Cur = pCmd->beginAntennaConfiguration();
01089         Cur != pCmd->endAntennaConfiguration();
01090         Cur++)
01091     {
01092     CRFTransmitter *pRfTx = (*Cur)->getRFTransmitter();
01093 
01094     /* we already have this element in our sample XML file, but
01095      * we check here to create one if it doesn't exist to show
01096      * a more general usage */
01097         if(NULL == pRfTx)
01098     {
01099             pRfTx = new CRFTransmitter();
01100             (*Cur)->setRFTransmitter(pRfTx);
01101     }
01102         /*
01103         ** Set the max power that we retreived from the capabilities 
01104         ** and the hopTableID and Channel index we got from the config
01105         */
01106         pRfTx->setChannelIndex(m_channelIndex);
01107         pRfTx->setHopTableID(m_hopTableID);
01108         pRfTx->setTransmitPower(m_PowerLevelIndex);
01109     }
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 CSET_READER_CONFIG_RESPONSE message.
01132      */
01133     pRsp = (CSET_READER_CONFIG_RESPONSE *) pRspMsg;
01134 
01135     /*
01136      * Check the LLRPStatus parameter.
01137      */
01138     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(),
01139                         "setImpinjReaderConfig"))
01140     {
01141         /* checkLLRPStatus already tattled */
01142         delete pRspMsg;
01143         return -1;
01144     }
01145 
01146     /*
01147      * Done with the response message.
01148      */
01149     delete pRspMsg;
01150 
01151     /*
01152      * Tattle progress, maybe
01153      */
01154     if(m_Verbose)
01155     {
01156         printf("INFO: Set Impinj Reader Configuration \n");
01157     }
01158 
01159     /*
01160      * Victory.
01161      */
01162     return 0;
01163 }
01164 
01213 int
01214 CMyApplication::addROSpec (void)
01215 {
01216     CROSpecStartTrigger *       pROSpecStartTrigger =
01217                                     new CROSpecStartTrigger();
01218     pROSpecStartTrigger->setROSpecStartTriggerType(
01219                                 ROSpecStartTriggerType_Null);
01220 
01221     CROSpecStopTrigger *        pROSpecStopTrigger = new CROSpecStopTrigger();
01222     pROSpecStopTrigger->setROSpecStopTriggerType(ROSpecStopTriggerType_Null);
01223     pROSpecStopTrigger->setDurationTriggerValue(0);     /* n/a */
01224 
01225     CROBoundarySpec *           pROBoundarySpec = new CROBoundarySpec();
01226     pROBoundarySpec->setROSpecStartTrigger(pROSpecStartTrigger);
01227     pROBoundarySpec->setROSpecStopTrigger(pROSpecStopTrigger);
01228 
01229     CAISpecStopTrigger *        pAISpecStopTrigger = new CAISpecStopTrigger();
01230     pAISpecStopTrigger->setAISpecStopTriggerType(
01231             AISpecStopTriggerType_Null);
01232     pAISpecStopTrigger->setDurationTrigger(0);
01233 
01234     CInventoryParameterSpec *   pInventoryParameterSpec =
01235                                     new CInventoryParameterSpec();
01236     pInventoryParameterSpec->setInventoryParameterSpecID(1234);
01237     pInventoryParameterSpec->setProtocolID(AirProtocols_EPCGlobalClass1Gen2);
01238 
01239     /* 
01240     ** configure to use two antennas 
01241     */
01242     llrp_u16v_t                 AntennaIDs = llrp_u16v_t(2);
01243     AntennaIDs.m_pValue[0] = 1;
01244     AntennaIDs.m_pValue[1] = 2;
01245 
01246     CAISpec *                   pAISpec = new CAISpec();
01247     pAISpec->setAntennaIDs(AntennaIDs);
01248     pAISpec->setAISpecStopTrigger(pAISpecStopTrigger);
01249     pAISpec->addInventoryParameterSpec(pInventoryParameterSpec);
01250 
01251     CROSpec *                   pROSpec = new CROSpec();
01252     pROSpec->setROSpecID(1111);
01253     pROSpec->setPriority(0);
01254     pROSpec->setCurrentState(ROSpecState_Disabled);
01255     pROSpec->setROBoundarySpec(pROBoundarySpec);
01256     pROSpec->addSpecParameter(pAISpec);
01257 
01258     CADD_ROSPEC *               pCmd;
01259     CMessage *                  pRspMsg;
01260     CADD_ROSPEC_RESPONSE *      pRsp;
01261 
01262     /*
01263      * Compose the command message.
01264      * N.B.: After the message is composed, all the parameters
01265      *       constructed, immediately above, are considered "owned"
01266      *       by the command message. When it is destructed so
01267      *       too will the parameters be.
01268      */
01269     pCmd = new CADD_ROSPEC();
01270     pCmd->setMessageID(m_messageID++);
01271     pCmd->setROSpec(pROSpec);
01272 
01273     /*
01274      * Send the message, expect the response of certain type
01275      */
01276     pRspMsg = transact(pCmd);
01277 
01278     /*
01279      * Done with the command message.
01280      * N.B.: And the parameters
01281      */
01282     delete pCmd;
01283 
01284     /*
01285      * transact() returns NULL if something went wrong.
01286      */
01287     if(NULL == pRspMsg)
01288     {
01289         /* transact already tattled */
01290         return -1;
01291     }
01292 
01293     /*
01294      * Cast to a ADD_ROSPEC_RESPONSE message.
01295      */
01296     pRsp = (CADD_ROSPEC_RESPONSE *) pRspMsg;
01297 
01298     /*
01299      * Check the LLRPStatus parameter.
01300      */
01301     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "addROSpec"))
01302     {
01303         /* checkLLRPStatus already tattled */
01304         delete pRspMsg;
01305         return -1;
01306     }
01307 
01308     /*
01309      * Done with the response message.
01310      */
01311     delete pRspMsg;
01312 
01313     /*
01314      * Tattle progress, maybe
01315      */
01316     if(m_Verbose)
01317     {
01318         printf("INFO: ROSpec added\n");
01319     }
01320 
01321     /*
01322      * Victory.
01323      */
01324     return 0;
01325 }
01326 
01327 
01345 int
01346 CMyApplication::enableROSpec (void)
01347 {
01348     CENABLE_ROSPEC *            pCmd;
01349     CMessage *                  pRspMsg;
01350     CENABLE_ROSPEC_RESPONSE *   pRsp;
01351 
01352     /*
01353      * Compose the command message
01354      */
01355     pCmd = new CENABLE_ROSPEC();
01356     pCmd->setMessageID(m_messageID++);
01357     pCmd->setROSpecID(1111);
01358 
01359     /*
01360      * Send the message, expect the response of certain type
01361      */
01362     pRspMsg = transact(pCmd);
01363 
01364     /*
01365      * Done with the command message
01366      */
01367     delete pCmd;
01368 
01369     /*
01370      * transact() returns NULL if something went wrong.
01371      */
01372     if(NULL == pRspMsg)
01373     {
01374         /* transact already tattled */
01375         return -1;
01376     }
01377 
01378     /*
01379      * Cast to a ENABLE_ROSPEC_RESPONSE message.
01380      */
01381     pRsp = (CENABLE_ROSPEC_RESPONSE *) pRspMsg;
01382 
01383     /*
01384      * Check the LLRPStatus parameter.
01385      */
01386     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "enableROSpec"))
01387     {
01388         /* checkLLRPStatus already tattled */
01389         delete pRspMsg;
01390         return -1;
01391     }
01392 
01393     /*
01394      * Done with the response message.
01395      */
01396     delete pRspMsg;
01397 
01398     /*
01399      * Tattle progress, maybe
01400      */
01401     if(m_Verbose)
01402     {
01403         printf("INFO: ROSpec enabled\n");
01404     }
01405 
01406     /*
01407      * Victory.
01408      */
01409     return 0;
01410 }
01411 
01412 
01430 int
01431 CMyApplication::startROSpec (void)
01432 {
01433     CSTART_ROSPEC *             pCmd;
01434     CMessage *                  pRspMsg;
01435     CSTART_ROSPEC_RESPONSE *    pRsp;
01436 
01437     /*
01438      * Compose the command message
01439      */
01440     pCmd = new CSTART_ROSPEC();
01441     pCmd->setMessageID(m_messageID++);
01442     pCmd->setROSpecID(1111);
01443 
01444     /*
01445      * Send the message, expect the response of certain type
01446      */
01447     pRspMsg = transact(pCmd);
01448 
01449     /*
01450      * Done with the command message
01451      */
01452     delete pCmd;
01453 
01454     /*
01455      * transact() returns NULL if something went wrong.
01456      */
01457     if(NULL == pRspMsg)
01458     {
01459         /* transact already tattled */
01460         return -1;
01461     }
01462 
01463     /*
01464      * Cast to a START_ROSPEC_RESPONSE message.
01465      */
01466     pRsp = (CSTART_ROSPEC_RESPONSE *) pRspMsg;
01467 
01468     /*
01469      * Check the LLRPStatus parameter.
01470      */
01471     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "startROSpec"))
01472     {
01473         /* checkLLRPStatus already tattled */
01474         delete pRspMsg;
01475         return -1;
01476     }
01477 
01478     /*
01479      * Done with the response message.
01480      */
01481     delete pRspMsg;
01482 
01483     /*
01484      * Tattle progress
01485      */
01486     if(m_Verbose)
01487     {
01488         printf("INFO: ROSpec started\n");
01489     }
01490 
01491     /*
01492      * Victory.
01493      */
01494     return 0;
01495 }
01496 
01514 int
01515 CMyApplication::stopROSpec (void)
01516 {
01517     CSTOP_ROSPEC *             pCmd;
01518     CMessage *                  pRspMsg;
01519     CSTOP_ROSPEC_RESPONSE *    pRsp;
01520 
01521     /*
01522      * Compose the command message
01523      */
01524     pCmd = new CSTOP_ROSPEC();
01525     pCmd->setMessageID(m_messageID++);
01526     pCmd->setROSpecID(1111);
01527 
01528     /*
01529      * Send the message, expect the response of certain type
01530      */
01531     pRspMsg = transact(pCmd);
01532 
01533     /*
01534      * Done with the command message
01535      */
01536     delete pCmd;
01537 
01538     /*
01539      * transact() returns NULL if something went wrong.
01540      */
01541     if(NULL == pRspMsg)
01542     {
01543         /* transact already tattled */
01544         return -1;
01545     }
01546 
01547     /*
01548      * Cast to a STOP_ROSPEC_RESPONSE message.
01549      */
01550     pRsp = (CSTOP_ROSPEC_RESPONSE *) pRspMsg;
01551 
01552     /*
01553      * Check the LLRPStatus parameter.
01554      */
01555     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "stopROSpec"))
01556     {
01557         /* checkLLRPStatus already tattled */
01558         delete pRspMsg;
01559         return -1;
01560     }
01561 
01562     /*
01563      * Done with the response message.
01564      */
01565     delete pRspMsg;
01566 
01567     /*
01568      * Tattle progress
01569      */
01570     if(m_Verbose)
01571     {
01572         printf("INFO: ROSpec stopped\n");
01573     }
01574 
01575     /*
01576      * Victory.
01577      */
01578     return 0;
01579 }
01580 
01581 
01601 int
01602 CMyApplication::awaitAndPrintReport (int timeout)
01603 {
01604     int                         bDone = 0;
01605     int                         retVal = 0;
01606     time_t                      startTime = time(NULL);
01607     time_t                      tempTime;
01608     /*
01609      * Keep receiving messages until done or until
01610      * something bad happens.
01611      */
01612     while(!bDone)
01613     {
01614         CMessage *              pMessage;
01615         const CTypeDescriptor * pType;
01616 
01617         /*
01618          * Wait up to 1 second for a report.  Check
01619          * That way, we can check the timestamp even if 
01620          * there are no reports coming in
01621          */
01622         pMessage = recvMessage(1000);
01623 
01624         /* validate the timestamp */
01625         tempTime = time(NULL);
01626         if(difftime(tempTime, startTime) > timeout)
01627         {
01628             bDone=1;
01629         }
01630 
01631         if(NULL == pMessage)
01632         {
01633             continue;
01634         }
01635 
01636         /*
01637          * What happens depends on what kind of message
01638          * received. Use the type label (m_pType) to
01639          * discriminate message types.
01640          */
01641         pType = pMessage->m_pType;
01642 
01643         /*
01644          * Is it a tag report? If so, print it out.
01645          */
01646         if(&CRO_ACCESS_REPORT::s_typeDescriptor == pType)
01647         {
01648             CRO_ACCESS_REPORT * pNtf;
01649 
01650             pNtf = (CRO_ACCESS_REPORT *) pMessage;
01651 
01652             printTagReportData(pNtf);
01653         }
01654 
01655         /*
01656          * Is it a reader event? This example only recognizes
01657          * AntennaEvents.
01658          */
01659         else if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor == pType)
01660         {
01661             CREADER_EVENT_NOTIFICATION *pNtf;
01662             CReaderEventNotificationData *pNtfData;
01663 
01664             pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage;
01665 
01666             pNtfData = pNtf->getReaderEventNotificationData();
01667             if(NULL != pNtfData)
01668             {
01669                 handleReaderEventNotification(pNtfData);
01670             }
01671             else
01672             {
01673                 /*
01674                  * This should never happen. Using continue
01675                  * to keep indent depth down.
01676                  */
01677                 printf("WARNING: READER_EVENT_NOTIFICATION without data\n");
01678             }
01679         }
01680 
01681         /*
01682          * Hmmm. Something unexpected. Just tattle and keep going.
01683          */
01684         else
01685         {
01686             printf("WARNING: Ignored unexpected message during monitor: %s\n",
01687                 pType->m_pName);
01688         }
01689 
01690         /*
01691          * Done with the received message
01692          */
01693         delete pMessage;
01694     }
01695 
01696     return retVal;
01697 }
01698 
01699 
01714 void
01715 CMyApplication::printTagReportData (
01716   CRO_ACCESS_REPORT *           pRO_ACCESS_REPORT)
01717 {
01718     std::list<CTagReportData *>::iterator Cur;
01719     std::list<CParameter *>::iterator CustCur;
01720 
01721     unsigned int                nEntry = 0;
01722     
01723     /*
01724      * Loop through and count the number of entries
01725      */
01726     for(
01727         Cur = pRO_ACCESS_REPORT->beginTagReportData();
01728         Cur != pRO_ACCESS_REPORT->endTagReportData();
01729         Cur++)
01730     {
01731         nEntry++;
01732     }
01733 
01734     if(m_Verbose)
01735     {
01736         printf("INFO: %u tag report entries\n", nEntry);
01737     }
01738 
01739     /*
01740      * Loop through again and print each entry.
01741      */
01742     for(
01743         Cur = pRO_ACCESS_REPORT->beginTagReportData();
01744         Cur != pRO_ACCESS_REPORT->endTagReportData();
01745         Cur++)
01746     {
01747         printOneTagReportData(*Cur);
01748     }
01749 }
01750 
01759 void
01760 CMyApplication::formatOneEPC (
01761   CParameter *pEPCParameter, 
01762   char *buf, 
01763   int buflen)
01764 {
01765     char *              p = buf;
01766     int                 bufsize = buflen;
01767     int                 written = 0;
01768 
01769     if(NULL != pEPCParameter)
01770     {
01771         const CTypeDescriptor *     pType;
01772         llrp_u96_t          my_u96;
01773         llrp_u1v_t          my_u1v;
01774         llrp_u8_t *         pValue = NULL;
01775         unsigned int        n, i;
01776 
01777         pType = pEPCParameter->m_pType;
01778         if(&CEPC_96::s_typeDescriptor == pType)
01779         {
01780             CEPC_96             *pEPC_96;
01781 
01782             pEPC_96 = (CEPC_96 *) pEPCParameter;
01783             my_u96 = pEPC_96->getEPC();
01784             pValue = my_u96.m_aValue;
01785             n = 12u;
01786         }
01787         else if(&CEPCData::s_typeDescriptor == pType)
01788         {
01789             CEPCData *          pEPCData;
01790 
01791             pEPCData = (CEPCData *) pEPCParameter;
01792             my_u1v = pEPCData->getEPC();
01793             pValue = my_u1v.m_pValue;
01794             n = (my_u1v.m_nBit + 7u) / 8u;
01795         }
01796 
01797         if(NULL != pValue)
01798         {
01799             for(i = 0; i < n; i++)
01800             {
01801                 if(0 < i && i%2 == 0 && 1 < bufsize)
01802                 {
01803                     *p++ = '-';
01804                     bufsize--;
01805                 }
01806                 if(bufsize > 2)
01807                 {
01808                     written = snprintf(p, bufsize, "%02X", pValue[i]);
01809                     bufsize -= written;
01810                     p+= written;
01811                 }
01812             }
01813         }
01814         else
01815         {
01816             written = snprintf(p, bufsize, "%s", "---unknown-epc-data-type---");
01817             bufsize -= written;
01818             p += written;
01819         }
01820     }
01821     else
01822     {
01823         written = snprintf(p, bufsize, "%s", "--null epc---");
01824         bufsize -= written;
01825         p += written;
01826     }
01827 
01828     // null terminate this for good practice
01829     buf[buflen-1] = '\0';
01830 
01831 }
01832 
01841 void
01842 CMyApplication::printOneTagReportData (
01843   CTagReportData *              pTagReportData)
01844 {
01845     char                        aBuf[64];
01846 
01847     /*
01848      * Print the EPC. It could be an 96-bit EPC_96 parameter
01849      * or an variable length EPCData parameter.
01850      */
01851 
01852     CParameter *                pEPCParameter =
01853                                     pTagReportData->getEPCParameter();
01854 
01855     formatOneEPC(pEPCParameter, aBuf, 64);
01856     
01857     /*
01858      * End of line
01859      */
01860     printf("EPC: %s\n", aBuf);
01861 }
01862 
01863 
01877 void
01878 CMyApplication::handleReaderEventNotification (
01879   CReaderEventNotificationData *pNtfData)
01880 {
01881     CAntennaEvent *             pAntennaEvent;
01882     CReaderExceptionEvent *     pReaderExceptionEvent;
01883     int                         nReported = 0;
01884 
01885     pAntennaEvent = pNtfData->getAntennaEvent();
01886     if(NULL != pAntennaEvent)
01887     {
01888         handleAntennaEvent(pAntennaEvent);
01889         nReported++;
01890     }
01891 
01892     pReaderExceptionEvent = pNtfData->getReaderExceptionEvent();
01893     if(NULL != pReaderExceptionEvent)
01894     {
01895         handleReaderExceptionEvent(pReaderExceptionEvent);
01896         nReported++;
01897     }
01898 
01899     /*
01900      * Similarly handle other events here:
01901      *      HoppingEvent
01902      *      GPIEvent
01903      *      ROSpecEvent
01904      *      ReportBufferLevelWarningEvent
01905      *      ReportBufferOverflowErrorEvent
01906      *      RFSurveyEvent
01907      *      AISpecEvent
01908      *      ConnectionAttemptEvent
01909      *      ConnectionCloseEvent
01910      *      Custom
01911      */
01912 
01913     if(0 == nReported)
01914     {
01915         printf("NOTICE: Unexpected (unhandled) ReaderEvent\n");
01916     }
01917 }
01918 
01919 
01931 void
01932 CMyApplication::handleAntennaEvent (
01933   CAntennaEvent *               pAntennaEvent)
01934 {
01935     EAntennaEventType           eEventType;
01936     llrp_u16_t                  AntennaID;
01937     char *                      pStateStr;
01938 
01939     eEventType = pAntennaEvent->getEventType();
01940     AntennaID = pAntennaEvent->getAntennaID();
01941 
01942     switch(eEventType)
01943     {
01944     case AntennaEventType_Antenna_Disconnected:
01945         pStateStr = "disconnected";
01946         break;
01947 
01948     case AntennaEventType_Antenna_Connected:
01949         pStateStr = "connected";
01950         break;
01951 
01952     default:
01953         pStateStr = "?unknown-event?";
01954         break;
01955     }
01956 
01957     printf("NOTICE: Antenna %d is %s\n", AntennaID, pStateStr);
01958 }
01959 
01960 
01973 void
01974 CMyApplication::handleReaderExceptionEvent (
01975   CReaderExceptionEvent *       pReaderExceptionEvent)
01976 {
01977     llrp_utf8v_t                Message;
01978 
01979     Message = pReaderExceptionEvent->getMessage();
01980 
01981     if(0 < Message.m_nValue && NULL != Message.m_pValue)
01982     {
01983         printf("NOTICE: ReaderException '%.*s'\n",
01984              Message.m_nValue, Message.m_pValue);
01985     }
01986     else
01987     {
01988         printf("NOTICE: ReaderException but no message\n");
01989     }
01990 }
01991 
01992 
02011 int
02012 CMyApplication::checkLLRPStatus (
02013   CLLRPStatus *                 pLLRPStatus,
02014   char *                        pWhatStr)
02015 {
02016     /*
02017      * The LLRPStatus parameter is mandatory in all responses.
02018      * If it is missing there should have been a decode error.
02019      * This just makes sure (remember, this program is a
02020      * diagnostic and suppose to catch LTKC mistakes).
02021      */
02022     if(NULL == pLLRPStatus)
02023     {
02024         printf("ERROR: %s missing LLRP status\n", pWhatStr);
02025         return -1;
02026     }
02027 
02028     /*
02029      * Make sure the status is M_Success.
02030      * If it isn't, print the error string if one.
02031      * This does not try to pretty-print the status
02032      * code. To get that, run this program with -vv
02033      * and examine the XML output.
02034      */
02035     if(StatusCode_M_Success != pLLRPStatus->getStatusCode())
02036     {
02037         llrp_utf8v_t            ErrorDesc;
02038 
02039         ErrorDesc = pLLRPStatus->getErrorDescription();
02040 
02041         if(0 == ErrorDesc.m_nValue)
02042         {
02043             printf("ERROR: %s failed, no error description given\n",
02044                 pWhatStr);
02045         }
02046         else
02047         {
02048             printf("ERROR: %s failed, %.*s\n",
02049                 pWhatStr, ErrorDesc.m_nValue, ErrorDesc.m_pValue);
02050         }
02051         return -2;
02052     }
02053 
02054     /*
02055      * Victory. Everything is fine.
02056      */
02057     return 0;
02058 }
02059 
02060 
02084 CMessage *
02085 CMyApplication::transact (
02086   CMessage *                    pSendMsg)
02087 {
02088     CConnection *               pConn = m_pConnectionToReader;
02089     CMessage *                  pRspMsg;
02090 
02091     /*
02092      * Print the XML text for the outbound message if
02093      * verbosity is 2 or higher.
02094      */
02095     if(1 < m_Verbose)
02096     {
02097         printf("\n===================================\n");
02098         printf("INFO: Transact sending\n");
02099         printXMLMessage(pSendMsg);
02100     }
02101 
02102     /*
02103      * Send the message, expect the response of certain type.
02104      * If LLRP::CConnection::transact() returns NULL then there was
02105      * an error. In that case we try to print the error details.
02106      */
02107     pRspMsg = pConn->transact(pSendMsg, 5000);
02108 
02109     if(NULL == pRspMsg)
02110     {
02111         const CErrorDetails *   pError = pConn->getTransactError();
02112 
02113         printf("ERROR: %s transact failed, %s\n",
02114             pSendMsg->m_pType->m_pName,
02115             pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given");
02116 
02117         if(NULL != pError->m_pRefType)
02118         {
02119             printf("ERROR: ... reference type %s\n",
02120                 pError->m_pRefType->m_pName);
02121         }
02122 
02123         if(NULL != pError->m_pRefField)
02124         {
02125             printf("ERROR: ... reference field %s\n",
02126                 pError->m_pRefField->m_pName);
02127         }
02128 
02129         return NULL;
02130     }
02131 
02132     /*
02133      * Print the XML text for the inbound message if
02134      * verbosity is 2 or higher.
02135      */
02136     if(1 < m_Verbose)
02137     {
02138         printf("\n- - - - - - - - - - - - - - - - - -\n");
02139         printf("INFO: Transact received response\n");
02140         printXMLMessage(pRspMsg);
02141     }
02142 
02143     /*
02144      * If it is an ERROR_MESSAGE (response from reader
02145      * when it can't understand the request), tattle
02146      * and declare defeat.
02147      */
02148     if(&CERROR_MESSAGE::s_typeDescriptor == pRspMsg->m_pType)
02149     {
02150         const CTypeDescriptor * pResponseType;
02151 
02152         pResponseType = pSendMsg->m_pType->m_pResponseType;
02153 
02154         printf("ERROR: Received ERROR_MESSAGE instead of %s\n",
02155             pResponseType->m_pName);
02156         delete pRspMsg;
02157         pRspMsg = NULL;
02158     }
02159 
02160     return pRspMsg;
02161 }
02162 
02163 
02188 CMessage *
02189 CMyApplication::recvMessage (
02190   int                           nMaxMS)
02191 {
02192     CConnection *               pConn = m_pConnectionToReader;
02193     CMessage *                  pMessage;
02194 
02195     /*
02196      * Receive the message subject to a time limit
02197      */
02198     pMessage = pConn->recvMessage(nMaxMS);
02199 
02200     /*
02201      * If LLRP::CConnection::recvMessage() returns NULL then there was
02202      * an error. In that case we try to print the error details.
02203      */
02204     if(NULL == pMessage)
02205     {
02206         const CErrorDetails *   pError = pConn->getRecvError();
02207 
02208         /* don't warn on timeout since this is a polling example */
02209         if(pError->m_eResultCode != RC_RecvTimeout)
02210         {
02211         printf("ERROR: recvMessage failed, %s\n",
02212             pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given");
02213         }
02214 
02215         if(NULL != pError->m_pRefType)
02216         {
02217             printf("ERROR: ... reference type %s\n",
02218                 pError->m_pRefType->m_pName);
02219         }
02220 
02221         if(NULL != pError->m_pRefField)
02222         {
02223             printf("ERROR: ... reference field %s\n",
02224                 pError->m_pRefField->m_pName);
02225         }
02226 
02227         return NULL;
02228     }
02229 
02230     /*
02231      * Print the XML text for the inbound message if
02232      * verbosity is 2 or higher.
02233      */
02234     if(1 < m_Verbose)
02235     {
02236         printf("\n===================================\n");
02237         printf("INFO: Message received\n");
02238         printXMLMessage(pMessage);
02239     }
02240 
02241     return pMessage;
02242 }
02243 
02244 
02262 int
02263 CMyApplication::sendMessage (
02264   CMessage *                    pSendMsg)
02265 {
02266     CConnection *               pConn = m_pConnectionToReader;
02267 
02268     /*
02269      * Print the XML text for the outbound message if
02270      * verbosity is 2 or higher.
02271      */
02272     if(1 < m_Verbose)
02273     {
02274         printf("\n===================================\n");
02275         printf("INFO: Sending\n");
02276         printXMLMessage(pSendMsg);
02277     }
02278 
02279     /*
02280      * If LLRP::CConnection::sendMessage() returns other than RC_OK
02281      * then there was an error. In that case we try to print
02282      * the error details.
02283      */
02284     if(RC_OK != pConn->sendMessage(pSendMsg))
02285     {
02286         const CErrorDetails *   pError = pConn->getSendError();
02287 
02288         printf("ERROR: %s sendMessage failed, %s\n",
02289             pSendMsg->m_pType->m_pName,
02290             pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given");
02291 
02292         if(NULL != pError->m_pRefType)
02293         {
02294             printf("ERROR: ... reference type %s\n",
02295                 pError->m_pRefType->m_pName);
02296         }
02297 
02298         if(NULL != pError->m_pRefField)
02299         {
02300             printf("ERROR: ... reference field %s\n",
02301                 pError->m_pRefField->m_pName);
02302         }
02303 
02304         return -1;
02305     }
02306 
02307     /*
02308      * Victory
02309      */
02310     return 0;
02311 }
02312 
02313 
02327 void
02328 CMyApplication::printXMLMessage (
02329   CMessage *                    pMessage)
02330 {
02331     char                        aBuf[100*1024];
02332 
02333     /*
02334      * Convert the message to an XML string.
02335      * This fills the buffer with either the XML string
02336      * or an error message. The return value could
02337      * be checked.
02338      */
02339 
02340     pMessage->toXMLString(aBuf, sizeof aBuf);
02341 
02342     /*
02343      * Print the XML Text to the standard output.
02344      */
02345     printf("%s", aBuf);
02346 }