packages feed

mercury-api-0.1.0.0: cbits/api/tm_reader.h

/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
#ifndef _TM_READER_H
#define _TM_READER_H
/**
 *  @file tm_reader.h
 *  @brief Mercury API Reader Interface
 *  @author Brian Fiegel
 *  @date 4/18/2009
 */

 /*
 * Copyright (c) 2009 ThingMagic, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/* Due to incompatibilities between winsock.h and winsock2.h (plus interactions
 * with windows.h) you're in for a storm of "redefinition" errors if you don't
 * include winsock2.h first.
 * 
 * This is surprisingly hard, because lots of other headers include winsock.h
 * themselves.  So include winsock2.h as early as possible.
 */
#if defined(WIN32) || defined(WINCE)
#include <winsock2.h>
#endif

#include "tm_config.h"

/**
 * TMR_ENABLE_JNI_SERIAL_READER_ONLY is used for building JNI project, and is defined from
 * Makefile.jni
 **/
#if !defined(TMR_ENABLE_SERIAL_READER_ONLY) && !defined(TMR_ENABLE_JNI_SERIAL_READER_ONLY)  && defined(TMR_ENABLE_LLRP_TRANSPORT)
#define TMR_ENABLE_LLRP_READER
#endif

#ifdef TMR_ENABLE_BACKGROUND_READS
#include <pthread.h>
#include <semaphore.h>
#endif

typedef struct TMR_Reader TMR_Reader;

#include "tmr_types.h"
#include "tmr_status.h"

#include "tmr_gpio.h"
#include "tmr_params.h"
#include "tmr_read_plan.h"
#include "tmr_tag_auth.h"
#include "tmr_tag_data.h"
#include "tmr_tag_lock_action.h"
#include "tmr_tag_protocol.h"
#include "tmr_tagop.h"

#include "tmr_serial_reader.h"
#ifdef TMR_ENABLE_LLRP_READER
#include "tmr_llrp_reader.h"
#endif

#ifdef  __cplusplus
extern "C" {
#endif


#ifndef DOXYGEN_IGNORE
typedef TMR_Status (*TMR_TransportNativeInit)(TMR_SR_SerialTransport *transport, TMR_SR_SerialPortNativeContext *context,
    const char *device);

typedef struct TMR_readParams
{
#if defined(TMR_ENABLE_BACKGROUND_READS)|| defined(SINGLE_THREAD_ASYNC_READ)
  uint32_t asyncOnTime;
  uint32_t asyncOffTime;
#endif
  TMR_ReadPlan defaultReadPlan;
  TMR_ReadPlan *readPlan;
} TMR_readParams;

typedef struct TMR_tagOpParams
{
  uint8_t antenna;
  TMR_TagProtocol protocol;
}TMR_tagOpParams;

typedef enum TMR_ReaderType
{
  TMR_READER_TYPE_INVALID,
  TMR_READER_TYPE_RQL,
  TMR_READER_TYPE_SERIAL,
  TMR_READER_TYPE_LLRP,
} TMR_ReaderType;

typedef enum TMR_ReadState
{
  TMR_READ_STATE_IDLE,
  TMR_READ_STATE_STARTING,
  TMR_READ_STATE_STARTED,
  TMR_READ_STATE_ACTIVE,
  TMR_READ_STATE_DONE,
} TMR_ReadState;


#endif /* DOXYGEN_IGNORE */

/**
 *  Reader Stats Flag Enum
 */
typedef enum TMR_Reader_StatsFlag
{
  TMR_READER_STATS_FLAG_NONE = 0x00,
	/** Total time the port has been transmitting, in milliseconds. Resettable */
  TMR_READER_STATS_FLAG_RF_ON_TIME = (1 << 0),
  /** Noise floor with the TX on for the antennas were last configured for searching */
  TMR_READER_STATS_FLAG_NOISE_FLOOR_SEARCH_RX_TX_WITH_TX_ON = (1 << 6),
  /** Current frequency in units of Khz */
  TMR_READER_STATS_FLAG_FREQUENCY = (1 << 7),
  /** Current temperature of the device in units of Celsius */
  TMR_READER_STATS_FLAG_TEMPERATURE = (1 << 8),
  /** Current antenna */
  TMR_READER_STATS_FLAG_ANTENNA_PORTS = (1 << 9),
  /** Current protocol */ 
  TMR_READER_STATS_FLAG_PROTOCOL = (1 << 10),
  /** Current connected antennas */
  TMR_READER_STATS_FLAG_CONNECTED_ANTENNAS = (1 << 11),
  /* ALL */
  TMR_READER_STATS_FLAG_ALL = (TMR_READER_STATS_FLAG_RF_ON_TIME |
      TMR_READER_STATS_FLAG_NOISE_FLOOR_SEARCH_RX_TX_WITH_TX_ON |
      TMR_READER_STATS_FLAG_TEMPERATURE |
      TMR_READER_STATS_FLAG_PROTOCOL |
      TMR_READER_STATS_FLAG_ANTENNA_PORTS |
      TMR_READER_STATS_FLAG_FREQUENCY |
      TMR_READER_STATS_FLAG_CONNECTED_ANTENNAS),
}TMR_Reader_StatsFlag;

/**
 * Per Antenna stats
 */
typedef struct TMR_StatsPerAntennaValues
{
	/** Antenna number */
	uint8_t antenna;
	/** Current RF on time (since start of search) (milliseconds) */
	uint32_t rfOnTime;
	/** Noise Floor (TX on, all connected antennas) (dBm) */
	int8_t noiseFloor;
} TMR_StatsPerAntennaValues;

/**
 * Object to hold the per antenna stats
 */
typedef struct TMR_StatsPerAntennaValuesList
{
	TMR_StatsPerAntennaValues *list;
	uint16_t max;
	uint16_t len;
} TMR_StatsPerAntennaValuesList;

/**
 * This object is returned from TMR_cmdGetReaderStats
 */
typedef struct TMR_Reader_StatsValues
{
	TMR_Reader_StatsFlag valid;
	/** Current temperature (degrees C) */
	int8_t temperature;
	/** Current tag protocol */
	TMR_TagProtocol protocol;
	/** Current antenna */
	uint16_t antenna;
	/** Current RF carrier frequency (KHZ) */
	uint32_t frequency;
	/** Current connected antennas */
	TMR_uint8List connectedAntennas;
	uint8_t _connectedAntennasStorage[TMR_SR_MAX_ANTENNA_PORTS];
	/** Per-antenna values */
	TMR_StatsPerAntennaValuesList perAntenna;
	TMR_StatsPerAntennaValues _perAntStorage[TMR_SR_MAX_ANTENNA_PORTS];
}TMR_Reader_StatsValues;

/** Type of functions to be registered as read callbacks */
typedef void (*TMR_ReadListener)(TMR_Reader *reader, const TMR_TagReadData *t,
                                 void *cookie);
/**
 * User-allocated structure containing the callback pointer and the
 * value to pass to that callback.
 */
typedef struct TMR_ReadListenerBlock
{
  /** Pointer to callback function */
  TMR_ReadListener listener;
  /** Value to pass to callback function */
  void *cookie;
  /** @private */
  struct TMR_ReadListenerBlock *next;
} TMR_ReadListenerBlock;

/** Type of functions to be registered as tagauth request callbacks 
 * @param reader  Reader object
 * @param trd  TagReadData object
 * @param cookie  Arbitrary data structure to be passed to callback
 * @param auth  [OUTPUT] Tag authentication value to initialize based on inputs
 */
typedef void (*TMR_AuthReqListener)(TMR_Reader *reader, const TMR_TagReadData *trd,
									void *cookie, TMR_TagAuthentication *auth);
/**
 * User-allocated structure containing the callback pointer and the
 * value to pass to that callback.
 */
typedef struct TMR_AuthReqListenerBlock
{
  /** Pointer to callback function */
  TMR_AuthReqListener listener;
  /** Value to pass to callback function */
  void *cookie;
  /** @private */
  struct TMR_AuthReqListenerBlock *next;
} TMR_AuthReqListenerBlock;

/** Type of functions to be registered as read error callbacks */
typedef void (*TMR_ReadExceptionListener)(TMR_Reader *reader, TMR_Status error, void *cookie);
/**
 * User-allocated structure containing the callback pointer and the
 * value to pass to that callback.
 */
typedef struct TMR_ReadExceptionListenerBlock
{
  /** Pointer to callback function */
  TMR_ReadExceptionListener listener;
  /** Value to pass to callback function */
  void *cookie;
  /** @private */
  struct TMR_ReadExceptionListenerBlock *next;
} TMR_ReadExceptionListenerBlock;

/** Type of functions to be registered as transport callbacks */
typedef void (*TMR_TransportListener) (bool tx, uint32_t dataLen,
                                       const uint8_t data[], uint32_t timeout,
                                       void *cookie);
/**
 * User-allocated structure containing the callback pointer and the
 * value to pass to that callback.
 */
typedef struct TMR_TransportListenerBlock
{
  /** Pointer to callback function */
  TMR_TransportListener listener;
  /** Value to pass to callback function */
  void *cookie;
  /** @private */
  struct TMR_TransportListenerBlock *next;
} TMR_TransportListenerBlock;

/** Type of functions to be registered as Status read callbacks */
typedef void (*TMR_StatsListener)(TMR_Reader *reader, const TMR_Reader_StatsValues* value,
                                void *cookie);
typedef void (*TMR_StatusListener)(TMR_Reader *reader, const TMR_SR_StatusReport report[],
                                 void *cookie);
/**
 * User-allocated structure containing the callback pointer and the
 * value to pass to that callback.
 */
typedef struct TMR_StatsListenerBlock
{
  /** Pointer to callback function */
  TMR_StatsListener listener;
  /** Value to pass to callback function */
  void *cookie;
  /** @private */
  struct TMR_StatsListenerBlock *next;
} TMR_StatsListenerBlock;

/**
 * User-allocated structure containing the callback pointer and the
 * value to pass to that callback.
 */
typedef struct TMR_StatusListenerBlock
{
  /** Pointer to callback function */
  TMR_StatusListener listener;
  /** Value to pass to callback function */
  void *cookie;
  /** @private */
  struct TMR_StatusListenerBlock *next;
} TMR_StatusListenerBlock;

/**
 * Private: should not be used by user level application.
 */
typedef struct TMR_Queue_tagReads
{
  union
  {
    /* Buffer to hold serial message response */
    uint8_t *sMsg;
#ifdef TMR_ENABLE_LLRP_READER
    /* Buffer to hold LLRP message response */
    LLRP_tSMessage *lMsg;
#endif
  } tagEntry;

  uint8_t bufPointer;
  /* Object to hold tag results */
  TMR_TagReadData trd;
  bool isStatusResponse;
  struct TMR_Queue_tagReads  *next;
}TMR_Queue_tagReads;

typedef TMR_SR_GEN2_QType TMR_GEN2_QType;
typedef TMR_SR_GEN2_QStatic TMR_GEN2_QStatic;
typedef TMR_SR_GEN2_Q TMR_GEN2_Q;

/**
 * @defgroup reader Reader
 *
 * TMR_Reader encapsulates a connection to a ThingMagic RFID reader
 * device and provides an interface to perform RFID operations such as
 * reading tags and writing tag IDs.  
 *
 * Reads can be done on demand, with the TMR_read() function, or
 * continuously in the background with the TMR_startReading()
 * function.  Background reads notify registered listeners of tags
 * that are read.
 *
 * Operations which take an argument for a tag to operate on may
 * optionally be passed a @c NULL argument. This lets the reader choose
 * what tag to use, but may not work if multiple tags are
 * present. This use is recommended only when exactly one tag is known
 * to be in range.
 */

/**
 * @ingroup reader
 * @struct TMR_Reader
 * 
 * The structure that represents a RFID reader. The user should
 * allocate a TMR_Reader structure and initialize it with
 * TMR_create().
 */
struct TMR_Reader
{
  /** @privatesection */

  enum TMR_ReaderType readerType;
  bool connected;
  TMR_TransportListenerBlock *transportListeners;

  TMR_readParams readParams;
  TMR_tagOpParams tagOpParams;
  char uri[TMR_MAX_READER_NAME_LENGTH];
  
  bool continuousReading;
  bool trueAsyncflag;
  bool searchStatus;
  /* Statistics response indicator */
  bool isStatusResponse;
  /* Option for Fast Search */
  bool fastSearch;
  /* Option for Trigger Read */
  bool triggerRead;
  /* Option for Duty cycle*/
  bool dutyCycle;
  /* Option for stop N tag trigger */
  bool isStopNTags;
  /* Param wait indicator for Reader and protocol param control during continuous read */
  bool paramWait;
  /* Param response for Reader and protocol param control during continuous read */
  uint8_t paramMessage[256];
  /* True Continuous Read Start indicator */
  bool hasContinuousReadStarted;
  /* Total tag count for sto N trigger */
  uint32_t numberOfTagsToRead;
  /* Does ResetStats feature work on this reader?
   * Unknown: NULL == pSupportsResetStats
   * Yes: (NULL != pSupportsResetStats) && (true == *pSupportsResetStats)
   * No: (NULL != pSupportsResetStats) && (false == *pSupportsResetStats)
   */
  bool* pSupportsResetStats/* = NULL*/;
  bool _storeSupportsResetStats;
  /* the option to request for background thread cancel */
  bool backgroundThreadCancel;

  union
  {
    TMR_SR_SerialReader serialReader;
    /*
     *TMR_RQL_RqlReader rqlReader;
     */
#ifdef TMR_ENABLE_LLRP_READER
    TMR_LLRP_LlrpReader llrpReader;
#endif
  }u;

#ifdef TMR_ENABLE_BACKGROUND_READS
  bool backgroundSetup, backgroundEnabled, backgroundRunning;
  bool parserSetup, parserEnabled, parserRunning;
#endif
  bool finishedReading;
#ifdef TMR_ENABLE_BACKGROUND_READS
  enum TMR_ReadState readState;
  unsigned int queue_depth;
  sem_t queue_slots, queue_length;
  pthread_mutex_t queue_lock;
  pthread_mutex_t backgroundLock;
  pthread_mutex_t parserLock;
  pthread_mutex_t listenerLock;  
  pthread_cond_t backgroundCond;
  pthread_cond_t parserCond;
  pthread_cond_t readCond;
  pthread_t backgroundReader;
  pthread_t backgroundParser;
  pthread_t autonomousBackgroundReader;
  TMR_AuthReqListenerBlock *authReqListeners;
#endif
  TMR_ReadListenerBlock *readListeners;
  TMR_ReadExceptionListenerBlock *readExceptionListeners;
  TMR_StatsListenerBlock *statsListeners;
#ifdef TMR_ENABLE_BACKGROUND_READS
  TMR_StatusListenerBlock *statusListeners;
  TMR_Queue_tagReads *tagQueueTail;
  TMR_Queue_tagReads *tagQueueHead;
#endif
  TMR_Reader_StatsFlag statsFlag;
  TMR_SR_StatusType streamStats;
  TMR_TRD_MetadataFlag userMetadataFlag;
  uint8_t portmask;


  /* Level 1 */
#ifndef TMR_ENABLE_SERIAL_READER_ONLY
  TMR_Status (*connect)(struct TMR_Reader *reader);
  TMR_Status (*destroy)(struct TMR_Reader *reader);
  TMR_Status (*read)(struct TMR_Reader *reader, uint32_t timeoutMs, int32_t *tagCount);
  TMR_Status (*hasMoreTags)(struct TMR_Reader *reader);
  TMR_Status (*getNextTag)(struct TMR_Reader *reader, TMR_TagReadData *read);
  TMR_Status (*writeTag)(struct TMR_Reader *reader, const TMR_TagFilter *filter, const TMR_TagData *data);
#endif /* TMR_ENABLE_SERIAL_READER_ONLY  */
  TMR_Status (*paramGet)(struct TMR_Reader *reader, TMR_Param key, void *value);
  TMR_Status (*paramSet)(struct TMR_Reader *reader, TMR_Param key, const void *value);
  
  /* Level 2 */
#ifndef TMR_ENABLE_SERIAL_READER_ONLY
  TMR_Status (*killTag)(struct TMR_Reader *reader, const TMR_TagFilter *filter, const TMR_TagAuthentication *auth);
  TMR_Status (*lockTag)(struct TMR_Reader *reader, const TMR_TagFilter *filter, TMR_TagLockAction *action);
  TMR_Status (*executeTagOp)(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *filter, TMR_uint8List *data);
  TMR_Status (*readTagMemBytes)(struct TMR_Reader *reader, const TMR_TagFilter *filter, 
                               uint32_t bank, uint32_t address,
                               uint16_t count, uint8_t data[]);
  TMR_Status (*readTagMemWords)(struct TMR_Reader *reader, const TMR_TagFilter *filter,
                               uint32_t bank, uint32_t address,
                               uint16_t count, uint16_t *data);
  TMR_Status (*writeTagMemBytes)(struct TMR_Reader *reader, const TMR_TagFilter *filter,
                               uint32_t bank, uint32_t address,
                               uint16_t count, const uint8_t data[]);
  TMR_Status (*writeTagMemWords)(struct TMR_Reader *reader, const TMR_TagFilter *filter,
                               uint32_t bank, uint32_t address,
                               uint16_t count, const uint16_t data[]);
  TMR_Status (*gpoSet)(struct TMR_Reader *reader, uint8_t count, const TMR_GpioPin state[]);
  TMR_Status (*gpiGet)(struct TMR_Reader *reader, uint8_t *count, TMR_GpioPin state[]);
  TMR_Status (*firmwareLoad)(TMR_Reader *reader, void *cookie, TMR_FirmwareDataProvider provider);
  TMR_Status (*modifyFlash) (TMR_Reader *reader, uint8_t sector, uint32_t address, uint32_t password,
                             uint8_t length, const uint8_t data[], uint32_t offset);
  TMR_Status (*reboot) (TMR_Reader *reader);
#endif /* TMR_ENABLE_SERIAL_READER_ONLY  */

  /* Level 3 */
#ifdef TMR_ENABLE_BACKGROUND_READS
  TMR_Status (*cmdAutonomousReading)(struct TMR_Reader *reader, TMR_TagReadData *trd, TMR_Reader_StatsValues *stats);
#endif
  TMR_Status (*cmdStopReading)(struct TMR_Reader *reader);
};

/**
 * @ingroup reader
 * The TMR_Reader struct being initialized should be preallocated by
 * the user.  No memory is allocated during the initialization
 * process, and the reader is not contacted at this point.
 *
 * @param reader The TMR_Reader structure to initialize
 * @param deviceUri an identifier for the reader to connect to, with
 * a URI syntax. The scheme can be \c eapi for the embedded
 * module protocol, \c rql for the request query language, or
 * \c tmr to guess. The remainder of the URI identifies the
 * stream that the protocol will be spoken over, either a local host
 * serial port device or a TCP network port.
 * Example URIs are:
 *  - tmr://192.168.10.8/ - Reader at TCP/IP address 192.168.10.8, RQL assumed
 *  - rql://192.168.10.8/ - RQL reader at TCP/IP address 192.168.10.8
 *  - tmr:///dev/ttyS1    - reader on serial port /dev/ttyS1, EAPI (serial) assumed
 *  - eapi:///COM2        - EAPI (serial) reader on serial port COM2
 *  - llrp+eapi://192.168.10.8 - EAPI tunneled over LLRP to a reader at
 * TCP/IP address 192.168.10.8
 *
 * @test Call with valid URI should not fail.
 * @test Call with invalid URI should fail.
 */
TMR_Status TMR_create(TMR_Reader *reader, const char* deviceUri);

 /**
 * @ingroup reader
  *
  * This function is a version of TMR_create() that dynamically
  * allocates the TMR_Reader structure and stores the pointer in
  * *reader.
  * 
  * @param[out] readerPointer Pointer to the TMR_Reader* in which to place the
  * pointer to the newly allocated reader structure.
  @ @param deviceUri As described in TMR_create().
  *
  * @test Call with valid URI should not fail.
  * @test Call with invalid URI should fail.
  * @test Multiple calls with different URIs should return distinct objects.
  */
TMR_Status TMR_create_alloc(TMR_Reader **readerPointer, const char* deviceUri);


/**
 * @ingroup reader
 * Establishes the connection to the reader at the URI specified in
 * the TMR_create() call. The existence of a reader at the address is
 * verified and the reader is brought into a state appropriate for
 * performing RF operations.
 *
 * @param reader The reader to connect 
 *
 * 
 * @test Connecting to existing reader should succeed.
 * @test Connecting to nonexisting reader should fail.
 */
TMR_Status TMR_connect(struct TMR_Reader *reader);

/**
 * @ingroup reader
 * Closes the connection to the reader and releases any resources
 * that have been consumed by the reader structure.
 *
 * @param reader The reader to shut down.
 *
 * @test Destroying existing connected reader should succed.
 * @test Destroying existing unconnected reader should succeed.
 * @test Destroying already-destroyed reader should fail.
 * @test Destroying reader allocated by TMR_create_alloc() should
 * free the allocated memory.
 */
TMR_Status TMR_destroy(TMR_Reader *reader);

/**
 * @ingroup reader
 * Search for tags for a fixed duration. Once this returns, the tags
 * are retrieved by calling TMR_getNextTag() until TMR_hasMoreTags()
 * returns false.
 *
 * @param reader The reader being operated on
 * @param timeoutMs The number of milliseconds to search for tags
 * @param[out] tagCount The number of tags read, or -1 if the number
 * is unknown. If NULL, no value will be stored.
 *
 * @test Call should fail if reader is not connected.
 * @test If call is successful as per TMR_Error, *tagCount should be
 * modified and contain a positive value.
 */
TMR_Status TMR_read(TMR_Reader *reader, uint32_t timeoutMs, int32_t *tagCount);

/**
 * @ingroup reader
 * @retval TMR_SUCCESS if there are more tags to be retrieved from the most recent TMR_read() operation.
 * @retval TMR_ERROR_NO_TAGS if no more tags are available for retrieval.
 * @retval Other TMR_ERRORs when appropriate.
 *
 * @param reader The reader being operated on
 * 
 * @test Call should return false before a read() call.
 * @test Call should return false after a read() call that set
 * *tagCount to zero.
 * @test Call should return true after a read() call that set
 * *tagCount to a nonzero value.
 * @test Call should return true through exactly as many getNextTag()
 * calls as specified by *tagCount.
 */
TMR_Status TMR_hasMoreTags(TMR_Reader *reader);

/**
 * @ingroup reader
 * Fetches the next tag from the last TMR_read() operation.
 *
 * @param reader The reader being operated on
 * @param[out] tagData The TMR_TagReadData structure to fill.
 * 
 * @test Call should fail before a read() call.
 * @test Call should fail after a read() call that set *tagCount to
 * zero.
 * @test Call should fill in a tag after a read() call that set
 * *tagCount to a nonzero value.
 * @test Call should succeed exactly as many times as specified by
 * *tagCount.
 */
TMR_Status TMR_getNextTag(TMR_Reader *reader, TMR_TagReadData *tagData);

/**
 * @ingroup reader
 * This method provides the direct execution of TagOp commands
 * Reader operates on the first tag found, with applicable tag filtering
 * Reader stops and the call returns immediately after finding one tag
 * and operating on it, unless the command timeout expires first
 * The operation is performed on the antenna specified in
 * /reader/tagop/antenna parameter
 * /reader/tagop/protocol specifies the protocol to be used
 *
 * @param reader The reader being operated on
 * @param tagop Pointer to the TMR_TagOp which needs to be executed
 * @param filter Tag Filter to be used
 * @param[out] data Data returned as a result of tag operation
 */
TMR_Status TMR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *filter, TMR_uint8List *data);

/**
 * @ingroup reader
 * Wrapper routine that searches for tags, allocates space for the
 * results, and returns the results in a single array.
 * 
 * @param reader The reader being operated on
 * @param timeoutMs The number of milliseconds to search for tags
 * @param[out] tagCount The number of tags found and the size of the allocated array.
 * @param[out] result The array of tag read data.
 *
 * @test Call should fail if reader is not connected.
 * @test If call is successful as per TMR_Error, *tagCount should be
 * modified and contain a positive value, and *result should be
 * modified and contain the corresponding number of tag read values.
 *
 * Out param "result" should be freed after using it.
 */

TMR_Status TMR_readIntoArray(struct TMR_Reader *reader, uint32_t timeoutMs, int32_t *tagCount, TMR_TagReadData *result[]);

/**
 * @deprecated This method is deprecated 
 *
 * Write a new EPC to an existing tag.  
 * 
 * The @c /reader/tagop/antenna parameter controls which antenna will
 * be used for the write operation. The @c /reader/tagop/protocol
 * parameter controls which protocol will be used.
 * 
 * @param reader The reader being operated on
 * @param target The existing tag to write.
 * @param data The EPC to write to the tag
 * @note target is not supported on serial or Astra readers and only
 * TagData filters are supported on other fixed readers.
 *
 * @return TMR_ERROR_NO_TAG_FOUND if no tag matching the filter could be found.
 *
 * @test Call should fail if reader is not connected.
 * @test Upon success, a subsequent TMR_read() should find the new tag ID.
 */
TMR_Status TMR_writeTag(TMR_Reader *reader, const TMR_TagFilter *target, TMR_TagData *data);

/**
 * @deprecated This method is deprecated
 *
 * Sends a kill command to a tag.
 *
 * @param reader The reader being operated on.
 * @param target The tag to kill, or @c NULL to kill the first tag seen.
 * @param auth The authentication needed to kill the tag.
 *
 * @return TMR_ERROR_NO_TAG_FOUND if no tag matching the filter could be found.
 */
TMR_Status TMR_killTag(TMR_Reader *reader, TMR_TagFilter *target, TMR_TagAuthentication *auth);


/**
 * @deprecated This method is deprecated
 *
 * Sends a lock command to a tag.
 *
 * @param reader The reader being operated on.
 * @param target The tag to kill, or @c NULL to kill the first tag seen.
 * @param action The locking action to apply.
 *
 * @return TMR_ERROR_NO_TAG_FOUND if no tag matching the filter could be found.
 */
TMR_Status TMR_lockTag(TMR_Reader *reader, TMR_TagFilter *target, TMR_TagLockAction *action);


/**
 * @ingroup reader
 * Read 8-bit bytes from the memory bank of a tag.
 *
 * @param reader The reader being operated on.
 * @param target The tag to read from, or @c NULL.
 * @param bank The tag memory bank to read from.
 * @param byteAddress The byte address to start reading at.
 * @param byteCount The number of bytes to read
 * @param[out] data The read data.
 */
TMR_Status TMR_readTagMemBytes(TMR_Reader *reader, TMR_TagFilter *target, 
                               uint32_t bank, uint32_t byteAddress, 
                               uint16_t byteCount, uint8_t data[]);

/**
 * @ingroup reader
 * Read 16-bit words from the memory bank of a tag.
 *
 * @param reader The reader being operated on.
 * @param target The tag to read from, or @c NULL.
 * @param bank The tag memory bank to read from.
 * @param wordAddress The word address to start reading at.
 * @param wordCount The number of words to read
 * @param[out] data The read data.
 */
TMR_Status TMR_readTagMemWords(TMR_Reader *reader, TMR_TagFilter *target, 
                               uint32_t bank, uint32_t wordAddress, 
                               uint16_t wordCount, uint16_t data[]);

/**
 * @deprecated This method is deprecated
 *
 * Write 8-bit bytes to the memory bank of a tag. If the tag's
 * fundamental memory unit is larger than 8 bits, trying to write
 * sub-unit quantities will produce an error.
 *
 * @param reader The reader to operate on.
 * @param target The tag to write to, or @c NULL.
 * @param bank The tag memory bank to write to.
 * @param byteAddress The byte address to start writing to.
 * @param byteCount The number of bytes to write.
 * @param data The bytes to write.
 */
TMR_Status TMR_writeTagMemBytes(TMR_Reader *reader, TMR_TagFilter *target,
                                uint32_t bank, uint32_t byteAddress,
                                uint16_t byteCount, const uint8_t data[]);

/**
 * @deprecated This method is deprecated
 *
 * Write 16-bit words to the memory bank of a tag. If the tag's
 * fundamental memory unit is larger than 16 bits, trying to write
 * sub-unit quantities will produce an error.
 *
 * @param reader The reader to operate on.
 * @param target The tag to write to, or @c NULL.
 * @param bank The tag memory bank to write to.
 * @param wordAddress The word address to start writing to.
 * @param wordCount The number of words to write.
 * @param data The words to write.
 */
TMR_Status TMR_writeTagMemWords(TMR_Reader *reader, TMR_TagFilter *target,
                                uint32_t bank, uint32_t wordAddress,
                                uint16_t wordCount, const uint16_t data[]);


/**
 * @ingroup reader
 * Set the state of some GPO pins.
 *
 * @param reader The reader to operate on.
 * @param count The length of the state array.
 * @param state Array of reader pins and the state to set them to.
 */
TMR_Status TMR_gpoSet(TMR_Reader *reader, uint8_t count, const TMR_GpioPin state[]);

/**
 * @ingroup reader
 * Get the state of all GPI pins.
 *
 * @param reader The reader to operate on.
 * @param[in] count Pointer to the allocated length of the state array.
 * @param[out] count Pointer to the number of entries in the state array.
 * @param[out] state Array of reader pins and the state to set them to.
 */
TMR_Status TMR_gpiGet(TMR_Reader *reader, uint8_t *count, TMR_GpioPin state[]);

/**
 * @ingroup reader
 * The TMR_firmwareLoad() method attempts to install firmware on the
 * reader, then restart and reinitialize.
 * 
 * @param reader The reader to operate on
 * @param cookie Value to pass to the callback function.
 * @param provider Callback function to provide firmware data.
 */
TMR_Status TMR_firmwareLoad(TMR_Reader *reader, void *cookie, TMR_FirmwareDataProvider provider);

/**
 * Cookie for state storage of a TMR_memoryProvider.
 */
typedef struct TMR_memoryCookie {
  /** Pointer to the start of the firmware image in memory */
  uint8_t *firmwareStart;
  /** Size of the firmware image */
  uint32_t firmwareSize;
} TMR_memoryCookie;

/**
 * This function can be used as a callback to TMR_firmwareLoad when
 * the firmware image exists in system memory. The cookie is a pointer
 * to a TMR_memoryCookie that is initialized with the start of the firmware
 * image in memory and its size.
 *
 * @param cookie TMR_memoryCookie value.
 * @param[in] size The number of bytes requested.
 * @param[out] size The number of bytes returned.
 * @param data Pointer to buffer to fill.
 * @return true if there is more firmware data to return.
 */
bool TMR_memoryProvider(void *cookie, uint16_t *size, uint8_t *data);

/**
 * This function can be used as a callback to TMR_firmwareLoad when
 * the firmware image exists as a file. 
 *
 * @param cookie FILE * pointing to the file to read from.
 * @param[in] size The number of bytes requested.
 * @param[out] size The number of bytes returned.
 * @param data Pointer to buffer to fill.
 * @return true if there is more firmware data to return.
 */
bool TMR_fileProvider(void *cookie, uint16_t *size, uint8_t *data);

/**
 * @ingroup reader
 * Set the value of a reader parameter.
 * 
 * @param reader The reader to operate on.
 * @param key The string identifying the parameter.
 * @param value The new value to use for the parameter. The caller may
 * not alter the value after passing it to this function.
 *
 * @test Call should fail if key is an invalid parameter name.
 * @test Call should fail if key is valid but unsupported by connected reader.
 * @test Call should succeed if key matches parameter name, independent of case.
 */
TMR_Status TMR_paramSet(struct TMR_Reader *reader, TMR_Param key, const void *value);

/**
 * @ingroup reader
 * Get the value of a reader parameter.
 *
 * @param reader The reader to operate on.
 * @param key The string identifying the parameter.

 * @param[out] value Pointer to the parameter value. For list types
 * (including TMR_String), the caller must allocate the pointed-to
 * space and set the size of the allocated space in the max field, and
 * the function will write into that space and set the actual length
 * of the data. If the list or string is larger than will fit in the
 * pointed-to space, the length will be larger than the allocated
 * space - be careful iterating over the results if there is a chance
 * of not passing in a large enough structure.
 *
 * @test Call should fail if key is an invalid parameter name.
 * @test Call should fail if key is valid but unsupported by connected reader.
 * @test Call should succeed if key matches parameter name, independent of case.
 */
TMR_Status TMR_paramGet(struct TMR_Reader *reader, TMR_Param key, void *value);

/**
 * @ingroup reader
 * Reboot the reader
 *
 * @param reader The reader to operate on.
 **/ 
TMR_Status TMR_reboot(struct TMR_Reader *reader);

/**
 * Get a list of the parameters available
 *
 * Supported Parameters:
 * @li /reader/antenna/checkPort
 * @li /reader/antenna/connectedPortList
 * @li /reader/antenna/portList
 * @li /reader/antenna/portSwitchGpos
 * @li /reader/antenna/returnLoss
 * @li /reader/antenna/settlingTimeList
 * @li /reader/antenna/txRxMap
 * @li /reader/asyncofftime
 * @li /reader/baudRate
 * @li /reader/commandTimeout
 * @li /reader/currentTime
 * @li /reader/description
 * @li /reader/extendedEpc
 * @li /reader/gen2/BLF
 * @li /reader/gen2/accessPassword
 * @li /reader/gen2/bap
 * @li /reader/gen2/protocolExtension
 * @li /reader/gen2/q
 * @li /reader/gen2/session
 * @li /reader/gen2/tagEncoding
 * @li /reader/gen2/target
 * @li /reader/gen2/tari
 * @li /reader/gen2/writeEarlyExit
 * @li /reader/gen2/writeMode
 * @li /reader/gen2/writeReplyTimeout
 * @li /reader/gpio/inputList
 * @li /reader/gpio/outputList
 * @li /reader/hostname
 * @li /reader/iso180006b/BLF
 * @li /reader/iso180006b/delimiter
 * @li /reader/iso180006b/modulationDepth
 * @li /reader/licenseKey
 * @li /reader/licensedFeatures
 * @li /reader/metadataflags
 * @li /reader/powerMode
 * @li /reader/probeBaudRates
 * @li /reader/radio/enablePowerSave
 * @li /reader/radio/enableSJC
 * @li /reader/radio/portReadPowerList
 * @li /reader/radio/portWritePowerList
 * @li /reader/radio/powerMax
 * @li /reader/radio/powerMin
 * @li /reader/radio/readPower
 * @li /reader/radio/temperature
 * @li /reader/radio/writePower
 * @li /reader/read/asyncOffTime
 * @li /reader/read/asyncOnTime
 * @li /reader/read/plan
 * @li /reader/region/hopTable
 * @li /reader/region/hopTime
 * @li /reader/region/id
 * @li /reader/region/lbt/enable
 * @li /reader/region/supportedRegions
 * @li /reader/selectedProtocols
 * @li /reader/statistics
 * @li /reader/stats
 * @li /reader/stats/enable
 * @li /reader/status/antennaEnable
 * @li /reader/status/frequencyEnable
 * @li /reader/status/temperatureEnable
 * @li /reader/tagReadData/enableReadFilter
 * @li /reader/tagReadData/readFilterTimeout
 * @li /reader/tagReadData/recordHighestRssi
 * @li /reader/tagReadData/reportRssiInDbm
 * @li /reader/tagReadData/tagopFailures
 * @li /reader/tagReadData/tagopSuccesses
 * @li /reader/tagReadData/uniqueByAntenna
 * @li /reader/tagReadData/uniqueByData
 * @li /reader/tagReadData/uniqueByProtocol
 * @li /reader/tagop/antenna
 * @li /reader/tagop/protocol
 * @li /reader/transportTimeout
 * @li /reader/trigger/read/Gpi
 * @li /reader/uri
 * @li /reader/userConfig
 * @li /reader/userMode
 * @li /reader/version/hardware
 * @li /reader/version/model
 * @li /reader/version/productGroup
 * @li /reader/version/productGroupID
 * @li /reader/version/productID
 * @li /reader/version/serial
 * @li /reader/version/software
 * @li /reader/version/supportedProtocols
 *
 * @ingroup reader
 *
 * @param reader The reader to operate on.
 * @param[out] keys Pointer to the list of parameters. The caller must
 * allocate space for the parameters.
 * @param[in] len Pointer to the allocated length of the space pointed to by keys.
 * @param[out] len Pointer to the number of parameters supported by
 * the reader, which may be larger or smaller than the provided
 * array. If it is larger than the provided array, the list is
 * truncated.
 */
TMR_Status TMR_paramList(struct TMR_Reader *reader, TMR_Param *keys, uint32_t *len);
/**
 * @reader pointer to TMR_Reader
 * @key pointer to TMR_Param
 */ 
void TMR_paramProbe (struct TMR_Reader *reader, TMR_Param key);

/**
 * @ingroup reader
 * Return the string name corresponding to a TMR_Param value.
 * Only present if TMR_ENABLE_PARAM_STRINGS is set.
 *
 * @param key The parameter ID.
 * @return The corresponding string name.
 */
const char* TMR_paramName(TMR_Param key);

/**
 * @ingroup reader
 * Return the TMR_Param ID corresponding to a string name.
 * Only present if TMR_ENABLE_PARAM_STRINGS is set.
 *
 * @param name the parameter 
 * @return The TMR_Param value of the name, or TMR_PARAM_NONE if no such
 * parameter exists.
 */
TMR_Param TMR_paramID(const char *name);


/**
 * @ingroup reader
 * 
 * Add a listener to the list of functions that will be called for
 * each message sent to or received from the reader.
 *
 * @param reader The reader to operate on.
 * @param block A structure containing a pointer to the listener
 * function and a user-supplied cookie value to pass to the function
 * when called.
 */
TMR_Status TMR_addTransportListener(TMR_Reader *reader, TMR_TransportListenerBlock *block);


/**
 * @ingroup reader
 * 
 * Remove a listener from the list of functions that will be called
 * for each message sent to or received from the reader.
 *
 * @param reader The reader to operate on.
 * @param block A structure containing a pointer to the listener
 * function and a user-supplied cookie value to pass to the function
 * when called.
 */
TMR_Status TMR_removeTransportListener(TMR_Reader *reader, TMR_TransportListenerBlock *block);

/**
 * @ingroup reader
 * Add a listener to the list of functions that will be called for
 * each background tag read.
 *
 * @param reader The reader to operate on.
 * @param block A structure containing a pointer to the listener
 * function and a user-supplied cookie value to pass to the function
 * when called.
 */
TMR_Status TMR_addReadListener(struct TMR_Reader *reader,
                               TMR_ReadListenerBlock *block);

/**
 * @ingroup reader
 * Add a listener to the list of functions that will be called for
 * each background tag read.
 *
 * @param reader The reader to operate on.
 * @param block A structure containing a pointer to the listener
 * function and a user-supplied cookie value to pass to the function
 * when called.
 */
TMR_Status TMR_addAuthReqListener(struct TMR_Reader *reader,
                                  TMR_AuthReqListenerBlock *block);

/**
 * @ingroup reader
 * Remove a listener from the list of functions that will be called
 * for each background tag read.
 *
 * @param reader The reader to operate on.
 * @param block A structure containing a pointer to the listener
 * function and a user-supplied cookie value to pass to the function
 * when called.
 */
TMR_Status TMR_removeReadListener(struct TMR_Reader *reader,
                                  TMR_ReadListenerBlock *block);

/**
 * @ingroup reader
 * Add a listener to the list of functions that will be called for
 * each error that occurs during background tag reading.
 *
 * @param reader The reader to operate on.
 * @param block A structure containing a pointer to the listener
 * function and a user-supplied cookie value to pass to the function
 * when called.
 */
TMR_Status TMR_addReadExceptionListener(struct TMR_Reader *reader,
                                        TMR_ReadExceptionListenerBlock *block);

/**
 * @ingroup reader
 * Remove a listener from the list of functions that will be called
 * for each error that occurs during background tag reading.
 *
 * @param reader The reader to operate on.
 * @param block A structure containing a pointer to the listener
 * function and a user-supplied cookie value to pass to the function
 * when called.
 */
TMR_Status TMR_removeReadExceptionListener(struct TMR_Reader *reader,
                                           TMR_ReadExceptionListenerBlock *block);

/**
 * @ingroup reader
 * Add a listener to the list of functions that will be called for
 * each background status response.
 *
 * @param reader The reader to operate on.
 * @param block A structure containing a pointer to the listener
 * function and a user-supplied cookie value to pass to the function
 * when called.
 */
TMR_Status TMR_addStatusListener(struct TMR_Reader *reader,
                               TMR_StatusListenerBlock *block);

/**
 * @ingroup reader
 * Remove a listener from the list of functions that will be called
 * for each background status response.
 *
 * @param reader The reader to operate on.
 * @param block A structure containing a pointer to the listener
 * function and a user-supplied cookie value to pass to the function
 * when called.
 */
TMR_Status TMR_removeStatusListener(struct TMR_Reader *reader,
                                  TMR_StatusListenerBlock *block);


/**
 * @ingroup reader
 * Add a listener to the list of functions that will be called for
 * each background status response.
 *
 * @param reader The reader to operate on.
 * @param block A structure containing a pointer to the listener
 * function and a user-supplied cookie value to pass to the function
 * when called.
 */
TMR_Status TMR_addStatsListener(struct TMR_Reader *reader,
                               TMR_StatsListenerBlock *block);

/**
 * @ingroup reader
 * Remove a listener from the list of functions that will be called
 * for each background status response.
 *
 * @param reader The reader to operate on.
 * @param block A structure containing a pointer to the listener
 * function and a user-supplied cookie value to pass to the function
 * when called.
 */
TMR_Status TMR_removeStatsListener(struct TMR_Reader *reader,
                                  TMR_StatsListenerBlock *block);


/**
 * @ingroup reader
 * Start reading tags in the background. The tags found will be passed
 * to the registered read listeners, and any errors that occur during
 * reading will be passed to the registered exception
 * listeners. Reading will continue until stopReading() is called.
 * The read listeners will be called from a background thread.
 *
 * @param reader The reader to operate on.
 */

TMR_Status TMR_startReading(struct TMR_Reader *reader);
TMR_Status TMR_receiveAutonomousReading(struct TMR_Reader *reader, TMR_TagReadData *trd, TMR_Reader_StatsValues *stats);
/**
 * @ingroup reader
 * Stop reading tags in the background. This function will wait until
 * the reader has stopped.
 *
 * @param reader The reader to operate on.
 */
TMR_Status TMR_stopReading(struct TMR_Reader *reader);

/**
 * @ingroup reader
 * Stores the transport init function against the provided scheme.
 *
 * @param scheme the transport scheme name.
 * @param nativeInit reference to the init function.
 */ 
TMR_Status TMR_setSerialTransport(char* scheme, TMR_TransportNativeInit nativeInit);

/**
 * @ingroup reader
 * This function will convert the error codes into proper error messages.
 *
 * @param reader The reader which resulted in error
 * @param status The status code which is to be converted
 */
const char *TMR_strerr(TMR_Reader *reader, TMR_Status status);

/**
 * @ingroup reader
 * This function will initialize the
 * TMR_StatValues structure with the default values
 */
TMR_Status TMR_STATS_init(TMR_Reader_StatsValues *stats);

/**
 * @ingroup reader
 * This function loads the reader configuration parameters from file and applies to module.
 *
 * @param reader The reader to operate on.
 * @param filePath load reader configurations from filepath.
 */
TMR_Status TMR_loadConfig(struct TMR_Reader *reader, char *filePath);

/**
 * @ingroup reader
 * This function saves the current reader configuration parameters and its values to a file.
 *
 * @param reader The reader to operate on.
 * @param filePath  save reader configurations from filepath.
 */
TMR_Status TMR_saveConfig(struct TMR_Reader *reader, char *filePath);

#ifndef DOXYGEN_IGNORE

TMR_Status TMR_reader_init_internal(struct TMR_Reader *reader);
/*TMR_Status TMR_init_statusListenerBlock(TMR_StatusListenerBlock *slb, TMR_StatusListener listener,
                                        void *cookie, TMR_SR_StatusContentFlags statusFlags);*/
TMR_Status validateReadPlan(TMR_Reader *reader, TMR_ReadPlan *plan, TMR_AntennaMapList *txRxMap, uint32_t protocols);

void TMR__notifyTransportListeners(TMR_Reader *reader, bool tx, 
                                   uint32_t dataLen, uint8_t *data,
                                   int timeout);

void notify_exception_listeners(TMR_Reader *reader, TMR_Status status);
void cleanup_background_threads(TMR_Reader *reader);

#ifdef TMR_ENABLE_SERIAL_READER_ONLY

#define TMR_connect(reader) (TMR_SR_connect(reader))
#define TMR_destroy(reader) (TMR_SR_destroy(reader))
#define TMR_read(reader, timeoutMs, tagCount) (TMR_SR_read((reader),(timeoutMs),(tagCount)))
#define TMR_hasMoreTags(reader) (TMR_SR_hasMoreTags(reader))
#define TMR_getNextTag(reader, read) (TMR_SR_getNextTag((reader),(read)))
#define TMR_writeTag(reader, filter, data) (TMR_SR_writeTag((reader),(filter),(data)))
#define TMR_readTagMemWords(reader, target, bank, address, count, data) (TMR_SR_readTagMemWords((reader),(target),(bank),(address),(count),(data)))
#define TMR_readTagMemBytes(reader, target, bank, address, count, data) (TMR_SR_readTagMemBytes((reader),(target),(bank),(address),(count),(data)))
#define TMR_writeTagMemWords(reader, target, bank, address, count, data) (TMR_SR_writeTagMemWords((reader),(target),(bank),(address),(count),(data)))
#define TMR_writeTagMemBytes(reader, target, bank, address, count, data) (TMR_SR_writeTagMemBytes((reader),(target),(bank),(address),(count),(data)))
#define TMR_killTag(reader, filter, auth) (TMR_SR_killTag((reader),(filter),(auth)))
#define TMR_lockTag(reader, filter, action) (TMR_SR_lockTag((reader),(filter),(action)))
#define TMR_executeTagOp(reader, tagop, filter, data) (TMR_SR_executeTagOp((reader), (tagop), (filter), (data)))
#define TMR_gpoSet(reader, count, state) (TMR_SR_gpoSet((reader),(count),(state)))
#define TMR_gpiGet(reader, count, state) (TMR_SR_gpiGet((reader),(count),(state)))
#define TMR_firmwareLoad(reader, cookie, provider) (TMR_SR_firmwareLoad((reader),(cookie),(provider)))
#define TMR_reboot(reader) (TMR_SR_reboot((reader)))

#else
/** 
 * The fact that these functions are implemented via macros is an
 * implementation detail, not something for the public API
 * documentation.
 */
#define TMR_connect(reader) ((reader)->connect(reader))
#define TMR_destroy(reader) ((reader)->destroy(reader))
#define TMR_read(reader, timeoutMs, tagCount) ((reader)->read((reader),(timeoutMs),(tagCount)))
#define TMR_hasMoreTags(reader) ((reader)->hasMoreTags(reader))
#define TMR_getNextTag(reader, read) ((reader)->getNextTag((reader),(read)))
#define TMR_writeTag(reader, filter, data) ((reader)->writeTag((reader),(filter),(data)))
#define TMR_readTagMemWords(reader, target, bank, address, count, data) ((reader)->readTagMemWords((reader),(target),(bank),(address),(count),(data)))
#define TMR_readTagMemBytes(reader, target, bank, address, count, data) ((reader)->readTagMemBytes((reader),(target),(bank),(address),(count),(data)))
#define TMR_writeTagMemWords(reader, target, bank, address, count, data) ((reader)->writeTagMemWords((reader),(target),(bank),(address),(count),(data)))
#define TMR_writeTagMemBytes(reader, target, bank, address, count, data) ((reader)->writeTagMemBytes((reader),(target),(bank),(address),(count),(data)))
#define TMR_killTag(reader, filter, auth) ((reader)->killTag((reader),(filter),(auth)))
#define TMR_lockTag(reader, filter, action) ((reader)->lockTag((reader),(filter),(action)))
#define TMR_executeTagOp(reader, tagop, filter, data) ((reader)->executeTagOp((reader), (tagop), (filter), (data)))
#define TMR_gpoSet(reader, count, state) ((reader)->gpoSet((reader),(count),(state)))
#define TMR_gpiGet(reader, count, state) ((reader)->gpiGet((reader),(count),(state)))
#define TMR_firmwareLoad(reader, cookie, provider) ((reader)->firmwareLoad((reader),(cookie),(provider)))
#define TMR_modifyFlash(reader, sector, address, password, length, data, offset)  ((reader->modifyFlash((reader),(sector),(address),(password),(length),(data),(offset)))
#define TMR_reboot(reader) ((reader)->reboot(reader))
#endif /* TMR_ENABLE_SERIAL_READER_ONLY  */

#endif /* DOXYGEN_IGNORE */

#ifdef  __cplusplus
}
#endif

#endif /* _TM_READER_H_ */