LTKCPP-- LLRP Toolkit C Plus Plus Library
docsample4.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,2010. All rights reserved.                *
00012  *                                                                           *
00013  *****************************************************************************/
00014 
00029 #include <stdio.h>
00030 #include "ltkcpp.h"
00031 #include "impinj_ltkcpp.h"
00032 #include "time.h"
00033 
00034 using namespace LLRP;
00035 
00036 /*
00037 ** Sorry, we use this linux safe method
00038 ** to print buffers.  WIndows has the same
00039 ** method, but by a different name
00040 */
00041 #if (WIN32)
00042 #define snprintf _snprintf
00043 #endif
00044 
00045 class CMyApplication
00046 {
00047 private:
00048 
00049     unsigned int m_modelNumber;
00050     unsigned int m_messageID;
00051 
00052   public:
00054     int                         m_Verbose;
00055 
00057     CConnection *               m_pConnectionToReader;
00058 
00059     inline
00060     CMyApplication (void)
00061      : m_Verbose(0), m_pConnectionToReader(NULL)
00062     {
00063         m_messageID = 0;
00064     }
00065 
00066     int
00067     run (
00068       char *                    pReaderHostName);
00069 
00070     int
00071     checkConnectionStatus (void);
00072 
00073     int
00074     enableImpinjExtensions (void);
00075 
00076     int
00077     resetConfigurationToFactoryDefaults (void);
00078 
00079     int 
00080     getReaderCapabilities(void);
00081 
00082     int
00083     setImpinjReaderConfig(void);
00084 
00085     int
00086     addROSpec (void);
00087 
00088     int
00089     enableROSpec (void);
00090 
00091     int
00092     startROSpec (void);
00093 
00094     int
00095     stopROSpec (void);
00096 
00097     int
00098     awaitAndPrintReport (int timeoutSec);
00099 
00100     void
00101     printTagReportData (
00102       CRO_ACCESS_REPORT *       pRO_ACCESS_REPORT);
00103 
00104     void
00105     printOneTagReportData (
00106       CTagReportData *          pTagReportData);
00107 
00108     int
00109     formatOneEPC (
00110       CParameter *          pEpcParameter,
00111       char *                buf,
00112       int                   buflen,
00113       char *                startStr);
00114 
00115     int getOnePhaseAngle(
00116       CImpinjRFPhaseAngle  *pRfPhase,
00117       double               *out);
00118 
00119     int
00120     getOnePeakRSSI (
00121       CImpinjPeakRSSI      *pPeakRSSI,
00122       double               *out);
00123 
00124     int
00125     getOneTimestamp (
00126       CParameter           *pTimestamp,
00127       unsigned long long   *out);
00128 
00129     int
00130     getOneAntenna (
00131       CAntennaID           *pAntenna,
00132       unsigned short       *out);
00133 
00134     int
00135     getOneChannelIndex (
00136       CChannelIndex        *pChannelIndex,
00137       unsigned short       *out);
00138 
00139     int 
00140     estimateVelocity(
00141       char *                epcStr,
00142       double                rssi, 
00143       double                phase, 
00144       unsigned short        channelIndex, 
00145       unsigned short        antenna, 
00146       unsigned long long    time, 
00147       double                *outVelocity);
00148 
00149     void
00150     handleReaderEventNotification (
00151       CReaderEventNotificationData *pNtfData);
00152 
00153     void
00154     handleAntennaEvent (
00155       CAntennaEvent *           pAntennaEvent);
00156 
00157     void
00158     handleReaderExceptionEvent (
00159       CReaderExceptionEvent *   pReaderExceptionEvent);
00160 
00161     int
00162     checkLLRPStatus (
00163       CLLRPStatus *             pLLRPStatus,
00164       char *                    pWhatStr);
00165 
00166     CMessage *
00167     transact (
00168       CMessage *                pSendMsg);
00169 
00170     CMessage *
00171     recvMessage (
00172       int                       nMaxMS);
00173 
00174     int
00175     sendMessage (
00176       CMessage *                pSendMsg);
00177 
00178     void
00179     printXMLMessage (
00180       CMessage *                pMessage);
00181 };
00182 
00183 
00184 /* BEGIN forward declarations */
00185 int
00186 main (
00187   int                           ac,
00188   char *                        av[]);
00189 
00190 void
00191 usage (
00192   char *                        pProgName);
00193 /* END forward declarations */
00194 
00195 
00211 int
00212 main (
00213   int                           ac,
00214   char *                        av[])
00215 {
00216     CMyApplication              myApp;
00217     char *                      pReaderHostName;
00218     int                         rc;
00219 
00220     /*
00221      * Process comand arguments, determine reader name
00222      * and verbosity level.
00223      */
00224     if(ac == 2)
00225     {
00226         pReaderHostName = av[1];
00227     }
00228     else if(ac == 3)
00229     {
00230         char *                  p = av[1];
00231 
00232         while(*p)
00233         {
00234             switch(*p++)
00235             {
00236             case '-':   /* linux conventional option warn char */
00237             case '/':   /* Windows/DOS conventional option warn char */
00238                 break;
00239 
00240             case 'v':
00241             case 'V':
00242                 myApp.m_Verbose++;
00243                 break;
00244 
00245             default:
00246                 usage(av[0]);
00247                 /* no return */
00248                 break;
00249             }
00250         }
00251 
00252         pReaderHostName = av[2];
00253     }
00254     else
00255     {
00256         usage(av[0]);
00257         /* no return */
00258     }
00259 
00260     /*
00261      * Run application, capture return value for exit status
00262      */
00263     rc = myApp.run(pReaderHostName);
00264 
00265     printf("INFO: Done\n");
00266 
00267     /*
00268      * Exit with the right status.
00269      */
00270     if(0 == rc)
00271     {
00272         exit(0);
00273     }
00274     else
00275     {
00276         exit(2);
00277     }
00278     /*NOTREACHED*/
00279 }
00280 
00281 
00293 void
00294 usage (
00295   char *                        pProgName)
00296 {
00297 #ifdef linux
00298     printf("Usage: %s [-v[v]] READERHOSTNAME\n", pProgName);
00299     printf("\n");
00300     printf("Each -v increases verbosity level\n");
00301 #endif /* linux */
00302 #ifdef WIN32
00303     printf("Usage: %s [/v[v]] READERHOSTNAME\n", pProgName);
00304     printf("\n");
00305     printf("Each /v increases verbosity level\n");
00306 #endif /* WIN32 */
00307     exit(1);
00308 }
00309 
00310 
00352 int
00353 CMyApplication::run (
00354   char *                        pReaderHostName)
00355 {
00356     CTypeRegistry *             pTypeRegistry;
00357     CConnection *               pConn;
00358     int                         rc;
00359 
00360     /*
00361      * Allocate the type registry. This is needed
00362      * by the connection to decode.
00363      */
00364     pTypeRegistry = getTheTypeRegistry();
00365     if(NULL == pTypeRegistry)
00366     {
00367         printf("ERROR: getTheTypeRegistry failed\n");
00368         return -1;
00369     }
00370 
00371     /*
00372      * Enroll impinj extension types into the 
00373      * type registry, in preparation for using 
00374      * Impinj extension params.
00375      */
00376     LLRP::enrollImpinjTypesIntoRegistry(pTypeRegistry);
00377 
00378     /*
00379      * Construct a connection (LLRP::CConnection).
00380      * Using a 32kb max frame size for send/recv.
00381      * The connection object is ready for business
00382      * but not actually connected to the reader yet.
00383      */
00384     pConn = new CConnection(pTypeRegistry, 32u*1024u);
00385     if(NULL == pConn)
00386     {
00387         printf("ERROR: new CConnection failed\n");
00388         return -2;
00389     }
00390 
00391     /*
00392      * Open the connection to the reader
00393      */
00394     if(m_Verbose)
00395     {
00396         printf("INFO: Connecting to %s....\n", pReaderHostName);
00397     }
00398 
00399     rc = pConn->openSecureConnectionToReader(pReaderHostName);
00400     if(0 != rc)
00401     {
00402         printf("ERROR: connect: %s (%d)\n", pConn->getConnectError(), rc);
00403         delete pConn;
00404         return -3;
00405     }
00406 
00407     /*
00408      * Record the pointer to the connection object so other
00409      * routines can use it.
00410      */
00411     m_pConnectionToReader = pConn;
00412 
00413     if(m_Verbose)
00414     {
00415         printf("INFO: Connected, checking status....\n");
00416     }
00417 
00418     /*
00419      * Commence the sequence and check for errors as we go.
00420      * See comments for each routine for details.
00421      * Each routine prints messages.
00422      */
00423     rc = 1;
00424     if(0 == checkConnectionStatus())
00425     {
00426         rc = 2;
00427         if(0 == enableImpinjExtensions())
00428         {
00429             rc = 3;
00430             if(0 == resetConfigurationToFactoryDefaults())
00431             {
00432                 rc = 4;
00433                 if(0 == getReaderCapabilities())
00434                 {
00435                     rc = 6;
00436                     if(0 == setImpinjReaderConfig())
00437                     {
00438                         rc = 7;
00439                         if(0 == addROSpec())
00440                         {
00441                             rc = 8;
00442                             if(0 == enableROSpec())
00443                             {
00444                                 rc = 9;
00445                                 if(0 == startROSpec())
00446                                 {
00447                                     rc = 10;
00448                                     if(0 == awaitAndPrintReport(60))
00449                                     {
00450                                         rc = 11;
00451                                         if(0 == stopROSpec())
00452                                         {
00453                                             rc = 0;
00454                                         }
00455                                     }
00456                                 }
00457                             }
00458                         }
00459                     }
00460                 }
00461             }
00462 
00463             /*
00464              * After we're done, try to leave the reader
00465              * in a clean state for next use. This is best
00466              * effort and no checking of the result is done.
00467              */
00468             if(m_Verbose)
00469             {
00470                 printf("INFO: Clean up reader configuration...\n");
00471             }
00472             resetConfigurationToFactoryDefaults();
00473         }
00474     }
00475 
00476     if(m_Verbose)
00477     {
00478         printf("INFO: Finished\n");
00479     }
00480 
00481     /*
00482      * Close the connection and release its resources
00483      */
00484     pConn->closeConnectionToReader();
00485     delete pConn;
00486 
00487     /*
00488      * Done with the registry.
00489      */
00490     delete pTypeRegistry;
00491 
00492     /*
00493      * When we get here all allocated memory should have been deallocated.
00494      */
00495 
00496     return rc;
00497 }
00498 
00499 
00530 int
00531 CMyApplication::checkConnectionStatus (void)
00532 {
00533     CMessage *                  pMessage;
00534     CREADER_EVENT_NOTIFICATION *pNtf;
00535     CReaderEventNotificationData *pNtfData;
00536     CConnectionAttemptEvent *   pEvent;
00537 
00538     /*
00539      * Expect the notification within 10 seconds.
00540      * It is suppose to be the very first message sent.
00541      */
00542     pMessage = recvMessage(10000);
00543 
00544     /*
00545      * recvMessage() returns NULL if something went wrong.
00546      */
00547     if(NULL == pMessage)
00548     {
00549         /* recvMessage already tattled */
00550         goto fail;
00551     }
00552 
00553     /*
00554      * Check to make sure the message is of the right type.
00555      * The type label (pointer) in the message should be
00556      * the type descriptor for READER_EVENT_NOTIFICATION.
00557      */
00558     if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor != pMessage->m_pType)
00559     {
00560         goto fail;
00561     }
00562 
00563     /*
00564      * Now that we are sure it is a READER_EVENT_NOTIFICATION,
00565      * traverse to the ReaderEventNotificationData parameter.
00566      */
00567     pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage;
00568     pNtfData = pNtf->getReaderEventNotificationData();
00569     if(NULL == pNtfData)
00570     {
00571         goto fail;
00572     }
00573 
00574     /*
00575      * The ConnectionAttemptEvent parameter must be present.
00576      */
00577     pEvent = pNtfData->getConnectionAttemptEvent();
00578     if(NULL == pEvent)
00579     {
00580         goto fail;
00581     }
00582 
00583     /*
00584      * The status in the ConnectionAttemptEvent parameter
00585      * must indicate connection success.
00586      */
00587     if(ConnectionAttemptStatusType_Success != pEvent->getStatus())
00588     {
00589         goto fail;
00590     }
00591 
00592     /*
00593      * Done with the message
00594      */
00595     delete pMessage;
00596 
00597     if(m_Verbose)
00598     {
00599         printf("INFO: Connection status OK\n");
00600     }
00601 
00602     /*
00603      * Victory.
00604      */
00605     return 0;
00606 
00607   fail:
00608     /*
00609      * Something went wrong. Tattle. Clean up. Return error.
00610      */
00611     printf("ERROR: checkConnectionStatus failed\n");
00612     delete pMessage;
00613     return -1;
00614 }
00615 
00633 int
00634 CMyApplication::enableImpinjExtensions (void)
00635 {
00636     CIMPINJ_ENABLE_EXTENSIONS *        pCmd;
00637     CMessage *                         pRspMsg;
00638     CIMPINJ_ENABLE_EXTENSIONS_RESPONSE *pRsp;
00639 
00640     /*
00641      * Compose the command message
00642      */
00643     pCmd = new CIMPINJ_ENABLE_EXTENSIONS();
00644     pCmd->setMessageID(m_messageID++);
00645     /*
00646      * Send the message, expect the response of certain type
00647      */
00648     pRspMsg = transact(pCmd);
00649 
00650     /*
00651      * Done with the command message
00652      */
00653     delete pCmd;
00654 
00655     /*
00656      * transact() returns NULL if something went wrong.
00657      */
00658     if(NULL == pRspMsg)
00659     {
00660         /* transact already tattled */
00661         return -1;
00662     }
00663 
00664     /*
00665      * Cast to a CIMPINJ_ENABLE_EXTENSIONS_RESPONSE message.
00666      */
00667     pRsp = (CIMPINJ_ENABLE_EXTENSIONS_RESPONSE *) pRspMsg;
00668 
00669     /*
00670      * Check the LLRPStatus parameter.
00671      */
00672     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(),
00673                         "enableImpinjExtensions"))
00674     {
00675         /* checkLLRPStatus already tattled */
00676         delete pRspMsg;
00677         return -1;
00678     }
00679 
00680     /*
00681      * Done with the response message.
00682      */
00683     delete pRspMsg;
00684 
00685     /*
00686      * Tattle progress, maybe
00687      */
00688     if(m_Verbose)
00689     {
00690         printf("INFO: Impinj Extensions are enabled\n");
00691     }
00692 
00693     /*
00694      * Victory.
00695      */
00696     return 0;
00697 }
00698 
00719 int
00720 CMyApplication::resetConfigurationToFactoryDefaults (void)
00721 {
00722     CSET_READER_CONFIG *        pCmd;
00723     CMessage *                  pRspMsg;
00724     CSET_READER_CONFIG_RESPONSE *pRsp;
00725 
00726     /*
00727      * Compose the command message
00728      */
00729     pCmd = new CSET_READER_CONFIG();
00730     pCmd->setMessageID(m_messageID++);
00731     pCmd->setResetToFactoryDefault(1);
00732 
00733     /*
00734      * Send the message, expect the response of certain type
00735      */
00736     pRspMsg = transact(pCmd);
00737 
00738     /*
00739      * Done with the command message
00740      */
00741     delete pCmd;
00742 
00743     /*
00744      * transact() returns NULL if something went wrong.
00745      */
00746     if(NULL == pRspMsg)
00747     {
00748         /* transact already tattled */
00749         return -1;
00750     }
00751 
00752     /*
00753      * Cast to a SET_READER_CONFIG_RESPONSE message.
00754      */
00755     pRsp = (CSET_READER_CONFIG_RESPONSE *) pRspMsg;
00756 
00757     /*
00758      * Check the LLRPStatus parameter.
00759      */
00760     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(),
00761                         "resetConfigurationToFactoryDefaults"))
00762     {
00763         /* checkLLRPStatus already tattled */
00764         delete pRspMsg;
00765         return -1;
00766     }
00767 
00768     /*
00769      * Done with the response message.
00770      */
00771     delete pRspMsg;
00772 
00773     /*
00774      * Tattle progress, maybe
00775      */
00776     if(m_Verbose)
00777     {
00778         printf("INFO: Configuration reset to factory defaults\n");
00779     }
00780 
00781     /*
00782      * Victory.
00783      */
00784     return 0;
00785 }
00786 
00803 int
00804 CMyApplication::getReaderCapabilities(void)
00805 {
00806     CGET_READER_CAPABILITIES          *pCmd;
00807     CMessage *                         pRspMsg;
00808     CGET_READER_CAPABILITIES_RESPONSE *pRsp;
00809     CGeneralDeviceCapabilities        *pDeviceCap;
00810     std::list<CTransmitPowerLevelTableEntry *>::iterator     PwrLvl;
00811     unsigned int bMajorVersion, bMinorVersion, bDevVersion, bBuildVersion = 0;
00812 
00813     /*
00814      * Compose the command message
00815      */
00816     pCmd = new CGET_READER_CAPABILITIES();
00817     pCmd->setMessageID(m_messageID++);
00818     pCmd->setRequestedData(GetReaderCapabilitiesRequestedData_All);
00819 
00820     /*
00821      * Send the message, expect the response of certain type
00822      */
00823     pRspMsg = transact(pCmd);
00824 
00825     /*
00826      * Done with the command message
00827      */
00828     delete pCmd;
00829 
00830     /*
00831      * transact() returns NULL if something went wrong.
00832      */
00833     if(NULL == pRspMsg)
00834     {
00835         /* transact already tattled */
00836         return -1;
00837     }
00838 
00839     /*
00840      * Cast to a CGET_READER_CAPABILITIES_RESPONSE message.
00841      */
00842     pRsp = (CGET_READER_CAPABILITIES_RESPONSE *) pRspMsg;
00843 
00844     /*
00845      * Check the LLRPStatus parameter.
00846      */
00847     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(),
00848                         "getReaderCapabilities"))
00849     {
00850         /* checkLLRPStatus already tattled */
00851         delete pRspMsg;
00852         return -1;
00853     }
00854 
00855     /* if this parameter is missing, or if this is not an Impinj
00856     ** reader, we can't determine its capabilities so we exit
00857     ** Impinj Private Enterprise NUmber is 25882 */
00858     if( (NULL == (pDeviceCap = pRsp->getGeneralDeviceCapabilities())) || 
00859         (25882 != pDeviceCap->getDeviceManufacturerName()))
00860     {
00861         delete pRspMsg;
00862         return -1;
00863     }
00864 
00865 
00866   /*
00867    * Get the version information from the reader and make sure we are 4.4 or better.
00868    */
00869   if  ( pDeviceCap->getReaderFirmwareVersion().m_nValue < 3)
00870   {
00871         printf("ERROR: Must have Firmware 4.4 or later for low level data example \n");
00872         delete pRspMsg;
00873         return -1;
00874   }
00875 
00876   /*
00877    * Parse to make sure it is really 4.4 or better
00878    */
00879   sscanf((char *) pDeviceCap->getReaderFirmwareVersion().m_pValue, "%u.%u.%u.%u", &bMajorVersion, &bMinorVersion, &bDevVersion, &bBuildVersion);
00880 
00881     if( (bMajorVersion < 4) && (bMinorVersion < 4) )
00882     {
00883         printf("ERROR: Must have Firmware 4.4 or later for low level data example \n");
00884         delete pRspMsg;
00885         return -1;
00886     }
00887 
00888     if(1 < m_Verbose)
00889     {
00890         printf("INFO: Reader Model Name %u\n", m_modelNumber);
00891     }
00892 
00893     /*
00894      * Done with the response message.
00895      */
00896     delete pRspMsg;
00897 
00898     /*
00899      * Tattle progress, maybe
00900      */
00901     if(m_Verbose)
00902     {
00903         printf("INFO: Found LLRP Capabilities \n");
00904     }
00905 
00906     /*
00907      * Victory.
00908      */
00909     return 0;
00910 }
00911 
00991 int
00992 CMyApplication::setImpinjReaderConfig(void)
00993 {
00994     CSET_READER_CONFIG          *pCmd;
00995     CMessage *                  pRspMsg;
00996     CSET_READER_CONFIG_RESPONSE *pRsp;
00997 
00998     /*
00999      * Compose the command message
01000      */
01001     pCmd = new CSET_READER_CONFIG();
01002     pCmd->setMessageID(m_messageID++);
01003 
01004     CAntennaConfiguration *pAnt = new(CAntennaConfiguration);
01005 
01006     /*
01007     ** Apply this configuration to all antennas 
01008     */
01009     pAnt->setAntennaID(0);
01010     
01011 
01012     CC1G2InventoryCommand *pC1G2Inv = new CC1G2InventoryCommand();
01013     
01014     /* set the mode to auto-set max throughput */
01015     CC1G2RFControl *pC1G2Rf = new CC1G2RFControl();
01016     pC1G2Rf->setModeIndex(2); /* DRM M=4 */
01017     pC1G2Rf->setTari(0);        /* tari is ignored by the reader */
01018     pC1G2Inv->setC1G2RFControl(pC1G2Rf);
01019 
01020     CC1G2SingulationControl *pC1G2Sing = new CC1G2SingulationControl();    
01021     pC1G2Sing->setSession(2);
01022     pC1G2Sing->setTagPopulation(1);
01023     pC1G2Sing->setTagTransitTime(0);
01024     pC1G2Inv->setC1G2SingulationControl(pC1G2Sing);
01025 
01026     pC1G2Inv->setTagInventoryStateAware(false);
01027 
01028     /* set the Impinj Inventory search mode as per the use case */
01029     CImpinjInventorySearchMode *pImpIsm = new CImpinjInventorySearchMode();
01030     pImpIsm->setInventorySearchMode(ImpinjInventorySearchType_Dual_Target);
01031     pC1G2Inv->addCustom(pImpIsm);
01032 
01033     /* set the Impinj Low Duty Cycle mode as per the use case */
01034     CImpinjLowDutyCycle *pImpLdc = new CImpinjLowDutyCycle();
01035     pImpLdc->setEmptyFieldTimeout(10000);
01036     pImpLdc->setFieldPingInterval(200);
01037     pImpLdc->setLowDutyCycleMode(ImpinjLowDutyCycleMode_Enabled);
01038     pC1G2Inv->addCustom(pImpLdc);
01039 
01040     pAnt->addAirProtocolInventoryCommandSettings(pC1G2Inv);
01041     pCmd->addAntennaConfiguration(pAnt);
01042 
01043     /* report every tag (N=1) since that is required for tag direction */
01044     CROReportSpec *pROrs = new CROReportSpec();
01045     pROrs->setROReportTrigger(ROReportTriggerType_Upon_N_Tags_Or_End_Of_ROSpec);
01046     pROrs->setN(1);
01047 
01048     /* lets turn off off report data that we don't need since our use 
01049     ** case suggests we are bandwidth constrained */
01050     CTagReportContentSelector *pROcontent = new CTagReportContentSelector();
01051     pROcontent->setEnableAccessSpecID(false);
01052 
01053     /* these are very handy to have with low level data */
01054     pROcontent->setEnableAntennaID(true);
01055     pROcontent->setEnableChannelIndex(true);
01056     pROcontent->setEnableFirstSeenTimestamp(true);
01057     
01058     pROcontent->setEnableInventoryParameterSpecID(false);
01059     pROcontent->setEnableLastSeenTimestamp(false);
01060     pROcontent->setEnablePeakRSSI(false);
01061     pROcontent->setEnableROSpecID(false);
01062     pROcontent->setEnableSpecIndex(false);
01063     pROcontent->setEnableTagSeenCount(false);
01064     CC1G2EPCMemorySelector *pC1G2Mem = new CC1G2EPCMemorySelector();
01065     pC1G2Mem->setEnableCRC(false);
01066     pC1G2Mem->setEnablePCBits(false);
01067     pROcontent->addAirProtocolEPCMemorySelector(pC1G2Mem);
01068 
01069     pROrs->setTagReportContentSelector(pROcontent);
01070 
01071     /* Turn on the low level phase data in the ImpinjTagContentSelector*/
01072     CImpinjTagReportContentSelector * pImpTagCnt = new CImpinjTagReportContentSelector();
01073     
01074     CImpinjEnableRFPhaseAngle       * pEnableRfPhase = new CImpinjEnableRFPhaseAngle();
01075     pEnableRfPhase->setRFPhaseAngleMode(ImpinjRFPhaseAngleMode_Enabled);
01076     pImpTagCnt->setImpinjEnableRFPhaseAngle(pEnableRfPhase);
01077 
01078     CImpinjEnablePeakRSSI       * pEnablePeakRssi = new CImpinjEnablePeakRSSI();
01079     pEnablePeakRssi->setPeakRSSIMode(ImpinjPeakRSSIMode_Enabled);
01080     pImpTagCnt->setImpinjEnablePeakRSSI(pEnablePeakRssi);
01081 
01082     CImpinjEnableSerializedTID  * pEnableSerializedTID = new CImpinjEnableSerializedTID();
01083     pEnableSerializedTID->setSerializedTIDMode(ImpinjSerializedTIDMode_Disabled);
01084     pImpTagCnt->setImpinjEnableSerializedTID(pEnableSerializedTID);   
01085 
01086     pROrs->addCustom(pImpTagCnt);
01087 
01088     pCmd->setROReportSpec(pROrs);
01089 
01090     /*
01091      * Send the message, expect the response of certain type
01092      */
01093     pRspMsg = transact(pCmd);
01094 
01095     /*
01096      * Done with the command message
01097      */
01098     delete pCmd;
01099 
01100     /*
01101      * transact() returns NULL if something went wrong.
01102      */
01103     if(NULL == pRspMsg)
01104     {
01105         /* transact already tattled */
01106         return -1;
01107     }
01108 
01109     /*
01110      * Cast to a CSET_READER_CONFIG_RESPONSE message.
01111      */
01112     pRsp = (CSET_READER_CONFIG_RESPONSE *) pRspMsg;
01113 
01114     /*
01115      * Check the LLRPStatus parameter.
01116      */
01117     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(),
01118                         "setImpinjReaderConfig"))
01119     {
01120         /* checkLLRPStatus already tattled */
01121         delete pRspMsg;
01122         return -1;
01123     }
01124 
01125     /*
01126      * Done with the response message.
01127      */
01128     delete pRspMsg;
01129 
01130     /*
01131      * Tattle progress, maybe
01132      */
01133     if(m_Verbose)
01134     {
01135         printf("INFO: Set Impinj Reader Configuration \n");
01136     }
01137 
01138     /*
01139      * Victory.
01140      */
01141     return 0;
01142 }
01143 
01193 int
01194 CMyApplication::addROSpec (void)
01195 {
01196     CROSpecStartTrigger *       pROSpecStartTrigger =
01197                                     new CROSpecStartTrigger();
01198     pROSpecStartTrigger->setROSpecStartTriggerType(
01199                                 ROSpecStartTriggerType_Null);
01200 
01201     CROSpecStopTrigger *        pROSpecStopTrigger = new CROSpecStopTrigger();
01202     pROSpecStopTrigger->setROSpecStopTriggerType(ROSpecStopTriggerType_Null);
01203     pROSpecStopTrigger->setDurationTriggerValue(0);     /* n/a */
01204 
01205     CROBoundarySpec *           pROBoundarySpec = new CROBoundarySpec();
01206     pROBoundarySpec->setROSpecStartTrigger(pROSpecStartTrigger);
01207     pROBoundarySpec->setROSpecStopTrigger(pROSpecStopTrigger);
01208 
01209     CAISpecStopTrigger *        pAISpecStopTrigger = new CAISpecStopTrigger();
01210     pAISpecStopTrigger->setAISpecStopTriggerType(
01211             AISpecStopTriggerType_Null);
01212     pAISpecStopTrigger->setDurationTrigger(0);
01213 
01214     CInventoryParameterSpec *   pInventoryParameterSpec =
01215                                     new CInventoryParameterSpec();
01216     pInventoryParameterSpec->setInventoryParameterSpecID(1234);
01217     pInventoryParameterSpec->setProtocolID(AirProtocols_EPCGlobalClass1Gen2);
01218 
01219     /* 
01220     ** configure to use two antennas to be compatible with
01221     ** our tag direction settings
01222     */
01223     llrp_u16v_t                 AntennaIDs = llrp_u16v_t(1);
01224     AntennaIDs.m_pValue[0] = 2;
01225 
01226     CAISpec *                   pAISpec = new CAISpec();
01227     pAISpec->setAntennaIDs(AntennaIDs);
01228     pAISpec->setAISpecStopTrigger(pAISpecStopTrigger);
01229     pAISpec->addInventoryParameterSpec(pInventoryParameterSpec);
01230 
01231     CROSpec *                   pROSpec = new CROSpec();
01232     pROSpec->setROSpecID(1111);
01233     pROSpec->setPriority(0);
01234     pROSpec->setCurrentState(ROSpecState_Disabled);
01235     pROSpec->setROBoundarySpec(pROBoundarySpec);
01236     pROSpec->addSpecParameter(pAISpec);
01237 
01238     CADD_ROSPEC *               pCmd;
01239     CMessage *                  pRspMsg;
01240     CADD_ROSPEC_RESPONSE *      pRsp;
01241 
01242     /*
01243      * Compose the command message.
01244      * N.B.: After the message is composed, all the parameters
01245      *       constructed, immediately above, are considered "owned"
01246      *       by the command message. When it is destructed so
01247      *       too will the parameters be.
01248      */
01249     pCmd = new CADD_ROSPEC();
01250     pCmd->setMessageID(m_messageID++);
01251     pCmd->setROSpec(pROSpec);
01252 
01253     /*
01254      * Send the message, expect the response of certain type
01255      */
01256     pRspMsg = transact(pCmd);
01257 
01258     /*
01259      * Done with the command message.
01260      * N.B.: And the parameters
01261      */
01262     delete pCmd;
01263 
01264     /*
01265      * transact() returns NULL if something went wrong.
01266      */
01267     if(NULL == pRspMsg)
01268     {
01269         /* transact already tattled */
01270         return -1;
01271     }
01272 
01273     /*
01274      * Cast to a ADD_ROSPEC_RESPONSE message.
01275      */
01276     pRsp = (CADD_ROSPEC_RESPONSE *) pRspMsg;
01277 
01278     /*
01279      * Check the LLRPStatus parameter.
01280      */
01281     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "addROSpec"))
01282     {
01283         /* checkLLRPStatus already tattled */
01284         delete pRspMsg;
01285         return -1;
01286     }
01287 
01288     /*
01289      * Done with the response message.
01290      */
01291     delete pRspMsg;
01292 
01293     /*
01294      * Tattle progress, maybe
01295      */
01296     if(m_Verbose)
01297     {
01298         printf("INFO: ROSpec added\n");
01299     }
01300 
01301     /*
01302      * Victory.
01303      */
01304     return 0;
01305 }
01306 
01307 
01325 int
01326 CMyApplication::enableROSpec (void)
01327 {
01328     CENABLE_ROSPEC *            pCmd;
01329     CMessage *                  pRspMsg;
01330     CENABLE_ROSPEC_RESPONSE *   pRsp;
01331 
01332     /*
01333      * Compose the command message
01334      */
01335     pCmd = new CENABLE_ROSPEC();
01336     pCmd->setMessageID(m_messageID++);
01337     pCmd->setROSpecID(1111);
01338 
01339     /*
01340      * Send the message, expect the response of certain type
01341      */
01342     pRspMsg = transact(pCmd);
01343 
01344     /*
01345      * Done with the command message
01346      */
01347     delete pCmd;
01348 
01349     /*
01350      * transact() returns NULL if something went wrong.
01351      */
01352     if(NULL == pRspMsg)
01353     {
01354         /* transact already tattled */
01355         return -1;
01356     }
01357 
01358     /*
01359      * Cast to a ENABLE_ROSPEC_RESPONSE message.
01360      */
01361     pRsp = (CENABLE_ROSPEC_RESPONSE *) pRspMsg;
01362 
01363     /*
01364      * Check the LLRPStatus parameter.
01365      */
01366     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "enableROSpec"))
01367     {
01368         /* checkLLRPStatus already tattled */
01369         delete pRspMsg;
01370         return -1;
01371     }
01372 
01373     /*
01374      * Done with the response message.
01375      */
01376     delete pRspMsg;
01377 
01378     /*
01379      * Tattle progress, maybe
01380      */
01381     if(m_Verbose)
01382     {
01383         printf("INFO: ROSpec enabled\n");
01384     }
01385 
01386     /*
01387      * Victory.
01388      */
01389     return 0;
01390 }
01391 
01392 
01410 int
01411 CMyApplication::startROSpec (void)
01412 {
01413     CSTART_ROSPEC *             pCmd;
01414     CMessage *                  pRspMsg;
01415     CSTART_ROSPEC_RESPONSE *    pRsp;
01416 
01417     /*
01418      * Compose the command message
01419      */
01420     pCmd = new CSTART_ROSPEC();
01421     pCmd->setMessageID(m_messageID++);
01422     pCmd->setROSpecID(1111);
01423 
01424     /*
01425      * Send the message, expect the response of certain type
01426      */
01427     pRspMsg = transact(pCmd);
01428 
01429     /*
01430      * Done with the command message
01431      */
01432     delete pCmd;
01433 
01434     /*
01435      * transact() returns NULL if something went wrong.
01436      */
01437     if(NULL == pRspMsg)
01438     {
01439         /* transact already tattled */
01440         return -1;
01441     }
01442 
01443     /*
01444      * Cast to a START_ROSPEC_RESPONSE message.
01445      */
01446     pRsp = (CSTART_ROSPEC_RESPONSE *) pRspMsg;
01447 
01448     /*
01449      * Check the LLRPStatus parameter.
01450      */
01451     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "startROSpec"))
01452     {
01453         /* checkLLRPStatus already tattled */
01454         delete pRspMsg;
01455         return -1;
01456     }
01457 
01458     /*
01459      * Done with the response message.
01460      */
01461     delete pRspMsg;
01462 
01463     /*
01464      * Tattle progress
01465      */
01466     if(m_Verbose)
01467     {
01468         printf("INFO: ROSpec started\n");
01469     }
01470 
01471     /*
01472      * Victory.
01473      */
01474     return 0;
01475 }
01476 
01494 int
01495 CMyApplication::stopROSpec (void)
01496 {
01497     CSTOP_ROSPEC *             pCmd;
01498     CMessage *                  pRspMsg;
01499     CSTOP_ROSPEC_RESPONSE *    pRsp;
01500 
01501     /*
01502      * Compose the command message
01503      */
01504     pCmd = new CSTOP_ROSPEC();
01505     pCmd->setMessageID(m_messageID++);
01506     pCmd->setROSpecID(1111);
01507 
01508     /*
01509      * Send the message, expect the response of certain type
01510      */
01511     pRspMsg = transact(pCmd);
01512 
01513     /*
01514      * Done with the command message
01515      */
01516     delete pCmd;
01517 
01518     /*
01519      * transact() returns NULL if something went wrong.
01520      */
01521     if(NULL == pRspMsg)
01522     {
01523         /* transact already tattled */
01524         return -1;
01525     }
01526 
01527     /*
01528      * Cast to a STOP_ROSPEC_RESPONSE message.
01529      */
01530     pRsp = (CSTOP_ROSPEC_RESPONSE *) pRspMsg;
01531 
01532     /*
01533      * Check the LLRPStatus parameter.
01534      */
01535     if(0 != checkLLRPStatus(pRsp->getLLRPStatus(), "stopROSpec"))
01536     {
01537         /* checkLLRPStatus already tattled */
01538         delete pRspMsg;
01539         return -1;
01540     }
01541 
01542     /*
01543      * Done with the response message.
01544      */
01545     delete pRspMsg;
01546 
01547     /*
01548      * Tattle progress
01549      */
01550     if(m_Verbose)
01551     {
01552         printf("INFO: ROSpec stopped\n");
01553     }
01554 
01555     /*
01556      * Victory.
01557      */
01558     return 0;
01559 }
01560 
01561 
01581 int
01582 CMyApplication::awaitAndPrintReport (int timeout)
01583 {
01584     int                         bDone = 0;
01585     int                         retVal = 0;
01586     time_t                      startTime = time(NULL);
01587     time_t                      tempTime;
01588     /*
01589      * Keep receiving messages until done or until
01590      * something bad happens.
01591      */
01592     while(!bDone)
01593     {
01594         CMessage *              pMessage;
01595         const CTypeDescriptor * pType;
01596 
01597         /*
01598          * Wait up to 1 second for a report.  Check
01599          * That way, we can check the timestamp even if 
01600          * there are no reports coming in
01601          */
01602         pMessage = recvMessage(1000);
01603 
01604         /* validate the timestamp */
01605         tempTime = time(NULL);
01606         if(difftime(tempTime, startTime) > timeout)
01607         {
01608             bDone=1;
01609         }
01610 
01611         if(NULL == pMessage)
01612         {
01613             continue;
01614         }
01615 
01616         /*
01617          * What happens depends on what kind of message
01618          * received. Use the type label (m_pType) to
01619          * discriminate message types.
01620          */
01621         pType = pMessage->m_pType;
01622 
01623         /*
01624          * Is it a tag report? If so, print it out.
01625          */
01626         if(&CRO_ACCESS_REPORT::s_typeDescriptor == pType)
01627         {
01628             CRO_ACCESS_REPORT * pNtf;
01629 
01630             pNtf = (CRO_ACCESS_REPORT *) pMessage;
01631 
01632             printTagReportData(pNtf);
01633         }
01634 
01635         /*
01636          * Is it a reader event? This example only recognizes
01637          * AntennaEvents.
01638          */
01639         else if(&CREADER_EVENT_NOTIFICATION::s_typeDescriptor == pType)
01640         {
01641             CREADER_EVENT_NOTIFICATION *pNtf;
01642             CReaderEventNotificationData *pNtfData;
01643 
01644             pNtf = (CREADER_EVENT_NOTIFICATION *) pMessage;
01645 
01646             pNtfData = pNtf->getReaderEventNotificationData();
01647             if(NULL != pNtfData)
01648             {
01649                 handleReaderEventNotification(pNtfData);
01650             }
01651             else
01652             {
01653                 /*
01654                  * This should never happen. Using continue
01655                  * to keep indent depth down.
01656                  */
01657                 printf("WARNING: READER_EVENT_NOTIFICATION without data\n");
01658             }
01659         }
01660 
01661         /*
01662          * Hmmm. Something unexpected. Just tattle and keep going.
01663          */
01664         else
01665         {
01666             printf("WARNING: Ignored unexpected message during monitor: %s\n",
01667                 pType->m_pName);
01668         }
01669 
01670         /*
01671          * Done with the received message
01672          */
01673         delete pMessage;
01674     }
01675 
01676     return retVal;
01677 }
01678 
01679 
01694 void
01695 CMyApplication::printTagReportData (
01696   CRO_ACCESS_REPORT *           pRO_ACCESS_REPORT)
01697 {
01698     std::list<CTagReportData *>::iterator Cur;
01699     std::list<CParameter *>::iterator CustCur;
01700 
01701     unsigned int                nEntry = 0;
01702     
01703     /*
01704      * Loop through and count the number of entries
01705      */
01706     for(
01707         Cur = pRO_ACCESS_REPORT->beginTagReportData();
01708         Cur != pRO_ACCESS_REPORT->endTagReportData();
01709         Cur++)
01710     {
01711         nEntry++;
01712     }
01713 
01714     if(m_Verbose)
01715     {
01716         printf("INFO: %u tag report entries\n", nEntry);
01717     }
01718 
01719     /*
01720      * Loop through again and print each entry.
01721      */
01722     for(
01723         Cur = pRO_ACCESS_REPORT->beginTagReportData();
01724         Cur != pRO_ACCESS_REPORT->endTagReportData();
01725         Cur++)
01726     {
01727         printOneTagReportData(*Cur);
01728     }
01729 }
01730 
01739 int
01740 CMyApplication::formatOneEPC (
01741   CParameter *pEPCParameter, 
01742   char *buf, 
01743   int buflen,
01744   char * startStr)
01745 {
01746     char *              p = buf;
01747     int                 bufsize = buflen;
01748     int                 written = 0;
01749 
01750     written = snprintf(p, bufsize, "%s", startStr); 
01751     bufsize -= written;
01752     p += written;
01753 
01754     if(NULL != pEPCParameter)
01755     {
01756         const CTypeDescriptor *     pType;
01757         llrp_u96_t          my_u96;
01758         llrp_u1v_t          my_u1v;
01759         llrp_u8_t *         pValue = NULL;
01760         unsigned int        n, i;
01761 
01762         pType = pEPCParameter->m_pType;
01763         if(&CEPC_96::s_typeDescriptor == pType)
01764         {
01765             CEPC_96             *pEPC_96;
01766 
01767             pEPC_96 = (CEPC_96 *) pEPCParameter;
01768             my_u96 = pEPC_96->getEPC();
01769             pValue = my_u96.m_aValue;
01770             n = 12u;
01771         }
01772         else if(&CEPCData::s_typeDescriptor == pType)
01773         {
01774             CEPCData *          pEPCData;
01775 
01776             pEPCData = (CEPCData *) pEPCParameter;
01777             my_u1v = pEPCData->getEPC();
01778             pValue = my_u1v.m_pValue;
01779             n = (my_u1v.m_nBit + 7u) / 8u;
01780         }
01781 
01782         if(NULL != pValue)
01783         {
01784             for(i = 0; i < n; i++)
01785             {
01786                 if(0 < i && i%2 == 0 && 1 < bufsize)
01787                 {
01788                     *p++ = '-';
01789                     bufsize--;
01790                 }
01791                 if(bufsize > 2)
01792                 {
01793                     written = snprintf(p, bufsize, "%02X", pValue[i]);
01794                     bufsize -= written;
01795                     p+= written;
01796                 }
01797             }
01798         }
01799         else
01800         {
01801             written = snprintf(p, bufsize, "%s", "---unknown-epc-data-type---");
01802             bufsize -= written;
01803             p += written;
01804         }
01805     }
01806     else
01807     {
01808         written = snprintf(p, bufsize, "%s", "--null epc---");
01809         bufsize -= written;
01810         p += written;
01811     }
01812 
01813     // null terminate this for good practice
01814     buf[buflen-1] = '\0';
01815 
01816     return buflen - bufsize;
01817 }
01818 
01819 
01828 int 
01829 CMyApplication::getOnePhaseAngle(
01830       CImpinjRFPhaseAngle  *pRfPhase,
01831       double               *out)
01832 {
01833     if(NULL != pRfPhase)
01834     {
01835         llrp_u16_t phase = pRfPhase->getPhaseAngle();
01836         *out = ((double) phase  * 360)/4096;
01837         return 1;
01838     }
01839     return 0;
01840 }
01841 
01850 int
01851 CMyApplication::getOnePeakRSSI (
01852   CImpinjPeakRSSI      *pPeakRSSI,
01853   double               *out)
01854 {
01855     if(NULL != pPeakRSSI)
01856     {
01857         llrp_s16_t rssival = pPeakRSSI->getRSSI();
01858         *out = ((double) rssival / 100);
01859         return 1;
01860     }
01861     return 0;
01862 }
01863 
01872 int
01873 CMyApplication::getOneTimestamp (
01874   CParameter           *pTimestamp,
01875   unsigned long long    *out)
01876 {
01877     llrp_u64_t ttime;
01878 
01879     if(NULL == pTimestamp)
01880     {
01881         return 0;
01882     }
01883 
01884     if(&CFirstSeenTimestampUTC::s_typeDescriptor == pTimestamp->m_pType)
01885     {
01886         CFirstSeenTimestampUTC *pftutc = (CFirstSeenTimestampUTC*) pTimestamp;
01887         ttime = pftutc->getMicroseconds();
01888     } else if (&CFirstSeenTimestampUptime::s_typeDescriptor == pTimestamp->m_pType)
01889     {
01890         CFirstSeenTimestampUptime *pftup = (CFirstSeenTimestampUptime*) pTimestamp;
01891         ttime = pftup->getMicroseconds();
01892     } else if(&CLastSeenTimestampUTC::s_typeDescriptor == pTimestamp->m_pType)
01893     {
01894         CLastSeenTimestampUTC *pltutc = (CLastSeenTimestampUTC*) pTimestamp;
01895         ttime = pltutc->getMicroseconds();
01896     } else if (&CLastSeenTimestampUTC::s_typeDescriptor == pTimestamp->m_pType)
01897     {
01898         CLastSeenTimestampUptime *pltup = (CLastSeenTimestampUptime*) pTimestamp;
01899         ttime = pltup->getMicroseconds();
01900     } 
01901 
01902     *out = ttime;
01903     return 1;
01904 }
01905 
01914 int
01915 CMyApplication::getOneAntenna (
01916   CAntennaID           *pAntenna,
01917   unsigned short       *out)
01918 {
01919     if(NULL != pAntenna)
01920     {
01921         *out = pAntenna->getAntennaID();
01922         return 1;
01923     }
01924     return 0;
01925 }
01926 
01935 int
01936 CMyApplication::getOneChannelIndex (
01937   CChannelIndex        *pChannelIndex,
01938   unsigned short       *out)
01939 {
01940     if(NULL != pChannelIndex)
01941     {
01942 
01943         *out = pChannelIndex->getChannelIndex();
01944         return 1;
01945     }
01946     return 0;
01947 }
01948 
01957 int 
01958 CMyApplication::estimateVelocity(
01959       char *                epcStr,                                     
01960       double                rssi, 
01961       double                phase, 
01962       unsigned short        channelIndex, 
01963       unsigned short        antenna, 
01964       unsigned long long    time, 
01965       double                *outVelocity)
01966     {
01967         int retVal = 0;
01968         static char lastEpcStr[128];
01969         static double lastrssi = 0;
01970         static double lastphase = 0;
01971         static unsigned short lastchannelindex = 0;
01972         static unsigned short lastantenna = 0;
01973         static unsigned long long lasttime = 0;
01974 
01975         /* only collect a velocity sample if we have 
01976         ** been on the same EPC, antenna and channel. It's best
01977         ** to run this example with only one EPC */
01978         if((0 == strcmp(epcStr, lastEpcStr)) &&
01979            (lastantenna == antenna) &&
01980            (lastchannelindex == channelIndex))
01981         {
01982             /* positive velocity is moving towards the antenna */
01983             double phaseChangeDegrees = (phase - lastphase);
01984             double timeChangeUsec = (double) (time - lasttime);
01985 
01986             /* always wrap the phase to between -180 and 180 */
01987             while( phaseChangeDegrees < -180)
01988                 phaseChangeDegrees += 360;
01989             while( phaseChangeDegrees > 180)
01990                 phaseChangeDegrees -= 360;
01991 
01992             /* if our phase changes close to 180 degrees, you can see we
01993             ** have an ambiguity of whether the phase advanced or retarded by
01994             ** 180 degrees (or slightly over). There is no way to tell unless 
01995             ** you use more advanced techiques with multiple channels.  So just 
01996             ** ignore any samples where phase change is > 90 */
01997 
01998             if( abs((int) phaseChangeDegrees) <= 90)
01999             {
02000                /* We can divide these two to get degrees/usec, but it would be more
02001                ** convenient to have this in a common unit like meters/second.  
02002                ** Here's a straightforward conversion.  NOTE: to be exact here, we 
02003                ** should use the channel index to find the channel frequency/wavelength.  
02004                ** For now, I'll just assume the wavelength corresponds to mid-band at 
02005                ** 0.32786885245901635 meters. The formula below eports meters per second. 
02006                ** Note that 360 degrees equals only 1/2 a wavelength of motion because 
02007                ** we are computing the round trip phase change.
02008                **
02009                **  phaseChange (degrees)   1/2 wavelength     0.327 meter      1000000 usec 
02010                **  --------------------- * -------------- * ---------------- * ------------ 
02011                **  timeChange (usec)       360 degrees       1  wavelength      1 second   
02012                **
02013                ** which should net out to estimated tag velocity in meters/second */
02014 
02015                *outVelocity = ((phaseChangeDegrees * 0.5 * 0.327868852 * 1000000)/(360 * timeChangeUsec ));
02016 
02017                retVal = 1;
02018             }
02019         }
02020 
02021         /* record these for next time */
02022         strcpy(lastEpcStr, epcStr);
02023         lastrssi = rssi;
02024         lastphase = phase;
02025         lastchannelindex = channelIndex;
02026         lastantenna = antenna;
02027         lasttime = time;
02028 
02029         return retVal;
02030     }
02031 
02040 void
02041 CMyApplication::printOneTagReportData (
02042   CTagReportData *              pTagReportData)
02043 {
02044     char                        epcBuf[128];
02045     char                        aBuf[128];
02046     char                        *ptr = aBuf;
02047     int                         len = 128;
02048     int                         written;
02049     unsigned long long          time;
02050     unsigned short              antenna, channelIndex;
02051     double                      rssi, phase, velocityInst;
02052 
02053     /* this is static to keep a moving average of velocity */
02054     static double               velocity = 0;
02055     std::list<CParameter *>::iterator Cur;
02056     /*
02057      * Print the EPC. It could be an 96-bit EPC_96 parameter
02058      * or an variable length EPCData parameter.
02059      */
02060 
02061     CParameter *                pEPCParameter =
02062                                     pTagReportData->getEPCParameter();
02063 
02064     /* save a copy of the EPC */
02065     memset(epcBuf, 0x00, sizeof(epcBuf));
02066     formatOneEPC(pEPCParameter, epcBuf, 128, "");
02067 
02068     written = snprintf(ptr, len, " epc=%s", epcBuf);
02069     ptr += written;
02070     len -= written;
02071 
02072     if(getOneTimestamp(pTagReportData->getFirstSeenTimestampUTC(), &time))
02073     {
02074     written = snprintf(ptr, len, " tm=%010u", time);
02075     ptr += written;
02076     len -= written;
02077     }
02078 
02079     if(getOneChannelIndex(pTagReportData->getChannelIndex(), &channelIndex))
02080     {
02081         written = snprintf(ptr, len, " idx=%02u", channelIndex);
02082         ptr += written;
02083         len -= written;
02084     }
02085 
02086     if(getOneAntenna(pTagReportData->getAntennaID(), &antenna))
02087     {
02088         written = snprintf(ptr, len, " ant=%01u", antenna);
02089         ptr += written;
02090         len -= written;
02091     }
02092 
02093     for(
02094         Cur = pTagReportData->beginCustom();
02095         Cur != pTagReportData->endCustom();
02096         Cur++)
02097     {
02098         /* look for our special Impinj Tag Report Data */
02099         if(&CImpinjRFPhaseAngle::s_typeDescriptor == (*Cur)->m_pType)
02100         {
02101             if(getOnePhaseAngle((CImpinjRFPhaseAngle*) *Cur, &phase))
02102             {
02103                 written = snprintf(ptr, len, " ph=%+04d", (int) phase);
02104                 ptr += written;
02105                 len -= written;
02106             }
02107         } else if (&CImpinjPeakRSSI::s_typeDescriptor == (*Cur)->m_pType)
02108         {
02109             if (getOnePeakRSSI((CImpinjPeakRSSI*) *Cur, &rssi))
02110             {
02111                 written = snprintf(ptr, len, " rs=%+3.2f", rssi);
02112                 ptr += written;
02113                 len -= written;
02114             }
02115         }
02116     }
02117 
02118     /* Pauls Test code for looking at low level data */
02119 
02120     if(estimateVelocity(&epcBuf[0], rssi, phase, channelIndex, antenna, time, &velocityInst))
02121     {
02122         /* keep a filtered value. Use a 1 pole IIR here for simplicity */
02123         velocity = (6*velocity + 4*velocityInst)/10.0;
02124 
02125         char *str = "  -  ";
02126         if (velocity > 0.25)
02127             str =   "---->";
02128         if (velocity < -0.25)
02129             str =   "<----";
02130         
02131         written =snprintf(ptr, len, " vel=%+2.2f filt=%+2.2f %s", 
02132             velocityInst, velocity, str);
02133         ptr += written;
02134         len -= written;
02135 
02136         /*
02137          * Only print if we have a velocity estimate
02138          */
02139         printf("%s\n", aBuf);
02140     }
02141 }
02142 
02143 
02157 void
02158 CMyApplication::handleReaderEventNotification (
02159   CReaderEventNotificationData *pNtfData)
02160 {
02161     CAntennaEvent *             pAntennaEvent;
02162     CReaderExceptionEvent *     pReaderExceptionEvent;
02163     int                         nReported = 0;
02164 
02165     pAntennaEvent = pNtfData->getAntennaEvent();
02166     if(NULL != pAntennaEvent)
02167     {
02168         handleAntennaEvent(pAntennaEvent);
02169         nReported++;
02170     }
02171 
02172     pReaderExceptionEvent = pNtfData->getReaderExceptionEvent();
02173     if(NULL != pReaderExceptionEvent)
02174     {
02175         handleReaderExceptionEvent(pReaderExceptionEvent);
02176         nReported++;
02177     }
02178 
02179     /*
02180      * Similarly handle other events here:
02181      *      HoppingEvent
02182      *      GPIEvent
02183      *      ROSpecEvent
02184      *      ReportBufferLevelWarningEvent
02185      *      ReportBufferOverflowErrorEvent
02186      *      RFSurveyEvent
02187      *      AISpecEvent
02188      *      ConnectionAttemptEvent
02189      *      ConnectionCloseEvent
02190      *      Custom
02191      */
02192 
02193     if(0 == nReported)
02194     {
02195         printf("NOTICE: Unexpected (unhandled) ReaderEvent\n");
02196     }
02197 }
02198 
02199 
02211 void
02212 CMyApplication::handleAntennaEvent (
02213   CAntennaEvent *               pAntennaEvent)
02214 {
02215     EAntennaEventType           eEventType;
02216     llrp_u16_t                  AntennaID;
02217     char *                      pStateStr;
02218 
02219     eEventType = pAntennaEvent->getEventType();
02220     AntennaID = pAntennaEvent->getAntennaID();
02221 
02222     switch(eEventType)
02223     {
02224     case AntennaEventType_Antenna_Disconnected:
02225         pStateStr = "disconnected";
02226         break;
02227 
02228     case AntennaEventType_Antenna_Connected:
02229         pStateStr = "connected";
02230         break;
02231 
02232     default:
02233         pStateStr = "?unknown-event?";
02234         break;
02235     }
02236 
02237     printf("NOTICE: Antenna %d is %s\n", AntennaID, pStateStr);
02238 }
02239 
02240 
02253 void
02254 CMyApplication::handleReaderExceptionEvent (
02255   CReaderExceptionEvent *       pReaderExceptionEvent)
02256 {
02257     llrp_utf8v_t                Message;
02258 
02259     Message = pReaderExceptionEvent->getMessage();
02260 
02261     if(0 < Message.m_nValue && NULL != Message.m_pValue)
02262     {
02263         printf("NOTICE: ReaderException '%.*s'\n",
02264              Message.m_nValue, Message.m_pValue);
02265     }
02266     else
02267     {
02268         printf("NOTICE: ReaderException but no message\n");
02269     }
02270 }
02271 
02272 
02291 int
02292 CMyApplication::checkLLRPStatus (
02293   CLLRPStatus *                 pLLRPStatus,
02294   char *                        pWhatStr)
02295 {
02296     /*
02297      * The LLRPStatus parameter is mandatory in all responses.
02298      * If it is missing there should have been a decode error.
02299      * This just makes sure (remember, this program is a
02300      * diagnostic and suppose to catch LTKC mistakes).
02301      */
02302     if(NULL == pLLRPStatus)
02303     {
02304         printf("ERROR: %s missing LLRP status\n", pWhatStr);
02305         return -1;
02306 
02307     }
02308 
02309     /*
02310      * Make sure the status is M_Success.
02311      * If it isn't, print the error string if one.
02312      * This does not try to pretty-print the status
02313      * code. To get that, run this program with -vv
02314      * and examine the XML output.
02315      */
02316     if(StatusCode_M_Success != pLLRPStatus->getStatusCode())
02317     {
02318         llrp_utf8v_t            ErrorDesc;
02319 
02320         ErrorDesc = pLLRPStatus->getErrorDescription();
02321 
02322         if(0 == ErrorDesc.m_nValue)
02323         {
02324             printf("ERROR: %s failed, no error description given\n",
02325                 pWhatStr);
02326         }
02327         else
02328         {
02329             printf("ERROR: %s failed, %.*s\n",
02330                 pWhatStr, ErrorDesc.m_nValue, ErrorDesc.m_pValue);
02331         }
02332         return -2;
02333     }
02334 
02335     /*
02336      * Victory. Everything is fine.
02337      */
02338     return 0;
02339 }
02340 
02341 
02365 CMessage *
02366 CMyApplication::transact (
02367   CMessage *                    pSendMsg)
02368 {
02369     CConnection *               pConn = m_pConnectionToReader;
02370     CMessage *                  pRspMsg;
02371 
02372     /*
02373      * Print the XML text for the outbound message if
02374      * verbosity is 2 or higher.
02375      */
02376     if(1 < m_Verbose)
02377     {
02378         printf("\n===================================\n");
02379         printf("INFO: Transact sending\n");
02380         printXMLMessage(pSendMsg);
02381     }
02382 
02383     /*
02384      * Send the message, expect the response of certain type.
02385      * If LLRP::CConnection::transact() returns NULL then there was
02386      * an error. In that case we try to print the error details.
02387      */
02388     pRspMsg = pConn->transact(pSendMsg, 5000);
02389 
02390     if(NULL == pRspMsg)
02391     {
02392         const CErrorDetails *   pError = pConn->getTransactError();
02393 
02394         printf("ERROR: %s transact failed, %s\n",
02395             pSendMsg->m_pType->m_pName,
02396             pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given");
02397 
02398         if(NULL != pError->m_pRefType)
02399         {
02400             printf("ERROR: ... reference type %s\n",
02401                 pError->m_pRefType->m_pName);
02402         }
02403 
02404         if(NULL != pError->m_pRefField)
02405         {
02406             printf("ERROR: ... reference field %s\n",
02407                 pError->m_pRefField->m_pName);
02408         }
02409 
02410         return NULL;
02411     }
02412 
02413     /*
02414      * Print the XML text for the inbound message if
02415      * verbosity is 2 or higher.
02416      */
02417     if(1 < m_Verbose)
02418     {
02419         printf("\n- - - - - - - - - - - - - - - - - -\n");
02420         printf("INFO: Transact received response\n");
02421         printXMLMessage(pRspMsg);
02422     }
02423 
02424     /*
02425      * If it is an ERROR_MESSAGE (response from reader
02426      * when it can't understand the request), tattle
02427      * and declare defeat.
02428      */
02429     if(&CERROR_MESSAGE::s_typeDescriptor == pRspMsg->m_pType)
02430     {
02431         const CTypeDescriptor * pResponseType;
02432 
02433         pResponseType = pSendMsg->m_pType->m_pResponseType;
02434 
02435         printf("ERROR: Received ERROR_MESSAGE instead of %s\n",
02436             pResponseType->m_pName);
02437         delete pRspMsg;
02438         pRspMsg = NULL;
02439     }
02440 
02441     return pRspMsg;
02442 }
02443 
02444 
02469 CMessage *
02470 CMyApplication::recvMessage (
02471   int                           nMaxMS)
02472 {
02473     CConnection *               pConn = m_pConnectionToReader;
02474     CMessage *                  pMessage;
02475 
02476     /*
02477      * Receive the message subject to a time limit
02478      */
02479     pMessage = pConn->recvMessage(nMaxMS);
02480 
02481     /*
02482      * If LLRP::CConnection::recvMessage() returns NULL then there was
02483      * an error. In that case we try to print the error details.
02484      */
02485     if(NULL == pMessage)
02486     {
02487         const CErrorDetails *   pError = pConn->getRecvError();
02488 
02489         /* don't warn on timeout since this is a polling example */
02490         if(pError->m_eResultCode != RC_RecvTimeout)
02491         {
02492         printf("ERROR: recvMessage failed, %s\n",
02493             pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given");
02494         }
02495 
02496         if(NULL != pError->m_pRefType)
02497         {
02498             printf("ERROR: ... reference type %s\n",
02499                 pError->m_pRefType->m_pName);
02500         }
02501 
02502         if(NULL != pError->m_pRefField)
02503         {
02504             printf("ERROR: ... reference field %s\n",
02505                 pError->m_pRefField->m_pName);
02506         }
02507 
02508         return NULL;
02509     }
02510 
02511     /*
02512      * Print the XML text for the inbound message if
02513      * verbosity is 2 or higher.
02514      */
02515     if(1 < m_Verbose)
02516     {
02517         printf("\n===================================\n");
02518         printf("INFO: Message received\n");
02519         printXMLMessage(pMessage);
02520     }
02521 
02522     return pMessage;
02523 }
02524 
02525 
02543 int
02544 CMyApplication::sendMessage (
02545   CMessage *                    pSendMsg)
02546 {
02547     CConnection *               pConn = m_pConnectionToReader;
02548 
02549     /*
02550      * Print the XML text for the outbound message if
02551      * verbosity is 2 or higher.
02552      */
02553     if(1 < m_Verbose)
02554     {
02555         printf("\n===================================\n");
02556         printf("INFO: Sending\n");
02557         printXMLMessage(pSendMsg);
02558     }
02559 
02560     /*
02561      * If LLRP::CConnection::sendMessage() returns other than RC_OK
02562      * then there was an error. In that case we try to print
02563      * the error details.
02564      */
02565     if(RC_OK != pConn->sendMessage(pSendMsg))
02566     {
02567         const CErrorDetails *   pError = pConn->getSendError();
02568 
02569         printf("ERROR: %s sendMessage failed, %s\n",
02570             pSendMsg->m_pType->m_pName,
02571             pError->m_pWhatStr ? pError->m_pWhatStr : "no reason given");
02572 
02573         if(NULL != pError->m_pRefType)
02574         {
02575             printf("ERROR: ... reference type %s\n",
02576                 pError->m_pRefType->m_pName);
02577         }
02578 
02579         if(NULL != pError->m_pRefField)
02580         {
02581             printf("ERROR: ... reference field %s\n",
02582                 pError->m_pRefField->m_pName);
02583         }
02584 
02585         return -1;
02586     }
02587 
02588     /*
02589      * Victory
02590      */
02591     return 0;
02592 }
02593 
02594 
02608 void
02609 CMyApplication::printXMLMessage (
02610   CMessage *                    pMessage)
02611 {
02612     char                        aBuf[100*1024];
02613 
02614     /*
02615      * Convert the message to an XML string.
02616      * This fills the buffer with either the XML string
02617      * or an error message. The return value could
02618      * be checked.
02619      */
02620 
02621     pMessage->toXMLString(aBuf, sizeof aBuf);
02622 
02623     /*
02624      * Print the XML Text to the standard output.
02625      */
02626     printf("%s", aBuf);
02627 }