diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,5 @@
+# Revision history for mercury-api
+
+## 0.1.0.0  -- 2017-06-05
+
+* First version. Released on an unsuspecting world.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,45 @@
+Copyright (c) 2017 Patrick Pelletier
+
+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.
+
+----------------------------------------------------------------------
+
+ThingMagic Mercury API Software License
+
+Copyright (c) 2009 - 2012 Trimble Navigation Limited
+
+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.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,55 @@
+Latest:
+[![Hackage](https://img.shields.io/hackage/v/hs-mercury-api.svg)](https://hackage.haskell.org/package/hs-mercury-api)
+Linux:
+[![Build Status](https://travis-ci.org/ppelleti/hs-mercury-api.svg?branch=master)](https://travis-ci.org/ppelleti/hs-mercury-api)
+Windows:
+[![Build status](https://ci.appveyor.com/api/projects/status/aywuy9y05ow8wja2/branch/master?svg=true)](https://ci.appveyor.com/project/ppelleti/hs-mercury-api/branch/master)
+
+This package is a Haskell binding to the [Mercury API][5] C API for
+[ThingMagic][6] RFID readers.  It is especially geared toward
+the [SparkFun Simultaneous RFID Reader][1], which uses ThingMagic's
+[M6e Nano][7] module, but it should work with other ThingMagic
+readers.  (Though currently, only support for serial readers is
+compiled in.)  Most of the function and type names are the same as
+their counterparts in the C API, with the `TMR_` prefix dropped.  For
+more in-depth, language-independent documentation of Mercury API, see
+[Mercury API Programmers Guide][2].
+
+This package includes a copy of the Mercury API C library, so no
+external libraries are necessary.  Several small bug fixes have been
+applied to the included version of the library.  (I have submitted
+these patches upstream, but I don't know if or when they will be
+included in the official version.)  If you need to upgrade to a newer
+version of Mercury API than the included one, see [UPGRADING.md][9].
+
+The Haskell binding doesn't support background reads.  I recommend
+that you just spawn a new Haskell thread and do foreground reads
+instead.
+
+Currently, only support for the serial reader is compiled in, but it
+probably wouldn't be too hard to enable LLRP support.  (I don't have
+any way to test LLRP, however, as the M6e Nano doesn't support it.)
+
+On Mac OS X, be sure to use the serial device that starts with
+`/dev/cu.`, not the serial device that starts with `/dev/tty.`.
+
+Only some parameters and some tagops are currently supported in the
+Haskell binding.  (There are a lot of them, and I only implemented the
+ones I needed.)  If you need support for additional parameters or
+tagops, please file an issue in GitHub and I will add them.
+
+Additional resources:
+
+* [RFID Basics][8]
+* [SparkFun Simultaneous RFID Reader hookup guide][3]
+* [ThingMagic manuals and firmware][4]
+
+[1]: https://www.sparkfun.com/products/14066
+[2]: http://www.thingmagic.com/images/Downloads/Docs/MercuryAPI_ProgrammerGuide_for_v1.27.3.pdf
+[3]: https://learn.sparkfun.com/tutorials/simultaneous-rfid-tag-reader-hookup-guide
+[4]: http://www.thingmagic.com/index.php/manuals-firmware
+[5]: http://www.thingmagic.com/index.php/manuals-firmware#Mercury_API
+[6]: http://www.thingmagic.com/
+[7]: http://www.thingmagic.com/index.php/embedded-rfid-readers/thingmagic-nano-module
+[8]: https://learn.sparkfun.com/tutorials/rfid-basics
+[9]: https://github.com/ppelleti/hs-mercury-api/blob/master/UPGRADING.md
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/UPGRADING.md b/UPGRADING.md
new file mode 100644
--- /dev/null
+++ b/UPGRADING.md
@@ -0,0 +1,30 @@
+Hopefully I will keep this package up-to-date with the latest version
+of Mercury API.  But if you're in the position of needing to update
+Mercury API, follow these instructions:
+
+* Unzip the Mercury API zipfile.
+
+* Copy the files from `c/src/api/` in the Mercury API distribution to
+  `cbits/api/` in this package.
+
+* Run `dos2unix` on the files you copied, to normalize the line
+  endings.  (In the Mercury API distribution, they are a random
+  combination of DOS and Unix line endings, often in the same file.)
+
+* Apply the patches from the `cbits/api/patches/` directory.
+
+* Update `mercury-api.cabal` with any additional C files that were
+  added in the new release.  Note that not all C files are needed; in
+  particular, `serial_transport_tcp_posix.c` and
+  `tmr_loadsave_configuration.c` are not needed.  Also, note that the
+  files are supposed to be listed in [dependency order][1].  (And
+  sadly, to get them in the right order, we have to list all the files
+  for both Windows and POSIX, because the files end up in the wrong
+  order if some are conditional and some are unconditional.  Yuck!)
+
+* Run `util/generate-tmr-hsc.pl` (no arguments needed), which will
+  update the generated files `Enums.hsc` and `Params.hs` based on the
+  new `.h` and `.c` files.  (In particular, this will automatically
+  pick up new status codes and new parameters.)
+
+[1]: https://ghc.haskell.org/trac/ghc/ticket/13786#comment:3
diff --git a/cbits/api/hex_bytes.c b/cbits/api/hex_bytes.c
new file mode 100644
--- /dev/null
+++ b/cbits/api/hex_bytes.c
@@ -0,0 +1,151 @@
+/**
+ *  @file hex_bytes.c
+ *  @brief Routines for converting between byte arrays and hex strings
+ *  @author Nathan Williams
+ *  @date 10/23/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.
+ */
+
+#include <stdlib.h>
+
+#include "tm_reader.h"
+#include "serial_reader_imp.h"
+
+static char hexchars[] = "0123456789ABCDEF";
+
+
+TMR_Status
+TMR_hexToBytes(const char *hex, uint8_t *bytes, uint32_t size,
+               uint32_t *convertLen)
+{
+  char c;
+  int i, len;
+  uint8_t val[2];
+
+  if (hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X'))
+  {
+    hex += 2;
+  }
+
+  len = 0;
+  while (size > 0 && *hex != '\0')
+  {
+    for (i = 0; i < 2; i++)
+    {
+      c = *hex++;
+      if (c >= '0' && c <= '9')
+        val[i] = c - '0';
+      else if (c >= 'a' && c <= 'f')
+        val[i] = 10 + c - 'a';
+      else if (c >= 'A' && c <= 'F')
+        val[i] = 10 + c - 'A';
+      else
+        return TMR_ERROR_INVALID;
+    }
+    *bytes = (val[0] << 4) | val[1];
+
+    len++;
+    bytes++;
+    size--;
+  }
+
+  if (convertLen != NULL)
+  {
+    *convertLen = len;
+  }
+
+  return TMR_SUCCESS;
+}
+
+void
+TMR_bytesToHex(const uint8_t *bytes, uint32_t size, char *hex)
+{
+
+  while (size--)
+  {
+    *hex++ = hexchars[*bytes >> 4];
+    *hex++ = hexchars[*bytes & 15];
+    bytes++;
+  }
+  *hex = '\0';
+}
+
+/**
+ * Convert a four-byte array into a null-terminated string
+ * with the format %02X.%02X.%02X.%02X (AA.BB.CC.DD).
+ *
+ * @param bytes The array of four bytes to convert
+ * @param buf The string to write to. Must be at least 12 bytes.
+ */
+void
+TMR_hexDottedQuad(const uint8_t bytes[4], char buf[12])
+{
+  int i;
+
+  for (i = 0; i < 4 ; i++)
+  {
+    *buf++ = hexchars[*bytes >> 4];
+    *buf++ = hexchars[*bytes & 15];
+    *buf++ = '.';
+    bytes++;
+  }
+  *--buf = '\0';
+}
+
+/**
+ * Convert a 12-byte null-terminated string hexDottedQuad into a uint32_t
+ *
+ * @param bytes The array of twelve bytes to convert
+ * @param result The resulting uint32_t
+ * @return uint32_t represented but the 12 bytes
+ */
+TMR_Status
+TMR_hexDottedQuadToUint32(const char bytes[12], uint32_t *result)
+{
+  TMR_Status retVal;
+  uint32_t tmpResult;
+  uint8_t byteVal;
+  int i,j;
+
+  tmpResult=0;
+  for (i = 0, j = 0; i < 12 ; i+=3,++j)
+  {
+    retVal = TMR_hexToBytes(&bytes[i], &byteVal, 1, NULL);
+    if (TMR_SUCCESS == retVal)
+    {
+      tmpResult |= (byteVal << (8 * (3-j)));
+    }
+    else
+    {
+      return retVal;
+    }
+  }
+
+  if (NULL != result)
+  {
+    *result = tmpResult;
+  }
+  return retVal;
+}
diff --git a/cbits/api/llrp_reader_imp.h b/cbits/api/llrp_reader_imp.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/llrp_reader_imp.h
@@ -0,0 +1,293 @@
+#ifndef _LLRP_READER_IMP_H
+#define _LLRP_READER_IMP_H
+
+/**
+ *  @file llrp_reader_imp.h
+ *  @brief LLRP reader internal implementation header
+ *  @author Somu
+ *  @date 05/25/2011
+ */
+
+/*
+ * Copyright (c) 2011 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.
+ */
+
+#include <time.h>
+#include "tm_reader.h"
+#include "tmr_status.h"
+#include "ltkc.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Magic Number to reboot the Thingmagic LLRP
+ * fixed reader.
+ **/
+#define TMR_POWER_CYCLE_MAGIC_NUMBER 0x20000920  
+
+/**
+ * LLRP specific AccessCommandOpSpecResult parameter typenums
+ **/
+#define TMR_LLRP_C1G2READOPSPECRESULT 349
+#define TMR_LLRP_C1G2WRITEOPSPECRESULT 350
+#define TMR_LLRP_C1G2KILLOPSPECRESULT 351
+#define TMR_LLRP_C1G2LOCKOPSPECRESULT 352
+#define TMR_LLRP_C1G2BLOCKERASEOPSPECRESULT 353
+#define TMR_LLRP_C1G2BLOCKWRITEOPSPECRESULT 354
+#define TMR_LLRP_CUSTOM_BLOCKPERMALOCKOPSPECRESULT 22
+#define TMR_LLRP_CUSTOM_HIGGS2PARTIALLOADIMAGEOPSPECRESULT 24
+#define TMR_LLRP_CUSTOM_HIGGS2FULLLOADIMAGEOPSPECRESULT 26
+#define TMR_LLRP_CUSTOM_HIGGS3FASTLOADIMAGEOPSPECRESULT 28
+#define TMR_LLRP_CUSTOM_HIGGS3LOADIMAGEOPSPECRESULT 30
+#define TMR_LLRP_CUSTOM_HIGGS3BLOCKREADLOCKOPSPECRESULT 32
+#define TMR_LLRP_CUSTOM_G2ISETREADPROTECTOPSPECRESULT 34                               
+#define TMR_LLRP_CUSTOM_G2XSETREADPROTECTOPSPECRESULT 36                               
+#define TMR_LLRP_CUSTOM_G2IRESETREADPROTECTOPSPECRESULT 38                             
+#define TMR_LLRP_CUSTOM_G2XRESETREADPROTECTOPSPECRESULT 40                             
+#define TMR_LLRP_CUSTOM_G2ICHANGEEASOPSPECRESULT 42                                    
+#define TMR_LLRP_CUSTOM_G2XCHANGEEASOPSPECRESULT 44                                    
+#define TMR_LLRP_CUSTOM_G2IEASALARMOPSPECRESULT 46                                     
+#define TMR_LLRP_CUSTOM_G2XEASALARMOPSPECRESULT 48                                     
+#define TMR_LLRP_CUSTOM_G2ICALIBRATEOPSPECRESULT 50                                    
+#define TMR_LLRP_CUSTOM_G2XCALIBRATEOPSPECRESULT 52                                    
+#define TMR_LLRP_CUSTOM_G2ICHANGECONFIGOPSPECRESULT 54                                 
+#define TMR_LLRP_CUSTOM_MONZA4QTREADWRITEOPSPECRESULT 57
+#define TMR_LLRP_CUSTOM_IDS_SETSFEPARAMETERSOPSPECRESULT 99
+#define TMR_LLRP_CUSTOM_IDS_GETMEASUREMENTSETUPOPSPECRESULT 93
+#define TMR_LLRP_CUSTOM_IDS_GETBATTERYLEVELOPSPECRESULT 103
+#define TMR_LLRP_CUSTOM_IDS_SETLOGLIMITSOPSPECRESULT 116
+#define TMR_LLRP_CUSTOM_IDS_SETSHELFLIFEOPSPECRESULT 124
+#define TMR_LLRP_CUSTOM_IDS_SETPASSWORDOPSPECRESULT 118
+#define TMR_LLRP_CUSTOM_WRITETAGOPSPECRESULT  61
+#define TMR_LLRP_CUSTOM_IDS_GETSENSORVALUEOPSPECRESULT 77
+#define TMR_LLRP_CUSTOM_IDS_SETLOGMODEOPSPECRESULT 85
+#define TMR_LLRP_CUSTOM_IDS_STARTLOGMODEOPSPECRESULT 87
+#define TMR_LLRP_CUSTOM_IDS_GETLOGSTATEOPSPECRESULT 79
+#define TMR_LLRP_CUSTOM_IDS_ENDLOGOPSPECRESULT 89
+#define TMR_LLRP_CUSTOM_IDS_INITIALIZEOPSPECRESULT 91
+#define TMR_LLRP_CUSTOM_IDS_ACCESSFIFOSTATUSOPSPECRESULT 101
+#define TMR_LLRP_CUSTOM_IDS_ACCESSFIFOWRITEOPSPECRESULT 114
+#define TMR_LLRP_CUSTOM_IDS_ACCESSFIFOREADOPSPECRESULT 112
+#define TMR_LLRP_CUSTOM_IDS_GETCALIBRATIONDATAOPSPECRESULT 95
+#define TMR_LLRP_CUSTOM_IDS_SETCALIBRATIONDATAOPSPECRESULT 97
+#define TMR_LLRP_CUSTOM_DENATRAN_IAV_ACTIVATESECUREMODEOPSPECRESULT 127
+#define TMR_LLRP_CUSTOM_DENATRAN_IAV_AUTHENTICATEOBUOPSPECRESULT 129
+#define TMR_LLRP_CUSTOM_DENATRAN_IAV_ACTIVATESINIAVMODEOPSPECRESULT 131
+#define TMR_LLRP_CUSTOM_DENATRAN_IAV_AUTHENTICATEIDOPSPECRESULT 133
+#define TMR_LLRP_CUSTOM_DENATRAN_IAV_AUTHENTICATEFULLPASS1OPSPECRESULT 135
+#define TMR_LLRP_CUSTOM_DENATRAN_IAV_AUTHENTICATEFULLPASS2OPSPECRESULT 137
+#define TMR_LLRP_CUSTOM_DENATRAN_IAV_OBUREADFROMMEMMAPOPSPECRESULT 139
+#define TMR_LLRP_CUSTOM_DENATRAN_IAV_OBUWRITETOMEMMAPOPSPECRESULT 141
+
+#ifdef TMR_ENABLE_ISO180006B
+#define TMR_LLRP_CUSTOM_ISO_READDATAOPSPECRESULT  65
+#define TMR_LLRP_CUSTOM_ISO_WRITEDATAOPSPECRESULT 68
+#define TMR_LLRP_CUSTOM_ISO_LOCKOPSPECRESULT 70
+#endif /* TMR_ENABLE_ISO180006B */
+
+/**
+ * Maximum number of ROSpecs supported by reader.
+ **/
+#define TMR_LLRP_MAX_ROSPECS 32
+/**
+ * Maximum milliseconds required for reader to stop an ongoing search
+ **/
+#define TMR_LLRP_STOP_TIMEOUT 5000
+
+/**
+ * This structure is returned from TMR_LLRP_cmdAntennaDetect.
+ **/
+typedef struct TMR_LLRP_PortDetect
+{
+  /** The port number. */
+  uint16_t port;
+  /** Whether the antenna is connected? */
+  bool connected;
+  /** Antenna gain */
+  int16_t gain;
+}TMR_LLRP_PortDetect;
+
+/**
+ * This struture is returned from ThingMagicDeDuplication
+ **/
+typedef struct TMR_LLRP_TMDeDuplication
+{
+  /** Record Highest RSSI */
+  llrp_u1_t highestRSSI;
+
+  /** Unique By Antenna */
+  llrp_u1_t uniquebyAntenna;
+
+  /** Unique By Data */
+  llrp_u1_t uniquebyData;
+}TMR_LLRP_TMDeDuplication;
+  
+/**
+ * This structure is returned from cmdGetThingmagicReaderConfiguration
+ **/
+typedef struct TMR_LLRP_TMReaderConfiguration
+{
+  /** Reader description */
+  llrp_utf8v_t description;
+  /** Reader Role */
+  llrp_utf8v_t role;
+  /** Reader host name */
+  llrp_utf8v_t hostName;
+} TMR_LLRP_TMReaderConfiguration;
+
+/**
+ * This value is returned from TMR_LLRP_cmdVersionModel.
+ **/
+# define  TMR_LLRP_MODEL_M6  0x06
+# define  TMR_LLRP_MODEL_ASTRA_EX 0x30
+# define  TMR_LLRP_MODEL_SARGAS 0x3430
+
+TMR_Status TMR_LLRP_notifyTransportListener(TMR_Reader *reader, LLRP_tSMessage *pMsg, bool tx, int timeout);
+TMR_Status TMR_LLRP_sendMessage(TMR_Reader *reader, LLRP_tSMessage *pMsg, int timeoutMs);
+TMR_Status TMR_LLRP_receiveMessage(TMR_Reader *reader, LLRP_tSMessage **pMsg, int timeoutMs);
+TMR_Status TMR_LLRP_sendTimeout(TMR_Reader *reader, LLRP_tSMessage *pMsg, LLRP_tSMessage **pRsp, int timeoutMs);
+TMR_Status TMR_LLRP_send(TMR_Reader *reader, LLRP_tSMessage *pMsg, LLRP_tSMessage **pRsp);
+void TMR_LLRP_freeMessage(LLRP_tSMessage *pMsg);
+TMR_Status TMR_LLRP_checkLLRPStatus(LLRP_tSLLRPStatus *pLLRPStatus);
+
+TMR_Status TMR_LLRP_cmdGetRegion(TMR_Reader *reader, TMR_Region *region);
+TMR_Status TMR_LLRP_cmdAntennaDetect(TMR_Reader *reader, uint8_t *count, TMR_LLRP_PortDetect *ports);
+TMR_Status TMR_LLRP_cmdGetTMAsyncOffTime(TMR_Reader *reader, uint32_t *offtime);
+
+TMR_Status TMR_LLRP_cmdGetGPIState(TMR_Reader *reader, uint8_t *count, TMR_GpioPin state[]);
+TMR_Status TMR_LLRP_cmdSetGPOState(TMR_Reader *reader, uint8_t count, const TMR_GpioPin state[]);
+
+TMR_Status TMR_LLRP_cmdGetReaderCapabilities(TMR_Reader *reader, TMR_LLRP_ReaderCapabilities *capabilities);
+
+TMR_Status TMR_LLRP_cmdGetReadTransmitPowerList(TMR_Reader *reader, TMR_PortValueList *pPortValueList);
+TMR_Status TMR_LLRP_cmdSetReadTransmitPowerList(TMR_Reader *reader, TMR_PortValueList *pPortValueList);
+
+TMR_Status TMR_LLRP_cmdGetWriteTransmitPowerList(TMR_Reader *reader, TMR_PortValueList *pPortValueList);
+TMR_Status TMR_LLRP_cmdSetWriteTransmitPowerList(TMR_Reader *reader, TMR_PortValueList *pPortValueList);
+TMR_Status TMR_LLRP_cmdGetTMDeviceInformationCapabilities(TMR_Reader *reader, int param, TMR_String  *version);
+TMR_Status TMR_LLRP_cmdGetActiveRFControl(TMR_Reader *reader, TMR_LLRP_RFControl *rfControl);
+TMR_Status TMR_LLRP_cmdSetActiveRFControl(TMR_Reader *reader, TMR_LLRP_RFControl *rfControl);
+TMR_Status TMR_LLRP_cmdGetGen2Session(TMR_Reader *reader, TMR_GEN2_Session  *session);
+TMR_Status TMR_LLRP_cmdSetGen2Session(TMR_Reader *reader, TMR_GEN2_Session  *session);
+TMR_Status TMR_LLRP_cmdSetTMAsyncOffTime(TMR_Reader *reader, uint32_t offtime);
+
+/*ThingMagic Licensed Features*/
+TMR_Status TMR_LLRP_cmdGetLicensedFeatures(TMR_Reader *reader, TMR_uint8List  *features);
+
+/*ThingMagic Selected Protocols*/
+TMR_Status TMR_LLRP_cmdGetSelectedProtocols(TMR_Reader *reader, TMR_TagProtocolList *protocolList);
+
+/* ThingMagic DeDuplication */
+TMR_Status TMR_LLRP_cmdGetThingMagicDeDuplication(TMR_Reader *reader, TMR_LLRP_TMDeDuplication *duplication);
+TMR_Status TMR_LLRP_cmdSetThingMagicDeDuplication(TMR_Reader *reader, TMR_LLRP_TMDeDuplication *duplication);
+
+/* Thingmagic Reader configuration */
+TMR_Status TMR_LLRP_cmdGetThingmagicReaderConfiguration(TMR_Reader *reader, TMR_LLRP_TMReaderConfiguration *config);
+TMR_Status TMR_LLRP_cmdSetThingmagicReaderConfiguration(TMR_Reader *reader, TMR_LLRP_TMReaderConfiguration *config);
+void TMR_LLRP_freeTMReaderConfiguration(TMR_LLRP_TMReaderConfiguration *config);
+
+/* Thingmagic Current Time */
+TMR_Status TMR_LLRP_cmdGetThingMagicCurrentTime(TMR_Reader *reader, struct tm *curTime);
+
+/* Thingmagic Reader Module Temperature */
+TMR_Status TMR_LLRP_cmdGetThingMagicReaderModuleTemperature(TMR_Reader *reader, uint8_t *temp);
+
+/* Thingmagic protocol configuration: Gen2 Q */
+TMR_Status TMR_LLRP_cmdSetGen2Q(TMR_Reader *reader, TMR_GEN2_Q *q);
+TMR_Status TMR_LLRP_cmdGetGen2Q(TMR_Reader *reader, TMR_GEN2_Q *q);
+
+/* Thingmagic Protocol configuration:Gen2 Target */
+TMR_Status TMR_LLRP_cmdSetGen2Target(TMR_Reader *reader, TMR_GEN2_Target *target);
+TMR_Status TMR_LLRP_cmdGetGen2Target(TMR_Reader *reader, TMR_GEN2_Target *target);
+
+/* Thingmagic LicenseKey */
+TMR_Status TMR_LLRP_cmdSetTMLicenseKey(TMR_Reader *reader, TMR_uint8List *license);
+
+/* Thingmagic ISO 18K6B Delimiter */
+TMR_Status TMR_LLRP_cmdSetISO18K6BDelimiter(TMR_Reader *reader, TMR_ISO180006B_Delimiter *delimiter);
+TMR_Status TMR_LLRP_cmdGetISO18K6BDelimiter(TMR_Reader *reader, TMR_ISO180006B_Delimiter *delimiter);
+
+/* Thingmagic ISO 18K6B Modulation Depth */
+TMR_Status TMR_LLRP_cmdSetISO18K6BModDepth(TMR_Reader *reader, TMR_ISO180006B_ModulationDepth *modDepth);
+TMR_Status TMR_LLRP_cmdGetISO18K6BModDepth(TMR_Reader *reader, TMR_ISO180006B_ModulationDepth *modDepth);
+
+/* Thingmagic ISO 1806B Link Frequency */
+TMR_Status TMR_LLRP_cmdSetISO18K6BLinkFrequency(TMR_Reader *reader, TMR_ISO180006B_LinkFrequency *linkFreq);
+TMR_Status TMR_LLRP_cmdGetISO18K6BLinkFrequency(TMR_Reader *reader, TMR_ISO180006B_LinkFrequency *linkFreq);
+
+/* Thingmagic Device Protocol Capabilities */
+TMR_Status TMR_LLRP_cmdGetTMDeviceProtocolCapabilities(TMR_Reader *reader, TMR_TagProtocolList * protocol);
+
+/* Thingmagic Device Antenna Detection */
+TMR_Status TMR_LLRP_cmdGetThingMagicAntennaDetection(TMR_Reader *reader, bool *antennaport);
+TMR_Status TMR_LLRP_cmdSetThingMagicAntennaDetection(TMR_Reader *reader, bool *antennaport);
+
+/* Read  */
+TMR_Status TMR_LLRP_cmdPrepareROSpec(TMR_Reader *reader, uint16_t timeout, TMR_uint8List *antennaList,
+            const TMR_TagFilter *filter, TMR_TagProtocol protocol);
+TMR_Status TMR_LLRP_cmdAddROSpec(TMR_Reader *reader, uint16_t readDuration, TMR_uint8List *antennaList,
+                                  const TMR_TagFilter *filter, TMR_TagProtocol protocol);
+TMR_Status TMR_LLRP_cmdEnableROSpec(TMR_Reader *reader);
+TMR_Status TMR_LLRP_cmdDisableROSpec(TMR_Reader *reader);
+TMR_Status TMR_LLRP_cmdStartROSpec(TMR_Reader *reader, llrp_u32_t roSpecId);
+TMR_Status TMR_LLRP_cmdStopROSpec(TMR_Reader *reader, bool receiveResponse);
+TMR_Status TMR_LLRP_cmdDeleteAllROSpecs(TMR_Reader *reader, bool receiveResponse);
+TMR_Status TMR_LLRP_parseMetadataFromMessage(TMR_Reader *reader, TMR_TagReadData *data, LLRP_tSTagReportData *msg);
+TMR_Status TMR_LLRP_verifyReadOperation(TMR_Reader *reader, int32_t *tagCount);
+TMR_Status TMR_LLRP_cmdStopReading(struct TMR_Reader *reader);
+
+TMR_Status TMR_LLRP_cmdGetVersionSerial(TMR_Reader *reader, TMR_String *version);
+TMR_Status TMR_LLRP_cmdrebootReader(TMR_Reader *reader);
+
+/* Reset Reader */
+TMR_Status TMR_LLRP_stopActiveROSpecs(TMR_Reader *reader);
+
+/* Reports, Notifications and Keepalives */
+TMR_Status TMR_LLRP_setKeepAlive(TMR_Reader *reader);
+TMR_Status TMR_LLRP_enableEventsAndReports(TMR_Reader *reader);
+TMR_Status TMR_LLRP_setHoldEventsAndReportsStatus(TMR_Reader *reader, llrp_u1_t status);
+TMR_Status TMR_LLRP_handleKeepAlive(TMR_Reader *reader, LLRP_tSMessage *pMsg);
+TMR_Status TMR_LLRP_startBackgroundReceiver(TMR_Reader *reader);
+TMR_Status TMR_LLRP_cmdSetEventNotificationSpec(TMR_Reader *reader, bool state);
+TMR_Status TMR_LLRP_handleReaderEvents(TMR_Reader *reader, LLRP_tSMessage *pMsg);
+TMR_Status TMR_LLRP_processReceivedMessage(TMR_Reader *reader, LLRP_tSMessage *pMsg);
+void TMR_LLRP_setBackgroundReceiverState(TMR_Reader *reader, bool state);
+
+/* Access Spec */
+TMR_Status TMR_LLRP_cmdEnableAccessSpec(TMR_Reader *reader, llrp_u32_t accessSpecId);
+TMR_Status TMR_LLRP_msgPrepareAccessCommand(TMR_Reader *reader, LLRP_tSAccessCommand *pAccessCommand,
+                                                              TMR_TagFilter *filter, TMR_TagOp *tagop);
+TMR_Status TMR_LLRP_cmdAddAccessSpec(TMR_Reader *reader, TMR_TagProtocol protocol, TMR_TagFilter *filter,
+                                            llrp_u32_t roSpecId, TMR_TagOp *tagop, bool isStandalone);
+TMR_Status TMR_LLRP_verifyOpSpecResultStatus(TMR_Reader *reader, LLRP_tSParameter *pParameter);
+TMR_Status TMR_LLRP_cmdDeleteAllAccessSpecs(TMR_Reader *reader);
+
+TMR_Status TMR_LLRP_parseCustomTagOpSpecResultType(LLRP_tEThingMagicCustomTagOpSpecResultType status);
+void TMR_LLRP_parseTagOpSpecData(LLRP_tSParameter *pParameter, TMR_uint8List *data);
+
+TMR_Status TMR_LLRP_cmdGetReport(TMR_Reader *reader);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LLRP_READER_IMP_H */
diff --git a/cbits/api/osdep.h b/cbits/api/osdep.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/osdep.h
@@ -0,0 +1,96 @@
+#ifndef _OSDEP_H
+#define _OSDEP_H
+
+/**
+ *  @file osdep.h
+ *  @brief Mercury API - OS dependencies
+ *  @author Nathan Williams
+ *  @date 2/24/2010
+ */
+
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#ifdef WINCE
+#include <stdint_win32.h>
+#else
+#include <stdint.h>
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* These are functions that must be provided for the library to operate */
+
+  /*
+  * Thing magic reader time objeect to reprejent the time stamp
+  */
+  typedef struct TMR_TimeStructure
+  {
+    uint32_t tm_sec;
+    uint32_t tm_min;
+    uint32_t tm_hour;
+    uint32_t tm_mday;
+    uint32_t tm_mon;
+    uint32_t tm_year;
+  }TMR_TimeStructure;
+
+/*
+ * The time function used to return the current time in
+ * thing magic time structure.
+ */
+TMR_TimeStructure tmr_gettimestructure(void);
+
+uint64_t tmr_gettime(void);
+
+/* The time functions collectively return a 64-bit counter in units of
+ * milliseconds. Both methods are used when timestamping events such
+ * as tag reads. For controlling elapsed time, only the lower one is
+ * used, so If your platform does not support more than 32 bits of
+ * millisecond counting, returning 0 from the high method will not
+ * cause problems internal to the library.
+ */
+
+/**
+ * Return the low 32-bits of a system millisecond counter. This is
+ * used internally for operation timing and to timestamp tag reads.
+ */
+uint32_t tmr_gettime_low(void);
+
+/**
+ * Return the high 32-bits of a system millisecond counter. This is
+ * used to timestamp tag reads.
+ */
+uint32_t tmr_gettime_high(void);
+
+/**
+ * Suspend operation for a given duration.
+ * @param sleepms The number of milliseconds to sleep for.
+ */
+void tmr_sleep(uint32_t sleepms);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OSDEP_H */
diff --git a/cbits/api/osdep_posix.c b/cbits/api/osdep_posix.c
new file mode 100644
--- /dev/null
+++ b/cbits/api/osdep_posix.c
@@ -0,0 +1,97 @@
+
+/**
+ *  @file osdep_posix.c
+ *  @brief Mercury API - POSIX platform implementation of OS dependencies
+ *  @author Nathan Williams
+ *  @date 2/24/2010
+ */
+
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#include <time.h>
+#include <sys/time.h>
+
+#include "osdep.h"
+
+uint64_t
+tmr_gettime()
+{
+  struct timeval tv;
+  uint64_t totalms;
+
+  gettimeofday(&tv, NULL);
+  totalms = (((uint64_t)tv.tv_sec) * 1000) + ((uint64_t) tv.tv_usec) / 1000;
+
+  return totalms;
+}
+
+uint32_t
+tmr_gettime_low()
+{
+
+  return (tmr_gettime() >>  0) & 0xffffffff;
+}
+
+uint32_t
+tmr_gettime_high()
+{
+
+  return (tmr_gettime() >> 32) & 0xffffffff;
+}
+
+
+void
+tmr_sleep(uint32_t sleepms)
+{
+  struct timespec sleep, rem;
+
+  sleep.tv_sec = sleepms / 1000;
+  sleep.tv_nsec = (sleepms % 1000) * 1000000L;
+
+  /* Sleep until the proper time has elapsed, and re-sleep if interrupted. */
+  while (-1 == nanosleep(&sleep, &rem))
+  {
+    sleep = rem;
+  }
+}
+
+TMR_TimeStructure 
+tmr_gettimestructure()
+{
+  time_t now;
+  uint64_t temp;
+  struct tm *timestamp;
+  TMR_TimeStructure timestructure;
+
+  temp = tmr_gettime();
+  now = (time_t)(temp/1000);
+  timestamp = localtime(&now);
+
+  timestructure.tm_year = (uint32_t)(1900 + timestamp->tm_year);
+  timestructure.tm_mon = (uint32_t)(1 + timestamp->tm_mon);
+  timestructure.tm_mday = (uint32_t)timestamp->tm_mday;
+  timestructure.tm_hour = (uint32_t)timestamp->tm_hour;
+  timestructure.tm_min = (uint32_t)timestamp->tm_min;
+  timestructure.tm_sec = (uint32_t)timestamp->tm_sec;
+  return timestructure;  
+}
diff --git a/cbits/api/osdep_win32.c b/cbits/api/osdep_win32.c
new file mode 100644
--- /dev/null
+++ b/cbits/api/osdep_win32.c
@@ -0,0 +1,86 @@
+/**
+ *  @file osdep_win32.c
+ *  @brief Mercury API - Windows platform implementation of OS dependencies
+*/
+
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#if !defined(_WINSOCK2API_) && !defined(_WINSOCKAPI_)
+#include <winsock2.h>
+#endif
+#include <time.h>
+#include "osdep.h"
+
+// https://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux
+#define SEC_TO_UNIX_EPOCH 11644473600LL
+
+uint64_t
+tmr_gettime()
+{
+  uint64_t totalms;
+  SYSTEMTIME st;
+  FILETIME ft;
+  LARGE_INTEGER li;    
+  GetSystemTime(&st);
+  SystemTimeToFileTime(&st, &ft);
+  li.LowPart = ft.dwLowDateTime;
+  li.HighPart = ft.dwHighDateTime;
+  totalms=(((uint64_t)li.LowPart) | ((uint64_t)li.HighPart)<<32)/10000;
+  totalms -= SEC_TO_UNIX_EPOCH * 1000;
+  return totalms;
+}
+
+uint32_t
+tmr_gettime_low()
+{
+  return (uint32_t) tmr_gettime();
+}
+
+uint32_t
+tmr_gettime_high()
+{
+  return (uint32_t) (tmr_gettime() >> 32);
+}
+
+void
+tmr_sleep(uint32_t sleepms)
+{
+  Sleep(sleepms);
+}
+
+TMR_TimeStructure 
+tmr_gettimestructure()
+{ 
+  SYSTEMTIME st;
+  TMR_TimeStructure timestructure;
+
+  GetSystemTime(&st);
+
+  timestructure.tm_year = (uint32_t)st.wYear;
+  timestructure.tm_mon = (uint32_t)st.wMonth;
+  timestructure.tm_mday = (uint32_t)st.wDay;
+  timestructure.tm_hour = (uint32_t)st.wHour;
+  timestructure.tm_min = (uint32_t)st.wMinute;
+  timestructure.tm_sec = (uint32_t)st.wSecond;
+  return timestructure;  
+}
diff --git a/cbits/api/patches/README.md b/cbits/api/patches/README.md
new file mode 100644
--- /dev/null
+++ b/cbits/api/patches/README.md
@@ -0,0 +1,23 @@
+These are patches to be applied to Mercury API to fix various bugs.
+I've submitted all of them (except `config.patch`) to ThingMagic for
+possible inclusion in a future release.
+
+`config.patch` - This increases the maximum length of URIs from 64 bytes to 256 bytes.  Unlike all the other patches, this is a configuration change, not a bug fix, so it has not been submitted upstream.
+
+`eintr.patch` - This retries the `select()` operation when it returns `EINTR`.  This is always good practice, but it seemed to be necessary in my situation to avoid failing with a timeout.  There are probably plenty of other places in the API where this should be done, too.
+
+`extern.patch` - This fixes a problem I ran into with `isSecureAccessEnabled` being multiply defined, when compiling with cabal.  (Strangely, doesn't happen when using ThingMagic's Makefile.)
+
+`host-c-library.patch` - The build failed when `TMR_USE_HOST_C_LIBRARY` was defined.  This fixes that.
+
+`infinite-loop.patch` - This avoids an infinite loop that I ran into, when somehow `readOffSet` was 142, and `dataLength` was 128.  Not sure how that happened, and it probably indicates another bug, but at least this fix prevents going into an infinite loop in that situation.
+
+`metadataflag-size.patch` - `paramSet()` treated `TMR_PARAM_METADATAFLAG` as `TMR_TRD_MetadataFlag`, while `paramGet()` treated `TMR_PARAM_METADATAFLAG` as `uint16_t`.  Since `sizeof(TMR_TRD_MetadataFlag)` is 4 but `sizeof(uint16_t)` is 2, the sizes didn't match.  This patch fixes `paramGet()` to also treat it as `TMR_TRD_MetadataFlag`.
+
+`mingw-dword-pointer.patch` - Fixes a compiler warning about `warning: passing argument 4 of 'ReadFile' from incompatible pointer type [-Wincompatible-pointer-types]`.  Somehow the warning was getting treated as an error on Appveyor.
+
+`mingw-snprintf.patch` - Fixes a problem I ran into on MinGW, where `sprintf_s()` doesn't seem to work properly, but `snprintf()` does work properly.
+
+`typos.patch` - This just fixes a bunch of small typos I found.
+
+`windows-time.patch` - On Windows, `tmr_gettime_low()` and `tmr_gettime_high()` were returning the number of 100-nanosecond units since 1/1/1601, rather than the number of milliseconds since 1/1/1970.  This caused the `timestampLow` and `timestampHigh` fields of `TMR_TagReadData` to be populated incorrectly.  This patch fixes that problem.
diff --git a/cbits/api/patches/config.patch b/cbits/api/patches/config.patch
new file mode 100644
--- /dev/null
+++ b/cbits/api/patches/config.patch
@@ -0,0 +1,23 @@
+commit 092146c3eb431d9358135e5a2919f5a9a6f4c0db
+Author: Patrick Pelletier <code@funwithsoftware.org>
+Date:   Thu May 25 15:55:39 2017 -0700
+
+    increase the maximum length of a reader URI
+    
+    This is necessary because in the case of test:// URIs, we are passing
+    an arbitrary filename.  Even 256 is fairly arbitrary, but it seems
+    like enough for most cases, while 64 seemed tight.
+
+diff --git a/tm_config.h b/tm_config.h
+index a749b26..ea5892e 100644
+--- a/tm_config.h
++++ b/tm_config.h
+@@ -56,7 +56,7 @@ extern "C" {
+ /**
+  * The longest possible name for a reader.
+  */
+-#define TMR_MAX_READER_NAME_LENGTH 64
++#define TMR_MAX_READER_NAME_LENGTH 256
+ 
+ /**
+  * The maximum number of protocols supported in a multiprotocol search command
diff --git a/cbits/api/patches/eintr.patch b/cbits/api/patches/eintr.patch
new file mode 100644
--- /dev/null
+++ b/cbits/api/patches/eintr.patch
@@ -0,0 +1,30 @@
+diff --git a/serial_transport_posix.c b/serial_transport_posix.c
+index 9146589..4127ee3 100644
+--- a/serial_transport_posix.c
++++ b/serial_transport_posix.c
+@@ -127,12 +127,19 @@ s_receiveBytes(TMR_SR_SerialTransport *this, uint32_t length,
+ 
+   do
+   {
+-    FD_ZERO(&set);
+-    FD_SET(c->handle, &set);
+-    tv.tv_sec = timeoutMs / 1000;
+-    tv.tv_usec = (timeoutMs % 1000) * 1000;
+-    /* Ideally should reset this timeout value every time through */
+-    ret = select(c->handle + 1, &set, NULL, NULL, &tv);
++    do
++    {
++      FD_ZERO(&set);
++      FD_SET(c->handle, &set);
++      tv.tv_sec = timeoutMs / 1000;
++      tv.tv_usec = (timeoutMs % 1000) * 1000;
++      /* Ideally should reset this timeout value every time through */
++      ret = select(c->handle + 1, &set, NULL, NULL, &tv);
++    } while (ret == -1 && errno == EINTR);
++    if (ret == -1)
++    {
++      return TMR_ERROR_COMM_ERRNO(errno);
++    }
+     if (ret < 1)
+     {
+       return TMR_ERROR_TIMEOUT;
diff --git a/cbits/api/patches/extern.patch b/cbits/api/patches/extern.patch
new file mode 100644
--- /dev/null
+++ b/cbits/api/patches/extern.patch
@@ -0,0 +1,28 @@
+diff --git a/serial_reader_imp.h b/serial_reader_imp.h
+index 9f5fd54..16e30b1 100644
+--- a/serial_reader_imp.h
++++ b/serial_reader_imp.h
+@@ -40,7 +40,7 @@ extern "C" {
+ /* This is used to enable the Gen2 secure readdata option */
+ 
+ #ifndef BARE_METAL
+-  bool isSecureAccessEnabled ;
++  extern bool isSecureAccessEnabled ;
+ #else
+   static bool isSecureAccessEnabled;	
+ #endif
+diff --git a/serial_reader_l3.c b/serial_reader_l3.c
+index 99986bf..71c4192 100644
+--- a/serial_reader_l3.c
++++ b/serial_reader_l3.c
+@@ -36,6 +36,10 @@
+ #include "serial_reader_imp.h"
+ #include "tmr_utils.h"
+ 
++#ifndef BARE_METAL
++bool isSecureAccessEnabled;
++#endif
++
+ void
+ notify_read_listeners(TMR_Reader *reader, TMR_TagReadData *trd);
+ #ifdef TMR_ENABLE_SERIAL_READER
diff --git a/cbits/api/patches/host-c-library.patch b/cbits/api/patches/host-c-library.patch
new file mode 100644
--- /dev/null
+++ b/cbits/api/patches/host-c-library.patch
@@ -0,0 +1,33 @@
+diff --git a/tm_reader_async.c b/tm_reader_async.c
+index 4bcec6f..a464c5f 100644
+--- a/tm_reader_async.c
++++ b/tm_reader_async.c
+@@ -40,6 +40,7 @@ TMR_Status restart_reading(struct TMR_Reader *reader);
+ #include <semaphore.h>
+ #include <time.h>
+ #include <stdio.h>
++#include <string.h>
+ 
+ #ifndef WIN32
+ #include <sys/time.h>
+diff --git a/tmr_utils.c b/tmr_utils.c
+index 194a63a..80c7ce9 100644
+--- a/tmr_utils.c
++++ b/tmr_utils.c
+@@ -28,6 +28,7 @@
+  */
+ 
+ #include <stddef.h>
++#include <string.h>
+ 
+ #include "osdep.h"
+ #include "tmr_types.h"
+@@ -171,7 +172,7 @@ TMR_stringCopy(TMR_String *dest, const char *src, int len)
+   }
+   if (dest->max > 0)
+   {
+-    tm_memcpy(dest->value, src, len);
++    memcpy(dest->value, src, len);
+     dest->value[len] = '\0';
+   }
+ }
diff --git a/cbits/api/patches/infinite-loop.patch b/cbits/api/patches/infinite-loop.patch
new file mode 100644
--- /dev/null
+++ b/cbits/api/patches/infinite-loop.patch
@@ -0,0 +1,13 @@
+diff --git a/serial_reader_l3.c b/serial_reader_l3.c
+index 99986bf..458740e 100644
+--- a/serial_reader_l3.c
++++ b/serial_reader_l3.c
+@@ -1767,7 +1767,7 @@ TMR_SR_parseMetadataFromMessage(TMR_Reader *reader, TMR_TagReadData *read, uint1
+     uint16_t epcDataLength;
+     while (dataLength != 0)
+     {
+-      if (readOffSet == dataLength)
++      if (readOffSet >= dataLength)
+         break;
+       bank = ((read->data.list[readOffSet] >> 4) & 0x1F);
+       epcDataLength = (read->data.list[readOffSet + 1] * 2);
diff --git a/cbits/api/patches/metadataflag-size.patch b/cbits/api/patches/metadataflag-size.patch
new file mode 100644
--- /dev/null
+++ b/cbits/api/patches/metadataflag-size.patch
@@ -0,0 +1,13 @@
+diff --git a/serial_reader.c b/serial_reader.c
+index 7001ab1..c711aac 100644
+--- a/serial_reader.c
++++ b/serial_reader.c
+@@ -4178,7 +4178,7 @@ TMR_SR_paramGet(struct TMR_Reader *reader, TMR_Param key, void *value)
+     break;
+   case TMR_PARAM_METADATAFLAG:
+ 	  {
+-		*(uint16_t *)value = reader->userMetadataFlag;
++		*(TMR_TRD_MetadataFlag *)value = reader->userMetadataFlag;
+ 		break;
+ 	  }
+ 		    
diff --git a/cbits/api/patches/mingw-dword-pointer.patch b/cbits/api/patches/mingw-dword-pointer.patch
new file mode 100644
--- /dev/null
+++ b/cbits/api/patches/mingw-dword-pointer.patch
@@ -0,0 +1,13 @@
+diff --git a/serial_transport_win32.c b/serial_transport_win32.c
+index ce4cc46..ff007b6 100644
+--- a/serial_transport_win32.c
++++ b/serial_transport_win32.c
+@@ -126,7 +126,7 @@ s_receiveBytes(TMR_SR_SerialTransport *this, uint32_t length,
+               uint32_t* messageLength, uint8_t* message, const uint32_t
+ timeoutMs)
+ {
+- uint32_t readLength;
++ DWORD readLength;
+  DWORD errorFlags;
+  COMSTAT comStat;
+  TMR_SR_SerialPortNativeContext *c;
diff --git a/cbits/api/patches/mingw-snprintf.patch b/cbits/api/patches/mingw-snprintf.patch
new file mode 100644
--- /dev/null
+++ b/cbits/api/patches/mingw-snprintf.patch
@@ -0,0 +1,13 @@
+diff --git a/serial_transport_win32.c b/serial_transport_win32.c
+index ce4cc46..e8e27cb 100644
+--- a/serial_transport_win32.c
++++ b/serial_transport_win32.c
+@@ -39,7 +39,7 @@
+ 
+ #  if defined(WINCE)
+ #    define snprintf _snprintf
+-#  else
++#  elif !defined(__GNUC__)
+ #    define snprintf sprintf_s
+ #  endif
+ 
diff --git a/cbits/api/patches/typos.patch b/cbits/api/patches/typos.patch
new file mode 100644
--- /dev/null
+++ b/cbits/api/patches/typos.patch
@@ -0,0 +1,884 @@
+diff --git a/llrp_reader_l3.c b/llrp_reader_l3.c
+index 555fe0a..de3fe19 100644
+--- a/llrp_reader_l3.c
++++ b/llrp_reader_l3.c
+@@ -9691,7 +9691,7 @@ TMR_LLRP_verifyOpSpecResultStatus(TMR_Reader *reader,
+ 
+           case LLRP_C1G2ReadResultType_Memory_Locked_Error:
+             {
+-              ret = TMR_ERROR_GEN2_PROCOCOL_MEMORY_LOCKED;
++              ret = TMR_ERROR_GEN2_PROTOCOL_MEMORY_LOCKED;
+               break;
+             }
+ 
+@@ -9725,7 +9725,7 @@ TMR_LLRP_verifyOpSpecResultStatus(TMR_Reader *reader,
+ 
+           case LLRP_C1G2WriteResultType_Tag_Memory_Locked_Error:
+             {
+-              ret = TMR_ERROR_GEN2_PROCOCOL_MEMORY_LOCKED;
++              ret = TMR_ERROR_GEN2_PROTOCOL_MEMORY_LOCKED;
+               break;
+             }
+ 
+@@ -9881,7 +9881,7 @@ TMR_LLRP_verifyOpSpecResultStatus(TMR_Reader *reader,
+ 
+           case LLRP_C1G2BlockEraseResultType_Tag_Memory_Locked_Error:
+             {
+-              ret = TMR_ERROR_GEN2_PROCOCOL_MEMORY_LOCKED;
++              ret = TMR_ERROR_GEN2_PROTOCOL_MEMORY_LOCKED;
+               break;
+             }
+ 
+@@ -9939,7 +9939,7 @@ TMR_LLRP_verifyOpSpecResultStatus(TMR_Reader *reader,
+ 
+           case LLRP_C1G2BlockWriteResultType_Tag_Memory_Locked_Error:
+             {
+-              ret = TMR_ERROR_GEN2_PROCOCOL_MEMORY_LOCKED;
++              ret = TMR_ERROR_GEN2_PROTOCOL_MEMORY_LOCKED;
+               break;
+             }
+ 
+diff --git a/osdep.h b/osdep.h
+index d9661ac..126e3b9 100644
+--- a/osdep.h
++++ b/osdep.h
+@@ -56,7 +56,7 @@ extern "C" {
+   }TMR_TimeStructure;
+ 
+ /*
+- * The time funcution used to return the current time in
++ * The time function used to return the current time in
+  * thing magic time structure.
+  */
+ TMR_TimeStructure tmr_gettimestructure(void);
+diff --git a/serial_reader.c b/serial_reader.c
+index 7001ab1..1d017b1 100644
+--- a/serial_reader.c
++++ b/serial_reader.c
+@@ -228,7 +228,7 @@ TMR_SR_boot(TMR_Reader *reader, uint32_t currentBaudRate)
+   }
+ 
+   /**
+-   * In case for M6E and it's varient  check for CRC
++   * In case for M6E and its variant check for CRC
+    **/
+   if ((TMR_SR_MODEL_M6E == reader->u.serialReader.versionInfo.hardware[0]) ||
+       (TMR_SR_MODEL_M6E_I == reader->u.serialReader.versionInfo.hardware[0]) ||
+@@ -426,7 +426,7 @@ TMR_SR_boot(TMR_Reader *reader, uint32_t currentBaudRate)
+       {
+         /*
+          * Modules with firmware older than wilder will throw 0x105 error, as it was not 
+-         * implemented. Catch this error and but do not return.
++         * implemented. Catch this error but do not return.
+          */
+ 		sr->productId = 0xFFFF;
+       }
+@@ -497,7 +497,7 @@ TMR_SR_boot(TMR_Reader *reader, uint32_t currentBaudRate)
+ 
+   /**
+    * Enable the extended EPC flag in case
+-   * of M5E and its varients
++   * of M5E and its variants
+    */
+   if ((TMR_SR_MODEL_M6E != sr->versionInfo.hardware[0]) &&
+       (TMR_SR_MODEL_MICRO != sr->versionInfo.hardware[0]) &&
+@@ -4020,7 +4020,7 @@ TMR_SR_paramGet(struct TMR_Reader *reader, TMR_Param key, void *value)
+     case TMR_SR_MODEL_MICRO:
+       {
+         /**
+-         * Micro has following varients.
++         * Micro has following variants.
+          **/
+         switch (sr->versionInfo.hardware[3])
+         {
+@@ -4751,7 +4751,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_GetSensorValue op;
+ 
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -4773,7 +4773,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_GetMeasurementSetup op;
+ 
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -4795,7 +4795,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_GetCalibrationData op;
+ 
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -4817,7 +4817,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_SetCalibrationData op;
+ 
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -4839,7 +4839,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_SetSfeParameters op;
+ 
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -4862,7 +4862,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_GetLogState op;
+ 
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -4884,7 +4884,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_SetLogMode op;
+ 
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -4907,7 +4907,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_Initialize op;
+       
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -4930,7 +4930,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_EndLog op;
+ 
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -4952,7 +4952,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_SetPassword op;
+ 
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -4974,7 +4974,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_AccessFifoStatus op;
+       
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -4995,7 +4995,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_AccessFifoRead op;
+ 
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -5016,7 +5016,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_AccessFifoWrite op;
+ 
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -5037,7 +5037,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_StartLog op;
+       
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -5059,7 +5059,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_GetBatteryLevel op;
+ 
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -5081,7 +5081,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_SetLogLimits op;
+ 
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+@@ -5103,7 +5103,7 @@ TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *
+     {
+       TMR_TagOp_GEN2_IDS_SL900A_SetShelfLife op;
+ 
+-      /* Set the protocol for tag opearation */
++      /* Set the protocol for tag operation */
+       ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+       if (TMR_SUCCESS != ret)
+       {
+diff --git a/serial_reader_imp.h b/serial_reader_imp.h
+index 9f5fd54..a96405f 100644
+--- a/serial_reader_imp.h
++++ b/serial_reader_imp.h
+@@ -467,7 +467,7 @@ typedef struct TMR_SR_Gen2ReaderWriteTimeOut
+   /* Status of reader timeout */
+   bool earlyexit;
+ 
+-  /* Timeout value used for write opearation */
++  /* Timeout value used for write operation */
+   uint16_t writetimeout;
+ }TMR_SR_Gen2ReaderWriteTimeOut;
+ /**
+@@ -677,11 +677,11 @@ TMR_Status TMR_SR_cmdSL900aGetBatteryLevel(TMR_Reader *reader, uint16_t timeout,
+                                            uint8_t CommandCode, uint32_t password, PasswordLevel level,BatteryType type,
+                                            TMR_uint8List *data, TMR_TagFilter* target);
+ TMR_Status TMR_SR_cmdSL900aAccessFifoStatus(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t CommandCode,
+-           uint32_t password, PasswordLevel level, AccessFifoOperation opearation, TMR_uint8List * data, TMR_TagFilter* target);
++           uint32_t password, PasswordLevel level, AccessFifoOperation operation, TMR_uint8List * data, TMR_TagFilter* target);
+ TMR_Status TMR_SR_cmdSL900aAccessFifoRead(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t CommandCode,
+-            uint32_t password, PasswordLevel level, AccessFifoOperation opearation, uint8_t length,TMR_uint8List * data, TMR_TagFilter* target);
++            uint32_t password, PasswordLevel level, AccessFifoOperation operation, uint8_t length,TMR_uint8List * data, TMR_TagFilter* target);
+ TMR_Status TMR_SR_cmdSL900aAccessFifoWrite(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t CommandCode,
+-           uint32_t password, PasswordLevel level, AccessFifoOperation opearation, TMR_uint8List *payLoad, TMR_uint8List * data, TMR_TagFilter* target);
++           uint32_t password, PasswordLevel level, AccessFifoOperation operation, TMR_uint8List *payLoad, TMR_uint8List * data, TMR_TagFilter* target);
+ TMR_Status TMR_SR_cmdHibikiReadLock(TMR_Reader *reader, uint16_t timeout,
+             TMR_GEN2_Password accessPassword, uint16_t mask, uint16_t action);
+ TMR_Status TMR_SR_cmdHibikiGetSystemInformation(TMR_Reader *reader, uint16_t timeout,
+@@ -945,7 +945,7 @@ TMR_SR_msgAddIdsSL900aSetPassword(uint8_t *msg, uint8_t *i, uint16_t timeout, TM
+                                   PasswordLevel newPasswordLevel, TMR_TagFilter* target);
+ void 
+ TMR_SR_msgAddIdsSL900aAccessFifoStatus(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+-                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, AccessFifoOperation opearation,
++                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, AccessFifoOperation operation,
+                                   TMR_TagFilter* target);
+ void 
+ TMR_SR_msgAddIdsSL900aGetBatteryLevel(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+@@ -953,11 +953,11 @@ TMR_SR_msgAddIdsSL900aGetBatteryLevel(uint8_t *msg, uint8_t *i, uint16_t timeout
+                                       TMR_TagFilter* target);
+ void 
+ TMR_SR_msgAddIdsSL900aAccessFifoRead(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+-                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, AccessFifoOperation opearation,
++                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, AccessFifoOperation operation,
+                                   uint8_t length, TMR_TagFilter* target);
+ void 
+ TMR_SR_msgAddIdsSL900aAccessFifoWrite(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+-                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, AccessFifoOperation opearation,
++                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, AccessFifoOperation operation,
+                                   TMR_uint8List *payLoad, TMR_TagFilter* target);
+ void 
+ TMR_SR_msgAddIdsSL900aStartLog(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+diff --git a/serial_reader_l3.c b/serial_reader_l3.c
+index 99986bf..c20af74 100644
+--- a/serial_reader_l3.c
++++ b/serial_reader_l3.c
+@@ -360,7 +360,7 @@ retryHeader:
+      }
+ 
+     /* We got a response for a different command than the one we
+-     * sent. This usually means we recieved the boot-time message from
++     * sent. This usually means we received the boot-time message from
+      * a M6e, and thus that the device was rebooted somewhere between
+      * the previous command and this one. Report this as a problem.
+      */
+@@ -1756,7 +1756,7 @@ TMR_SR_parseMetadataFromMessage(TMR_Reader *reader, TMR_TagReadData *read, uint1
+ 	}
+ 
+   /**
+-   * if the gen2AllMemoryBankEnabled is enbled,
++   * if the gen2AllMemoryBankEnabled is enabled,
+    * extract the values
+    **/
+   if (reader->u.serialReader.gen2AllMemoryBankEnabled)
+@@ -3778,7 +3778,7 @@ TMR_SR_msgSetupMultipleProtocolSearch(TMR_Reader *reader, uint8_t *msg, TMR_SR_O
+     case TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE:
+       {
+         /**
+-        * simple read plan uses this funcution, only when tagop is NULL,
++        * simple read plan uses this function, only when tagop is NULL,
+         * s0, need to check for simple read plan tagop.
+         **/
+         if (TMR_READ_PLAN_TYPE_MULTI == reader->readParams.readPlan->type)
+@@ -5162,7 +5162,7 @@ void TMR_SR_msgAddIdsSL900aGetBatteryLevel(uint8_t *msg, uint8_t *i, uint16_t ti
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param data If the operation is success, this data contains the requested value
+  * @param target Filter to be applied.
+@@ -5234,7 +5234,7 @@ void TMR_SR_msgAddIdsSL900aGetSensorValue(uint8_t *msg, uint8_t *i, uint16_t tim
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param data If the operation is success, this data contains the requested value
+  * @param target Filter to be applied.
+@@ -5304,7 +5304,7 @@ void TMR_SR_msgAddIdsSL900aGetMeasurementSetup(uint8_t *msg, uint8_t *i, uint16_
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param data If the operation is success, this data contains the requested value
+  * @param target Filter to be applied.
+@@ -5374,7 +5374,7 @@ void TMR_SR_msgAddIdsSL900aGetLogState(uint8_t *msg, uint8_t *i, uint16_t timeou
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param to specify SL900A sensor type
+  * @param data If the operation is success, this data contains the requested value
+@@ -5459,7 +5459,7 @@ void TMR_SR_msgAddIdsSL900aSetLogMode(uint8_t *msg, uint8_t *i, uint16_t timeout
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param level IDS password level
+  * @param form IDS logging form
+@@ -5518,7 +5518,7 @@ void TMR_SR_msgAddIdsSL900aInitialize(uint8_t *msg, uint8_t *i, uint16_t timeout
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param delayTime to secify delayTime
+  * @param applicatioData to specify applicationData
+@@ -5569,7 +5569,7 @@ void TMR_SR_msgAddIdsSL900aEndLog(uint8_t *msg, uint8_t *i, uint16_t timeout, TM
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param data If the operation is success, this data contains the requested value
+  * @param target Filter to be applied.
+@@ -5589,7 +5589,7 @@ TMR_SR_cmdSL900aEndLog(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password a
+ }
+ 
+ /**
+- * Helper funcution to form the IDS SL900A SetPassword command
++ * Helper function to form the IDS SL900A SetPassword command
+  */ 
+ void TMR_SR_msgAddIdsSL900aSetPassword(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                        uint8_t CommandCode, uint32_t password, PasswordLevel level, uint32_t newPassword,
+@@ -5619,7 +5619,7 @@ void TMR_SR_msgAddIdsSL900aSetPassword(uint8_t *msg, uint8_t *i, uint16_t timeou
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param data If the operation is success, this data contains the requested value
+  * @param target Filter to be applied.
+@@ -5669,7 +5669,7 @@ void TMR_SR_msgAddIdsSL900aAccessFifoStatus(uint8_t *msg, uint8_t *i, uint16_t t
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param data If the operation is success, this data contains the requested value
+  * @param target Filter to be applied.
+@@ -5740,7 +5740,7 @@ void TMR_SR_msgAddIdsSL900aAccessFifoRead(uint8_t *msg, uint8_t *i, uint16_t tim
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param data If the operation is success, this data contains the requested value
+  * @param target Filter to be applied.
+@@ -5814,7 +5814,7 @@ void TMR_SR_msgAddIdsSL900aAccessFifoWrite(uint8_t *msg, uint8_t *i, uint16_t ti
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param data If the operation is success, this data contains the requested value
+  * @param target Filter to be applied.
+@@ -5885,7 +5885,7 @@ void TMR_SR_msgAddIdsSL900aStartLog(uint8_t *msg, uint8_t *i, uint16_t timeout,
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param startTime to specify count start time
+  * @param target Filter to be applied.
+@@ -5932,7 +5932,7 @@ void TMR_SR_msgAddIdsSL900aGetCalibrationData(uint8_t *msg, uint8_t *i, uint16_t
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param data If the operation is success, this data contains the requested value
+  * @param target Filter to be applied.
+@@ -6017,7 +6017,7 @@ void TMR_SR_msgAddIdsSL900aSetCalibrationData(uint8_t *msg, uint8_t *i, uint16_t
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param calibration to spcify the calibration data
+  * @param target Filter to be applied.
+@@ -6067,7 +6067,7 @@ void TMR_SR_msgAddIdsSL900aSetSfeParameters(uint8_t *msg, uint8_t *i, uint16_t t
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param sfe to spcify the sfe parameters
+  * @param target Filter to be applied.
+@@ -6184,7 +6184,7 @@ void TMR_SR_msgAddIdsSL900aSetShelfLife(uint8_t *msg, uint8_t *i, uint16_t timeo
+  * @param reader The reader
+  * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+  * @param accessPassword The access password to use to write on the tag
+- * @param commandcode to specify the opearation
++ * @param commandcode to specify the operation
+  * @param password to specify SL900A password access level values
+  * @param data If the operation is success, this data contains the requested value
+  * @param target Filter to be applied.
+@@ -6809,7 +6809,7 @@ TMR_SR_cmdResetReaderStatistics(TMR_Reader *reader, TMR_SR_ReaderStatisticsFlag
+ 
+ 
+ /**
+- * Helper funcution to be used in GetReaderStats
++ * Helper function to be used in GetReaderStats
+  */ 
+ TMR_Status
+ TMR_fillReaderStats(TMR_Reader *reader, TMR_Reader_StatsValues* stats, uint16_t flag, uint8_t* msg, uint8_t offset)
+diff --git a/tm_config.h b/tm_config.h
+index 989fa86..691b095 100644
+--- a/tm_config.h
++++ b/tm_config.h
+@@ -153,14 +153,14 @@ Note:To run readsync_baremetal codelet you have to
+ 
+ /**
+  * Enabling  this option will enable the support for the parameters defined 
+- * in stdio.h header file like FILE *. This check is required as stdio.h doese not
++ * in stdio.h header file like FILE *. This check is required as stdio.h does not
+  * exist in some of the embedded  architectures.
+  */
+ #define  TMR_ENABLE_STDIO
+   
+ /**
+  * Enabling  this option will enable the support for the parameters defined 
+- * in string.h header file like sterror(). This check is required as string.h doese not
++ * in string.h header file like strerror(). This check is required as string.h does not
+  * exist in some of the embedded  architectures.
+  */
+ #define  TMR_USE_STRERROR
+@@ -214,14 +214,14 @@ Note:To run readsync_baremetal codelet you have to
+ 
+ /**
+  * Enabling  this option will enable the support for the parameters defined 
+- * in stdio.h header file like FILE *. This check is required as stdio.h doese not
++ * in stdio.h header file like FILE *. This check is required as stdio.h does not
+  * exist in some of the embedded  architectures.
+  */
+ #undef  TMR_ENABLE_STDIO
+   
+ /**
+  * Enabling  this option will enable the support for the parameters defined 
+- * in string.h header file like sterror(). This check is required as string.h doese not
++ * in string.h header file like strerror(). This check is required as string.h does not
+  * exist in some of the embedded  architectures.
+  */
+ #undef  TMR_USE_STRERROR
+diff --git a/tm_reader.c b/tm_reader.c
+index 5ba8edf..1b71dec 100644
+--- a/tm_reader.c
++++ b/tm_reader.c
+@@ -3058,7 +3058,7 @@ TMR_init_GEN2_Impinj_Monza4_Payload(TMR_Monza4_Payload *payload)
+ }
+ 
+ /**
+- * Helper funcution to update or modifying the sfe parameters
++ * Helper function to update or modifying the sfe parameters
+  */
+ TMR_Status
+ TMR_update_GEN2_IDS_SL900A_SfeParameters(TMR_TagOp_GEN2_IDS_SL900A_SfeParameters *sfe)
+@@ -3122,7 +3122,7 @@ TMR_update_GEN2_IDS_SL900A_SfeParameters(TMR_TagOp_GEN2_IDS_SL900A_SfeParameters
+ }
+ 
+ /**
+- * Helper funcution to update or modifying the calibration Data
++ * Helper function to update or modifying the calibration Data
+  */
+ TMR_Status
+ TMR_update_GEN2_IDS_SL900A_CalibrationData(TMR_TagOp_GEN2_IDS_SL900A_CalibrationData *cal)
+@@ -3219,7 +3219,7 @@ TMR_update_GEN2_IDS_SL900A_CalibrationData(TMR_TagOp_GEN2_IDS_SL900A_Calibration
+ }
+ 
+ /**
+- * Helper funcution to set the calibration Data
++ * Helper function to set the calibration Data
+  */
+ TMR_Status
+ TMR_init_GEN2_IDS_SL900A_CalibrationData(uint8_t byte[7], TMR_TagOp_GEN2_IDS_SL900A_CalibrationData *cal)
+@@ -3249,7 +3249,7 @@ TMR_init_GEN2_IDS_SL900A_CalibrationData(uint8_t byte[7], TMR_TagOp_GEN2_IDS_SL9
+ }
+ 
+ /**
+- * Helper funcution to set the sfe parameters
++ * Helper function to set the sfe parameters
+  */
+ TMR_Status
+ TMR_init_GEN2_IDS_SL900A_SfeParameters(uint8_t byte[2], TMR_TagOp_GEN2_IDS_SL900A_SfeParameters *sfe)
+diff --git a/tm_reader.h b/tm_reader.h
+index 559c0c5..49630cf 100644
+--- a/tm_reader.h
++++ b/tm_reader.h
+@@ -130,9 +130,9 @@ typedef enum TMR_Reader_StatsFlag
+   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 uints of Khz */
++  /** Current frequency in units of Khz */
+   TMR_READER_STATS_FLAG_FREQUENCY = (1 << 7),
+-  /** Current temperature of the device in units of Celcius */
++  /** 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),
+@@ -381,7 +381,7 @@ struct TMR_Reader
+   bool isStopNTags;
+   /* Param wait indicator for Reader and protocol param control during continuous read */
+   bool paramWait;
+-  /* Param responsefor Reader and protocol param control during continuous read */
++  /* Param response for Reader and protocol param control during continuous read */
+   uint8_t paramMessage[256];
+   /* True Continuous Read Start indicator */
+   bool hasContinuousReadStarted;
+@@ -1013,7 +1013,7 @@ 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 recieved from the reader.
++ * 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
+@@ -1027,7 +1027,7 @@ TMR_Status TMR_addTransportListener(TMR_Reader *reader, TMR_TransportListenerBlo
+  * @ingroup reader
+  * 
+  * Remove a listener from the list of functions that will be called
+- * for each message sent to or recieved from the reader.
++ * 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
+@@ -1179,9 +1179,9 @@ TMR_Status TMR_stopReading(struct TMR_Reader *reader);
+ 
+ /**
+  * @ingroup reader
+- * Stores the transport init function againest the provided scheme.
++ * Stores the transport init function against the provided scheme.
+  *
+- * @param scheme the transport schme name.
++ * @param scheme the transport scheme name.
+  * @param nativeInit reference to the init function.
+  */ 
+ TMR_Status TMR_setSerialTransport(char* scheme, TMR_TransportNativeInit nativeInit);
+@@ -1197,14 +1197,14 @@ const char *TMR_strerr(TMR_Reader *reader, TMR_Status status);
+ 
+ /**
+  * @ingroup reader
+- * This funcution will initialize the
++ * This function will initialize the
+  * TMR_StatValues structure with the default values
+  */
+ TMR_Status TMR_STATS_init(TMR_Reader_StatsValues *stats);
+ 
+ /**
+  * @ingroup reader
+- * This funcution loads the reader configuration parameters from file and applies to module.
++ * 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.
+@@ -1213,7 +1213,7 @@ TMR_Status TMR_loadConfig(struct TMR_Reader *reader, char *filePath);
+ 
+ /**
+  * @ingroup reader
+- * This funcution saves the current reader configuration parameters and its values to a file.
++ * 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.
+diff --git a/tmr_gen2.h b/tmr_gen2.h
+index 311ad27..9696f61 100644
+--- a/tmr_gen2.h
++++ b/tmr_gen2.h
+@@ -135,7 +135,7 @@ typedef struct TMR_GEN2_Select
+   bool invert;
+   /** The memory bank in which to compare the mask */
+   TMR_GEN2_Bank bank;
+-  /** The location (in bits) at which t to begin comparing the mask */
++  /** The location (in bits) at which to begin comparing the mask */
+   uint32_t bitPointer;
+   /** The length (in bits) of the mask */
+   uint16_t maskBitLength;
+diff --git a/tmr_params.h b/tmr_params.h
+index 581c5d2..d48c9bc 100644
+--- a/tmr_params.h
++++ b/tmr_params.h
+@@ -67,7 +67,7 @@ typedef enum TMR_Param
+   TMR_PARAM_ANTENNA_PORTSWITCHGPOS,
+   /** "/reader/antenna/settlingTimeList", TMR_PortValueList  */
+   TMR_PARAM_ANTENNA_SETTLINGTIMELIST,
+-  /** "reader/antenna/returnLoss", TMR_PortValueList */
++  /** "/reader/antenna/returnLoss", TMR_PortValueList */
+   TMR_PARAM_ANTENNA_RETURNLOSS,
+   /** "/reader/antenna/txRxMap", TMR_AntennaMapList  */
+   TMR_PARAM_ANTENNA_TXRXMAP,
+@@ -85,15 +85,15 @@ typedef enum TMR_Param
+   TMR_PARAM_GEN2_SESSION,
+   /** "/reader/gen2/target", TMR_GEN2_Target */
+   TMR_PARAM_GEN2_TARGET,
+-  /** "/reader/gen2/BLF", TMR_Gen2_LinkFrequency */
++  /** "/reader/gen2/BLF", TMR_GEN2_LinkFrequency */
+   TMR_PARAM_GEN2_BLF,
+-  /** "/reader/gen2/tari", TMR_Gen2_Tari */
++  /** "/reader/gen2/tari", TMR_GEN2_Tari */
+   TMR_PARAM_GEN2_TARI,
+-  /**"/reader/gen2/writeMode", TMR_Gen2_WriteMode*/
++  /**"/reader/gen2/writeMode", TMR_GEN2_WriteMode */
+   TMR_PARAM_GEN2_WRITEMODE,
+-  /** "/reader/gen2/bap", TMR_Gen2_Bap */
++  /** "/reader/gen2/bap", TMR_GEN2_Bap */
+   TMR_PARAM_GEN2_BAP,
+-  /** "/reader/gen2/protocolExtension", TMR_PARAM_GEN2_PROTOCOLEXTENSION */
++  /** "/reader/gen2/protocolExtension", TMR_GEN2_ProtocolExtension */
+   TMR_PARAM_GEN2_PROTOCOLEXTENSION,
+   /** "/reader/iso180006b/BLF", TMR_ISO180006B_LinkFrequency */
+   TMR_PARAM_ISO180006B_BLF,
+@@ -107,7 +107,7 @@ typedef enum TMR_Param
+   TMR_PARAM_READ_ASYNCONTIME,
+   /** "/reader/read/plan", TMR_ReadPlan */
+   TMR_PARAM_READ_PLAN,
+-  /** "/reader/radio/enablePowerSave, bool **/
++  /** "/reader/radio/enablePowerSave", bool **/
+   TMR_PARAM_RADIO_ENABLEPOWERSAVE,
+   /** "/reader/radio/powerMax", int16_t */
+   TMR_PARAM_RADIO_POWERMAX,
+@@ -165,7 +165,7 @@ typedef enum TMR_Param
+   TMR_PARAM_EXTENDEDEPC,
+   /** "/reader/statistics", TMR_SR_ReaderStatistics */
+   TMR_PARAM_READER_STATISTICS,
+-  /** "/reader/stats", TMR_ */
++  /** "/reader/stats", TMR_Reader_StatsValues */
+   TMR_PARAM_READER_STATS,
+   /** "/reader/uri", TMR_String */
+   TMR_PARAM_URI,
+@@ -193,7 +193,7 @@ typedef enum TMR_Param
+   TMR_PARAM_TAGREADDATA_UNIQUEBYPROTOCOL,
+   /** "/reader/description", TMR_String */
+   TMR_PARAM_READER_DESCRIPTION,
+-  /** "reader/hostname", TMR_String */
++  /** "/reader/hostname", TMR_String */
+   TMR_PARAM_READER_HOSTNAME,
+   /** "/reader/currentTime", struct tm */
+   TMR_PARAM_CURRENTTIME,
+@@ -201,12 +201,13 @@ typedef enum TMR_Param
+ 	TMR_PARAM_READER_WRITE_REPLY_TIMEOUT,
+ 	/** "/reader/gen2/writeEarlyExit", bool */
+ 	TMR_PARAM_READER_WRITE_EARLY_EXIT,
+-  /** "reader/stats/enable", TMR_StatsEnable */
++  /** "/reader/stats/enable", TMR_StatsEnable */
+   TMR_PARAM_READER_STATS_ENABLE,
+   /** "/reader/trigger/read/Gpi", TMR_uint8List */
+   TMR_PARAM_TRIGGER_READ_GPI,
+   /** "/reader/metadataflags", TMR_TRD_MetadataFlag*/
+   TMR_PARAM_METADATAFLAG,
++  /** "/reader/licensedFeatures", TMR_uint8List */
+   TMR_PARAM_LICENSED_FEATURES,
+   TMR_PARAM_SELECTED_PROTOCOLS,
+   TMR_PARAM_END,
+diff --git a/tmr_serial_reader.h b/tmr_serial_reader.h
+index b246277..bca3fe9 100644
+--- a/tmr_serial_reader.h
++++ b/tmr_serial_reader.h
+@@ -169,7 +169,7 @@ typedef struct TMR_SR_GEN2_Q
+ } TMR_SR_GEN2_Q;
+ 
+ 
+-/** An antenna port with an associated uint16_t value. */
++/** An antenna port with an associated int32_t value. */
+ typedef struct TMR_PortValue
+ {
+   /** The port number */
+@@ -309,7 +309,7 @@ typedef struct TM_SR_SerialReader
+   int tagsRemaining;
+   /* Buffer tag records fetched from module but not yet passed to caller. */
+   uint8_t bufResponse[TMR_SR_MAX_PACKET_SIZE];
+-  /* bufResopnse read index */
++  /* bufResponse read index */
+   uint8_t bufPointer;
+   /* Number of tag records in buffer but not yet passed to caller */
+   uint8_t tagsRemainingInBuffer;
+diff --git a/tmr_serial_transport.h b/tmr_serial_transport.h
+index c618d1e..290cf23 100644
+--- a/tmr_serial_transport.h
++++ b/tmr_serial_transport.h
+@@ -80,7 +80,7 @@ struct TMR_SR_SerialTransport
+   /**
+    * This callback causes the communication interface to be opened but
+    * does not transmit any serial-layer data. This should perform
+-   * actionms such as opening a serial port device or establishing a
++   * actions such as opening a serial port device or establishing a
+    * network connection within a wrapper protocol.
+    *
+    * @param this The TMR_SR_SerialTransport structure.
+@@ -109,7 +109,7 @@ struct TMR_SR_SerialTransport
+    * @param this The TMR_SR_SerialTransport structure.
+    * @param length The number of bytes to receive.
+    * @param[out] messageLength The number of bytes received.
+-   * @param[out] message Pointer to the location to store recieved bytes.
++   * @param[out] message Pointer to the location to store received bytes.
+    * @param timeoutMs The duration for the operation to complete.
+    */
+   TMR_Status (*receiveBytes)(TMR_SR_SerialTransport *, uint32_t length,
+diff --git a/tmr_status.h b/tmr_status.h
+index 50ccc16..2832184 100644
+--- a/tmr_status.h
++++ b/tmr_status.h
+@@ -78,7 +78,7 @@ typedef uint32_t TMR_Status;
+ #define TMR_ERROR_INVALID_BAUD_RATE                       TMR_ERROR_CODE(0x10a)
+ /**Region is not supported. */
+ #define TMR_ERROR_INVALID_REGION                          TMR_ERROR_CODE(0x10b)
+-/** License key code in invalid */
++/** License key code is invalid */
+ #define TMR_ERROR_INVALID_LICENSE_KEY                     TMR_ERROR_CODE(0x10c)
+ /**Firmware is corrupt: Checksum doesn't match content. */
+ #define TMR_ERROR_BL_INVALID_IMAGE_CRC                    TMR_ERROR_CODE(0x200)
+@@ -137,10 +137,10 @@ typedef uint32_t TMR_Status;
+ /**Internal reader error.  Contact support. */
+ #define TMR_ERROR_GEN2_PROTOCOL_MEMORY_OVERRUN_BAD_PC     TMR_ERROR_CODE(0x423)
+ /**Internal reader error.  Contact support. */
+-#define TMR_ERROR_GEN2_PROCOCOL_MEMORY_LOCKED             TMR_ERROR_CODE(0x424)
++#define TMR_ERROR_GEN2_PROTOCOL_MEMORY_LOCKED             TMR_ERROR_CODE(0x424)
+ /**Authentication failed with specified key. */
+ #define TMR_ERROR_GEN2_PROTOCOL_V2_AUTHEN_FAILED				TMR_ERROR_CODE(0x425)
+-/** Untrace opearation failed. */
++/** Untrace operation failed. */
+ #define TMR_ERROR_GEN2_PROTOCOL_V2_UNTRACE_FAILED				TMR_ERROR_CODE(0x426)
+ /**Internal reader error.  Contact support. */
+ #define TMR_ERROR_GEN2_PROTOCOL_INSUFFICIENT_POWER        TMR_ERROR_CODE(0x42b)
+diff --git a/tmr_strerror.c b/tmr_strerror.c
+index 211695c..4540a5a 100644
+--- a/tmr_strerror.c
++++ b/tmr_strerror.c
+@@ -174,7 +174,7 @@ TMR_strerr(TMR_Reader *reader, TMR_Status status)
+     return "Other Gen2 error";
+   case TMR_ERROR_GEN2_PROTOCOL_MEMORY_OVERRUN_BAD_PC:
+     return "Gen2 memory overrun - bad PC";
+-  case TMR_ERROR_GEN2_PROCOCOL_MEMORY_LOCKED:\
++  case TMR_ERROR_GEN2_PROTOCOL_MEMORY_LOCKED:
+     return "Gen2 memory locked";
+   case TMR_ERROR_GEN2_PROTOCOL_INSUFFICIENT_POWER:
+     return "Gen2 tag has insufficent power for operation";
+@@ -185,7 +185,7 @@ TMR_strerr(TMR_Reader *reader, TMR_Status status)
+ 	case TMR_ERROR_GEN2_PROTOCOL_V2_AUTHEN_FAILED:
+ 		return "Authentication failed with specified key.";
+ 	case TMR_ERROR_GEN2_PROTOCOL_V2_UNTRACE_FAILED:
+-		return "Untrace opearation failed.";
++		return "Untrace operation failed.";
+   case TMR_ERROR_AHAL_INVALID_FREQ:
+     return "Invalid frequency";
+   case TMR_ERROR_AHAL_CHANNEL_OCCUPIED:
+diff --git a/tmr_tag_data.h b/tmr_tag_data.h
+index 2f1ad8e..be42c53 100644
+--- a/tmr_tag_data.h
++++ b/tmr_tag_data.h
+@@ -140,7 +140,7 @@ typedef struct TMR_TagReadData
+   uint8_t gpioCount;
+   /** Number of times the tag was read */
+   uint32_t readCount;
+-  /** Strength of the signal recieved from the tag */
++  /** Strength of the signal received from the tag */
+   int32_t rssi;
+   /** RF carrier frequency the tag was read with */
+   uint32_t frequency;
+diff --git a/tmr_tag_protocol.h b/tmr_tag_protocol.h
+index 1c47fce..da5b267 100644
+--- a/tmr_tag_protocol.h
++++ b/tmr_tag_protocol.h
+@@ -67,4 +67,4 @@ typedef struct TMR_TagProtocolList
+ #endif
+ 
+ 
+-#endif /* _TMR_TAG_PROTOCL_H_ */
++#endif /* _TMR_TAG_PROTOCOL_H_ */
+diff --git a/tmr_tagop.h b/tmr_tagop.h
+index eb92f85..7b22248 100644
+--- a/tmr_tagop.h
++++ b/tmr_tagop.h
+@@ -363,7 +363,7 @@ typedef struct SecurePasswordLookup
+ 
+ typedef struct TMR_TagOp_GEN2_SecureReadData
+ {
+-  /** Gen2 read opearation */
++  /** Gen2 read operation */
+   TMR_TagOp_GEN2_ReadData readData;
+ 
+   /** type of Gen2 Secure operation*/
+@@ -1291,7 +1291,7 @@ typedef struct TMR_TagOp_GEN2_IDS_SL900A_Initialize
+   Delay delayTime;
+ }TMR_TagOp_GEN2_IDS_SL900A_Initialize;
+ 
+-/** Sub-Class for specifying AccessFifo opearation */
++/** Sub-Class for specifying AccessFifo operation */
+ typedef enum AccessFifoOperation
+ {
+   /* Read from FIFO */
+@@ -1312,7 +1312,7 @@ typedef struct TMR_TagOp_GEN2_IDS_SL900A_AccessFifo
+   uint32_t AccessPassword;
+   /* IDS SL900A Password */
+   uint32_t Password;
+-  /* specify the opearationn do be done on fifo */
++  /* specify the operation do be done on fifo */
+   AccessFifoOperation operation;
+ }TMR_TagOp_GEN2_IDS_SL900A_AccessFifo;
+ 
diff --git a/cbits/api/patches/windows-time.patch b/cbits/api/patches/windows-time.patch
new file mode 100644
--- /dev/null
+++ b/cbits/api/patches/windows-time.patch
@@ -0,0 +1,55 @@
+diff --git a/osdep_win32.c b/osdep_win32.c
+index ba65bfa..4ea7603 100644
+--- a/osdep_win32.c
++++ b/osdep_win32.c
+@@ -31,8 +31,8 @@
+ #include <time.h>
+ #include "osdep.h"
+ 
+-/* FILETIME of Jan 1 1970 00:00:00. */
+-static const unsigned __int64 epoch = ((unsigned __int64) 116444736000000000ULL);
++// https://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux
++#define SEC_TO_UNIX_EPOCH 11644473600LL
+ 
+ uint64_t
+ tmr_gettime()
+@@ -41,35 +41,25 @@ tmr_gettime()
+   SYSTEMTIME st;
+   FILETIME ft;
+   LARGE_INTEGER li;    
+-  struct timeval tv;
+   GetSystemTime(&st);
+   SystemTimeToFileTime(&st, &ft);
+   li.LowPart = ft.dwLowDateTime;
+   li.HighPart = ft.dwHighDateTime;
+-  tv.tv_sec = (long) ((li.QuadPart - epoch) / 10000000L);
+-  tv.tv_usec =(long) (st.wMilliseconds * 1000);
+-  totalms = (((uint64_t)tv.tv_sec) * 1000) + ((uint64_t) tv.tv_usec) / 1000;
++  totalms=(((uint64_t)li.LowPart) | ((uint64_t)li.HighPart)<<32)/10000;
++  totalms -= SEC_TO_UNIX_EPOCH * 1000;
+   return totalms;
+ }
+ 
+ uint32_t
+ tmr_gettime_low()
+ {
+-  SYSTEMTIME st;
+-  FILETIME ft;
+-  GetSystemTime(&st);
+-  SystemTimeToFileTime(&st, &ft);
+-  return ft.dwLowDateTime;
++  return (uint32_t) tmr_gettime();
+ }
+ 
+ uint32_t
+ tmr_gettime_high()
+ {
+-  SYSTEMTIME st;
+-  FILETIME ft;
+-  GetSystemTime(&st);
+-  SystemTimeToFileTime(&st, &ft);
+-  return ft.dwHighDateTime;
++  return (uint32_t) (tmr_gettime() >> 32);
+ }
+ 
+ void
diff --git a/cbits/api/serial_reader.c b/cbits/api/serial_reader.c
new file mode 100644
--- /dev/null
+++ b/cbits/api/serial_reader.c
@@ -0,0 +1,6169 @@
+/**
+ *  @file serial_reader.c
+ *  @brief Mercury API - serial reader high level implementation
+ *  @author Nathan Williams
+ *  @date 10/28/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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "tm_reader.h"
+#include "serial_reader_imp.h"
+#include "tmr_utils.h"
+#include "osdep.h"
+
+#define HASPORT(mask, port) ((1 << ((port)-1)) & (mask))
+#define TMR_MAX_PROTOCOLS   (32)
+
+#ifdef TMR_ENABLE_SERIAL_READER
+
+static TMR_Status
+initTxRxMapFromPorts(TMR_Reader *reader)
+{
+  TMR_Status ret;
+  TMR_SR_PortDetect ports[TMR_SR_MAX_ANTENNA_PORTS];
+  uint8_t i, numPorts;
+  TMR_SR_SerialReader *sr;
+
+  numPorts = numberof(ports);
+  sr = &reader->u.serialReader;
+
+  /* Need number of ports to set up Tx-Rx map */
+  ret = TMR_SR_cmdAntennaDetect(reader, &numPorts, ports);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  sr->portMask = 0;
+
+  /* Modify TxRxMap according to reader product */
+  switch (sr->productId)
+  {
+    case 0x0001:
+    {
+      /* Ruggedized Reader (Tool Link, Vega) */
+      TMR_AntennaMap newMap[] = {{1,2,2}, {2,5,5}, {3,1,1}};
+      numPorts = 3;
+
+      for (i = 0; i < numPorts; i++)
+      {
+        sr->portMask |= 1 << (newMap[i].antenna - 1);
+        sr->staticTxRxMapData[i].antenna = newMap[i].antenna;
+        sr->staticTxRxMapData[i].rxPort  = newMap[i].rxPort;
+        sr->staticTxRxMapData[i].txPort  = newMap[i].txPort;
+
+        if (0 == reader->tagOpParams.antenna && ports[i].detected)
+        {
+          reader->tagOpParams.antenna = ports[i].port;
+        }
+      }
+      break;
+    }
+
+    case 0x0002:
+      /*
+       * USB Reader -- Default map is okay
+       * M5e-C only has 1 antenna port, anyway
+       *
+       * However, M6eMicro USB has 2 ports and no auto antenna detection,
+       * so manually limit to first port for now.
+       * TODO: Revisit if M6eMicro USB starts supporting port 2 in future.
+       * port for now.
+       */
+      if ((TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0]) &&
+        (sr->versionInfo.hardware[3] == TMR_SR_MODEL_M6E_MICRO_USB))
+      {
+        numPorts = 1;
+
+        /* skip the antenna port 2 */
+        for (i = 0; i < numPorts; i++)
+        {
+          sr->portMask |= 1 << (ports[i].port - 1);
+          sr->staticTxRxMapData[i].antenna = ports[i].port;
+          sr->staticTxRxMapData[i].txPort = ports[i].port;
+          sr->staticTxRxMapData[i].rxPort = ports[i].port;
+
+          if (0 == reader->tagOpParams.antenna && ports[i].detected)
+          {
+            reader->tagOpParams.antenna = ports[i].port;
+          }
+        }
+        break;
+      }
+    default:
+    {
+      for (i = 0; i < numPorts; i++)
+      {
+        sr->portMask |= 1 << (ports[i].port - 1);
+        sr->staticTxRxMapData[i].antenna = ports[i].port;
+        sr->staticTxRxMapData[i].txPort = ports[i].port;
+        sr->staticTxRxMapData[i].rxPort = ports[i].port;
+
+        if (0 == reader->tagOpParams.antenna && ports[i].detected)
+        {
+          reader->tagOpParams.antenna = ports[i].port;
+        }
+      }
+      break;
+    }
+  }
+
+  sr->staticTxRxMap.max = TMR_SR_MAX_ANTENNA_PORTS;
+  sr->staticTxRxMap.len = numPorts;
+  sr->staticTxRxMap.list = sr->staticTxRxMapData;
+  sr->txRxMap = &sr->staticTxRxMap;
+
+  return TMR_SUCCESS;
+}
+
+static TMR_Status
+TMR_SR_configPreamble(TMR_SR_SerialReader *sr)
+{
+  TMR_Status ret = TMR_SUCCESS;
+  bool value;
+
+  /* Only some readers support wakeup preambles */
+  switch (sr->versionInfo.hardware[0])
+  {
+  case TMR_SR_MODEL_M6E:
+  case TMR_SR_MODEL_MICRO:
+  case TMR_SR_MODEL_M6E_I:
+    value = true;
+    break;
+  case TMR_SR_MODEL_M6E_NANO:
+    value = false;
+    break;
+  default:
+    value = false;
+    break;
+  }
+  sr->supportsPreamble = value;
+
+  return ret;
+}
+
+static TMR_Status
+TMR_SR_boot(TMR_Reader *reader, uint32_t currentBaudRate)
+{
+  TMR_Status ret;
+  uint8_t program;
+  bool boolval;
+  TMR_SR_SerialReader *sr;
+  TMR_SR_SerialTransport *transport;
+  int i;
+  bool value;
+
+  ret = TMR_SUCCESS;
+  sr = &reader->u.serialReader;
+  transport = &sr->transport;
+
+  /* Get current program */
+  ret = TMR_SR_cmdGetCurrentProgram(reader, &program);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* If bootloader, enter app */
+  if ((program & 0x3) == 1)
+  {
+    ret = TMR_SR_cmdBootFirmware(reader);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+  }
+
+  /*
+   * Once out of bootloader, configure for wakeup preambles.
+   * Bootloader doesn't support preambles, and some versions
+   * fail to respond to normal commands afterwards.
+   *
+   * It is safe to avoid preambles up to this point because
+   * TMR_SR_connect has already been talking to the module
+   * to keep it awake.
+   */
+  ret = TMR_SR_configPreamble(sr);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Initialize cached power mode value */
+  /* Should read power mode as soon as possible.
+   * Default mode assumes module is in deep sleep and
+   * adds a lengthy "wake-up preamble" to every command.
+   */
+  if (sr->powerMode == TMR_SR_POWER_MODE_INVALID)
+  {
+    ret = TMR_paramGet(reader, TMR_PARAM_POWERMODE, &sr->powerMode);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+  }
+
+  /**
+   * In case for M6E and its variant check for CRC
+   **/
+  if ((TMR_SR_MODEL_M6E == reader->u.serialReader.versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_M6E_I == reader->u.serialReader.versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_M6E_NANO == reader->u.serialReader.versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_MICRO == reader->u.serialReader.versionInfo.hardware[0]))
+  {
+    /**
+     * Get the transport/BUS type
+     **/
+    ret = TMR_SR_cmdGetReaderConfiguration(reader, TMR_SR_CONFIGURATION_CURRENT_MSG_TRANSPORT, &reader->u.serialReader.transportType);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+    /**
+     * In case of USB port disable the CRC
+     **/
+    if (TMR_SR_MSG_SOURCE_USB == reader->u.serialReader.transportType)
+    {
+      value = false;
+      ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_SEND_CRC, &value);
+      if (TMR_SUCCESS == ret)
+      {
+        reader->u.serialReader.crcEnabled = false;
+      }
+      else
+      {
+        /**
+         * Not Fatal, Going ahead with CRC enabled
+         **/ 
+      }
+    }
+  }
+
+  if (sr->baudRate != currentBaudRate)
+  {
+    if (NULL != transport->setBaudRate)
+    {
+      /**
+       * some transport layer does not support baud rate settings.
+       * for ex: TCP transport. In that case skip the baud rate
+       * settings.
+       */ 
+
+      /* Bring baud rate up to the parameterized value */
+      ret = TMR_SR_cmdSetBaudRate(reader, sr->baudRate);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      ret = transport->setBaudRate(transport, sr->baudRate);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+    }
+  }
+
+  /*ret = TMR_SR_cmdVersion(reader, &sr->versionInfo);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }*/
+
+  /* If we need to check the version information for something operational,
+     this is the place to do it. */
+  sr->gpioDirections = -1; /* Needs fetching */
+  reader->continuousReading = ((TMR_SR_MODEL_M6E == sr->versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_M6E_I == sr->versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_M6E_NANO == reader->u.serialReader.versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0]));
+  reader->continuousReading = false; //fix bug 1745 in the current release temporarily
+
+  /**
+   * This version check is required for the new reader stats.
+   * Older firmwares does not support this. Currently, firmware version
+   * 1.21.1.2 has support for new reader stats.
+   **/
+  if (
+    (((TMR_SR_MODEL_M6E == sr->versionInfo.hardware[0]) || (TMR_SR_MODEL_M6E_I == sr->versionInfo.hardware[0]))
+    && compareVersion(reader, 1, 21, 1, 2))
+    || ((TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0]) && compareVersion(reader, 1, 3, 0, 20))
+    || ((TMR_SR_MODEL_M6E_NANO == sr->versionInfo.hardware[0]) && compareVersion(reader, 1, 3, 2, 74))
+    )
+  {
+    reader->_storeSupportsResetStats = true;
+    reader->pSupportsResetStats = &(reader->_storeSupportsResetStats);
+  }
+  else
+  {
+    reader->_storeSupportsResetStats = false;
+    reader->pSupportsResetStats = &(reader->_storeSupportsResetStats);
+  }
+
+  /* Initialize the paramPresent and paramConfirmed bits. */
+  /* This block is expected to be collapsed by the compiler into a
+   * small number of constant-value writes into the sr->paramPresent
+   * array.
+   */
+  for (i = 0 ; i < TMR_PARAMWORDS; i++)
+  {
+    sr->paramPresent[i] = 0;
+  }
+
+  BITSET(sr->paramPresent, TMR_PARAM_BAUDRATE);
+  BITSET(sr->paramPresent, TMR_PARAM_PROBEBAUDRATES);  
+  BITSET(sr->paramPresent, TMR_PARAM_COMMANDTIMEOUT);
+  BITSET(sr->paramPresent, TMR_PARAM_TRANSPORTTIMEOUT);
+  BITSET(sr->paramPresent, TMR_PARAM_POWERMODE);
+  BITSET(sr->paramPresent, TMR_PARAM_USERMODE);
+  BITSET(sr->paramPresent, TMR_PARAM_ANTENNA_CHECKPORT);
+  BITSET(sr->paramPresent, TMR_PARAM_ANTENNA_PORTLIST);
+  BITSET(sr->paramPresent, TMR_PARAM_ANTENNA_CONNECTEDPORTLIST);
+  BITSET(sr->paramPresent, TMR_PARAM_ANTENNA_PORTSWITCHGPOS);
+  BITSET(sr->paramPresent, TMR_PARAM_ANTENNA_SETTLINGTIMELIST);
+  BITSET(sr->paramPresent, TMR_PARAM_ANTENNA_RETURNLOSS);
+  BITSET(sr->paramPresent, TMR_PARAM_ANTENNA_TXRXMAP);
+  BITSET(sr->paramPresent, TMR_PARAM_GPIO_INPUTLIST);
+  BITSET(sr->paramPresent, TMR_PARAM_GPIO_OUTPUTLIST);
+  BITSET(sr->paramPresent, TMR_PARAM_GEN2_ACCESSPASSWORD);
+  BITSET(sr->paramPresent, TMR_PARAM_GEN2_Q);
+  BITSET(sr->paramPresent, TMR_PARAM_GEN2_BAP);
+  BITSET(sr->paramPresent, TMR_PARAM_GEN2_TAGENCODING);
+  BITSET(sr->paramPresent, TMR_PARAM_GEN2_SESSION);
+  BITSET(sr->paramPresent, TMR_PARAM_GEN2_TARGET);
+  BITSET(sr->paramPresent, TMR_PARAM_GEN2_PROTOCOLEXTENSION);
+  BITSET(sr->paramPresent, TMR_PARAM_READ_ASYNCOFFTIME);
+  BITSET(sr->paramPresent, TMR_PARAM_READ_ASYNCONTIME);
+  BITSET(sr->paramPresent, TMR_PARAM_READ_PLAN);
+  BITSET(sr->paramPresent, TMR_PARAM_RADIO_ENABLEPOWERSAVE);
+  BITSET(sr->paramPresent, TMR_PARAM_RADIO_POWERMAX);
+  BITSET(sr->paramPresent, TMR_PARAM_RADIO_POWERMIN);
+  BITSET(sr->paramPresent, TMR_PARAM_RADIO_PORTREADPOWERLIST);
+  BITSET(sr->paramPresent, TMR_PARAM_RADIO_PORTWRITEPOWERLIST);
+  BITSET(sr->paramPresent, TMR_PARAM_RADIO_READPOWER);
+  BITSET(sr->paramPresent, TMR_PARAM_RADIO_WRITEPOWER);
+  BITSET(sr->paramPresent, TMR_PARAM_RADIO_TEMPERATURE);
+  BITSET(sr->paramPresent, TMR_PARAM_TAGREADDATA_RECORDHIGHESTRSSI);
+  BITSET(sr->paramPresent, TMR_PARAM_TAGREADDATA_REPORTRSSIINDBM);
+  BITSET(sr->paramPresent, TMR_PARAM_TAGREADDATA_UNIQUEBYANTENNA);
+  BITSET(sr->paramPresent, TMR_PARAM_TAGREADDATA_UNIQUEBYDATA);
+  BITSET(sr->paramPresent, TMR_PARAM_TAGOP_ANTENNA);
+  BITSET(sr->paramPresent, TMR_PARAM_TAGOP_PROTOCOL);
+  BITSET(sr->paramPresent, TMR_PARAM_VERSION_HARDWARE);
+  BITSET(sr->paramPresent, TMR_PARAM_VERSION_MODEL);
+  BITSET(sr->paramPresent, TMR_PARAM_VERSION_SOFTWARE);
+  BITSET(sr->paramPresent, TMR_PARAM_VERSION_SERIAL);
+  BITSET(sr->paramPresent, TMR_PARAM_VERSION_SUPPORTEDPROTOCOLS);
+  BITSET(sr->paramPresent, TMR_PARAM_REGION_ID);
+  BITSET(sr->paramPresent, TMR_PARAM_REGION_SUPPORTEDREGIONS);
+  BITSET(sr->paramPresent, TMR_PARAM_REGION_HOPTABLE);
+  BITSET(sr->paramPresent, TMR_PARAM_REGION_HOPTIME);
+  BITSET(sr->paramPresent, TMR_PARAM_REGION_LBT_ENABLE);
+  BITSET(sr->paramPresent, TMR_PARAM_EXTENDEDEPC);
+  BITSET(sr->paramPresent, TMR_PARAM_READER_STATS);
+  BITSET(sr->paramPresent, TMR_PARAM_READER_STATISTICS); 
+  BITSET(sr->paramPresent, TMR_PARAM_URI);
+  BITSET(sr->paramPresent, TMR_PARAM_PRODUCT_GROUP_ID);
+  BITSET(sr->paramPresent, TMR_PARAM_PRODUCT_GROUP);
+  BITSET(sr->paramPresent, TMR_PARAM_PRODUCT_ID);
+  BITSET(sr->paramPresent, TMR_PARAM_TAGREADATA_TAGOPSUCCESSCOUNT);
+  BITSET(sr->paramPresent, TMR_PARAM_TAGREADATA_TAGOPFAILURECOUNT);
+  BITSET(sr->paramPresent, TMR_PARAM_TAGREADDATA_ENABLEREADFILTER);
+  BITSET(sr->paramPresent, TMR_PARAM_READER_WRITE_REPLY_TIMEOUT);
+  BITSET(sr->paramPresent, TMR_PARAM_READER_WRITE_EARLY_EXIT);
+  BITSET(sr->paramPresent, TMR_PARAM_ISO180006B_DELIMITER);
+  BITSET(sr->paramPresent, TMR_PARAM_ISO180006B_MODULATION_DEPTH);
+  BITSET(sr->paramPresent, TMR_PARAM_READER_STATS_ENABLE);
+  BITSET(sr->paramPresent, TMR_PARAM_TRIGGER_READ_GPI);
+  if ((TMR_SR_MODEL_M6E == sr->versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_M6E_NANO == reader->u.serialReader.versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_M6E_I == sr->versionInfo.hardware[0]))
+
+  {
+    BITSET(sr->paramPresent, TMR_PARAM_LICENSE_KEY);
+    BITSET(sr->paramPresent, TMR_PARAM_USER_CONFIG);
+    BITSET(sr->paramPresent, TMR_PARAM_RADIO_ENABLESJC);
+    BITSET(sr->paramPresent, TMR_PARAM_TAGREADDATA_READFILTERTIMEOUT);
+    BITSET(sr->paramPresent, TMR_PARAM_TAGREADDATA_UNIQUEBYPROTOCOL);
+  }
+
+  for (i = 0 ; i < TMR_PARAMWORDS; i++)
+  {
+    sr->paramConfirmed[i] = sr->paramPresent[i];
+  }
+
+  /* Get productGroupID early, so other params (e.g., txRxMap) can use it */
+  {
+    ret = TMR_SR_cmdGetReaderConfiguration(reader, TMR_SR_CONFIGURATION_PRODUCT_GROUP_ID, &sr->productId);
+    if (TMR_SUCCESS != ret)
+    {
+      if (TMR_ERROR_MSG_INVALID_PARAMETER_VALUE == ret)
+      {
+        /*
+         * Modules with firmware older than wilder will throw 0x105 error, as it was not 
+         * implemented. Catch this error but do not return.
+         */
+		sr->productId = 0xFFFF;
+      }
+      else
+      {
+        return ret;
+      }
+    }
+    /* 
+     * If product is ruggedized reader, 
+     * set reader's GPO pin which is used for antenna port switching
+     */
+    if (1 == sr->productId)
+    {
+      uint8_t pin = 1;
+      ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_ANTENNA_CONTROL_GPIO, &pin);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+    }
+  }
+  /* Set region if user set the param */
+  if (TMR_REGION_NONE != sr->regionId)
+  {
+    ret = TMR_SR_cmdSetRegion(reader, sr->regionId);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+  }
+
+  ret = TMR_SR_cmdGetCurrentProtocol(reader, &sr->currentProtocol);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  if (TMR_TAG_PROTOCOL_NONE == sr->currentProtocol)
+  {
+	TMR_TagProtocolList protocolList;
+	TMR_TagProtocol protocols[TMR_MAX_PROTOCOLS];
+	uint8_t index;
+	protocolList.list = &protocols[0];
+	protocolList.max = TMR_MAX_PROTOCOLS;
+	/* 
+	 * Serach whether GEN2 Protocol is supported by reader in its protocol list. 
+	 * If so set it as current protocol, else leave protocol selection to user.
+	 */ 
+	ret = TMR_SR_cmdGetAvailableProtocols(reader, &protocolList);
+	for(index = 0; index < protocolList.len; index++)
+	{
+	  if(TMR_TAG_PROTOCOL_GEN2 == protocolList.list[index])
+	  {
+		ret = TMR_SR_cmdSetProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+		if (TMR_SUCCESS != ret)
+		{
+		  return ret;
+		}
+		sr->currentProtocol = TMR_TAG_PROTOCOL_GEN2;
+		break;
+	  }
+	}
+  }
+  reader->tagOpParams.protocol = sr->currentProtocol;
+
+  reader->tagOpParams.antenna = 0;
+  ret = initTxRxMapFromPorts(reader);
+
+  /**
+   * Enable the extended EPC flag in case
+   * of M5E and its variants
+   */
+  if ((TMR_SR_MODEL_M6E != sr->versionInfo.hardware[0]) &&
+      (TMR_SR_MODEL_MICRO != sr->versionInfo.hardware[0]) &&
+      (TMR_SR_MODEL_M6E_NANO != sr->versionInfo.hardware[0]) &&
+      (TMR_SR_MODEL_M6E_I != sr->versionInfo.hardware[0]))
+  {
+    /* Do this only if the module is other than M6e*/
+    boolval = true;
+    ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_EXTENDED_EPC, &boolval);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+    reader->u.serialReader.extendedEPC = boolval;
+  }
+  /* Report RSSI in dbm */
+  if ((TMR_SR_MODEL_M6E != sr->versionInfo.hardware[0]) &&
+      (TMR_SR_MODEL_MICRO != sr->versionInfo.hardware[0]) &&
+      (TMR_SR_MODEL_M6E_NANO !=  sr->versionInfo.hardware[0]) &&
+      (TMR_SR_MODEL_M6E_I != sr->versionInfo.hardware[0]))
+  {
+    /* Do this only if the module is other than M6e*/
+    boolval = true;
+    ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_RSSI_IN_DBM, &boolval);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+  }
+  else
+  { /* Do this only in case of M6e */
+    int32_t timeout = 0;
+
+    /* Get reader's enable read filter setting */
+    ret = TMR_SR_cmdGetReaderConfiguration(reader, TMR_SR_CONFIGURATION_ENABLE_READ_FILTER, &reader->u.serialReader.enableReadFiltering);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+    
+    /* Get reader's read filter entry timeout */
+    ret = TMR_SR_cmdGetReaderConfiguration(reader, TMR_SR_CONFIGURATION_READ_FILTER_TIMEOUT, &timeout);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+    reader->u.serialReader.readFilterTimeout = (0 == timeout) ? TMR_DEFAULT_READ_FILTER_TIMEOUT : timeout;
+
+  }
+
+  
+  return ret;
+}
+
+/**
+ * Probing the correct baudrate to communicate with the serial reader.
+ *
+ * @param reader The reader
+ * @param currentBaudRate the baud rate at which module is communicating.
+ */
+TMR_Status
+TMR_SR_cmdProbeBaudRate(TMR_Reader *reader, uint32_t *currentBaudRate)
+{
+  TMR_Status ret;
+  TMR_SR_SerialReader *sr;
+  TMR_SR_SerialTransport *transport;
+  uint32_t rate = 0x00;
+  int i,count = 2;
+
+  ret = TMR_SUCCESS;
+  sr = &reader->u.serialReader;
+  transport = &reader->u.serialReader.transport;
+
+  for (i = 0; (uint32_t)i < sr->probeBaudRates.len; i++)
+  {
+    if (i <= 1 && count)
+    { 
+      rate = sr->baudRate; /* Try this first */
+      /* Module might be in deep sleep mode, if there is no response for the
+      * first attempt, Try the same baudrate again. i = 0 and i = 1
+      */
+      count--;
+
+      /* Hold i=0 (undo increment) until count has expired */
+
+      i--;
+    }
+    else
+    {
+      rate = sr->probeBaudRates.list[i];
+      if (rate == sr->baudRate)
+        continue; /* We already tried this one */
+    }
+
+    if (NULL != transport->setBaudRate)
+    {
+      /**
+      * some transport layer does not support baud rate settings.
+      * for ex: TCP transport. In that case skip the baud rate
+      * settings.
+      */ 
+      ret = transport->setBaudRate(transport, rate);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+    }
+
+    ret = transport->flush(transport);
+    if ((TMR_SUCCESS != ret) && (TMR_ERROR_UNIMPLEMENTED != ret))
+    {
+      return ret;
+    }
+contact:
+    ret = TMR_SR_cmdVersion(reader, &(reader->u.serialReader.versionInfo));
+    if (TMR_SUCCESS == ret)
+    {
+      /* Got a reply?  Then this is the right baud rate! */
+      break;
+    }
+
+    /* Timeouts are okay -- they usually mean "wrong baud rate",
+    * so just try the next one.  All other errors are real
+    * and should be forwarded immediately. */
+    else if (TMR_ERROR_TIMEOUT != ret)
+    {
+      if (TMR_ERROR_COMM(ret))
+      {
+        ret = verifySearchStatus(reader);
+        if (TMR_SUCCESS == ret)
+        {
+          goto contact;
+        }
+        else
+        {
+          return ret;
+        }
+      } 
+      else
+      {
+        return ret;
+      }
+    }
+  }
+  if (i == sr->probeBaudRates.len)
+  {
+    return TMR_ERROR_TIMEOUT;
+  }
+
+  /* copy the baud rate */
+  *currentBaudRate = rate;  
+  return ret;
+}
+
+TMR_Status
+TMR_SR_connect(TMR_Reader *reader)
+{
+  TMR_Status ret;
+  uint32_t rate;
+  TMR_SR_SerialReader *sr;
+  TMR_SR_SerialTransport *transport;
+  
+  ret = TMR_SUCCESS;
+  sr = &reader->u.serialReader;
+  transport = &reader->u.serialReader.transport;
+
+  ret = transport->open(transport);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  rate = sr->probeBaudRates.list[0]; //this fixes the compilation errors in some compilers
+  ret = TMR_SR_cmdProbeBaudRate(reader, &rate);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  reader->connected = true;
+
+  /* Boot */
+  ret = TMR_SR_boot(reader, rate);
+
+  if(ret !=TMR_SUCCESS)
+  {
+    if(ret == TMR_ERROR_AUTOREAD_ENABLED)
+    {
+      ret = verifySearchStatus(reader);
+			if (TMR_SUCCESS != ret)
+      {
+				return ret;
+			}
+      ret = TMR_SR_boot(reader, rate);
+    }
+  }
+
+  return ret;
+}
+
+TMR_Status
+TMR_SR_destroy(TMR_Reader *reader)
+{
+  TMR_SR_SerialTransport *transport;
+  reader->hasContinuousReadStarted = false;
+
+  transport = &reader->u.serialReader.transport;
+
+  /**
+   * Enable the CRC, in case it is disabled
+   **/
+  if (false == reader->u.serialReader.crcEnabled)
+  {
+    reader->u.serialReader.crcEnabled = true;
+    TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_SEND_CRC, &reader->u.serialReader.crcEnabled);
+  }
+
+  transport->shutdown(transport);
+  reader->connected = false;
+
+#ifdef TMR_ENABLE_BACKGROUND_READS
+  /* Cleanup background threads */
+  cleanup_background_threads(reader);
+#endif
+
+  return TMR_SUCCESS;
+}
+
+static TMR_Status
+autoDetectAntennaList(struct TMR_Reader *reader)
+{
+  TMR_Status ret;
+  TMR_SR_PortDetect ports[TMR_SR_MAX_ANTENNA_PORTS];
+  TMR_SR_PortPair searchList[TMR_SR_MAX_ANTENNA_PORTS];
+  uint8_t i, listLen, numPorts;
+  uint16_t j;
+  TMR_AntennaMapList *map;
+    
+  ret = TMR_SUCCESS;
+  map = reader->u.serialReader.txRxMap;
+
+  /* 1. Detect current set of antennas */
+  numPorts = TMR_SR_MAX_ANTENNA_PORTS;
+  ret = TMR_SR_cmdAntennaDetect(reader, &numPorts, ports);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* 2. Set antenna list based on detected antennas (Might be clever
+   * to cache this and not bother sending the set-list command
+   * again, but it's more code and data space).
+   */
+  for (i = 0, listLen = 0; i < numPorts; i++)
+  {
+    if (ports[i].detected)
+    {
+      /* Ensure that the port exists in the map */
+      for (j = 0; j < map->len; j++)
+        if (ports[i].port == map->list[j].txPort)
+        {
+          searchList[listLen].txPort = map->list[j].txPort;
+          searchList[listLen].rxPort = map->list[j].rxPort;
+          listLen++;
+          break;
+        }
+    }
+  }
+  if (0 == listLen) /* No ports auto-detected */
+  {
+    return TMR_ERROR_NO_ANTENNA;
+  }
+  ret = TMR_SR_cmdSetAntennaSearchList(reader, listLen, searchList);
+  
+  return ret;
+}
+
+static TMR_Status
+setAntennaList(struct TMR_Reader *reader, TMR_uint8List *antennas)
+{
+  TMR_SR_PortPair searchList[16];
+  uint16_t i, j, listLen;
+  TMR_AntennaMapList *map;
+
+  map = reader->u.serialReader.txRxMap;
+
+  /** @todo cache the set list and don't reset it if it hasn't changed */
+  listLen = 0;
+  for (i = 0; i < antennas->len ; i++)
+  {
+    for (j = 0; j < map->len; j++)
+    {
+      if (antennas->list[i] == map->list[j].antenna)
+      {
+        searchList[listLen].txPort = map->list[j].txPort;
+        searchList[listLen].rxPort = map->list[j].rxPort;
+        listLen++;
+        break;
+      }
+    }
+  }
+  return TMR_SR_cmdSetAntennaSearchList(reader,(uint8_t)listLen, searchList);
+}
+
+static TMR_Status
+setProtocol(struct TMR_Reader *reader, TMR_TagProtocol protocol)
+{
+  TMR_Status ret;
+
+  if(reader->u.serialReader.currentProtocol != protocol)
+  {
+  ret = TMR_SR_cmdSetProtocol(reader, protocol);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Set extended EPC -- This bit is reset when the protocol changes */
+  if (reader->u.serialReader.extendedEPC)
+  {  
+    bool boolval;
+    boolval = true;
+    ret = TMR_SR_cmdSetReaderConfiguration(reader,
+					   TMR_SR_CONFIGURATION_EXTENDED_EPC,
+					   &boolval);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+  }
+  reader->u.serialReader.currentProtocol = protocol;
+
+  /* Set enable filtering -- module automatically resets this when protocol is changed */
+  ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_ENABLE_READ_FILTER, &reader->u.serialReader.enableReadFiltering);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  {
+    /* Set the read filter timeout */
+    uint32_t moduleValue = (TMR_DEFAULT_READ_FILTER_TIMEOUT == reader->u.serialReader.readFilterTimeout) ?
+                                                                0 : reader->u.serialReader.readFilterTimeout;
+    ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_READ_FILTER_TIMEOUT, &moduleValue);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+    reader->u.serialReader.readFilterTimeout = moduleValue;
+  }
+  }
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Compare two firmware versions, return true current firmware is higher than refernced firmware.
+ * else return false;
+ **/
+bool
+compareVersion(TMR_Reader *reader, uint8_t firstByte, uint8_t secondByte, uint8_t thirdByte, uint8_t fourthByte)
+{
+  TMR_SR_SerialReader *sr = &reader->u.serialReader;
+  uint8_t temp;
+  
+  /* compre the first byte */
+  temp = sr->versionInfo.fwVersion[0];
+  if (temp > firstByte)
+  {
+    /* Higher version, return true */
+    return true;
+  }
+  else if (temp < firstByte)
+  {
+    /* lower version, return flase */
+    return false;
+  }
+  else
+  {
+    /* Compare the second byte */
+    temp = sr->versionInfo.fwVersion[1];
+    if (temp > secondByte)
+    {
+      /* Higher version, return true */
+      return true;
+    }
+    else if (temp < secondByte)
+    {
+      /* lower version, return flase */
+      return false;
+    }
+    else
+    {
+      /* compare the third byte */
+      temp = sr->versionInfo.fwVersion[2];
+      if (temp > thirdByte)
+      {
+        /* Higher version, return true */
+        return true;
+      }
+      else if (temp < thirdByte)
+      {
+        /* lower version, return flase */
+        return false;
+      }
+      else
+      {
+        /* compare the fourth byte */
+        temp = sr->versionInfo.fwVersion[3];
+        if (temp > fourthByte)
+        {
+          return true;
+        }
+        else if (temp < fourthByte)
+        {
+          /* lower version, return flase */
+          return false;
+        }
+        else
+        {
+          /* both the firmwares are equal */
+          return true;
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Compare antenna list in readplans list, return true if antenna
+ * list are consistent across the entire set of read plans.
+ **/
+bool
+compareAntennas(TMR_MultiReadPlan *multi)
+{
+  TMR_ReadPlan *plan1, *plan2;
+
+  uint8_t allAntennasNull = 0;
+  uint8_t matchingPlanCount = 0;
+  uint8_t i;
+  bool status = false;
+
+  for (i = 0; i < multi->planCount; i++)
+  {
+    plan1 = multi->plans[0];
+    plan2 = multi->plans[i];
+
+    if ((0 != plan1->u.simple.antennas.len) && (0 != plan2->u.simple.antennas.len))
+    {
+      uint8_t j;
+
+      if (plan1->u.simple.antennas.len == plan2->u.simple.antennas.len)
+      {
+        for (j = 0; j < plan1->u.simple.antennas.len; j++)
+        {
+          if (plan1->u.simple.antennas.list[j] != plan2->u.simple.antennas.list[j])
+          {
+            status = false;
+            break;
+          }
+        }
+        if (j == plan1->u.simple.antennas.len)
+        {
+          matchingPlanCount++;
+        }
+      }
+    }
+    else if ((0 == plan1->u.simple.antennas.len) && (0 == plan2->u.simple.antennas.len))
+    {
+      allAntennasNull++;
+    }
+    else
+    {
+      status = false;
+      break;
+    }
+  }
+
+  if ((matchingPlanCount == multi->planCount) || (allAntennasNull == multi->planCount))
+  {
+    status = true;
+  }
+
+  return status;
+}
+
+TMR_Status
+prepForSearch(TMR_Reader *reader, TMR_uint8List *antennaList)
+{
+  TMR_Status ret;
+  if (antennaList->len == 0)
+  {
+    ret = autoDetectAntennaList(reader);
+  }
+  else
+  {
+    ret = setAntennaList(reader, antennaList);
+  }
+  return ret;
+}
+
+static TMR_Status
+prepEmbReadTagMultiple(TMR_Reader *reader, uint8_t *msg, uint8_t *i,
+            uint16_t timeout, TMR_SR_SearchFlag searchFlag,
+            const TMR_TagFilter *filter, TMR_TagProtocol protocol,
+            TMR_GEN2_Password accessPassword, uint8_t *lenbyte)
+{
+  TMR_Status ret;
+
+  ret = TMR_SR_msgSetupReadTagMultiple(reader,
+        msg, i, (uint16_t)timeout, searchFlag, filter, protocol, accessPassword);
+  
+  /* Embedded command count (Currently supports only one command)*/
+  SETU8(msg, *i, 1);  
+  *lenbyte = (*i)++;
+  return ret;
+}
+
+static TMR_Status
+TMR_SR_read_internal(struct TMR_Reader *reader, uint32_t timeoutMs,
+                     int32_t *tagCount, TMR_ReadPlan *rp)
+{
+  TMR_Status ret = TMR_SUCCESS;
+  TMR_SR_SerialReader *sr;
+  TMR_SR_MultipleStatus multipleStatus = {0};
+  uint32_t count, elapsed, elapsed_tagop;
+  uint32_t readTimeMs, starttimeLow, starttimeHigh;
+  TMR_uint8List *antennaList = NULL;
+
+  sr = &reader->u.serialReader;
+
+  if (TMR_READ_PLAN_TYPE_MULTI == rp->type)
+  {
+    int i;
+    TMR_TagProtocolList p;
+    TMR_TagProtocolList *protocolList = &p;
+    TMR_TagFilter *filters[TMR_MAX_SERIAL_MULTIPROTOCOL_LENGTH];
+    TMR_TagProtocol protocols[TMR_MAX_SERIAL_MULTIPROTOCOL_LENGTH];
+
+
+    if (TMR_MAX_SERIAL_MULTIPROTOCOL_LENGTH < rp->u.multi.planCount)
+    {
+      return TMR_ERROR_TOO_BIG ;
+    }
+
+    protocolList->len = rp->u.multi.planCount;
+    protocolList->max = rp->u.multi.planCount;
+
+
+    protocolList->list = protocols;
+
+    for (i = 0; i < rp->u.multi.planCount; i++)
+    {
+      protocolList->list[i] = rp->u.multi.plans[i]->u.simple.protocol;
+      filters[i]= rp->u.multi.plans[i]->u.simple.filter; 
+    }
+    
+    if (
+        ((0 < rp->u.multi.planCount) &&
+         (rp->u.multi.plans[0]->type == TMR_READ_PLAN_TYPE_SIMPLE) &&
+         (compareAntennas(&rp->u.multi)) &&
+         ((TMR_SR_MODEL_M6E == sr->versionInfo.hardware[0]) ||
+          (TMR_SR_MODEL_M6E_I == sr->versionInfo.hardware[0]) ||
+          (TMR_SR_MODEL_M6E_NANO == sr->versionInfo.hardware[0]) ||
+          (TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0])))
+        || (true == reader->continuousReading)
+       )
+    {
+      TMR_SR_SearchFlag antennas = TMR_SR_SEARCH_FLAG_CONFIGURED_LIST;
+      antennas |= ((reader->continuousReading)? TMR_SR_SEARCH_FLAG_TAG_STREAMING : 0);
+      antennaList = &(rp->u.multi.plans[0]->u.simple.antennas);
+      ret = prepForSearch(reader, antennaList);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /**
+       * take the time stamp only in case of sync read,
+       * async read does not depend on this
+       **/
+      if (!reader->continuousReading)
+      {
+        /* Cache the read time so it can be put in tag read data later */
+        tm_gettime_consistent(&starttimeHigh, &starttimeLow);
+        sr->readTimeHigh = starttimeHigh;
+        sr->readTimeLow = starttimeLow;
+        sr->lastSentTagTimestampHigh = starttimeHigh;
+        sr->lastSentTagTimestampLow = starttimeLow;
+      }
+
+      if (reader->continuousReading)
+      {
+        bool value = false;
+        ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_ENABLE_READ_FILTER, &value);
+        if (TMR_SUCCESS != ret)
+        {
+          return ret;
+        }
+      }
+
+      ret = TMR_SR_cmdMultipleProtocolSearch(reader, 
+          TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE,
+		  protocolList, reader->userMetadataFlag,
+          antennas,
+          filters,
+          (uint16_t)timeoutMs, &count);
+
+      if (NULL != tagCount)
+      {
+        *tagCount += count;
+      }
+      return ret;
+    }
+
+  }
+
+  if (TMR_READ_PLAN_TYPE_SIMPLE == rp->type)
+  {
+    antennaList = &rp->u.simple.antennas;
+    reader->fastSearch = rp->u.simple.useFastSearch;
+    reader->triggerRead = rp->u.simple.triggerRead.enable;
+    if (!reader->continuousReading)
+    {
+      /* Currently only supported for sync read case */
+      reader->isStopNTags = rp->u.simple.stopOnCount.stopNTriggerStatus;
+      reader->numberOfTagsToRead = rp->u.simple.stopOnCount.noOfTags;
+    }
+  }
+  else if (TMR_READ_PLAN_TYPE_MULTI == rp->type)
+  {
+    uint32_t subTimeout;
+    int i;
+
+    subTimeout = 0;
+    if (0 == rp->u.multi.totalWeight)
+    {
+      subTimeout = timeoutMs / rp->u.multi.planCount;
+    }
+
+    for (i = 0; i < rp->u.multi.planCount; i++)
+    {
+      if (rp->u.multi.totalWeight)
+      {
+        subTimeout = rp->u.multi.plans[i]->weight * timeoutMs 
+          / rp->u.multi.totalWeight;
+      }
+      ret = TMR_SR_read_internal(reader, subTimeout, tagCount, 
+        rp->u.multi.plans[i]);
+      if (TMR_SUCCESS != ret && TMR_ERROR_NO_TAGS_FOUND != ret)
+      {
+        return ret;
+      }
+    }
+    return ret;
+  }
+  else
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  /* At this point we're guaranteed to have a simple read plan */
+  ret = prepForSearch(reader, antennaList);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  
+  /* Set protocol to that specified by the read plan. */
+  ret = setProtocol(reader, rp->u.simple.protocol);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  if (reader->continuousReading)
+  {
+    bool value = false;
+    ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_ENABLE_READ_FILTER, &value);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+  }
+
+  /* Cache the read time so it can be put in tag read data later */
+  tm_gettime_consistent(&starttimeHigh, &starttimeLow);
+  sr->readTimeHigh = starttimeHigh;
+  sr->readTimeLow = starttimeLow;
+  sr->lastSentTagTimestampHigh = starttimeHigh;
+  sr->lastSentTagTimestampLow = starttimeLow;
+
+  /* Cache search timeout for later call to streaming receive */
+  sr->searchTimeoutMs = timeoutMs;
+
+  elapsed = tm_time_subtract(tmr_gettime_low(), starttimeLow);
+  elapsed_tagop = elapsed;
+  
+  /**
+   * Ignoring the elapsed time calculation in case of true
+   * continuous reading,
+   */
+  if ((reader->continuousReading) && (0 != timeoutMs))
+  {
+    elapsed = timeoutMs - 1;
+  }
+
+  while (elapsed <= timeoutMs)
+  {
+    readTimeMs = timeoutMs - elapsed;
+    if (readTimeMs > 65535)
+    {
+      readTimeMs = 65535;
+    }
+
+    if (NULL == rp->u.simple.tagop)
+    {
+      if(reader->continuousReading)
+      {
+        TMR_TagProtocolList p;
+        TMR_TagProtocolList *protocolList = &p;
+        TMR_TagFilter *filters[TMR_MAX_SERIAL_MULTIPROTOCOL_LENGTH];
+        TMR_TagProtocol protocols[TMR_MAX_SERIAL_MULTIPROTOCOL_LENGTH];
+        TMR_SR_SearchFlag antennas;
+        
+        protocolList->len = 1;
+        protocolList->max = 1;
+        protocolList->list = protocols;
+
+        protocolList->list[0] = rp->u.simple.protocol;
+        filters[0]= rp->u.simple.filter;
+    
+        antennas = TMR_SR_SEARCH_FLAG_CONFIGURED_LIST;
+        antennas |= ((reader->continuousReading)? TMR_SR_SEARCH_FLAG_TAG_STREAMING : 0);
+        antennaList = &(rp->u.simple.antennas);
+        ret = TMR_SR_cmdMultipleProtocolSearch(reader,
+                            TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE,
+                            protocolList, reader->userMetadataFlag,
+                            antennas,
+                            filters,
+                            (uint16_t)timeoutMs, &count);
+      }
+      else
+      {
+        ret = TMR_SR_cmdReadTagMultiple(reader,(uint16_t)readTimeMs,
+          (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+          rp->u.simple.filter,
+          rp->u.simple.protocol,
+          &count);
+      }
+    }
+    else
+    {
+      uint8_t msg[256];
+      uint8_t i, lenbyte;
+
+      /* Since this is embedded tagop, removing elapsed time based on
+       * continuous reading should not be done 
+       */
+      readTimeMs = timeoutMs - elapsed_tagop;
+      if (readTimeMs > 65535)
+      {
+        readTimeMs = 65535;
+      }
+
+      i = 2;
+     
+      /**
+       * add the tagoperation
+       **/
+      ret = TMR_SR_addTagOp(reader, rp->u.simple.tagop, rp, msg, &i, readTimeMs, &lenbyte);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      msg[lenbyte] = i - (lenbyte + 2); /* Install length of subcommand */
+      msg[1] = i - 3; /* Install length */
+      ret = TMR_SR_executeEmbeddedRead(reader, msg, (uint16_t)timeoutMs, &multipleStatus);
+      count = multipleStatus.tagsFound;
+
+
+      /* Update embedded tagop success/failure count */
+      reader->u.serialReader.tagopSuccessCount += multipleStatus.successCount;
+      reader->u.serialReader.tagopFailureCount += multipleStatus.failureCount;
+    }
+
+    if (TMR_ERROR_NO_TAGS_FOUND == ret)
+    {
+      count = 0;
+      ret = TMR_SUCCESS;
+    }
+	else if (TMR_ERROR_TM_ASSERT_FAILED == ret)
+	{
+	  return ret;
+	}
+    else if (TMR_ERROR_TIMEOUT == ret)
+    {
+      return ret;
+    }
+    else if (TMR_SUCCESS != ret)
+    {
+      uint16_t remainingTagsCount;
+      TMR_Status ret1;
+      reader->isStopNTags = false;
+
+      /* Check for the tag count (in case of module error)*/
+      ret1 = TMR_SR_cmdGetTagsRemaining(reader, &remainingTagsCount);
+      if (TMR_SUCCESS != ret1)
+      {
+        return ret1;
+      }
+      sr->tagsRemaining += remainingTagsCount;
+      if (NULL != tagCount)
+      {
+        *tagCount += remainingTagsCount;
+      }
+      return ret;
+    }
+
+    sr->tagsRemaining += count;
+    if (NULL != tagCount)
+    {
+      *tagCount += count;
+    }
+
+    if (reader->continuousReading)
+    {
+      sr->tagsRemaining = 1;
+      break;
+    }
+    else if (reader->isStopNTags && !reader->continuousReading)
+    {
+      /** 
+       * No need to loop back for stop N tags
+       **/
+      break;
+    }
+    else
+    {
+      elapsed = tm_time_subtract(tmr_gettime_low(), starttimeLow);
+    }
+  }
+
+  return ret;
+}
+
+/* Reset reader stats (unless command not supported by reader)
+ */
+static
+TMR_Status
+_resetReaderStats(TMR_Reader *reader, TMR_Reader_StatsFlag statFlags)
+{
+  TMR_Status ret;
+
+  if ((NULL != reader->pSupportsResetStats) && (false == *(reader->pSupportsResetStats)))
+  {
+    /* Command not supported, just skip it */
+    ret = TMR_SUCCESS;
+  }
+  else
+  {
+    ret = TMR_SR_cmdResetReaderStats(reader, statFlags);
+
+    /* Initialize reader->pSupportsResetStats, if necessary*/
+    if (NULL == reader->pSupportsResetStats)
+    {
+      switch (ret)
+      { 
+      case TMR_SUCCESS:
+        reader->_storeSupportsResetStats = true;
+        reader->pSupportsResetStats = &(reader->_storeSupportsResetStats);
+        break;
+      case TMR_ERROR_MSG_WRONG_NUMBER_OF_DATA:
+      case TMR_ERROR_INVALID_OPCODE:
+      case TMR_ERROR_UNIMPLEMENTED_OPCODE:
+      case TMR_ERROR_UNIMPLEMENTED_FEATURE:
+      case TMR_ERROR_INVALID:
+      case TMR_ERROR_UNIMPLEMENTED:
+      case TMR_ERROR_UNSUPPORTED:
+      case TMR_ERROR_UNSUPPORTED_READER_TYPE:
+        /* If command unsupported, make a note not to do it again then
+         * proceed normally */
+        reader->_storeSupportsResetStats = false;
+        reader->pSupportsResetStats = &(reader->_storeSupportsResetStats);
+        ret = TMR_SUCCESS;
+        break;
+      }
+    }
+  }
+  return ret;
+}
+
+TMR_Status
+TMR_SR_read(struct TMR_Reader *reader, uint32_t timeoutMs, int32_t *tagCount)
+{
+  TMR_Status ret;
+  TMR_ReadPlan *rp;
+
+  /**
+   * Reset the reader statistics at the beginning of every search,
+   * currently reader statistics only supports in m6e.. 
+   * TO DO: Enable this for other readers in future.
+   */ 
+  ret = _resetReaderStats(reader, TMR_READER_STATS_FLAG_ALL);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  if (!reader->continuousReading)
+  {
+    /**
+    * In case of sync read only
+    * clear tag buffer
+    */
+    ret = TMR_SR_cmdClearTagBuffer(reader);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+  }
+
+  reader->u.serialReader.tagsRemaining = 0;
+
+#ifdef TMR_ENABLE_BACKGROUND_READS
+  if (false == reader->backgroundEnabled)
+  /**
+   * if TMR_ENABLE_BACKGROUND_READS is not defined, then
+   * only sync read is possible. (Continuous and pseudo async reads
+   * are not available)
+   **/
+#endif
+  {
+    /* If sync read, then reset tagop result count here */
+    reader->u.serialReader.tagopSuccessCount = 0;
+    reader->u.serialReader.tagopFailureCount = 0;
+  }
+  rp = reader->readParams.readPlan;
+
+  if (tagCount)
+  {
+    *tagCount = 0;
+  }
+  
+  ret = TMR_SR_read_internal(reader, timeoutMs, tagCount, rp);
+  if (ret != TMR_SUCCESS)
+  {
+	  return ret;
+  }
+  if (reader->continuousReading)
+	reader->hasContinuousReadStarted = true;
+  return ret;
+}
+
+TMR_Status
+verifySearchStatus(TMR_Reader *reader)
+{
+  TMR_SR_SerialReader *sr;
+  TMR_Status ret;
+  uint8_t *msg;
+  uint32_t timeoutMs;
+  bool crcEnable;
+
+  sr = &reader->u.serialReader;
+  msg = sr->bufResponse;
+  timeoutMs = sr->searchTimeoutMs;
+
+  reader->u.serialReader.crcEnabled = false;
+  TMR_SR_cmdStopReading(reader);
+  
+  while(true)
+  {
+    ret = TMR_SR_receiveMessage(reader, msg, TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE, timeoutMs);
+
+    if(TMR_SUCCESS == ret || TMR_ERROR_DEVICE_RESET == ret)
+    {
+      if ((0x2F == msg[2]) && (0x02 == msg[5]))
+      {
+        /**
+         * 0x2F with type 0x02 means stop continuous reading.
+         * Module has already pushed all the tagreads before
+         * sending this response. i.e., reading is finished
+         **/
+		if (TMR_SR_MSG_SOURCE_USB == reader->u.serialReader.transportType)
+		{
+		  crcEnable = false;
+		  ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_SEND_CRC, &crcEnable);
+		  if (TMR_SUCCESS == ret)
+			reader->u.serialReader.crcEnabled = false;
+		  else
+			reader->u.serialReader.crcEnabled = true;
+		}
+		else
+		{
+			reader->u.serialReader.crcEnabled = true;
+		}
+        return TMR_SUCCESS;
+      }
+      else if ((0x2F == msg[2]) && (0x01 == msg[3] && (0x00 == msg[4])))
+      {
+        /**
+         * 0x2F with error status can also be treated as response for
+         * stop continuous reading.
+         **/
+        return TMR_SUCCESS;
+      }
+    }
+    else
+    {
+      /**
+       * We might get comm errors here, either CRC or TIMEOUT errors
+       * What should we do here??
+       **/
+      if (TMR_ERROR_CRC_ERROR == ret)
+      {
+        /**
+         * When the module is pushing all tags out, just don't bother about
+         * CRC and keep waiting for response for stopReading
+         **/
+        continue;
+      }
+      if (TMR_ERROR_TIMEOUT == ret)
+      {
+        return ret;
+      }
+    }
+  }
+}
+
+TMR_Status
+TMR_SR_hasMoreTags(struct TMR_Reader *reader)
+{
+  TMR_SR_SerialReader* sr;
+  TMR_Status ret;
+
+  sr = &reader->u.serialReader;
+
+//#ifdef TMR_ENABLE_BACKGROUND_READS
+  if ((reader->continuousReading) && (0 == sr->tagsRemainingInBuffer))
+  {
+    uint8_t *msg;
+    uint32_t timeoutMs;
+    uint8_t response_type_pos;
+    uint8_t response_type;
+    
+    msg = sr->bufResponse;
+    timeoutMs = sr->searchTimeoutMs;
+
+    ret = TMR_SR_receiveMessage(reader, msg, TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE, timeoutMs);
+
+    if (TMR_ERROR_TAG_ID_BUFFER_AUTH_REQUEST == ret)
+    {
+      /* Tag password needed to complete tagop.
+       * Parse TagReadData and pass to password-generating callback,
+       * which will return the appropriate authentication. */
+      uint16_t flags = 0;
+      uint8_t bufptr;
+      TMR_TagReadData trd;
+      TMR_TagAuthentication tauth;
+
+      TMR_TRD_init(&trd);
+
+      /* In case of streaming the flags always start at position 8 */
+      bufptr = 8;
+      flags = GETU16AT(msg, bufptr);
+      bufptr += 2;
+      bufptr++;  /* Skip tag count (always = 1) */
+      TMR_SR_parseMetadataFromMessage(reader, &trd, flags, &bufptr, msg);
+      TMR_SR_postprocessReaderSpecificMetadata(&trd, sr);
+      trd.reader = reader;
+
+#ifndef BARE_METAL
+      // printf("Parsed 0604 TagReadData: readCount=%d rssi=%d ant=%d, freq=%d, t_hi=%X, t_lo=%X\n", 
+      //trd.readCount, trd.rssi, trd.antenna, trd.frequency, trd.timestampHigh, trd.timestampLow, trd.phase);
+      {
+        notify_authreq_listeners(reader, &trd, &tauth);		
+      }
+#endif
+
+      /* TODO: Factor out password generation into callback */
+	  reader->hasContinuousReadStarted = false;
+      ret = TMR_SR_cmdAuthReqResponse(reader, &tauth);
+	  if (reader->continuousReading)
+		reader->hasContinuousReadStarted = true;
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+      else
+      {
+        return TMR_ERROR_TAG_ID_BUFFER_AUTH_REQUEST;
+      }
+    }
+
+    if ((TMR_SUCCESS != ret) && (TMR_ERROR_TAG_ID_BUFFER_FULL != ret)
+        && ((TMR_ERROR_NO_TAGS_FOUND != ret)
+        || ((TMR_ERROR_NO_TAGS_FOUND == ret) && (0 == msg[1]))))
+    {
+		if (msg[5] != 0x04 || msg[2] != 0x2f)
+		{
+			reader->u.serialReader.isBasetimeUpdated = false;
+			return ret;
+		}
+    }
+
+    ret = (0 == GETU16AT(msg, 3)) ? TMR_SUCCESS : TMR_ERROR_CODE(GETU16AT(msg, 3));
+    if ((TMR_SUCCESS == ret) && (0 == msg[1]))
+    {
+      /**
+       * In case of streaming and ISO protocol after every search cycle
+       * module sends the response for embedded operation status as
+       * FF 00 22 00 00.
+       * In this case return back with 0x400 error, because success response will deceive
+       * the read thread to process it. For GEN2 case we got the response with 0x400 status.
+       **/
+      return TMR_ERROR_NO_TAGS_FOUND;
+    }
+    if (((0x2F == msg[2]) && (TMR_ERROR_TAG_ID_BUFFER_FULL == ret))
+      ||((0x22 == msg[2]) && (TMR_ERROR_TAG_ID_BUFFER_FULL == ret)))
+    {
+      return ret;
+    }
+
+    if (0x2F == msg[2])
+    {
+      if (0x02 == msg[5])
+      {
+        /**
+         * 0x2F with type 0x02 means stop continuous reading.
+         * Module has already pushed all the tagreads before
+         * sending this response. i.e., reading is finished
+         **/
+        reader->finishedReading = true;
+        reader->u.serialReader.isBasetimeUpdated = false;
+        return TMR_ERROR_END_OF_READING;
+      }
+	  else if (0x03 == msg[5])
+      {
+      /**
+         * 0x2F with type 0x03 means left over client Auth message/response, ignore it.
+         **/		
+        return TMR_ERROR_TAG_ID_BUFFER_AUTH_REQUEST;		
+      }
+	  else if (0x04 == msg[5])
+	  {
+		  memcpy(&reader->paramMessage[0], msg, (msg[1] + 5) * sizeof(uint8_t));
+		  reader->paramWait = false;
+	  }
+      /**
+       * Control comes here in case of the response received
+       * for start continuous reading command. (0x2F with type 0x01)
+       **/
+      return TMR_ERROR_NO_TAGS;
+    }
+    else if (msg[1] < 6)
+    { /* Need at least enough bytes to get to Response Type field */
+      return TMR_ERROR_PARSE;
+    }
+
+    response_type_pos = (0x10 == (msg[5] & 0x10)) ? 10 : 8;
+
+    response_type = msg[response_type_pos];
+    switch (response_type)
+    {
+    case 0x02:
+      /* Handle status stream responses */
+      reader->isStatusResponse = true;
+      sr->bufPointer = 9;
+      return TMR_SUCCESS;
+    case 0x01:
+      /* Stream continues after this message */
+      reader->isStatusResponse = false;
+      sr->tagsRemainingInBuffer = 1;
+      sr->bufPointer = 11;
+      return TMR_SUCCESS;
+    case 0x00:
+      /* while fixing bug#4190, Missed updating base timestamp for embedded read. 
+      Because of this time stamps are falling back.To fix this issue updated base time stamp. */
+      reader->u.serialReader.isBasetimeUpdated = false;
+      /* Stream ends with this message */
+      sr->tagsRemaining = 0;
+
+      if (sr->oldQ.type != TMR_SR_GEN2_Q_INVALID)
+      {
+        ret = TMR_paramSet(reader, TMR_PARAM_GEN2_Q, &(sr->oldQ));
+        if (TMR_SUCCESS != ret)
+        {
+          return ret;
+        }
+        sr->oldQ.type = TMR_SR_GEN2_Q_INVALID;
+      }
+
+      if (NULL != reader->readParams.readPlan->u.simple.tagop)
+      {
+        response_type_pos += 7;
+        sr->tagopSuccessCount += GETU16(msg, response_type_pos);
+        sr->tagopFailureCount += GETU16(msg, response_type_pos);
+      }
+      if (TMR_SUCCESS == ret)
+      { /* If things look good so far, signal that we are done with tags */
+        return TMR_ERROR_NO_TAGS;
+      }
+      /* otherwise feed the error back (should only be TMR_ERROR_TAG_ID_BUFFER_FULL) */
+      return ret;
+    default:
+      /* Unknown response type */
+      return TMR_ERROR_PARSE;
+    }
+  }
+  else
+//#endif
+  {
+    /**
+     * TMR_SR_hasMoreTags control comes here only in case of sync reading
+     * And in case of pseudo async reading when TMR_ENABLE_BACKGROUND_READS
+     * is defined.
+     **/
+    ret = (sr->tagsRemaining > 0) ? TMR_SUCCESS : TMR_ERROR_NO_TAGS;
+    return ret;
+  }
+}
+
+TMR_Status
+TMR_SR_getNextTag(struct TMR_Reader *reader, TMR_TagReadData *read)
+{
+  TMR_SR_SerialReader *sr;
+  TMR_Status ret;
+  uint8_t *msg;
+  uint8_t i;
+  uint16_t flags = 0;
+  uint32_t timeoutMs;
+  uint8_t subResponseLen = 0;
+  uint8_t crclen = 2 ;
+  uint8_t epclen = 0;
+
+  sr = &reader->u.serialReader;
+  timeoutMs = sr->searchTimeoutMs;
+
+  {
+    msg = sr->bufResponse;
+
+    if (sr->tagsRemaining == 0)
+    {
+      return TMR_ERROR_NO_TAGS;
+    }
+
+    if (sr->tagsRemainingInBuffer == 0)
+    {
+      /* Fetch the next set of tags from the reader */
+      if (reader->continuousReading)
+      {
+        ret = TMR_SR_hasMoreTags(reader);
+        if (TMR_SUCCESS != ret)
+        {
+          return ret;
+        }
+      }
+      else
+      {
+        if (reader->u.serialReader.opCode == TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE)
+        {
+          i = 2;
+          SETU8(msg, i, TMR_SR_OPCODE_GET_TAG_ID_BUFFER);
+          SETU16(msg, i, reader->userMetadataFlag);
+          SETU8(msg, i, 0); /* read options */
+          msg[1] = i-3; /* Install length */
+          ret = TMR_SR_send(reader, msg);
+          if (TMR_SUCCESS != ret)
+          {
+            return ret;
+          }
+          sr->tagsRemainingInBuffer = msg[8];
+          sr->bufPointer = 9;
+        }
+        else if (reader->u.serialReader.opCode == TMR_SR_OPCODE_READ_TAG_ID_SINGLE)
+        {
+          TMR_SR_receiveMessage(reader, msg, reader->u.serialReader.opCode, timeoutMs);
+          sr->tagsRemainingInBuffer = (uint8_t)GETU32AT(msg , 9);
+          sr->tagsRemaining = sr->tagsRemainingInBuffer;
+          sr->bufPointer = 13 ;
+        }
+        else
+        {
+           return TMR_ERROR_INVALID_OPCODE; 
+        }
+      }
+    }
+
+    i = sr->bufPointer;
+    if (reader->u.serialReader.opCode == TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE)
+    {
+      flags = GETU16AT(msg, reader->continuousReading ? 8 : 5);
+      TMR_SR_parseMetadataFromMessage(reader, read, flags, &i, msg);
+      
+    }
+    if (reader->u.serialReader.opCode == TMR_SR_OPCODE_READ_TAG_ID_SINGLE)
+    {
+      flags = GETU16AT(msg, i + 6);
+      subResponseLen = msg[i+1];
+      i += 7;
+      TMR_SR_parseMetadataOnly(reader, read, flags, &i, msg);
+      epclen = subResponseLen + 4 - (i - sr->bufPointer) - crclen;
+      read->tag.epcByteCount=epclen;
+      memcpy(&(read->tag.epc), &msg[i], read->tag.epcByteCount);
+      i+=epclen;
+      read->tag.crc = GETU16(msg, i);
+    }
+    sr->bufPointer = i;
+    
+    
+    TMR_SR_postprocessReaderSpecificMetadata(read, sr);
+
+    sr->tagsRemainingInBuffer--;
+
+    if (false == reader->continuousReading)
+    {
+      sr->tagsRemaining--;
+    }
+    read->reader = reader;
+
+    return TMR_SUCCESS;
+  }
+}
+
+TMR_Status 
+TMR_SR_writeTag(struct TMR_Reader *reader, const TMR_TagFilter *filter,
+                const TMR_TagData *data)
+{
+  TMR_Status ret;
+  TMR_SR_SerialReader *sr;
+
+  sr = &reader->u.serialReader;
+
+  ret = setProtocol(reader, reader->tagOpParams.protocol);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  if (TMR_TAG_PROTOCOL_GEN2 == reader->tagOpParams.protocol)
+  {  
+    return TMR_SR_cmdWriteGen2TagEpc(reader, filter, sr->gen2AccessPassword, (uint16_t)(sr->commandTimeout), 
+                                 data->epcByteCount, data->epc, 0);
+  }
+  else
+  {
+    return TMR_ERROR_UNIMPLEMENTED;
+  }
+}
+
+
+TMR_Status
+TMR_SR_readTagMemWords(TMR_Reader *reader, const TMR_TagFilter *target, 
+                       uint32_t bank, uint32_t wordAddress, 
+                       uint16_t wordCount, uint16_t data[])
+{
+  TMR_Status ret;
+
+  ret = TMR_SR_readTagMemBytes(reader, target, bank, wordAddress * 2,
+                               wordCount * 2, (uint8_t *)data);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+#ifndef TMR_BIG_ENDIAN_HOST
+  {
+    uint16_t i;
+    uint8_t *data8;
+    /* We used the uint16_t data as temporary storage for the values read,
+       but we need to adjust for possible endianness differences.
+       This is technically correct on all platforms, though it's a no-op
+       on big-endian ones. */
+    data8 = (uint8_t *)data;
+    for (i = 0; i < wordCount; i++)
+    {
+      data[i] = (data8[2*i] << 8) | data8[2*i + 1];
+    }
+  }
+#endif
+
+  return TMR_SUCCESS;
+}
+
+
+static TMR_Status
+TMR_SR_readTagMemBytesUnaligned(TMR_Reader *reader,
+                                const TMR_TagFilter *target, 
+                                uint32_t bank, uint32_t byteAddress, 
+                                uint16_t byteCount, uint8_t data[])
+{
+  TMR_Status ret;
+  TMR_TagReadData read;
+  uint16_t wordCount;
+  uint8_t buf[254];
+  TMR_SR_SerialReader *sr;
+
+  sr = &reader->u.serialReader;
+
+  wordCount = (uint16_t)((byteCount + 1 + (byteAddress & 1) ) / 2);
+  read.data.max = 254;
+  read.data.list = buf;
+  read.metadataFlags = 0;
+
+  ret = TMR_SR_cmdGEN2ReadTagData(reader, (uint16_t)(sr->commandTimeout),
+                                  (TMR_GEN2_Bank)bank, byteAddress / 2, (uint8_t)wordCount,
+                                  sr->gen2AccessPassword, target, &read);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  memcpy(data, buf + (byteAddress & 1), byteCount);
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_readTagMemBytes(TMR_Reader *reader, const TMR_TagFilter *target, 
+                       uint32_t bank, uint32_t byteAddress, 
+                       uint16_t byteCount, uint8_t data[])
+{
+  TMR_Status ret;
+  TMR_TagReadData read;
+  TMR_SR_SerialReader *sr;
+
+  sr = &reader->u.serialReader;
+
+  ret = setProtocol(reader, reader->tagOpParams.protocol);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  read.data.max = byteCount;
+  read.data.list = (uint8_t *)data;
+  read.metadataFlags = 0;
+
+  if (TMR_TAG_PROTOCOL_GEN2 == reader->tagOpParams.protocol)
+  {
+    /*
+     * Handling unaligned reads takes spare memory; avoid allocating that
+     * (on that stack) if not necessary.
+     */
+    if ((byteAddress & 1) || (byteCount & 1))
+    {
+      return TMR_SR_readTagMemBytesUnaligned(reader, target, bank, byteAddress,
+                                             byteCount, data);
+    }
+
+    return TMR_SR_cmdGEN2ReadTagData(reader, (uint16_t)(sr->commandTimeout),
+                                     (TMR_GEN2_Bank)bank, byteAddress / 2, byteCount / 2,
+                                     sr->gen2AccessPassword, target, &read);
+  }
+#ifdef TMR_ENABLE_ISO180006B
+  else if (TMR_TAG_PROTOCOL_ISO180006B == reader->tagOpParams.protocol)
+  {
+    return TMR_SR_cmdISO180006BReadTagData(reader,(uint16_t)(sr->commandTimeout),
+                                           (uint8_t)byteAddress, (uint8_t)byteCount, target,
+                                           &read);
+  }
+#endif /* TMR_ENABLE_ISO180006B */
+  else
+  {
+    return TMR_ERROR_UNIMPLEMENTED;
+  }
+}
+
+TMR_Status
+TMR_SR_modifyFlash(TMR_Reader *reader, uint8_t sector, uint32_t address,
+                   uint32_t password, uint8_t length, const uint8_t data[],
+                   uint32_t offset)
+{
+  /**
+   * As only M6e reader and it's varient supports modifying the flash in 
+   * application mode.Hence, this check is required.
+   */
+  if ((TMR_SR_MODEL_M6E == reader->u.serialReader.versionInfo.hardware[0])||
+      (TMR_SR_MODEL_MICRO == reader->u.serialReader.versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_M6E_NANO == reader->u.serialReader.versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_M6E_I == reader->u.serialReader.versionInfo.hardware[0]))
+  {
+    return TMR_SR_cmdModifyFlashSector(reader, sector, address, password, length,
+                                       data, offset);
+  }
+  else
+    return TMR_ERROR_UNSUPPORTED;
+}
+TMR_Status
+TMR_SR_writeTagMemWords(struct TMR_Reader *reader, const TMR_TagFilter *filter,
+                        uint32_t bank, uint32_t address,
+                        uint16_t count, const uint16_t data[])
+{
+  const uint8_t *dataPtr;
+#ifndef TMR_BIG_ENDIAN_HOST
+  uint8_t buf[254];
+  int i;
+
+    for (i = 0 ; i < count ; i++)
+    {
+      buf[2*i    ] = data[i] >> 8;
+      buf[2*i + 1] = data[i] & 0xff;
+    }
+    dataPtr = buf;
+#else
+    dataPtr = (const uint8_t *)data;
+#endif
+
+    return TMR_SR_writeTagMemBytes(reader, filter, bank, address * 2, count * 2,
+                                   dataPtr);
+}
+
+TMR_Status
+TMR_SR_writeTagMemBytes(struct TMR_Reader *reader, const TMR_TagFilter *filter,
+                        uint32_t bank, uint32_t address,
+                        uint16_t count, const uint8_t data[])
+{
+  TMR_Status ret;
+  TMR_SR_SerialReader *sr;
+  TMR_GEN2_WriteMode mode;
+  TMR_GEN2_WriteMode *value = &mode;
+ 
+  sr = &reader->u.serialReader;
+  TMR_paramGet(reader, TMR_PARAM_GEN2_WRITEMODE, value);
+
+  ret = setProtocol(reader, reader->tagOpParams.protocol);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  if (TMR_TAG_PROTOCOL_GEN2 == reader->tagOpParams.protocol)
+  {
+    /* Buffer for converting to Gen2 native word size.
+     * A waste of space, but the only way to do byte/word conversions without
+     * munging the original data input.  ReadTagMemBytes is deprecated, anyway,
+     * along with all the other protocol-independent methods, so avoid using it,
+     * if possible. */
+    uint16_t data16[TMR_SR_MAX_PACKET_SIZE/2];
+    uint16_t wordCount;
+    uint16_t iWord;
+
+    /* Misaligned writes are not permitted */
+    if ((address & 1) || (count & 1))
+    {
+      return TMR_ERROR_INVALID;
+    }
+
+    wordCount = count/2;
+    for (iWord=0; iWord<wordCount; iWord++)
+    {
+      data16[iWord] = 0;
+      data16[iWord] |= data[(2*iWord)+0];
+      data16[iWord] <<= 8;
+      data16[iWord] |= data[(2*iWord)+1];
+    }
+
+    switch (mode)
+    {
+    case TMR_GEN2_WORD_ONLY:
+      return TMR_SR_cmdGEN2WriteTagData(reader, (uint16_t)(sr->commandTimeout),
+        (TMR_GEN2_Bank)bank, address / 2, (uint8_t)count, data,
+        sr->gen2AccessPassword, filter);
+    case TMR_GEN2_BLOCK_ONLY:
+      return TMR_SR_cmdBlockWrite(reader,(uint16_t)sr->commandTimeout, (TMR_GEN2_Bank)bank, address / 2, (uint8_t)(count/2), data16, sr->gen2AccessPassword, filter);
+    case TMR_GEN2_BLOCK_FALLBACK:
+
+      ret =  TMR_SR_cmdBlockWrite(reader,(uint16_t)sr->commandTimeout, (TMR_GEN2_Bank)bank, address / 2, (uint8_t)(count/2), data16, sr->gen2AccessPassword, filter);
+      if (TMR_SUCCESS == ret)
+      {
+        return ret;
+      }
+      else 
+      {
+        return TMR_SR_cmdGEN2WriteTagData(reader, (uint16_t)(sr->commandTimeout),
+          (TMR_GEN2_Bank)bank, address / 2, (uint8_t)count, data,
+          sr->gen2AccessPassword, filter);
+
+      }
+    default: 
+      return TMR_ERROR_INVALID_WRITE_MODE;
+    }
+
+
+  }
+#ifdef TMR_ENABLE_ISO180006B
+  else if (TMR_TAG_PROTOCOL_ISO180006B == reader->tagOpParams.protocol)
+  {
+    if (count != 1)
+    {
+      return TMR_ERROR_INVALID;
+    }
+    return TMR_SR_cmdISO180006BWriteTagData(reader, (uint16_t)(sr->commandTimeout),
+                                            (uint8_t)address, 1, data, filter);
+  }
+#endif
+  else
+  {
+    return TMR_ERROR_INVALID;
+  }
+}
+
+
+TMR_Status
+TMR_SR_lockTag(struct TMR_Reader *reader, const TMR_TagFilter *filter,
+               TMR_TagLockAction *action)
+{
+  TMR_Status ret;
+  TMR_SR_SerialReader *sr;
+
+  sr = &reader->u.serialReader;
+
+  ret = setProtocol(reader, reader->tagOpParams.protocol);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  if (TMR_TAG_PROTOCOL_GEN2 == reader->tagOpParams.protocol)
+  {
+    if (TMR_LOCK_ACTION_TYPE_GEN2_LOCK_ACTION != action->type)
+    {
+      /* Lock type doesn't match tagop protocol */
+      return TMR_ERROR_INVALID;
+    }
+    return TMR_SR_cmdGEN2LockTag(reader, (uint16_t)sr->commandTimeout,
+                                 action->u.gen2LockAction.mask, 
+                                 action->u.gen2LockAction.action, 
+                                 sr->gen2AccessPassword,
+                                 filter);
+  }
+#ifdef TMR_ENABLE_ISO180006B
+  else if (TMR_TAG_PROTOCOL_ISO180006B == reader->tagOpParams.protocol)
+  {
+    if (TMR_LOCK_ACTION_TYPE_ISO180006B_LOCK_ACTION != action->type)
+    {
+      /* Lock type doesn't match tagop protocol */
+      return TMR_ERROR_INVALID;
+    }
+    return TMR_SR_cmdISO180006BLockTag(reader, (uint16_t)(sr->commandTimeout),
+                                       action->u.iso180006bLockAction.address, 
+                                       filter);
+  }
+#endif
+  else
+  {
+    return TMR_ERROR_UNIMPLEMENTED;
+  }
+}
+
+TMR_Status
+TMR_SR_reboot(TMR_Reader *reader)
+{
+  TMR_Status ret;
+
+  ret = TMR_SR_cmdrebootReader(reader);
+
+  return ret;
+}
+
+TMR_Status
+TMR_SR_killTag(struct TMR_Reader *reader, const TMR_TagFilter *filter,
+               const TMR_TagAuthentication *auth)
+{
+  TMR_Status ret;
+  TMR_SR_SerialReader *sr;
+
+  sr = &reader->u.serialReader;
+
+  ret = setProtocol(reader, reader->tagOpParams.protocol);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  if (TMR_TAG_PROTOCOL_GEN2 == reader->tagOpParams.protocol)
+  {
+    if (TMR_AUTH_TYPE_GEN2_PASSWORD != auth->type)
+    {
+      /* Auth type doesn't match tagop protocol */
+      return TMR_ERROR_INVALID;
+    }
+
+    return TMR_SR_cmdKillTag(reader,
+                             (uint16_t)(sr->commandTimeout),
+                             auth->u.gen2Password,
+                             filter);
+  }
+  else
+  {
+    return TMR_ERROR_UNIMPLEMENTED;
+  }
+}
+
+TMR_Status
+TMR_SR_gpoSet(struct TMR_Reader *reader, uint8_t count,
+              const TMR_GpioPin state[])
+{
+  TMR_Status ret;
+  int i;
+  
+  for (i = 0; i < count; i++)
+  {
+    ret = TMR_SR_cmdSetGPIO(reader, state[i].id, state[i].high);
+    if (TMR_SUCCESS != ret)
+      return ret;
+  }
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status TMR_SR_gpiGet(struct TMR_Reader *reader, uint8_t *count,
+                         TMR_GpioPin state[])
+{
+  TMR_Status ret;
+  TMR_GpioPin pinStates[4];
+  uint8_t i,j, numPins;
+
+  numPins = numberof(pinStates);
+  ret = TMR_SR_cmdGetGPIO(reader, &numPins, pinStates);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  if (numPins > *count)
+  {
+    numPins = *count;
+  }
+
+  *count = 0;
+  j = 0;
+  for (i = 0 ; i < numPins ; i++)
+  {
+    if (!pinStates[i].output)
+    {
+      /* If pin is input, only then copy to output */
+      state[j].id = pinStates[i].id;
+      state[j].high = pinStates[i].high;
+      state[j].output = pinStates[i].output;
+      (*count)++;
+      j ++;
+    }
+  }
+
+  return TMR_SUCCESS;
+}
+
+#ifdef TMR_ENABLE_STDIO
+TMR_Status
+TMR_SR_firmwareLoad(struct TMR_Reader *reader, void *cookie,
+                    TMR_FirmwareDataProvider provider)
+{
+  static const uint8_t magic[] =
+    { 0x54, 0x4D, 0x2D, 0x53, 0x50, 0x61, 0x69, 0x6B, 0x00, 0x00, 0x00, 0x02 };
+
+  TMR_Status ret;
+  uint8_t buf[256];
+  uint16_t packetLen, packetRemaining, size, offset;
+  uint32_t len, rate, address, remaining;
+  TMR_SR_SerialReader *sr;
+  TMR_SR_SerialTransport *transport;
+
+  sr = &reader->u.serialReader;
+  transport = &sr->transport;
+
+  remaining = numberof(magic) + 4;
+  offset = 0;
+  
+  while (remaining > 0)
+  {
+    size = (uint16_t)remaining;
+    if (false == provider(cookie, &size, buf + offset))
+    {
+      return TMR_ERROR_FIRMWARE_FORMAT;
+    }
+    
+    remaining -= size;
+    offset += size;
+  }
+
+  if (0 != memcmp(buf, magic, numberof(magic)))
+  {
+    return TMR_ERROR_FIRMWARE_FORMAT;
+  }
+
+  len = GETU32AT(buf, 12);
+
+  /* @todo get any params we want to reset */
+
+  /*
+   * Drop baud to 9600 so we know for sure what it will be after going
+   * back to the bootloader.  (Older firmwares always revert to 9600.
+   * Newer ones keep the current baud rate.)
+   */
+  if (NULL != transport->setBaudRate)
+  {
+    /**
+     * some transport layer does not support baud rate settings.
+     * for ex: TCP transport. In that case skip the baud rate
+     * settings.
+     */ 
+
+    ret = TMR_SR_cmdSetBaudRate(reader, 9600);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+    ret = transport->setBaudRate(transport, 9600);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+  }
+  ret = TMR_SR_cmdBootBootloader(reader);
+  if ((TMR_SUCCESS != ret)
+      /* Invalid Opcode okay -- means "already in bootloader" */
+      && (TMR_ERROR_INVALID_OPCODE != ret))
+  {
+    return ret;
+  }
+
+  /*
+   * Wait for the bootloader to be entered. 200ms is enough.
+   */
+  tmr_sleep(200);
+
+  /* Bootloader doesn't support wakeup preambles */
+  sr->supportsPreamble = false;
+
+  /* Bootloader doesn't support high speed operation */
+  rate = sr->baudRate;
+  if (rate > 115200)
+  {
+    rate = 115200;
+  }
+
+  if (NULL != transport->setBaudRate)
+  {
+    /**
+     * some transport layer does not support baud rate settings.
+     * for ex: TCP transport. In that case skip the baud rate
+     * settings.
+     */ 
+
+    ret = TMR_SR_cmdSetBaudRate(reader, rate);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+    ret = transport->setBaudRate(transport, rate);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+  }
+  ret = TMR_SR_cmdEraseFlash(reader, 2, 0x08959121);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  address = 0;
+  remaining = len;
+  while (remaining > 0)
+  {
+    packetLen = 240;
+    if (packetLen > remaining)
+    {
+      packetLen = (uint16_t)remaining;
+    }
+    offset = 0;
+    packetRemaining = packetLen;
+    while (packetRemaining > 0)
+    {
+      size = packetRemaining;
+      if (false == provider(cookie, &size, buf + offset))
+      {
+        return TMR_ERROR_FIRMWARE_FORMAT;
+      }
+      packetRemaining -= size;
+      offset += size;
+    }
+    ret = TMR_SR_cmdWriteFlashSector(reader, 2, address, 0x02254410,(uint8_t) packetLen,
+                                     buf, 0);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+    address += packetLen;
+    remaining -= packetLen;
+  }
+  
+  ret = TMR_SR_boot(reader, rate);
+  if(ret != TMR_SUCCESS)
+  {
+    if(ret == TMR_ERROR_AUTOREAD_ENABLED)
+    {
+      ret = TMR_ERROR_FIRMWARE_UPDATE_ON_AUTOREAD;
+      return ret;
+    }
+  }
+      return ret;
+}
+#endif
+
+static TMR_Status
+getHardwareInfo(struct TMR_Reader *reader, void *value)
+{
+  //TMR_Status ret;
+  //uint8_t buf[127];
+  char tmp[255];
+  //uint8_t count;
+  TMR_SR_VersionInfo *info;
+
+  info = &reader->u.serialReader.versionInfo;
+
+  TMR_hexDottedQuad(info->hardware, tmp);
+  /**
+   * Commented below code to fix the Bug#2117
+   */
+  /*
+     tmp[11] = '-';
+     count = 127;
+     ret = TMR_SR_cmdGetHardwareVersion(reader, 0, 0, &count, buf);
+     if (TMR_SUCCESS != ret)
+     {
+     count = 0;
+     tmp[11] = '\0';
+     }
+
+     TMR_bytesToHex(buf, count, tmp + 12);
+     TMR_stringCopy(value, tmp, 12 + 2*count);*/
+  TMR_stringCopy(value, tmp, (int)strlen(tmp));
+
+  return TMR_SUCCESS;
+}
+
+static TMR_Status
+getSerialNumber(struct TMR_Reader *reader, void *value)
+{
+  /* See http://trac/swtree/changeset/6498 for previous implementation */
+  TMR_Status ret;
+  uint8_t buf[127];
+  uint8_t count;
+  char tmp[127];
+  int tmplen;
+
+  count = 127;
+  tmplen = 0;
+  ret = TMR_SR_cmdGetHardwareVersion(reader, 0, 0x40, &count, buf);
+  if (TMR_SUCCESS != ret)
+  {
+    count = 0;
+  }
+  else
+  {
+    int idx;
+    uint8_t len;
+
+    idx = 3;
+    len = buf[idx++];
+    if (len > (count-3))
+    {
+      ret = TMR_ERROR_UNIMPLEMENTED;
+    }
+    else
+    {
+      for (tmplen=0; tmplen<len; tmplen++)
+      {
+        tmp[tmplen] = (char)buf[idx+tmplen];
+      }
+    }
+  }
+  if (0 == count)
+  {
+    TMR_String *serial = (TMR_String *)value;
+    /**
+     * Command failure: 
+     * Serial number not implemented on this reader
+     * Leave value at default "no value" 
+     */
+    serial->value[0] = '\0';
+    return TMR_SUCCESS;
+  }
+  TMR_stringCopy(value, tmp, tmplen);
+  return ret;
+}
+
+/* Abuse the structure layout of TMR_SR_PortPowerAndSettlingTime a bit
+ * so that this can be one function instead of three only slightly
+ * different pieces of code. Since all three per-port values are
+ * represented as uint16_t, take an additional 'offset' parameter that
+ * gives the pointer distance from the first element to the element
+ * (readPower, writePower, settlingTime) that we actually want to set.
+ */
+static TMR_Status
+setPortValues(struct TMR_Reader *reader, const TMR_PortValueList *list,
+              int offset)
+{
+  TMR_Status ret;
+  TMR_SR_PortPowerAndSettlingTime ports[TMR_SR_MAX_ANTENNA_PORTS];
+  uint8_t count;
+  uint16_t i, j;
+
+  count = numberof(ports);
+
+  ret = TMR_SR_cmdGetAntennaPortPowersAndSettlingTime(reader, &count, ports);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* If a value is left out, 0 is assumed */
+  /*for (j = 0; j < count; j++)
+  {
+    *(&ports[j].readPower + offset) = 0;
+  }*/
+
+  /* 
+   * For each settling time in the user's list, try to find an
+   * existing entry in the list returned from the reader.
+   */
+  for (i = 0; i < list->len; i++)
+  {
+    for (j = 0 ; j < count ; j++)
+    {
+      if (list->list[i].port == ports[j].port)
+      {
+        break;
+      }
+    }
+    if (j == count)
+    {
+      if (count == TMR_SR_MAX_ANTENNA_PORTS)
+      {
+        return TMR_ERROR_TOO_BIG;
+      }
+      ports[j].port = list->list[i].port;
+      ports[j].readPower = 0;
+      ports[j].writePower = 0;
+      ports[j].settlingTime = 0;
+      count++;
+    }
+
+    if (list->list[i].value > 32767 || list->list[i].value < -32768)
+    {
+      return TMR_ERROR_ILLEGAL_VALUE;
+    }
+    *(&ports[j].readPower + offset) = (int16_t)(list->list[i].value);
+  }
+  return TMR_SR_cmdSetAntennaPortPowersAndSettlingTime(reader, count, ports);
+}
+
+/* See comment before setPortValues() for the meaning of offset */
+static TMR_Status
+getPortValues(struct TMR_Reader *reader, TMR_PortValueList *list, int offset)
+{
+  TMR_Status ret;
+  TMR_SR_PortPowerAndSettlingTime ports[TMR_SR_MAX_ANTENNA_PORTS];
+  uint8_t count;
+  uint16_t i, j;
+
+  count = numberof(ports);
+
+  ret = TMR_SR_cmdGetAntennaPortPowersAndSettlingTime(reader, &count, ports);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  for (i = 0, j = 0; i < count; i++)
+  {
+    if ((0 == *(&ports[i].readPower + offset)  && ((TMR_SR_MODEL_MICRO != reader->u.serialReader.versionInfo.hardware[0])
+      || (TMR_SR_MODEL_M6E_NANO != reader->u.serialReader.versionInfo.hardware[0]))) 
+        || (((TMR_SR_MODEL_MICRO == reader->u.serialReader.versionInfo.hardware[0]) ||
+        (TMR_SR_MODEL_M6E_NANO == reader->u.serialReader.versionInfo.hardware[0]))
+          && (-32768 ==  *(&ports[i].readPower + offset))))
+    {
+      continue;
+    }
+    if (j < list->max)
+    {
+      list->list[j].port = ports[i].port;
+      list->list[j].value = (int32_t)*(&ports[i].readPower + offset);
+    }
+    j++;
+  }
+  list->len = (uint8_t)j;
+
+  return TMR_SUCCESS;
+}
+
+static TMR_Status
+TMR_SR_paramSet(struct TMR_Reader *reader, TMR_Param key, const void *value)
+{
+  TMR_Status ret;
+  TMR_SR_Configuration readerkey;
+  TMR_SR_ProtocolConfiguration protokey;
+  TMR_SR_SerialReader *sr;
+  TMR_SR_SerialTransport *transport;
+
+  ret = TMR_SUCCESS;
+  sr = &reader->u.serialReader;
+  readerkey = TMR_SR_CONFIGURATION_TRANSMIT_POWER_SAVE;
+  protokey.protocol = TMR_TAG_PROTOCOL_GEN2;
+
+  if (0 == BITGET(sr->paramConfirmed, key))
+  {
+    TMR_paramProbe(reader, key);
+  }
+
+  if (BITGET(sr->paramConfirmed, key) && (0 == BITGET(sr->paramPresent, key)))
+  {
+    return TMR_ERROR_NOT_FOUND;
+  }
+
+  switch (key)
+  {
+  case TMR_PARAM_REGION_ID:
+    sr->regionId = *(TMR_Region*)value;
+    if (reader->connected)
+    {
+      ret = TMR_SR_cmdSetRegion(reader, sr->regionId);
+    }
+    break;
+
+  case TMR_PARAM_URI:
+  case TMR_PARAM_PRODUCT_GROUP_ID:
+  case TMR_PARAM_PRODUCT_GROUP:
+  case TMR_PARAM_PRODUCT_ID:
+  case TMR_PARAM_TAGREADATA_TAGOPSUCCESSCOUNT:
+  case TMR_PARAM_TAGREADATA_TAGOPFAILURECOUNT:
+    {
+      ret = TMR_ERROR_READONLY;
+      break;
+    }
+
+  case TMR_PARAM_STATUS_ENABLE_ANTENNAREPORT:
+    {
+      *(bool *)value ? (reader->streamStats |= TMR_SR_STATUS_ANTENNA) :
+        (reader->streamStats &= ~TMR_SR_STATUS_ANTENNA) ;
+      break;
+    }
+  case TMR_PARAM_STATUS_ENABLE_FREQUENCYREPORT:
+    {
+      *(bool *)value ? (reader->streamStats |= TMR_SR_STATUS_FREQUENCY) :
+        (reader->streamStats &= ~TMR_SR_STATUS_FREQUENCY) ;
+      break;
+    }
+  case TMR_PARAM_STATUS_ENABLE_TEMPERATUREREPORT:
+    {
+      *(bool *)value ? (reader->streamStats |= TMR_SR_STATUS_TEMPERATURE) :
+        (reader->streamStats &= ~TMR_SR_STATUS_TEMPERATURE) ;
+      break;
+    }
+
+  case TMR_PARAM_BAUDRATE:
+  {
+    uint32_t rate;
+
+    transport = &sr->transport;
+    rate = *(uint32_t *)value;
+
+    if (reader->connected)
+    {
+      if (NULL != transport->setBaudRate)
+      {
+        /**
+         * some transport layer does not support baud rate settings.
+         * for ex: TCP transport. In that case skip the baud rate
+         * settings.
+         */ 
+        ret = TMR_SR_cmdSetBaudRate(reader, rate);
+        if (TMR_SUCCESS != ret)
+        {
+          break;
+        }
+        sr->baudRate = rate;
+        transport->setBaudRate(transport, sr->baudRate);
+      }
+    }
+    else
+    {
+      sr->baudRate = rate;
+    }
+    break;
+  }
+
+  case TMR_PARAM_PROBEBAUDRATES:
+  {
+    const TMR_uint32List *u32List;
+    uint8_t i;
+    u32List = value;
+
+    if (u32List->len > sr->probeBaudRates.max)
+    {
+      ret = TMR_ERROR_TOO_BIG;
+      break;
+    }
+
+    for(i = 0; i < u32List->len; i++)
+    {
+      sr->probeBaudRates.list[i] = u32List->list[i];
+    }
+
+    sr->probeBaudRates.len = u32List->len;
+    break;
+  }
+
+  case TMR_PARAM_COMMANDTIMEOUT:
+	{
+      uint32_t val = *(uint32_t*)value;
+	  if (((uint32_t)1<<31) & val)
+	  {
+	    ret = TMR_ERROR_ILLEGAL_VALUE; 
+	  }
+	  else
+	  {
+        sr->commandTimeout = *(uint32_t *)value;
+	  }
+	}
+    break;
+  case TMR_PARAM_TRANSPORTTIMEOUT:
+    {
+      uint32_t val = *(uint32_t*)value;
+      if (((uint32_t)1<<31) & val)
+      {
+        ret = TMR_ERROR_ILLEGAL_VALUE; 
+      }
+      else
+      {
+        /**
+         * In case user specified the timeout value for connect
+         * Enable the usrTimoutEnable option
+         */
+        sr->transportTimeout = *(uint32_t *)value;
+        sr->usrTimeoutEnable = true;
+      }
+    }
+	break;
+  case TMR_PARAM_RADIO_ENABLEPOWERSAVE:
+	readerkey = TMR_SR_CONFIGURATION_TRANSMIT_POWER_SAVE;
+	break;
+  case TMR_PARAM_RADIO_ENABLESJC:
+	readerkey = TMR_SR_CONFIGURATION_SELF_JAMMER_CANCELLATION;
+	break;
+  case TMR_PARAM_EXTENDEDEPC:
+    readerkey = TMR_SR_CONFIGURATION_EXTENDED_EPC;
+    break;
+
+  case TMR_PARAM_TAGREADDATA_UNIQUEBYPROTOCOL:
+    if ((TMR_SR_MODEL_M6E == sr->versionInfo.hardware[0]) || 
+        (TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0]) ||
+        (TMR_SR_MODEL_M6E_NANO == sr->versionInfo.hardware[0]) ||
+        (TMR_SR_MODEL_M6E_I == sr->versionInfo.hardware[0]))
+    {
+      ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_UNIQUE_BY_PROTOCOL, value);
+    }
+    else
+    {
+      ret = TMR_ERROR_NOT_FOUND;
+    }
+    break;
+    
+  case TMR_PARAM_TAGREADDATA_READFILTERTIMEOUT:
+    if ((TMR_SR_MODEL_M6E == sr->versionInfo.hardware[0]) || 
+        (TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0]) ||
+        (TMR_SR_MODEL_M6E_NANO == sr->versionInfo.hardware[0]) ||
+        (TMR_SR_MODEL_M6E_I == sr->versionInfo.hardware[0]))
+    {
+      int32_t timeout = (TMR_DEFAULT_READ_FILTER_TIMEOUT == *(int32_t *)value) ? 0 : *(int32_t *)value;
+      ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_READ_FILTER_TIMEOUT, &timeout);
+      if (TMR_SUCCESS == ret)
+      {
+        reader->u.serialReader.readFilterTimeout = timeout;
+      }
+    }
+    else
+    {
+      ret = TMR_ERROR_NOT_FOUND;
+    }
+    break;
+
+  case TMR_PARAM_TAGREADDATA_ENABLEREADFILTER:
+    if ((TMR_SR_MODEL_M6E == sr->versionInfo.hardware[0]) || (TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_M6E_NANO == sr->versionInfo.hardware[0]) ||(TMR_SR_MODEL_M6E_I == sr->versionInfo.hardware[0]))
+    {
+      ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_ENABLE_READ_FILTER, value);
+      if (TMR_SUCCESS == ret)
+      {
+        reader->u.serialReader.enableReadFiltering = *(bool *)value;
+      }
+    }
+    else
+    {
+      ret = TMR_ERROR_READONLY;
+    }
+    break;
+
+  case TMR_PARAM_RADIO_READPOWER:
+	ret = TMR_SR_cmdSetReadTxPower(reader, *(int32_t *)value);
+	break;
+  case TMR_PARAM_RADIO_WRITEPOWER:
+    ret = TMR_SR_cmdSetWriteTxPower(reader, *(int32_t *)value);
+    break;
+
+  case TMR_PARAM_RADIO_PORTREADPOWERLIST:
+    ret = setPortValues(reader, value, 0);
+    break;
+
+  case TMR_PARAM_RADIO_PORTWRITEPOWERLIST:
+    ret = setPortValues(reader, value, 1);
+    break;
+
+  case TMR_PARAM_ANTENNA_SETTLINGTIMELIST:
+    ret = setPortValues(reader, value, 2);
+    break;
+
+  case TMR_PARAM_ANTENNA_CHECKPORT:
+    readerkey = TMR_SR_CONFIGURATION_SAFETY_ANTENNA_CHECK;
+    break;
+
+  case TMR_PARAM_TAGREADDATA_RECORDHIGHESTRSSI:
+    readerkey = TMR_SR_CONFIGURATION_RECORD_HIGHEST_RSSI;
+    break;
+
+  case TMR_PARAM_TAGREADDATA_REPORTRSSIINDBM:
+    readerkey = TMR_SR_CONFIGURATION_RSSI_IN_DBM;
+    break;
+
+  case TMR_PARAM_TAGREADDATA_UNIQUEBYANTENNA:
+    readerkey = TMR_SR_CONFIGURATION_UNIQUE_BY_ANTENNA;
+    break;
+
+  case TMR_PARAM_TAGREADDATA_UNIQUEBYDATA:
+    readerkey = TMR_SR_CONFIGURATION_UNIQUE_BY_DATA;
+    break;
+
+  case TMR_PARAM_ANTENNA_PORTSWITCHGPOS:
+  {
+    const TMR_uint8List *u8list;
+    uint16_t i;
+
+    u8list = value;
+    reader->portmask = 0;
+    for (i = 0 ; i < u8list->len && i < u8list->max ; i++)
+    {
+      reader->portmask |= 1 << (u8list->list[i] - 1);
+    }
+    
+    ret = TMR_SR_cmdSetReaderConfiguration(
+    reader, TMR_SR_CONFIGURATION_ANTENNA_CONTROL_GPIO, &reader->portmask);
+
+    if (TMR_SUCCESS != ret)
+    {
+      break;
+    }
+    ret = initTxRxMapFromPorts(reader);
+    
+    break;
+  }
+ 
+  case TMR_PARAM_TRIGGER_READ_GPI:
+    {
+      uint8_t portmask;
+      const TMR_uint8List *u8list;
+      uint16_t i;
+
+      u8list = value;
+      portmask = 0;
+      for (i = 0 ; i < u8list->len && i < u8list->max ; i++)
+      {
+        portmask |= 1 << (u8list->list[i] - 1);
+      }
+
+      ret = TMR_SR_cmdSetReaderConfiguration(
+        reader, TMR_SR_CONFIGURATION_TRIGGER_READ_GPIO, &portmask);
+      break;
+    }
+
+  case TMR_PARAM_ANTENNA_TXRXMAP:
+  {
+    const TMR_AntennaMapList *map;
+    TMR_AntennaMapList *mymap;
+    uint8_t len;
+    uint16_t i, j;
+
+    map = value;
+    mymap = sr->txRxMap;
+
+    if (map->len > mymap->max)
+    {
+      ret = TMR_ERROR_TOO_BIG;
+      break;
+    }
+
+    len = 0;
+
+    for (i = 0 ; i < map->len ; i++)
+    {
+      if (!HASPORT(sr->portMask, map->list[i].txPort) ||
+          !HASPORT(sr->portMask, map->list[i].rxPort))
+      {
+        return TMR_ERROR_NO_ANTENNA;
+      }
+
+      /* Error check for txrxmap */
+      for (j = i+1; j < map->len; j++)
+      {
+        if (map->list[i].antenna == map->list[j].antenna)
+        {
+          return TMR_ERROR_INVALID_ANTENNA_CONFIG;
+        }
+      }
+
+      len = i+1;
+    }
+
+    for (i = 0; i < len; i ++)
+    {
+      mymap->list[i] = map->list[i];
+    }
+    mymap->len = len;
+    break;
+  }
+
+  case TMR_PARAM_REGION_HOPTABLE:
+  {
+    const TMR_uint32List *u32list;
+
+    u32list = value;
+
+    ret = TMR_SR_cmdSetFrequencyHopTable(reader, (uint8_t)u32list->len, u32list->list);
+    break;
+  }
+
+  case TMR_PARAM_REGION_HOPTIME:
+    ret = TMR_SR_cmdSetFrequencyHopTime(reader, *(uint32_t *)value);
+    break;
+
+  case TMR_PARAM_REGION_LBT_ENABLE:
+  {
+    uint32_t hopTable[64];
+    uint8_t count;
+
+    count = numberof(hopTable);
+    ret = TMR_SR_cmdGetFrequencyHopTable(reader, &count, hopTable);
+    if (TMR_SUCCESS != ret)
+    {
+      break;
+    }
+
+    ret = TMR_SR_cmdSetRegionLbt(reader, sr->regionId, *(bool *)value);
+    if (TMR_SUCCESS != ret)
+    {
+      break;
+    }
+
+    ret = TMR_SR_cmdSetFrequencyHopTable(reader, count, hopTable);
+    break;
+  }
+
+  case TMR_PARAM_TAGOP_ANTENNA:
+  {
+    uint16_t i;
+    TMR_AntennaMapList *map;
+    uint8_t antenna;
+    uint8_t txPort, rxPort;
+
+    map = sr->txRxMap;
+    antenna = *(uint8_t *)value;
+
+    txPort = rxPort = 0;
+    for (i = 0; i < map->len && i < map->max; i++)
+    {
+      if (map->list[i].antenna == antenna)
+      {
+        txPort = map->list[i].txPort;
+        rxPort = map->list[i].rxPort;
+        reader->tagOpParams.antenna = antenna;
+        break;
+      }
+    }
+    if (txPort == 0)
+    {
+      ret = TMR_ERROR_NO_ANTENNA;
+    }
+    else
+    {
+      ret = TMR_SR_cmdSetTxRxPorts(reader, txPort, rxPort);
+    }
+    break;
+  }
+
+  case TMR_PARAM_TAGOP_PROTOCOL:
+    if (0 == ((1 << (*(TMR_TagProtocol *)value - 1)) &
+              sr->versionInfo.protocols))
+    {
+      ret = TMR_ERROR_UNSUPPORTED;
+    }
+    else
+    {
+      reader->tagOpParams.protocol = *(TMR_TagProtocol *)value;
+	  if (reader->connected)
+	  {
+	    ret = setProtocol(reader, reader->tagOpParams.protocol);
+		if (TMR_SUCCESS == ret)
+		{
+		  reader->u.serialReader.currentProtocol = reader->tagOpParams.protocol;
+    }
+	  }
+    }
+    break;
+
+  case TMR_PARAM_READ_PLAN:
+  {
+    const TMR_ReadPlan *plan;
+    TMR_ReadPlan tmpPlan;
+
+    plan = value;
+    tmpPlan = *plan;
+
+    ret = validateReadPlan(reader, &tmpPlan, 
+                sr->txRxMap, sr->versionInfo.protocols);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+    
+    *reader->readParams.readPlan = tmpPlan;
+    break;
+  }
+
+  case TMR_PARAM_GPIO_INPUTLIST:
+  case TMR_PARAM_GPIO_OUTPUTLIST:
+  if ((TMR_SR_MODEL_M6E == sr->versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_M6E_I == sr->versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_M6E_NANO == sr->versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0]))
+  {
+      const TMR_uint8List *u8list;      
+      int bit, i, newDirections, pin;
+
+      u8list = value;
+
+      if (key == TMR_PARAM_GPIO_OUTPUTLIST)
+      {
+        newDirections = 0;
+      }
+      else
+      {
+        newDirections = 0x1e;
+      }
+
+      for (i = 0 ; i < u8list->len && i < u8list->max ; i++)
+      {
+        if (key == TMR_PARAM_GPIO_OUTPUTLIST)
+        {
+          newDirections |= (1 << u8list->list[i]);
+        }
+        else
+        {
+          newDirections &= ~(1 << u8list->list[i]);
+        }
+      }
+
+      for (pin = 0 ; pin < u8list->len ; pin++)
+      {
+        bit = 1 << (u8list->list[pin]);
+
+        ret = TMR_SR_cmdSetGPIODirection(reader, u8list->list[pin],
+          (newDirections & bit) != 0);
+        if (TMR_SUCCESS != ret)
+        {
+          return ret;
+        }
+
+      }
+      break;
+    }
+  case TMR_PARAM_RADIO_POWERMAX:
+  case TMR_PARAM_RADIO_POWERMIN:
+  case TMR_PARAM_REGION_SUPPORTEDREGIONS:
+  case TMR_PARAM_ANTENNA_PORTLIST:
+  case TMR_PARAM_ANTENNA_CONNECTEDPORTLIST:
+  case TMR_PARAM_VERSION_SUPPORTEDPROTOCOLS:
+  case TMR_PARAM_RADIO_TEMPERATURE:
+  case TMR_PARAM_VERSION_HARDWARE:
+  case TMR_PARAM_VERSION_MODEL:
+  case TMR_PARAM_VERSION_SOFTWARE:
+  case TMR_PARAM_ANTENNA_RETURNLOSS:
+  case TMR_PARAM_GEN2_PROTOCOLEXTENSION:
+    ret = TMR_ERROR_READONLY;
+    break;
+
+  case TMR_PARAM_POWERMODE:
+    if (reader->connected)
+    {
+      ret = TMR_SR_cmdSetPowerMode(reader, *(TMR_SR_PowerMode *)value);
+      if (TMR_SUCCESS == ret)
+      {
+        sr->powerMode = *(TMR_SR_PowerMode *)value;
+      }
+    }
+    else
+    {
+      sr->powerMode = *(TMR_SR_PowerMode *)value;
+    }
+    break;
+
+  case TMR_PARAM_USERMODE:
+    ret = TMR_SR_cmdSetUserMode(reader, *(TMR_SR_UserMode *)value);
+    break;
+
+  case TMR_PARAM_GEN2_Q:
+    protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_Q;
+    break;
+
+  case TMR_PARAM_GEN2_TAGENCODING:
+    protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_TAGENCODING;
+    break;
+
+  case TMR_PARAM_GEN2_SESSION:
+    protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_SESSION;
+    break;
+
+  case TMR_PARAM_GEN2_TARGET:
+    protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_TARGET;
+    break;
+
+  case TMR_PARAM_GEN2_BLF:
+    protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_LINKFREQUENCY;
+    break;
+
+  case TMR_PARAM_GEN2_TARI:
+    protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_TARI;
+    break;
+
+  case TMR_PARAM_GEN2_WRITEMODE:
+    sr->writeMode = *(TMR_GEN2_WriteMode *)value;
+    break;
+
+  case TMR_PARAM_GEN2_BAP:
+    protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_BAP;
+    break;
+
+#ifdef TMR_ENABLE_ISO180006B
+  case TMR_PARAM_ISO180006B_BLF:
+    protokey.protocol = TMR_TAG_PROTOCOL_ISO180006B;
+    protokey.u.iso180006b = TMR_SR_ISO180006B_CONFIGURATION_LINKFREQUENCY;
+    break;
+  case TMR_PARAM_ISO180006B_MODULATION_DEPTH:
+    {
+      protokey.protocol = TMR_TAG_PROTOCOL_ISO180006B;
+      protokey.u.iso180006b = TMR_SR_ISO180006B_CONFIGURATION_MODULATION_DEPTH;
+      break;
+    }
+  case TMR_PARAM_ISO180006B_DELIMITER:
+    {
+      protokey.protocol = TMR_TAG_PROTOCOL_ISO180006B;
+      protokey.u.iso180006b = TMR_SR_ISO180006B_CONFIGURATION_DELIMITER;
+      break;
+    }
+#endif /* TMR_ENABLE_ISO180006B */
+
+  case TMR_PARAM_GEN2_ACCESSPASSWORD:
+    sr->gen2AccessPassword = *(TMR_GEN2_Password *)value;
+    break;
+
+  case TMR_PARAM_LICENSE_KEY:
+    {
+	  uint32_t supportedProtocols;
+      TMR_uint8List *license = (TMR_uint8List *)value;
+
+      ret = TMR_SR_cmdSetProtocolLicenseKey(reader, TMR_SR_SET_LICENSE_KEY, license->list, license->len, &supportedProtocols);
+	}
+	break;
+
+  case TMR_PARAM_USER_CONFIG:
+    {
+	  TMR_SR_UserConfigOp *config = (TMR_SR_UserConfigOp *)value;
+
+	  switch(config->op)
+	  {
+	  case TMR_USERCONFIG_SAVE:
+	    /* Save the configuration section to flash */
+	    ret = TMR_SR_cmdSetUserProfile(reader, TMR_USERCONFIG_SAVE, config->category, TMR_SR_CUSTOM_CONFIGURATION);
+		break;
+
+	  case TMR_USERCONFIG_RESTORE:
+	    /* Restore the saved configuration section from flash */
+	    ret = TMR_SR_cmdSetUserProfile(reader, TMR_USERCONFIG_RESTORE, config->category, TMR_SR_CUSTOM_CONFIGURATION);
+		break;
+
+	  case TMR_USERCONFIG_CLEAR:
+	    /*  Clear configuration section from flash, and restore default configuration section */
+	    ret = TMR_SR_cmdSetUserProfile(reader, TMR_USERCONFIG_CLEAR, config->category, TMR_SR_CUSTOM_CONFIGURATION);
+		break;
+
+    case TMR_USERCONFIG_VERIFY:
+      ret = TMR_SR_cmdSetUserProfile(reader, TMR_USERCONFIG_VERIFY, config->category, TMR_SR_CUSTOM_CONFIGURATION);
+      break;
+      
+    case TMR_USERCONFIG_SAVE_WITH_READPLAN:
+      /* Save the read plan configuration section to flash */
+      ret = TMR_SR_cmdSetUserProfile(reader, TMR_USERCONFIG_SAVE_WITH_READPLAN, config->category, TMR_SR_CUSTOM_CONFIGURATION);
+      break;
+
+  default:
+    ret = TMR_ERROR_NOT_FOUND;
+  }
+
+	}
+	break;
+  
+  case TMR_PARAM_READER_STATISTICS:
+  /* Only RF On time statistic can be reset to 0 */
+  ret = TMR_SR_cmdResetReaderStatistics(reader, TMR_SR_READER_STATS_ALL);
+  break;
+
+  case TMR_PARAM_READER_STATS:
+  {
+    if ((NULL != reader->pSupportsResetStats) && (false == *(reader->pSupportsResetStats)))
+    {
+      /* Command not supported, pop up the error */
+      return TMR_ERROR_UNSUPPORTED;
+    }
+
+    /* Only RF On time statistic can be reset to 0 */
+    ret = TMR_SR_cmdResetReaderStats(reader, TMR_READER_STATS_FLAG_ALL);
+    break;
+  }
+
+  case TMR_PARAM_READER_STATS_ENABLE:
+  {
+    if ((NULL != reader->pSupportsResetStats) && (false == *(reader->pSupportsResetStats)))
+    {
+      /* Command not supported, pop up the error */
+      return TMR_ERROR_UNSUPPORTED;
+    }
+
+    /* Store the statitics flags requested by the user */
+    reader->statsFlag = *(TMR_Reader_StatsFlag *)value;
+    break;
+  }
+
+  case TMR_PARAM_READER_WRITE_REPLY_TIMEOUT:
+  case TMR_PARAM_READER_WRITE_EARLY_EXIT:
+    {
+      TMR_SR_Gen2ReaderWriteTimeOut timeout;
+
+      /* in case of timeout check for range */
+      switch (key)
+      {
+      case TMR_PARAM_READER_WRITE_REPLY_TIMEOUT:
+        {
+          if ( *(uint16_t *)value < 1000 || *(uint16_t *)value > 21000)
+            return TMR_ERROR_MSG_INVALID_PARAMETER_VALUE;
+          break;
+        }
+      default:
+        ;
+      }      
+
+      /* Get the values before setting it */
+      ret = TMR_SR_cmdGetReaderWriteTimeOut(reader, protokey.protocol, &timeout);
+      if (TMR_SUCCESS != ret)
+      {
+        break;
+      }
+
+      /* set the parameter asked by the user */
+      switch (key)
+      {
+      case TMR_PARAM_READER_WRITE_REPLY_TIMEOUT:
+        {
+          timeout.writetimeout = *(uint16_t *)value;
+          break;
+        }
+      case TMR_PARAM_READER_WRITE_EARLY_EXIT:
+        {
+          timeout.earlyexit = !(*(bool *)value);
+          break;
+        }
+      default:
+        ret = TMR_ERROR_NOT_FOUND;
+      }
+
+      /* set the vakue */
+      ret = TMR_SR_cmdSetReaderWriteTimeOut (reader,protokey.protocol, &timeout);
+      break;
+    }
+  case TMR_PARAM_METADATAFLAG:
+	  {
+		if (*(TMR_TRD_MetadataFlag *)value & TMR_TRD_METADATA_FLAG_PROTOCOL)
+			reader->userMetadataFlag = *(TMR_TRD_MetadataFlag *)value;
+		else
+			ret = TMR_ERROR_MSG_INVALID_PARAMETER_VALUE;
+		break;
+	  }
+
+  default:
+    ret = TMR_ERROR_NOT_FOUND;
+  }
+
+  switch (key)
+  {
+  case TMR_PARAM_ANTENNA_CHECKPORT:
+  case TMR_PARAM_RADIO_ENABLEPOWERSAVE:
+  case TMR_PARAM_RADIO_ENABLESJC:
+  case TMR_PARAM_TAGREADDATA_RECORDHIGHESTRSSI:
+  case TMR_PARAM_TAGREADDATA_REPORTRSSIINDBM:
+  case TMR_PARAM_TAGREADDATA_UNIQUEBYANTENNA:
+  case TMR_PARAM_TAGREADDATA_UNIQUEBYDATA:
+      ret = TMR_SR_cmdSetReaderConfiguration(reader, readerkey, value);
+    break;
+
+  case TMR_PARAM_EXTENDEDEPC:
+    {
+      if ((TMR_SR_MODEL_M6E == reader->u.serialReader.versionInfo.hardware[0])||
+          (TMR_SR_MODEL_MICRO == reader->u.serialReader.versionInfo.hardware[0])||
+          (TMR_SR_MODEL_M6E_NANO == reader->u.serialReader.versionInfo.hardware[0])||
+          (TMR_SR_MODEL_M6E_I == reader->u.serialReader.versionInfo.hardware[0]))
+      {
+        ret = TMR_ERROR_UNSUPPORTED;
+      }
+      else
+      {
+        ret = TMR_SR_cmdSetReaderConfiguration(reader, readerkey, value);
+        if(TMR_SUCCESS == ret)
+        {
+          /* cache the extended epc setting */
+          reader->u.serialReader.extendedEPC = *(bool *)value;
+        }
+      }
+    }
+    break;
+
+  case TMR_PARAM_GEN2_BAP:
+    {
+      TMR_GEN2_Bap *bap;
+      bap = (TMR_GEN2_Bap *)value;
+
+      if (NULL == (TMR_GEN2_Bap *)value)
+      {
+        /** It means user is disabling the bap support, make the flag down 
+         * and skip the command sending
+         **/ 
+        sr->isBapEnabled = false;
+        break;
+      }
+      else if ((-1 > bap->powerUpDelayUs) || (-1 > bap->freqHopOfftimeUs))
+      {
+        /*
+         * Invalid values for BAP parameters,
+         * Accepts only positive values or -1 for NULL
+         */ 
+        return TMR_ERROR_ILLEGAL_VALUE;
+      }
+      else if ((-1 == bap->powerUpDelayUs) && (-1 == bap->freqHopOfftimeUs))
+      {
+        /**
+         * Here -1 signifies NULL. API should skips the parameter and does not sent the matching
+         * command to the reader. Let reader use its own default
+         **/
+        sr->isBapEnabled = true;
+        break;
+      }
+      else
+      {
+        /*
+         * do a paramGet of BAP parameters. This serves two purposes.
+         * 1. API knows wheather module supports the BAP options or not.
+         * 2. API can assign default values to the fields, are not set by the user.
+         */
+        TMR_GEN2_Bap getBapParams;
+
+        ret = TMR_SR_cmdGetProtocolConfiguration(reader, protokey.protocol, 
+            protokey, &getBapParams);
+
+        if (TMR_SUCCESS != ret)
+        {
+          /* throw the error and come out from the loop */
+          break;
+        }
+        else
+        {
+          /*
+           * Modify the get BAP structure if either of the set BAP params are -1
+           */
+          sr->isBapEnabled = true;
+
+          if (-1 == bap->powerUpDelayUs)
+          {
+            bap->powerUpDelayUs = getBapParams.powerUpDelayUs;
+          }
+          if (-1 == bap->freqHopOfftimeUs)
+          {
+            bap->freqHopOfftimeUs = getBapParams.freqHopOfftimeUs;
+          }
+        }
+      }
+      // No break -- fall through to regular Gen2 param handler
+    }
+
+  case TMR_PARAM_GEN2_Q:
+  case TMR_PARAM_GEN2_TAGENCODING:
+  case TMR_PARAM_GEN2_SESSION:
+  case TMR_PARAM_GEN2_TARGET:
+  case TMR_PARAM_GEN2_BLF:
+  case TMR_PARAM_GEN2_TARI:
+#ifdef TMR_ENABLE_ISO180006B
+  case TMR_PARAM_ISO180006B_BLF:
+  case TMR_PARAM_ISO180006B_MODULATION_DEPTH:
+  case TMR_PARAM_ISO180006B_DELIMITER:
+#endif /* TMR_ENABLE_ISO180006B */
+    ret = TMR_SR_cmdSetProtocolConfiguration(reader, protokey.protocol, 
+                                             protokey, value);
+    break;
+
+  default:
+    ;
+  }
+  return ret;
+}
+
+static TMR_Status
+TMR_SR_paramGet(struct TMR_Reader *reader, TMR_Param key, void *value)
+{
+  TMR_Status ret;
+  TMR_SR_Configuration readerkey;
+  TMR_SR_ProtocolConfiguration protokey;
+  TMR_SR_SerialReader *sr;
+
+  ret = TMR_SUCCESS;
+  sr = &reader->u.serialReader;
+  readerkey = TMR_SR_CONFIGURATION_TRANSMIT_POWER_SAVE;
+  protokey.protocol = TMR_TAG_PROTOCOL_GEN2;
+
+  if (BITGET(sr->paramConfirmed, key) && 0 == BITGET(sr->paramPresent, key))
+  {
+    return TMR_ERROR_NOT_FOUND;
+  }
+
+  switch (key)
+  {
+  case TMR_PARAM_BAUDRATE:
+    *(uint32_t *)value = sr->baudRate;
+    break;
+
+  case TMR_PARAM_PROBEBAUDRATES:
+    {
+      TMR_uint32List *uint32List;
+      uint8_t i;
+
+      uint32List = value;
+
+      if (sr->probeBaudRates.len > uint32List->max)
+      {
+        sr->probeBaudRates.len = uint32List->max;
+      }
+
+      if (sr->probeBaudRates.len)
+      {
+        for(i = 0; i < sr->probeBaudRates.len; i++)
+        {
+          uint32List->list[i] = sr->probeBaudRates.list[i];
+        }
+        uint32List->len = sr->probeBaudRates.len;
+      }
+      else
+      {
+        //list is empty
+      }
+      break;
+    }
+
+  case TMR_PARAM_URI:
+    if (NULL != value)
+    {
+      TMR_stringCopy((TMR_String *)value, reader->uri, (int)strlen(reader->uri));
+    }
+    else
+    {
+      ret = TMR_ERROR_ILLEGAL_VALUE;
+    }
+    break;
+
+  case TMR_PARAM_COMMANDTIMEOUT:
+    *(uint32_t *)value = sr->commandTimeout;
+    break;
+
+  case TMR_PARAM_TRANSPORTTIMEOUT:
+    *(uint32_t *)value = sr->transportTimeout;
+    break;
+
+  case TMR_PARAM_REGION_ID:
+    {
+      if ((TMR_REGION_NONE == sr->regionId) && (reader->connected))
+      {
+        ret = TMR_SR_cmdGetRegion(reader, &sr->regionId);
+      }
+      *(TMR_Region *)value = sr->regionId;
+    }
+	break;
+
+  case TMR_PARAM_RADIO_ENABLEPOWERSAVE:
+	readerkey = TMR_SR_CONFIGURATION_TRANSMIT_POWER_SAVE;
+	break;
+
+  case TMR_PARAM_RADIO_ENABLESJC:
+    readerkey = TMR_SR_CONFIGURATION_SELF_JAMMER_CANCELLATION;
+	break;
+
+  case TMR_PARAM_TAGREADDATA_READFILTERTIMEOUT:
+  if ((TMR_SR_MODEL_M6E == sr->versionInfo.hardware[0]) || 
+      (TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_M6E_NANO == sr->versionInfo.hardware[0]) ||
+      (TMR_SR_MODEL_M6E_I == sr->versionInfo.hardware[0]))
+  {
+    *(int32_t *)value = sr->readFilterTimeout;
+  }
+  else
+  {
+    ret = TMR_ERROR_NOT_FOUND;
+  }
+  break;
+
+  case TMR_PARAM_TAGREADDATA_ENABLEREADFILTER:
+    *(bool *)value = sr->enableReadFiltering;
+    break;
+
+  case TMR_PARAM_EXTENDEDEPC:
+    readerkey = TMR_SR_CONFIGURATION_EXTENDED_EPC;
+    break;
+
+  case TMR_PARAM_RADIO_POWERMAX:
+  {
+    TMR_SR_PowerWithLimits power;
+
+    ret = TMR_SR_cmdGetReadTxPowerWithLimits(reader, &power);
+    if (TMR_SUCCESS != ret)
+    {
+      break;
+    }
+    *(int16_t *)value = power.maxPower;
+    break;
+  }
+
+  case TMR_PARAM_RADIO_POWERMIN:
+  {
+    TMR_SR_PowerWithLimits power;
+
+    ret = TMR_SR_cmdGetReadTxPowerWithLimits(reader, &power);
+    if (TMR_SUCCESS != ret)
+      break;
+    *(int16_t *)value = power.minPower;
+    break;
+  }
+
+  case TMR_PARAM_RADIO_READPOWER:
+    ret = TMR_SR_cmdGetReadTxPower(reader, (int32_t *)value);
+    break;
+
+  case TMR_PARAM_RADIO_WRITEPOWER:
+    ret = TMR_SR_cmdGetWriteTxPower(reader, (int32_t *)value);
+    break;
+
+
+  case TMR_PARAM_ANTENNA_CHECKPORT:
+    readerkey = TMR_SR_CONFIGURATION_SAFETY_ANTENNA_CHECK;
+    break;
+
+  case TMR_PARAM_TAGREADDATA_RECORDHIGHESTRSSI:
+    readerkey = TMR_SR_CONFIGURATION_RECORD_HIGHEST_RSSI;
+    break;
+
+  case TMR_PARAM_TAGREADDATA_REPORTRSSIINDBM:
+    readerkey = TMR_SR_CONFIGURATION_RSSI_IN_DBM;
+    break;
+
+  case TMR_PARAM_TAGREADDATA_UNIQUEBYANTENNA:
+    readerkey = TMR_SR_CONFIGURATION_UNIQUE_BY_ANTENNA;
+    break;
+
+  case TMR_PARAM_TAGREADDATA_UNIQUEBYDATA:
+    readerkey = TMR_SR_CONFIGURATION_UNIQUE_BY_DATA;
+    break;
+
+  case TMR_PARAM_TAGREADDATA_UNIQUEBYPROTOCOL:
+    if ((TMR_SR_MODEL_M6E == sr->versionInfo.hardware[0]) || 
+        (TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0]) ||
+        (TMR_SR_MODEL_M6E_NANO == sr->versionInfo.hardware[0]) ||
+        (TMR_SR_MODEL_M6E_I == sr->versionInfo.hardware[0]))
+    {
+      ret = TMR_SR_cmdGetReaderConfiguration(reader, TMR_SR_CONFIGURATION_UNIQUE_BY_PROTOCOL, value);
+    }
+    else
+    {
+      ret = TMR_ERROR_NOT_FOUND;
+    }
+    break;
+
+  case TMR_PARAM_PRODUCT_GROUP_ID:
+    readerkey = TMR_SR_CONFIGURATION_PRODUCT_GROUP_ID;
+    break;
+
+  case TMR_PARAM_PRODUCT_ID:
+    readerkey = TMR_SR_CONFIGURATION_PRODUCT_ID;
+    break;
+
+  case TMR_PARAM_STATUS_ENABLE_ANTENNAREPORT:
+    *(bool *)value = (reader->streamStats & TMR_SR_STATUS_ANTENNA) ? true : false;
+    break;
+  case TMR_PARAM_STATUS_ENABLE_FREQUENCYREPORT:
+    *(bool *)value = (reader->streamStats & TMR_SR_STATUS_FREQUENCY) ? true : false;
+    break;
+  case TMR_PARAM_STATUS_ENABLE_TEMPERATUREREPORT:
+    *(bool *)value = (reader->streamStats & TMR_SR_STATUS_TEMPERATURE) ? true : false;
+    break;
+
+  case TMR_PARAM_ANTENNA_PORTSWITCHGPOS:
+  {
+    TMR_uint8List *u8list;
+    u8list = value;
+
+    ret = TMR_SR_cmdGetReaderConfiguration(
+	reader, TMR_SR_CONFIGURATION_ANTENNA_CONTROL_GPIO, &reader->portmask);
+    if (TMR_SUCCESS != ret)
+    {
+      break;
+    }
+    u8list->len = 0;
+    if (reader->portmask & 1)
+    {
+      LISTAPPEND(u8list, 1);
+    }
+    if (reader->portmask & 2)
+    {
+      LISTAPPEND(u8list, 2);
+    }
+	if (reader->portmask & 3)
+    {
+      LISTAPPEND(u8list, 3);
+    }
+    break;
+  }
+
+  case TMR_PARAM_TRIGGER_READ_GPI:
+    {
+      uint8_t portmask;
+      TMR_uint8List *u8list;
+
+      u8list = value;
+
+      ret = TMR_SR_cmdGetReaderConfiguration(
+        reader, TMR_SR_CONFIGURATION_TRIGGER_READ_GPIO, &portmask);
+      if (TMR_SUCCESS != ret)
+      {
+        break;
+      }
+      u8list->len = 0;
+      if (portmask & 1)
+      {
+        LISTAPPEND(u8list, 1);
+      }
+      if (portmask & 2)
+      {
+        LISTAPPEND(u8list, 2);
+      }
+      break;
+    }
+
+  case TMR_PARAM_ANTENNA_SETTLINGTIMELIST:
+    ret = getPortValues(reader, value, 2);
+    break;
+
+  case TMR_PARAM_RADIO_PORTREADPOWERLIST:
+    ret = getPortValues(reader, value, 0);
+    break;
+
+  case TMR_PARAM_RADIO_PORTWRITEPOWERLIST:
+    ret = getPortValues(reader, value, 1);
+    break;
+  
+  case TMR_PARAM_ANTENNA_RETURNLOSS:
+    ret = TMR_SR_cmdGetAntennaReturnLoss(reader, value);
+    break;
+
+  case TMR_PARAM_GPIO_INPUTLIST:
+  case TMR_PARAM_GPIO_OUTPUTLIST:
+  {
+    TMR_uint8List *u8list;
+
+    u8list = value;
+
+    u8list->len = 0;
+    if ((TMR_SR_MODEL_M6E == sr->versionInfo.hardware[0]) ||
+        (TMR_SR_MODEL_M6E_I == sr->versionInfo.hardware[0]) ||
+        (TMR_SR_MODEL_M6E_NANO == sr->versionInfo.hardware[0]) ||
+        (TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0]))
+    {
+      int pin, wantout;
+      bool out;
+      TMR_GpioPin pinStates[16];
+      uint8_t numPins;
+
+      sr->gpioDirections = -1;
+      numPins = numberof(pinStates);
+      ret = TMR_SR_cmdGetGPIO(reader, &numPins, pinStates);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+ 
+      wantout = (key == TMR_PARAM_GPIO_OUTPUTLIST) ? 1 : 0;
+      if (-1 == sr->gpioDirections)
+      {
+        /* Cache the current state */
+        sr->gpioDirections = 0;
+        for (pin = 1; pin <= numPins ; pin++)
+        {
+          ret = TMR_SR_cmdGetGPIODirection(reader, pin, &out);
+          if (TMR_SUCCESS != ret)
+          {
+            return ret;
+          }
+          if (out)
+          {
+            sr->gpioDirections |= 1 << pin;
+          }
+        }
+      }
+      for (pin = 1; pin <= numPins ; pin++)
+      {
+        if (wantout == ((sr->gpioDirections >> pin) & 1))
+        {
+          LISTAPPEND(u8list, pin);
+        }
+      }
+    }
+    else
+    {
+      LISTAPPEND(u8list, 1);
+      LISTAPPEND(u8list, 2);
+    }
+    break;
+  }
+
+  case TMR_PARAM_ANTENNA_PORTLIST:
+  {
+    uint8_t i;
+    TMR_uint8List *u8list;
+
+    u8list = value;
+
+    u8list->len = 0;
+    for (i = 0; i < reader->u.serialReader.txRxMap->len; i++)
+    {
+      LISTAPPEND(u8list, reader->u.serialReader.txRxMap->list[i].antenna);
+    }
+    break;
+  }
+
+  case TMR_PARAM_ANTENNA_CONNECTEDPORTLIST:
+  {
+    // Store detected ports in array for quick lookup
+    bool detected[TMR_SR_MAX_ANTENNA_PORTS+1];
+    uint8_t i;
+    TMR_uint8List *u8list;
+
+    for (i=0; i<TMR_SR_MAX_ANTENNA_PORTS; i++)
+    {
+      detected[i] = false;
+    }
+    u8list = value;
+
+    {
+      TMR_SR_PortDetect ports[TMR_SR_MAX_ANTENNA_PORTS];
+      uint8_t numPorts;
+
+      numPorts = numberof(ports);
+      ret = TMR_SR_cmdAntennaDetect(reader, &numPorts, ports);
+      if (TMR_SUCCESS != ret)
+      {
+        break;
+      }
+      for (i=0; i<numPorts; i++)
+      {
+        detected[ports[i].port] = ports[i].detected;
+      }
+    }
+    
+    u8list->len = 0;
+    for (i=0; i<reader->u.serialReader.txRxMap->len; i++)
+    {
+      int ant = reader->u.serialReader.txRxMap->list[i].antenna;
+      int tx  = reader->u.serialReader.txRxMap->list[i].txPort;
+      int rx  = reader->u.serialReader.txRxMap->list[i].rxPort;
+
+      if (detected[tx] && detected[rx])
+      {
+        LISTAPPEND(u8list, ant);
+      }
+    }
+    break;
+  }
+
+  case TMR_PARAM_ANTENNA_TXRXMAP:
+  {
+    TMR_AntennaMapList *map, *mymap;
+    uint16_t i;
+
+    map = value;
+    mymap = sr->txRxMap;
+
+    for (i = 0 ; i < mymap->len && i < map->max ; i++)
+      map->list[i] = mymap->list[i];
+    map->len = mymap->len;
+    break;
+  }
+
+  case TMR_PARAM_REGION_HOPTABLE:
+  {
+    TMR_uint32List *u32List;
+    uint8_t count;
+
+    u32List = value;
+
+    count = (uint8_t)u32List->max;
+    ret = TMR_SR_cmdGetFrequencyHopTable(reader,&count, u32List->list);
+    if (TMR_SUCCESS != ret)
+    {
+      break;
+    }
+    u32List->len = count;
+    break;
+  }
+
+  case TMR_PARAM_REGION_HOPTIME:
+    ret = TMR_SR_cmdGetFrequencyHopTime(reader, value);
+    break;
+
+  case TMR_PARAM_REGION_LBT_ENABLE:
+    ret = TMR_SR_cmdGetRegionConfiguration(reader,
+                                           TMR_SR_REGION_CONFIGURATION_LBT_ENABLED, value);
+    if (TMR_SUCCESS != ret && TMR_ERROR_IS_CODE(ret))
+    {
+      *(bool *)value = false;
+      ret = TMR_SUCCESS;
+    }
+    break;
+
+  case TMR_PARAM_TAGOP_ANTENNA:
+    *(uint8_t *)value = reader->tagOpParams.antenna;
+    break;
+
+  case TMR_PARAM_TAGOP_PROTOCOL:
+    *(TMR_TagProtocol *)value = reader->tagOpParams.protocol;
+    break;
+
+  case TMR_PARAM_POWERMODE:
+    if (reader->connected)
+    {
+      TMR_SR_PowerMode pm;
+      ret = TMR_SR_cmdGetPowerMode(reader, &pm);
+      if (TMR_SUCCESS == ret)
+      {
+        sr->powerMode = pm;
+      }
+    }
+    *(TMR_SR_PowerMode*)value = sr->powerMode;
+    break;
+
+  case TMR_PARAM_USERMODE:
+    ret = TMR_SR_cmdGetUserMode(reader, value);
+    break;
+
+  case TMR_PARAM_GEN2_Q:
+    protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_Q;
+    break;
+
+  case TMR_PARAM_GEN2_TAGENCODING:
+    protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_TAGENCODING;
+    break;
+
+  case TMR_PARAM_GEN2_SESSION:
+    protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_SESSION;
+    break;
+
+  case TMR_PARAM_GEN2_TARGET:
+    protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_TARGET;
+    break;
+
+  case TMR_PARAM_GEN2_BLF:
+    protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_LINKFREQUENCY;
+    break;
+
+  case TMR_PARAM_GEN2_TARI:
+    protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_TARI;
+    break;
+    
+  case TMR_PARAM_GEN2_BAP:
+    protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_BAP;
+    break;
+
+  case TMR_PARAM_GEN2_WRITEMODE:
+    *(TMR_GEN2_WriteMode *)value = sr->writeMode;
+    break;
+
+  case TMR_PARAM_GEN2_PROTOCOLEXTENSION:
+	protokey.u.gen2 = TMR_SR_GEN2_CONFIGURATION_PROTCOLEXTENSION;
+    break;
+
+#ifdef TMR_ENABLE_ISO180006B
+  case TMR_PARAM_ISO180006B_BLF:
+    protokey.protocol = TMR_TAG_PROTOCOL_ISO180006B;
+    protokey.u.iso180006b = TMR_SR_ISO180006B_CONFIGURATION_LINKFREQUENCY;
+    break;
+  case TMR_PARAM_ISO180006B_MODULATION_DEPTH:
+    {
+      protokey.protocol = TMR_TAG_PROTOCOL_ISO180006B;
+      protokey.u.iso180006b = TMR_SR_ISO180006B_CONFIGURATION_MODULATION_DEPTH;
+      break;
+    }
+  case TMR_PARAM_ISO180006B_DELIMITER:
+    {
+      protokey.protocol = TMR_TAG_PROTOCOL_ISO180006B;
+      protokey.u.iso180006b = TMR_SR_ISO180006B_CONFIGURATION_DELIMITER;
+      break;
+    }
+#endif /* TMR_ENABLE_ISO180006B */
+
+  case TMR_PARAM_GEN2_ACCESSPASSWORD:
+    *(TMR_GEN2_Password *)value = sr->gen2AccessPassword;
+    break;
+
+  case TMR_PARAM_REGION_SUPPORTEDREGIONS:
+    ret = TMR_SR_cmdGetAvailableRegions(reader, value);
+    break;
+
+  case TMR_PARAM_VERSION_SUPPORTEDPROTOCOLS:
+    ret = TMR_SR_cmdGetAvailableProtocols(reader, value);
+    break;
+
+  case TMR_PARAM_RADIO_TEMPERATURE:
+    ret = TMR_SR_cmdGetTemperature(reader, value);
+    break;
+
+  case TMR_PARAM_VERSION_HARDWARE:
+    ret = getHardwareInfo(reader, value);
+    break;
+
+  case TMR_PARAM_VERSION_SERIAL:
+    ret = getSerialNumber(reader, value);
+    break;
+
+  case TMR_PARAM_VERSION_MODEL:
+  {
+    const char *model = NULL;
+
+    switch (sr->versionInfo.hardware[0])
+    {
+    case TMR_SR_MODEL_M5E:
+      model = "M5e";
+      break;
+    case TMR_SR_MODEL_M5E_COMPACT:
+      model = "M5e Compact";
+      break;
+    case TMR_SR_MODEL_M5E_I:
+      {
+        /**
+         * I - International . It has following Variants.
+         **/
+        switch (sr->versionInfo.hardware[3])
+        {
+          case TMR_SR_MODEL_M5E_I_REV_EU:
+            model = "M5e EU";
+            break;
+          case TMR_SR_MODEL_M5E_I_REV_NA:
+            model = "M5e NA";
+            break;
+          case TMR_SR_MODEL_M5E_I_REV_JP:
+            model = "M5E JP";
+            break;
+          case TMR_SR_MODEL_M5E_I_REV_PRC:
+            model = "M5e PRC";
+            break;
+          default:
+            model = "Unknown";
+            break;
+        }
+        break;
+      }
+    case TMR_SR_MODEL_M4E:
+      model = "M4e";
+      break;
+    case TMR_SR_MODEL_M6E:
+      model = "M6e";
+      break;
+  case TMR_SR_MODEL_M6E_I:
+	{
+		/**
+		* M6e I has following variants
+		**/
+		switch (sr->versionInfo.hardware[3])
+		{
+		case TMR_SR_MODEL_M6E_I_PRC:
+			model = "M6e PRC";
+			break;
+		case TMR_SR_MODEL_M6E_I_JIC:
+			model = "M6e JIC";
+			break;
+		default:
+			model = "Unknown";
+		}
+	}
+	break;
+    case TMR_SR_MODEL_MICRO:
+      {
+        /**
+         * Micro has following variants.
+         **/
+        switch (sr->versionInfo.hardware[3])
+        {
+        case TMR_SR_MODEL_M6E_MICRO:
+          model = "M6e Micro";
+          break;
+        case TMR_SR_MODEL_M6E_MICRO_USB:
+          model = "M6e Micro USB";
+          break;
+		    case TMR_SR_MODEL_M6E_MICRO_USB_PRO:
+          model = "M6e Micro USBPro";
+          break;
+        }
+      }
+      break;
+    case TMR_SR_MODEL_M6E_NANO:
+      model = "M6e Nano";
+      break;
+	default:
+      model = "Unknown";
+    }
+    TMR_stringCopy(value, model, (int)strlen(model));
+    break;
+  }    
+
+  case TMR_PARAM_VERSION_SOFTWARE:
+  {
+    char tmp[38];
+    TMR_SR_VersionInfo *info;
+
+    info = &sr->versionInfo;
+
+    TMR_hexDottedQuad(info->fwVersion, tmp);
+    tmp[11] = '-';
+    TMR_hexDottedQuad(info->fwDate, tmp + 12);
+    tmp[23] = '-';
+    tmp[24] = 'B';
+    tmp[25] = 'L';
+    TMR_hexDottedQuad(info->bootloader, tmp+26);
+    TMR_stringCopy(value, tmp, 37);
+    break;
+  }
+
+  case TMR_PARAM_LICENSE_KEY:
+    ret = TMR_ERROR_UNSUPPORTED;
+	break;
+  
+  case TMR_PARAM_USER_CONFIG:
+    ret = TMR_ERROR_UNSUPPORTED;
+	break;
+
+  case TMR_PARAM_READER_STATS:
+  {
+    if ((NULL != reader->pSupportsResetStats) && (false == *(reader->pSupportsResetStats)))
+    {
+      /* Command not supported, pop up the error */
+      return TMR_ERROR_UNSUPPORTED;
+    }
+    
+    /**
+     * We should ask for the fields which are requested by the user,
+     * if no fields are requested by the user, then fetch all fields.
+     */
+    if (TMR_READER_STATS_FLAG_NONE == reader->statsFlag)
+    {
+      reader->statsFlag = TMR_READER_STATS_FLAG_ALL;
+    }
+    ret = TMR_SR_cmdGetReaderStats(reader, reader->statsFlag, value);
+    break;
+  }
+
+  case TMR_PARAM_READER_STATS_ENABLE:
+  {
+    if ((NULL != reader->pSupportsResetStats) && (false == *(reader->pSupportsResetStats)))
+    {
+      /* Command not supported, pop up the error */
+      return TMR_ERROR_UNSUPPORTED;
+    }
+
+    *(TMR_Reader_StatsFlag *)value = reader->statsFlag;
+    break;
+  }
+
+  case TMR_PARAM_READER_STATISTICS:
+  ret = TMR_SR_cmdGetReaderStatistics(reader, TMR_SR_READER_STATS_ALL, value);
+  break;
+
+  case TMR_PARAM_PRODUCT_GROUP:
+    {
+      const char *group;
+      TMR_SR_ProductGroupID id = (TMR_SR_ProductGroupID)sr->productId;
+      switch (id)
+      {
+        case TMR_SR_PRODUCT_MODULE:
+        case TMR_SR_PRODUCT_INVALID:
+          group = "Embedded Reader";
+          break;
+        case TMR_SR_PRODUCT_RUGGEDIZED_READER:
+          group = "Ruggedized Reader";
+          break;
+        case TMR_SR_PRODUCT_USB_READER:
+          group = "USB Reader";
+          break;
+        default:
+          group = "Unknown";
+          break;
+      }
+      if (NULL != value)
+      {
+        TMR_stringCopy(value, group, (int)strlen(group));
+      }
+      else
+      {
+        ret = TMR_ERROR_ILLEGAL_VALUE;
+      }
+      break;
+    }
+
+  case TMR_PARAM_TAGREADATA_TAGOPSUCCESSCOUNT:
+    {
+      *(uint16_t *)value = sr->tagopSuccessCount;
+      break;
+    }
+
+  case TMR_PARAM_TAGREADATA_TAGOPFAILURECOUNT:
+    {
+      *(uint16_t *)value = sr->tagopFailureCount;
+      break;
+    }
+  case TMR_PARAM_READER_WRITE_REPLY_TIMEOUT:
+  case TMR_PARAM_READER_WRITE_EARLY_EXIT:
+    {
+      TMR_SR_Gen2ReaderWriteTimeOut timeout;
+      ret = TMR_SR_cmdGetReaderWriteTimeOut(reader, protokey.protocol, &timeout);
+      if (TMR_SUCCESS != ret)
+      {
+        break;
+      }
+      switch (key)
+      {
+      case TMR_PARAM_READER_WRITE_REPLY_TIMEOUT:
+        {
+          *(uint16_t *)value = (uint16_t)timeout.writetimeout;
+          break;
+        }
+      case TMR_PARAM_READER_WRITE_EARLY_EXIT:
+        {
+          *(bool *)value = !((bool)timeout.earlyexit);
+          break;
+        }
+      default:
+        ret = TMR_ERROR_NOT_FOUND;
+      }
+    }
+    break;
+  case TMR_PARAM_METADATAFLAG:
+	  {
+		*(TMR_TRD_MetadataFlag *)value = reader->userMetadataFlag;
+		break;
+	  }
+		    
+  default:
+    ret = TMR_ERROR_NOT_FOUND;
+  }
+
+  switch (key)
+  {
+  case TMR_PARAM_ANTENNA_CHECKPORT:
+  case TMR_PARAM_RADIO_ENABLEPOWERSAVE:
+  case TMR_PARAM_RADIO_ENABLESJC:
+  case TMR_PARAM_TAGREADDATA_RECORDHIGHESTRSSI:
+  case TMR_PARAM_TAGREADDATA_REPORTRSSIINDBM:
+  case TMR_PARAM_TAGREADDATA_UNIQUEBYANTENNA:
+  case TMR_PARAM_TAGREADDATA_UNIQUEBYDATA:  
+  case TMR_PARAM_PRODUCT_GROUP_ID:
+  case TMR_PARAM_PRODUCT_ID:
+	  ret = TMR_SR_cmdGetReaderConfiguration(reader, readerkey, value);
+	  break;
+
+  case TMR_PARAM_EXTENDEDEPC:
+    {
+      if ((TMR_SR_MODEL_M6E == sr->versionInfo.hardware[0]) ||
+          (TMR_SR_MODEL_M6E_I == sr->versionInfo.hardware[0]) ||
+          (TMR_SR_MODEL_M6E_NANO == sr->versionInfo.hardware[0]) ||
+          (TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0]))
+      {
+        ret = TMR_ERROR_UNSUPPORTED;
+      }
+      else
+      {
+        ret = TMR_SR_cmdGetReaderConfiguration(reader, readerkey, value);
+      }
+    }
+    break;
+
+  case TMR_PARAM_GEN2_Q:
+  case TMR_PARAM_GEN2_TAGENCODING:
+  case TMR_PARAM_GEN2_SESSION:
+  case TMR_PARAM_GEN2_TARGET:
+  case TMR_PARAM_GEN2_BLF:
+  case TMR_PARAM_GEN2_TARI:
+  case TMR_PARAM_GEN2_BAP:
+  case TMR_PARAM_GEN2_PROTOCOLEXTENSION:
+#ifdef TMR_ENABLE_ISO180006B
+  case TMR_PARAM_ISO180006B_BLF:
+  case TMR_PARAM_ISO180006B_MODULATION_DEPTH:
+  case TMR_PARAM_ISO180006B_DELIMITER:
+#endif /* TMR_ENABLE_ISO180006B */
+	  ret = TMR_SR_cmdGetProtocolConfiguration(reader, protokey.protocol, 
+		  protokey, value);
+	  break;
+
+  default:
+	  ;
+  }
+
+  if (0 == BITGET(sr->paramConfirmed, key))
+  {
+    if ((TMR_SUCCESS == ret) || ret == TMR_ERROR_AUTOREAD_ENABLED )
+    {
+      BITSET(sr->paramPresent, key);
+    }
+    BITSET(sr->paramConfirmed, key);
+  }
+
+  return ret;
+}
+
+TMR_Status
+TMR_SR_SerialReader_init(TMR_Reader *reader)
+{
+  reader->readerType = TMR_READER_TYPE_SERIAL;
+
+#ifndef TMR_ENABLE_SERIAL_READER_ONLY
+  reader->connect = TMR_SR_connect;
+  reader->destroy = TMR_SR_destroy;
+  reader->read = TMR_SR_read;
+  reader->hasMoreTags = TMR_SR_hasMoreTags;
+  reader->getNextTag = TMR_SR_getNextTag;
+  reader->executeTagOp = TMR_SR_executeTagOp;
+  reader->readTagMemWords = TMR_SR_readTagMemWords;
+  reader->readTagMemBytes = TMR_SR_readTagMemBytes;
+  reader->writeTagMemBytes = TMR_SR_writeTagMemBytes;
+  reader->writeTagMemWords = TMR_SR_writeTagMemWords;
+  reader->writeTag = TMR_SR_writeTag;
+  reader->killTag = TMR_SR_killTag;
+  reader->lockTag = TMR_SR_lockTag;
+  reader->gpiGet = TMR_SR_gpiGet;
+  reader->gpoSet = TMR_SR_gpoSet;
+#ifdef TMR_ENABLE_STDIO
+  reader->firmwareLoad = TMR_SR_firmwareLoad;
+#endif
+  reader->modifyFlash = TMR_SR_modifyFlash;
+  reader->reboot = TMR_SR_reboot;
+#endif
+  reader->cmdStopReading = TMR_SR_cmdStopReading;
+#ifdef TMR_ENABLE_BACKGROUND_READS
+  reader->cmdAutonomousReading = TMR_SR_receiveAutonomousReading;
+#endif
+
+  reader->paramSet = TMR_SR_paramSet;
+  reader->paramGet = TMR_SR_paramGet;
+ 
+  memset(reader->u.serialReader.paramConfirmed,0,
+         sizeof(reader->u.serialReader.paramConfirmed));
+  memset(reader->u.serialReader.paramPresent,0,
+         sizeof(reader->u.serialReader.paramPresent));
+  reader->u.serialReader.baudRate = 115200;
+  reader->u.serialReader.currentProtocol = TMR_TAG_PROTOCOL_NONE;
+  reader->u.serialReader.versionInfo.hardware[0] = TMR_SR_MODEL_UNKNOWN;
+  reader->u.serialReader.supportsPreamble = false;
+  reader->u.serialReader.extendedEPC = false;
+  reader->u.serialReader.powerMode = TMR_SR_POWER_MODE_INVALID;
+  reader->u.serialReader.transportTimeout = 5000;
+  reader->u.serialReader.commandTimeout = 1000;
+  reader->u.serialReader.regionId = TMR_REGION_NONE;
+  reader->u.serialReader.tagsRemaining = 0;
+  reader->u.serialReader.tagsRemainingInBuffer = 0;
+  reader->u.serialReader.gen2AccessPassword = 0;
+  reader->u.serialReader.oldQ.type = TMR_SR_GEN2_Q_INVALID;
+  reader->u.serialReader.writeMode = TMR_GEN2_WORD_ONLY;
+  reader->u.serialReader.tagopSuccessCount = 0;
+  reader->u.serialReader.tagopFailureCount = 0;
+  reader->u.serialReader.enableReadFiltering = true;
+  reader->u.serialReader.readFilterTimeout = 0;
+  reader->u.serialReader.usrTimeoutEnable = false;
+  reader->u.serialReader.crcEnabled = true;
+  reader->u.serialReader.transportType = TMR_SR_MSG_SOURCE_UNKNOWN;
+  reader->u.serialReader.gen2AllMemoryBankEnabled = false;
+  reader->u.serialReader.isBapEnabled = false;
+  reader->u.serialReader.probeBaudRates.list = reader->u.serialReader.baudRates;
+  reader->u.serialReader.probeBaudRates.max = TMR_MAX_PROBE_BAUDRATE_LENGTH;
+  reader->u.serialReader.probeBaudRates.len = 0;
+  reader->u.serialReader.enableAutonomousRead = false;
+  reader->u.serialReader.isBasetimeUpdated = false;
+  {
+    //initialize the probe baud rate list with the supported  baud rate values
+    TMR_uint32List value;
+    uint32_t rates[TMR_MAX_PROBE_BAUDRATE_LENGTH] ={9600, 115200, 921600, 19200, 38400, 57600,230400, 460800};
+    value.list = rates;
+    value.len = value.max = 8;
+
+    TMR_paramSet(reader, TMR_PARAM_PROBEBAUDRATES, &value);
+  }
+
+  return TMR_reader_init_internal(reader);
+}
+
+uint16_t TMR_SR_getConfigWord(TMR_Reader *reader, TMR_TagOp_GEN2_NXP_Untraceable op)
+{
+	uint16_t configWord = 0x0000;
+	uint16_t Mask;
+	int Pos;
+
+	if(op.epc == 1)
+	{
+		configWord |= 0x0001 << 14;
+	}
+	Mask = 0x1F;
+	Pos = 9;
+	configWord |= (uint16_t)((op.epcLength & Mask) << Pos);
+
+	Mask = 0x03;
+	Pos = 7;
+	configWord |= (uint16_t)((op.tid & Mask) << Pos);
+
+	if (op.userMemory == 1)
+	{
+		configWord |= 0x0001 << 6;
+	}
+
+	Mask = 0x03;
+	Pos = 4;
+	configWord |= (uint16_t)((op.range & Mask) << Pos);
+
+	return configWord;
+}
+
+TMR_Status
+TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *filter, TMR_uint8List *data)
+{ 
+  TMR_Status ret;
+  TMR_SR_SerialReader *sr;
+
+  sr = &reader->u.serialReader;
+
+  switch (tagop->type)
+  {
+  case (TMR_TAGOP_GEN2_WRITETAG):
+    {
+      TMR_TagOp_GEN2_WriteTag op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      op = tagop->u.gen2.u.writeTag;
+
+      return TMR_SR_cmdWriteGen2TagEpc(reader, filter, sr->gen2AccessPassword, 
+        (uint16_t)(sr->commandTimeout),
+        op.epcptr->epcByteCount,
+        op.epcptr->epc,
+        false);
+    }
+  case (TMR_TAGOP_GEN2_KILL):
+    {
+	  TMR_TagOp_GEN2_Kill op;
+           
+	  ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+	  if (TMR_SUCCESS != ret)
+	  {
+		return ret;
+	  }
+
+      op = tagop->u.gen2.u.kill;
+
+      return TMR_SR_cmdKillTag(reader,
+        (uint16_t)(sr->commandTimeout),
+        op.password,
+        filter);
+    }
+  case (TMR_TAGOP_GEN2_LOCK):
+    {
+	  TMR_TagOp_GEN2_Lock op;
+           
+	  ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+	  if (TMR_SUCCESS != ret)
+	  {
+		return ret;
+	  }
+
+      op = tagop->u.gen2.u.lock;
+
+      return TMR_SR_cmdGEN2LockTag(reader, (uint16_t)sr->commandTimeout,
+        op.mask, op.action, op.accessPassword, filter);
+    }
+  case (TMR_TAGOP_GEN2_WRITEDATA):
+    {
+      TMR_TagOp_GEN2_WriteData op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+	return ret;
+      }
+
+      op = tagop->u.gen2.u.writeData;
+      return TMR_SR_writeTagMemWords(reader, filter, op.bank, op.wordAddress, op.data.len, op.data.list);
+    }
+  case (TMR_TAGOP_GEN2_READDATA):
+    {
+      TMR_TagOp_GEN2_ReadData op;
+      TMR_TagReadData read;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+    }
+
+      if (NULL != data)
+      {
+        read.data.len = 0;
+        read.data.list = data->list;
+        read.data.max = data->max;
+      }
+      else
+      {
+        read.data.list = NULL;
+      }
+      read.metadataFlags = 0;
+      op = tagop->u.gen2.u.readData;
+      ret = TMR_SR_cmdGEN2ReadTagData(reader, (uint16_t)(sr->commandTimeout), op.bank,
+                                      op.wordAddress, op.len, sr->gen2AccessPassword, filter, &read);
+      if (NULL != data)
+      {
+        data->len = read.data.len;
+      }
+      
+      return ret;
+    }
+  case (TMR_TAGOP_GEN2_BLOCKWRITE):
+    {
+      TMR_TagOp_GEN2_BlockWrite op;
+           
+	  ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+	  if (TMR_SUCCESS != ret)
+	  {
+		return ret;
+    }
+
+    op = tagop->u.gen2.u.blockWrite;
+    return TMR_SR_cmdBlockWrite(reader,(uint16_t)sr->commandTimeout, op.bank,
+            op.wordPtr, op.data.len, op.data.list, sr->gen2AccessPassword, filter);
+    }
+  case (TMR_TAGOP_GEN2_BLOCKPERMALOCK):
+    {
+      TMR_TagOp_GEN2_BlockPermaLock op;
+           
+	  ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+	  if (TMR_SUCCESS != ret)
+	  {
+		return ret;
+    }
+
+      op = tagop->u.gen2.u.blockPermaLock;
+
+      return TMR_SR_cmdBlockPermaLock(reader, (uint16_t)sr->commandTimeout, op.readLock, op.bank,
+        op.blockPtr, op.mask.len, op.mask.list, sr->gen2AccessPassword, filter, data);
+    }
+
+  case (TMR_TAGOP_GEN2_BLOCKERASE):
+    {
+      TMR_TagOp_GEN2_BlockErase op;
+      
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      op = tagop->u.gen2.u.blockErase;
+      return TMR_SR_cmdBlockErase(reader, (uint16_t)sr->commandTimeout, op.bank, op.wordPtr,
+                                                op.wordCount, sr->gen2AccessPassword, filter);
+    }
+	
+#ifdef TMR_ENABLE_GEN2_CUSTOM_TAGOPS
+  case (TMR_TAGOP_GEN2_ALIEN_HIGGS2_PARTIALLOADIMAGE):
+    {
+      TMR_TagOp_GEN2_Alien_Higgs2_PartialLoadImage op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+      op = tagop->u.gen2.u.custom.u.alien.u.higgs2.u.partialLoadImage;
+      if (op.epcptr->epcByteCount > 12 || op.epcptr->epcByteCount <=0 )
+      { /* Only 96 bit epc */
+        return TMR_ERROR_PROTOCOL_INVALID_EPC;
+      }
+      return TMR_SR_cmdHiggs2PartialLoadImage(reader, (uint16_t)sr->commandTimeout, 
+        op.accessPassword, op.killPassword, op.epcptr->epcByteCount, op.epcptr->epc, filter);
+    }
+  case (TMR_TAGOP_GEN2_ALIEN_HIGGS2_FULLLOADIMAGE):
+    {
+      TMR_TagOp_GEN2_Alien_Higgs2_FullLoadImage op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      op = tagop->u.gen2.u.custom.u.alien.u.higgs2.u.fullLoadImage;
+      if (op.epcptr->epcByteCount > 12 || op.epcptr->epcByteCount <= 0 )
+      { /* Only 96 bit epc */
+        return TMR_ERROR_PROTOCOL_INVALID_EPC;
+      }
+      return TMR_SR_cmdHiggs2FullLoadImage(reader, (uint16_t)sr->commandTimeout, op.accessPassword,
+        op.killPassword, op.lockBits, op.pcWord, op.epcptr->epcByteCount, op.epcptr->epc, filter);
+    }
+  case (TMR_TAGOP_GEN2_ALIEN_HIGGS3_FASTLOADIMAGE):
+    {
+      /* The FastLoadImage command automatically erases the content of all
+       * User Memory. If this is undesirable then use the LoadImage or multiple Write
+       * Tag Data commands.
+       */
+      TMR_TagOp_GEN2_Alien_Higgs3_FastLoadImage op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      op = tagop->u.gen2.u.custom.u.alien.u.higgs3.u.fastLoadImage;
+      if (op.epcptr->epcByteCount > 12 || op.epcptr->epcByteCount <= 0 )
+      { /* Only 96 bit epc */
+        return TMR_ERROR_PROTOCOL_INVALID_EPC;
+      }
+      return TMR_SR_cmdHiggs3FastLoadImage(reader, (uint16_t)sr->commandTimeout, op.currentAccessPassword, op.accessPassword,
+        op.killPassword, op.pcWord, op.epcptr->epcByteCount, op.epcptr->epc, filter);
+    }
+  case (TMR_TAGOP_GEN2_ALIEN_HIGGS3_LOADIMAGE):
+    {
+      TMR_TagOp_GEN2_Alien_Higgs3_LoadImage op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      op = tagop->u.gen2.u.custom.u.alien.u.higgs3.u.loadImage;
+      if (op.epcAndUserData->len > 76 || op.epcAndUserData->len <= 0 )
+      { /* Only 76 byte epcAndUserData */
+        return TMR_ERROR_MSG_INVALID_PARAMETER_VALUE;
+      }
+      return TMR_SR_cmdHiggs3LoadImage(reader, (uint16_t)sr->commandTimeout, op.currentAccessPassword,
+        op.accessPassword, op.killPassword, op.pcWord, (uint8_t)op.epcAndUserData->len, op.epcAndUserData->list, filter);
+    }
+  case (TMR_TAGOP_GEN2_ALIEN_HIGGS3_BLOCKREADLOCK):
+    {
+      TMR_TagOp_GEN2_Alien_Higgs3_BlockReadLock op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+      op = tagop->u.gen2.u.custom.u.alien.u.higgs3.u.blockReadLock;
+
+      return TMR_SR_cmdHiggs3BlockReadLock(reader, (uint16_t)sr->commandTimeout, op.accessPassword, op.lockBits, filter);
+    }
+  case (TMR_TAGOP_GEN2_NXP_SETREADPROTECT):
+    {
+      TMR_TagOp_GEN2_NXP_SetReadProtect op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+      
+      op = tagop->u.gen2.u.custom.u.nxp.u.setReadProtect;
+
+      return TMR_SR_cmdNxpSetReadProtect(reader, (uint16_t)sr->commandTimeout,
+        tagop->u.gen2.u.custom.chipType, op.accessPassword, filter);
+    }
+  case (TMR_TAGOP_GEN2_NXP_RESETREADPROTECT):
+    {
+      TMR_TagOp_GEN2_NXP_ResetReadProtect op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+      
+      op = tagop->u.gen2.u.custom.u.nxp.u.resetReadProtect;
+      return TMR_SR_cmdNxpResetReadProtect(reader, (uint16_t)sr->commandTimeout,
+          tagop->u.gen2.u.custom.chipType, op.accessPassword, filter);
+    }
+  case (TMR_TAGOP_GEN2_NXP_CHANGEEAS):
+    {
+      TMR_TagOp_GEN2_NXP_ChangeEAS op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      op = tagop->u.gen2.u.custom.u.nxp.u.changeEAS;
+      return TMR_SR_cmdNxpChangeEas(reader, (uint16_t)sr->commandTimeout, tagop->u.gen2.u.custom.chipType,
+        op.accessPassword, op.reset, filter);
+    }
+  case (TMR_TAGOP_GEN2_NXP_EASALARM):
+    {
+      TMR_TagOp_GEN2_NXP_EASAlarm op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      op = tagop->u.gen2.u.custom.u.nxp.u.EASAlarm;
+      return TMR_SR_cmdNxpEasAlarm(reader, (uint16_t)sr->commandTimeout, tagop->u.gen2.u.custom.chipType,
+        op.dr, op.m, op.trExt, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_NXP_CALIBRATE):
+    {
+      TMR_TagOp_GEN2_NXP_Calibrate op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+      
+      op = tagop->u.gen2.u.custom.u.nxp.u.calibrate;
+      return TMR_SR_cmdNxpCalibrate(reader, (uint16_t)sr->commandTimeout, tagop->u.gen2.u.custom.chipType,
+        op.accessPassword, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_NXP_CHANGECONFIG):
+    {
+      TMR_TagOp_GEN2_NXP_ChangeConfig op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+       
+      if(NULL != data)
+      {
+        data->len = 0;      
+      }
+
+      op = tagop->u.gen2.u.custom.u.nxp.u.changeConfig;
+      return TMR_SR_cmdNxpChangeConfig(reader, (uint16_t)sr->commandTimeout, tagop->u.gen2.u.custom.chipType,
+        op.accessPassword, op.configWord, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_NXP_UNTRACEABLE):
+	{
+	  TMR_TagOp_GEN2_NXP_Untraceable op;
+	  uint16_t configWord;
+	  ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+	  op = tagop->u.gen2.u.custom.u.nxp.u.untraceable;
+	  configWord = TMR_SR_getConfigWord(reader,op);
+	  return TMR_SR_cmdGen2v2NXPUntraceable(reader,(uint16_t)sr->commandTimeout, tagop->u.gen2.u.custom.chipType,
+		 sr->gen2AccessPassword, configWord , op, data, filter);
+	}
+  case (TMR_TAGOP_GEN2_NXP_AUTHENTICATE):
+	{
+	  TMR_TagOp_GEN2_NXP_Authenticate op;
+
+	  ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+	  op = tagop->u.gen2.u.custom.u.nxp.u.authenticate;
+	  return TMR_SR_cmdGen2v2NXPAuthenticate(reader,(uint16_t)sr->commandTimeout, tagop->u.gen2.u.custom.chipType,
+		 sr->gen2AccessPassword, op, data, filter);
+	}
+  case (TMR_TAGOP_GEN2_NXP_READBUFFER):
+	{
+	  TMR_TagOp_GEN2_NXP_Readbuffer op;
+
+	  ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+	  op = tagop->u.gen2.u.custom.u.nxp.u.readBuffer;
+	  return TMR_SR_cmdGen2v2NXPReadBuffer(reader,(uint16_t)sr->commandTimeout, tagop->u.gen2.u.custom.chipType,
+		 sr->gen2AccessPassword, op, data, filter);
+	}
+  case (TMR_TAGOP_GEN2_IMPINJ_MONZA4_QTREADWRITE):
+    {
+      TMR_TagOp_GEN2_Impinj_Monza4_QTReadWrite op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.impinj.u.monza4.u.qtReadWrite;
+      return TMR_SR_cmdMonza4QTReadWrite(reader, (uint16_t)sr->commandTimeout, op.accessPassword,
+        op.controlByte, op.payload, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_IDS_SL900A_GETSENSOR):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_GetSensorValue op;
+
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.sensor;
+      return TMR_SR_cmdSL900aGetSensorValue(reader, (uint16_t)sr->commandTimeout, op.AccessPassword, op.CommandCode,
+        op.Password,op.sl900A.level, op.sl900A.sensortype, data, filter);
+    }
+
+  case (TMR_TAGOP_GEN2_IDS_SL900A_GETMEASUREMENTSETUP):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_GetMeasurementSetup op;
+
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.measurementSetup;
+      return TMR_SR_cmdSL900aGetMeasurementSetup(reader, (uint16_t)sr->commandTimeout, op.AccessPassword, op.CommandCode,
+        op.Password,op.sl900A.level, data, filter);
+    }
+
+  case (TMR_TAGOP_GEN2_IDS_SL900A_GETCALIBRATIONDATA):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_GetCalibrationData op;
+
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.calibrationData;
+      return TMR_SR_cmdSL900aGetCalibrationData(reader, (uint16_t)sr->commandTimeout, op.AccessPassword, op.CommandCode,
+          op.Password, op.sl900A.level, data, filter);
+    }
+
+  case (TMR_TAGOP_GEN2_IDS_SL900A_SETCALIBRATIONDATA):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_SetCalibrationData op;
+
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.setCalibration;
+      return TMR_SR_cmdSL900aSetCalibrationData(reader, (uint16_t)sr->commandTimeout, op.AccessPassword, op.CommandCode,
+          op.Password, op.sl900A.level, op.cal.raw, filter);
+    }
+
+  case (TMR_TAGOP_GEN2_IDS_SL900A_SETSFEPARAMETERS):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_SetSfeParameters op;
+
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.setSfeParameters;
+      return TMR_SR_cmdSL900aSetSfeParameters(reader, (uint16_t)sr->commandTimeout, op.AccessPassword, op.CommandCode,
+          op.Password, op.sl900A.level, op.sfe->raw, filter);
+    }
+
+  case (TMR_TAGOP_GEN2_IDS_SL900A_GETLOGSTATE):
+
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_GetLogState op;
+
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.getLog;
+      return TMR_SR_cmdSL900aGetLogState(reader, (uint16_t)sr->commandTimeout, op.AccessPassword, op.CommandCode,
+        op.Password, op.sl900A.level, data, filter);
+    }
+
+  case (TMR_TAGOP_GEN2_IDS_SL900A_SETLOGMODE):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_SetLogMode op;
+
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.setLogMode;
+      return TMR_SR_cmdSL900aSetLogMode(reader, (uint16_t)sr->commandTimeout, op.AccessPassword, op.CommandCode,
+        op.Password, op.sl900A.level, op.sl900A.dataLog, op.sl900A.rule, op.Ext1Enable, op.Ext2Enable, op.TempEnable,
+        op.BattEnable, op.LogInterval, filter);
+    }
+
+  case (TMR_TAGOP_GEN2_IDS_SL900A_INITIALIZE):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_Initialize op;
+      
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.initialize;
+
+      return TMR_SR_cmdSL900aInitialize(reader, (uint16_t)sr->commandTimeout, op.AccessPassword, op.CommandCode,
+        op.Password, op.sl900A.level, op.delayTime.raw, op.applicationData.raw, filter);
+    }
+
+  case (TMR_TAGOP_GEN2_IDS_SL900A_ENDLOG):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_EndLog op;
+
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.endLog;
+      return TMR_SR_cmdSL900aEndLog(reader, (uint16_t)sr->commandTimeout, op.AccessPassword, op.CommandCode,
+        op.Password,op.sl900A.level, filter);
+    }
+    
+  case (TMR_TAGOP_GEN2_IDS_SL900A_SETPASSWORD):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_SetPassword op;
+
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.setPassword;
+      return TMR_SR_cmdSL900aSetPassword(reader, (uint16_t)sr->commandTimeout, op.AccessPassword, op.CommandCode,
+          op.Password,op.sl900A.level, op.NewPassword, op.NewPasswordLevel, filter);
+    }
+
+  case (TMR_TAGOP_GEN2_IDS_SL900A_ACCESSFIFOSTATUS):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_AccessFifoStatus op;
+      
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.accessFifoStatus;
+      return TMR_SR_cmdSL900aAccessFifoStatus(reader, (uint16_t)sr->commandTimeout, op.status.AccessPassword, op.status.CommandCode,
+        op.status.Password, op.status.sl900A.level, op.status.operation, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_IDS_SL900A_ACCESSFIFOREAD):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_AccessFifoRead op;
+
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.accessFifoRead;
+      return TMR_SR_cmdSL900aAccessFifoRead(reader, (uint16_t)sr->commandTimeout, op.read.AccessPassword, op.read.CommandCode,
+        op.read.Password, op.read.sl900A.level, op.read.operation,op.length, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_IDS_SL900A_ACCESSFIFOWRITE):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_AccessFifoWrite op;
+
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.accessFifoWrite;
+      return TMR_SR_cmdSL900aAccessFifoWrite(reader, (uint16_t)sr->commandTimeout, op.write.AccessPassword, op.write.CommandCode,
+        op.write.Password, op.write.sl900A.level, op.write.operation, op.payLoad, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_IDS_SL900A_STARTLOG):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_StartLog op;
+      
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+      
+      op = tagop->u.gen2.u.custom.u.ids.u.startLog;
+
+      return TMR_SR_cmdSL900aStartLog(reader, (uint16_t)sr->commandTimeout, op.AccessPassword, op.CommandCode,
+        op.Password, op.sl900A.level, op.startTime, filter);
+    }
+  case (TMR_TAGOP_GEN2_IDS_SL900A_GETBATTERYLEVEL):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_GetBatteryLevel op;
+
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.batteryLevel;
+
+      return TMR_SR_cmdSL900aGetBatteryLevel(reader, (uint16_t)sr->commandTimeout, op.AccessPassword, op.CommandCode,
+          op.Password, op.sl900A.level, op.batteryType, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_IDS_SL900A_SETLOGLIMITS):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_SetLogLimits op;
+
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.setLogLimit;
+
+      return TMR_SR_cmdSL900aSetLogLimit(reader, (uint16_t)sr->commandTimeout, op.AccessPassword, op.CommandCode,
+          op.Password, op.sl900A.level, op.limit.extremeLower, op.limit.lower, op.limit.upper, op.limit.extremeUpper, filter);
+    }
+  case (TMR_TAGOP_GEN2_IDS_SL900A_SETSHELFLIFE):
+    {
+      TMR_TagOp_GEN2_IDS_SL900A_SetShelfLife op;
+
+      /* Set the protocol for tag operation */
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      /* Do some error checking */
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.ids.u.setShelfLife;
+
+      return TMR_SR_cmdSL900aSetShelfLife(reader, (uint16_t)sr->commandTimeout, op.AccessPassword, op.CommandCode,
+          op.Password, op.sl900A.level, op.shelfLifeBlock0->raw, op.shelfLifeBlock1->raw, filter);
+    }
+  case (TMR_TAGOP_GEN2_DENATRAN_IAV_ACTIVATESECUREMODE):
+    {
+      TMR_TagOp_GEN2_Denatran_IAV_Activate_Secure_Mode op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.IavDenatran.u.secureMode;
+      return TMR_SR_cmdIAVDenatranCustomOp(reader, (uint16_t)sr->commandTimeout, sr->gen2AccessPassword,
+          op.mode, op.payload, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_DENATRAN_IAV_AUTHENTICATEOBU):
+    {
+      TMR_TagOp_GEN2_Denatran_IAV_Authenticate_OBU op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.IavDenatran.u.authenticateOBU;
+      return TMR_SR_cmdIAVDenatranCustomOp(reader, (uint16_t)sr->commandTimeout, sr->gen2AccessPassword,
+          op.mode, op.payload, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_ACTIVATE_SINIAV_MODE):
+    {
+      TMR_TagOp_GEN2_Denatran_IAV_Activate_Siniav_Mode op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.IavDenatran.u.activateSiniavMode;
+      return TMR_SR_cmdIAVDenatranCustomActivateSiniavMode(reader, (uint16_t)sr->commandTimeout, sr->gen2AccessPassword,
+        op.mode, op.payload, data, filter, op.isTokenDesc, op.token);
+    }
+  case (TMR_TAGOP_GEN2_OBU_AUTH_ID):
+    {
+      TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_ID op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthId;
+      return TMR_SR_cmdIAVDenatranCustomOp(reader, (uint16_t)sr->commandTimeout, sr->gen2AccessPassword,
+          op.mode, op.payload, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_AUTHENTICATE_OBU_FULL_PASS1):
+    {
+      TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass1 op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthFullPass1;
+      return TMR_SR_cmdIAVDenatranCustomOp(reader, (uint16_t)sr->commandTimeout, sr->gen2AccessPassword,
+          op.mode, op.payload, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_AUTHENTICATE_OBU_FULL_PASS2):
+    {
+      TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass2 op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthFullPass2;
+      return TMR_SR_cmdIAVDenatranCustomOp(reader, (uint16_t)sr->commandTimeout, sr->gen2AccessPassword,
+          op.mode, op.payload, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_OBU_READ_FROM_MEM_MAP):
+    {
+      TMR_TagOp_GEN2_Denatran_IAV_OBU_ReadFromMemMap op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.IavDenatran.u.obuReadFromMemMap;
+      return TMR_SR_cmdIAVDenatranCustomReadFromMemMap(reader, (uint16_t)sr->commandTimeout, sr->gen2AccessPassword,
+          op.mode, op.payload, data, filter, op.readPtr);
+    }
+  case (TMR_TAGOP_GEN2_DENATRAN_IAV_READ_SEC):
+    {
+      TMR_TagOp_GEN2_Denatran_IAV_Read_Sec op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.IavDenatran.u.readSec;
+      return TMR_SR_cmdIAVDenatranCustomReadSec(reader, (uint16_t)sr->commandTimeout, sr->gen2AccessPassword,
+          op.mode, op.payload, data, filter, op.readPtr);
+
+    }
+  case (TMR_TAGOP_GEN2_OBU_WRITE_TO_MEM_MAP):
+    {
+
+      TMR_TagOp_GEN2_Denatran_IAV_OBU_WriteToMemMap op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.IavDenatran.u.obuWriteToMemMap;
+      return TMR_SR_cmdIAVDenatranCustomWriteToMemMap(reader, (uint16_t)sr->commandTimeout, sr->gen2AccessPassword,
+        op.mode, op.payload, data, filter, op.writePtr, op.wordData,op.tagIdentification, op.dataBuf);
+    }
+  case (TMR_TAGOP_GEN2_DENATRAN_IAV_WRITE_SEC):
+    {
+
+      TMR_TagOp_GEN2_Denatran_IAV_Write_Sec op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.IavDenatran.u.writeSec;
+      return TMR_SR_cmdIAVDenatranCustomWriteSec(reader, (uint16_t)sr->commandTimeout, sr->gen2AccessPassword,
+          op.mode, op.payload, data, filter, op.dataWords, op.dataBuf);
+    }
+ 
+  case (TMR_TAGOP_GEN2_DENATRAN_IAV_GET_TOKEN_ID):
+    {
+      TMR_TagOp_GEN2_Denatran_IAV_Get_Token_Id op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if ( TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if (NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.IavDenatran.u.getTokenId;
+      return TMR_SR_cmdIAVDenatranCustomGetTokenId(reader, (uint16_t)sr->commandTimeout, sr->gen2AccessPassword,
+          op.mode, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_DENATRAN_IAV_AUTHENTICATE_OBU_FULL_PASS):
+    {
+      TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthFullPass;
+      return TMR_SR_cmdIAVDenatranCustomOp(reader, (uint16_t)sr->commandTimeout,
+          sr->gen2AccessPassword, op.mode, op.payload, data, filter);
+    }
+  case (TMR_TAGOP_GEN2_DENATRAN_IAV_G0_PA_OBU_AUTHENTICATE_ID):
+    {
+      TMR_TagOp_GEN2_Denatran_IAV_G0_PA_OBU_Auth_ID op;
+
+      ret = setProtocol(reader, TMR_TAG_PROTOCOL_GEN2);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if(NULL != data)
+      {
+        data->len = 0;
+      }
+
+      op = tagop->u.gen2.u.custom.u.IavDenatran.u.g0paobuauthid;
+      return TMR_SR_cmdIAVDenatranCustomOp(reader, (uint16_t)sr->commandTimeout,
+          sr->gen2AccessPassword, op.mode, op.payload, data, filter);
+    }
+#endif /* TMR_ENABLE_GEN2_CUSTOM_TAGOPS */
+
+#ifdef TMR_ENABLE_ISO180006B
+  case (TMR_TAGOP_ISO180006B_READDATA):
+    {
+      TMR_TagOp_ISO180006B_ReadData op;
+	    TMR_TagReadData read;
+	    
+	    ret = setProtocol(reader, TMR_TAG_PROTOCOL_ISO180006B);
+	    if (TMR_SUCCESS != ret)
+	    {
+	      return ret;
+      }
+
+      if (NULL != data)
+      {
+        read.data.max = data->max;
+        read.data.len = 0;
+        read.data.list = data->list;
+      }
+      else
+      {
+        read.data.list = NULL;
+      }
+      read.metadataFlags = 0;
+
+      op = tagop->u.iso180006b.u.readData;
+	    ret = TMR_SR_cmdISO180006BReadTagData(reader, (uint16_t)sr->commandTimeout,
+                op.byteAddress, op.len, filter, &read);
+      if (NULL != data)
+      {
+        data->len = read.data.len;
+      }
+      return ret;
+    }
+  case (TMR_TAGOP_ISO180006B_WRITEDATA):
+    {
+      TMR_TagOp_ISO180006B_WriteData op;
+           
+	  ret = setProtocol(reader, TMR_TAG_PROTOCOL_ISO180006B);
+	  if (TMR_SUCCESS != ret)
+	  {
+		return ret;
+    }
+      op = tagop->u.iso180006b.u.writeData;
+      return TMR_SR_cmdISO180006BWriteTagData(reader, (uint16_t)(sr->commandTimeout), op.byteAddress,
+        (uint8_t)op.data.len, op.data.list, filter);
+    }
+  case (TMR_TAGOP_ISO180006B_LOCK):
+    {
+      TMR_TagOp_ISO180006B_Lock op;
+  
+	  ret = setProtocol(reader, TMR_TAG_PROTOCOL_ISO180006B);
+	  if (TMR_SUCCESS != ret)
+	  {
+	    return ret;
+	  }
+
+      op = tagop->u.iso180006b.u.lock;
+      return TMR_SR_cmdISO180006BLockTag(reader, (uint16_t)(sr->commandTimeout), op.address, filter);
+
+    }
+
+#endif /* TMR_ENABLE_ISO180006B */
+  default:
+    {
+      return TMR_ERROR_UNIMPLEMENTED_FEATURE; 
+    }
+
+  }  
+}
+
+/**
+ * Internal method used for adding the tagop
+ **/ 
+TMR_Status
+TMR_SR_addTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop,TMR_ReadPlan *rp, uint8_t *msg, uint8_t *j, uint32_t readTimeMs, uint8_t *byte )
+{
+ 
+  TMR_Status ret = TMR_SUCCESS;
+  TMR_SR_SerialReader *sr;
+  uint8_t i, lenbyte;
+  i = *j; lenbyte = *byte;
+
+  sr = &reader->u.serialReader;
+  
+
+  switch (tagop->type)
+  {
+    case (TMR_TAGOP_GEN2_WRITETAG):
+      {
+        TMR_TagOp_GEN2_WriteTag *args;
+
+        args = &rp->u.simple.tagop->u.gen2.u.writeTag;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddGEN2WriteTagEPC(msg,&i, 0, args->epcptr->epc, args->epcptr->epcByteCount);
+        break;
+      }
+    case TMR_TAGOP_GEN2_READDATA:
+      {
+        TMR_TagOp_GEN2_ReadData *args;
+
+        args = &rp->u.simple.tagop->u.gen2.u.readData;
+
+        /**
+         * If user wants to read all the memory bank data,
+         * In that case args.bank value should be greater than 3
+         **/
+        if ((uint8_t)args->bank > 3)
+        {
+          /* enable the gen2AllMemoryBankEnabled option */
+          sr->gen2AllMemoryBankEnabled = true;
+        }
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddGEN2DataRead(msg, &i, 2000, args->bank, args->wordAddress,
+            args->len, 0x00, false);
+        break;
+      }
+    case TMR_TAGOP_GEN2_SECURE_READDATA:
+      {
+        TMR_TagOp_GEN2_SecureReadData *args;
+        uint8_t accessPassword[4];
+        int index = 0;
+
+        /* Enable the Secure ReadData option */
+        isSecureAccessEnabled = true;
+
+        args = &rp->u.simple.tagop->u.gen2.u.secureReadData;
+        if (args->passwordType == TMR_SECURE_GEN2_LOOKUP_TABLE_PASSWORD)
+        {
+          /* Do this in case of look up table */
+          accessPassword[index++] = args->password.secureAddressLength;
+          accessPassword[index++] = args->password.secureAddressOffset;
+          accessPassword[index++] = (args->password.secureFlashOffset >> 8);
+          accessPassword[index++] = (args->password.secureFlashOffset & 0xFF);
+
+          sr->gen2AccessPassword = (uint32_t)accessPassword[0] << 24 |
+            (uint32_t)accessPassword[1] << 16 |
+            (uint32_t)accessPassword[2] << 8  |
+            (uint32_t)accessPassword[3];
+        }
+        else
+        {
+          /* Do this in case of Gen2 password */
+          sr->gen2AccessPassword = args->password.gen2PassWord.u.gen2Password;
+        }
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND | TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddGEN2DataRead(msg, &i, 2000, args->readData.bank, args->readData.wordAddress,
+            args->readData.len,args->type, false);
+
+				isSecureAccessEnabled = false;
+        break;
+      }
+    case TMR_TAGOP_GEN2_WRITEDATA:
+      {
+        TMR_TagOp_GEN2_WriteData *args;
+        int idx ;
+
+        args = &rp->u.simple.tagop->u.gen2.u.writeData;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddGEN2DataWrite(msg, &i, 0, args->bank, args->wordAddress);
+
+        for(idx = 0 ; idx< args->data.len; idx++)
+        {
+          msg[i++]= (args->data.list[idx]>>8) & 0xFF;
+          msg[i++]= (args->data.list[idx]>>0) & 0xFF;
+        }
+        break;
+      }
+    case TMR_TAGOP_GEN2_LOCK:
+      {
+        TMR_TagOp_GEN2_Lock *args;
+
+        args = &rp->u.simple.tagop->u.gen2.u.lock;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->accessPassword, &lenbyte);
+
+        TMR_SR_msgAddGEN2LockTag(msg, &i, 0, args->mask, args->action, 0);
+        break;
+      }
+    case TMR_TAGOP_GEN2_KILL:
+      {
+        TMR_TagOp_GEN2_Kill *args;
+
+        args = &rp->u.simple.tagop->u.gen2.u.kill;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddGEN2KillTag(msg, &i, 0, args->password);
+        break;
+      }
+    case TMR_TAGOP_GEN2_BLOCKWRITE:
+      {
+        TMR_TagOp_GEN2_BlockWrite *args;
+        args = &rp->u.simple.tagop->u.gen2.u.blockWrite;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddGEN2BlockWrite(msg, &i, 0, args->bank, args->wordPtr, args->data.len, args->data.list, 0, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_BLOCKPERMALOCK:
+      {
+        TMR_TagOp_GEN2_BlockPermaLock *args;
+        args = &rp->u.simple.tagop->u.gen2.u.blockPermaLock;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddGEN2BlockPermaLock(msg, &i, 0,args->readLock, args->bank, args->blockPtr, args->mask.len, 
+            args->mask.list, 0, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_BLOCKERASE:
+      {
+        TMR_TagOp_GEN2_BlockErase *args;
+        args = &rp->u.simple.tagop->u.gen2.u.blockErase;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddGEN2BlockErase(msg, &i, 0, args->wordPtr, args->bank, args->wordCount, 0, NULL);
+        break;
+      }
+	  
+#ifdef TMR_ENABLE_GEN2_CUSTOM_TAGOPS
+    case TMR_TAGOP_GEN2_ALIEN_HIGGS2_PARTIALLOADIMAGE:
+      {
+        TMR_TagOp_GEN2_Alien_Higgs2_PartialLoadImage *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.alien.u.higgs2.u.partialLoadImage;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddHiggs2PartialLoadImage(msg, &i, 0, args->accessPassword, args->killPassword, 
+            args->epcptr->epcByteCount, args->epcptr->epc, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_ALIEN_HIGGS2_FULLLOADIMAGE:
+      {
+        TMR_TagOp_GEN2_Alien_Higgs2_FullLoadImage *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.alien.u.higgs2.u.fullLoadImage;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddHiggs2FullLoadImage(msg, &i, 0, args->accessPassword, args->killPassword, args->lockBits, 
+            args->pcWord, args->epcptr->epcByteCount, args->epcptr->epc, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_ALIEN_HIGGS3_FASTLOADIMAGE:
+      {
+        TMR_TagOp_GEN2_Alien_Higgs3_FastLoadImage *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.alien.u.higgs3.u.fastLoadImage;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->currentAccessPassword, &lenbyte);
+
+        TMR_SR_msgAddHiggs3FastLoadImage(msg, &i, 0, args->currentAccessPassword, args->accessPassword, 
+            args->killPassword, args->pcWord, args->epcptr->epcByteCount, args->epcptr->epc, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_ALIEN_HIGGS3_LOADIMAGE:
+      {
+        TMR_TagOp_GEN2_Alien_Higgs3_LoadImage *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.alien.u.higgs3.u.loadImage;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->currentAccessPassword, &lenbyte);
+
+        TMR_SR_msgAddHiggs3LoadImage(msg, &i, 0, args->currentAccessPassword, args->accessPassword, 
+            args->killPassword, args->pcWord, (uint8_t)args->epcAndUserData->len, args->epcAndUserData->list, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_ALIEN_HIGGS3_BLOCKREADLOCK:
+      {
+        TMR_TagOp_GEN2_Alien_Higgs3_BlockReadLock *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.alien.u.higgs3.u.blockReadLock;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->accessPassword, &lenbyte);
+
+        TMR_SR_msgAddHiggs3BlockReadLock(msg, &i, 0, args->accessPassword, args->lockBits, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_NXP_SETREADPROTECT:
+      {
+        TMR_TagOp_GEN2_NXP_SetReadProtect *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.nxp.u.setReadProtect;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->accessPassword, &lenbyte);
+
+        TMR_SR_msgAddNXPSetReadProtect(msg, &i, 0, rp->u.simple.tagop->u.gen2.u.custom.chipType, args->accessPassword, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_NXP_RESETREADPROTECT:
+      {
+        TMR_TagOp_GEN2_NXP_ResetReadProtect *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.nxp.u.resetReadProtect;
+
+        if (rp->u.simple.tagop->u.gen2.u.custom.chipType == TMR_SR_GEN2_NXP_G2X_SILICON)
+        {
+          /* NXP_G2XL_ResetReadProtect can not be embedded.
+           * Throw un supported exception to the user
+           */
+          return TMR_ERROR_UNSUPPORTED;
+        }
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->accessPassword, &lenbyte);
+
+        TMR_SR_msgAddNXPResetReadProtect(msg, &i, 0, rp->u.simple.tagop->u.gen2.u.custom.chipType, args->accessPassword, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_NXP_CHANGEEAS:
+      {
+        TMR_TagOp_GEN2_NXP_ChangeEAS *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.nxp.u.changeEAS;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->accessPassword, &lenbyte);
+
+        TMR_SR_msgAddNXPChangeEAS(msg, &i, 0, rp->u.simple.tagop->u.gen2.u.custom.chipType, args->accessPassword, args->reset, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_NXP_EASALARM:
+      {
+        return TMR_ERROR_UNSUPPORTED;
+      }
+    case TMR_TAGOP_GEN2_NXP_CALIBRATE:
+      {
+        TMR_TagOp_GEN2_NXP_Calibrate *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.nxp.u.calibrate;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->accessPassword, &lenbyte);
+
+        TMR_SR_msgAddNXPCalibrate(msg, &i, 0, rp->u.simple.tagop->u.gen2.u.custom.chipType, args->accessPassword, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_NXP_CHANGECONFIG:
+      {
+        TMR_TagOp_GEN2_NXP_ChangeConfig *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.nxp.u.changeConfig;
+
+        if (rp->u.simple.tagop->u.gen2.u.custom.chipType == TMR_SR_GEN2_NXP_G2X_SILICON)
+        {
+          /* Change Config is not supported for G2xL silicon*/
+          return TMR_ERROR_UNSUPPORTED;
+        }
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->accessPassword, &lenbyte);
+
+        TMR_SR_msgAddNXPChangeConfig(msg, &i, 0, rp->u.simple.tagop->u.gen2.u.custom.chipType, 0, args->configWord, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_IMPINJ_MONZA4_QTREADWRITE:
+      {
+        TMR_TagOp_GEN2_Impinj_Monza4_QTReadWrite *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.impinj.u.monza4.u.qtReadWrite;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->accessPassword, &lenbyte);
+
+        TMR_SR_msgAddMonza4QTReadWrite(msg, &i, 0, 0, args->controlByte, args->payload, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_IDS_SL900A_GETSENSOR:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_GetSensorValue *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.sensor;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aGetSensorValue(msg, &i, 0, 0, args->CommandCode, args->Password, args->sl900A.level,
+            args->sl900A.sensortype, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_IDS_SL900A_GETMEASUREMENTSETUP:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_GetMeasurementSetup *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.measurementSetup;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aGetMeasurementSetup(msg, &i, 0, 0, args->CommandCode, args->Password, args->sl900A.level, NULL);
+      }
+
+    case TMR_TAGOP_GEN2_IDS_SL900A_GETLOGSTATE:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_GetLogState *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.getLog;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aGetLogState(msg, &i, 0, 0, args->CommandCode, args->Password, args->sl900A.level,NULL);
+
+        break;
+      }
+    case TMR_TAGOP_GEN2_IDS_SL900A_SETLOGMODE:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_SetLogMode *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.setLogMode;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aSetLogMode(msg, &i, 0, 0, args->CommandCode, args->Password, args->sl900A.level,
+            args->sl900A.dataLog, args->sl900A.rule, args->Ext1Enable, args->Ext2Enable, args->TempEnable,
+            args->BattEnable, args->LogInterval, NULL);
+
+        break;
+      }
+
+    case TMR_TAGOP_GEN2_IDS_SL900A_INITIALIZE:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_Initialize *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.initialize;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aInitialize(msg, &i, 0, 0, args->CommandCode, args->Password, args->sl900A.level,
+            args->delayTime.raw, args->applicationData.raw, NULL);
+
+        break;
+      }
+    case TMR_TAGOP_GEN2_IDS_SL900A_ENDLOG:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_EndLog *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.endLog;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aEndLog(msg, &i, 0, 0, args->CommandCode, args->Password, args->sl900A.level, NULL);
+        break;
+
+      }
+    case TMR_TAGOP_GEN2_IDS_SL900A_SETPASSWORD:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_SetPassword *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.setPassword;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aSetPassword(msg, &i, 0, 0, args->CommandCode, args->Password, args->sl900A.level,
+            args->NewPassword, args->NewPasswordLevel,  NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_IDS_SL900A_STARTLOG:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_StartLog *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.startLog;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aStartLog(msg, &i, 0, 0, args->CommandCode, args->Password, args->sl900A.level, args->startTime, NULL);
+        break;
+
+      }
+    case TMR_TAGOP_GEN2_IDS_SL900A_ACCESSFIFOSTATUS:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_AccessFifoStatus *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.accessFifoStatus;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->status.AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aAccessFifoStatus(msg, &i, 0, 0, args->status.CommandCode, args->status.Password, args->status.sl900A.level, args->status.operation, NULL);
+        break;
+
+      }
+    case TMR_TAGOP_GEN2_IDS_SL900A_ACCESSFIFOREAD:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_AccessFifoRead *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.accessFifoRead;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->read.AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aAccessFifoRead(msg, &i, 0, 0, args->read.CommandCode, args->read.Password, args->read.sl900A.level, args->read.operation, args->length, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_IDS_SL900A_ACCESSFIFOWRITE:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_AccessFifoWrite *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.accessFifoWrite;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->write.AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aAccessFifoWrite(msg, &i, 0, 0, args->write.CommandCode, args->write.Password, args->write.sl900A.level, args->write.operation, args->payLoad, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_IDS_SL900A_GETCALIBRATIONDATA:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_GetCalibrationData *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.calibrationData;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aGetCalibrationData(msg, &i, 0, 0, args->CommandCode, args->Password, args->sl900A.level, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_IDS_SL900A_SETCALIBRATIONDATA:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_SetCalibrationData *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.setCalibration;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aSetCalibrationData(msg, &i, 0, 0, args->CommandCode, args->Password, args->sl900A.level, args->cal.raw, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_IDS_SL900A_SETSFEPARAMETERS:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_SetSfeParameters *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.setSfeParameters;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aSetSfeParameters(msg, &i, 0, 0, args->CommandCode, args->Password, args->sl900A.level, args->sfe->raw, NULL);
+        break;
+
+      }
+    case TMR_TAGOP_GEN2_IDS_SL900A_GETBATTERYLEVEL:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_GetBatteryLevel *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.batteryLevel;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aGetBatteryLevel(msg, &i, 0, 0, args->CommandCode, args->Password, args->sl900A.level, args->batteryType, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_IDS_SL900A_SETLOGLIMITS:
+      {
+        TMR_TagOp_GEN2_IDS_SL900A_SetLogLimits *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.ids.u.setLogLimit;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, args->AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIdsSL900aSetLogLimit(msg, &i, 0, 0, args->CommandCode, args->Password, args->sl900A.level, args->limit.extremeLower,
+            args->limit.lower, args->limit.upper, args->limit.extremeUpper, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_DENATRAN_IAV_ACTIVATESECUREMODE:
+      {
+        TMR_TagOp_GEN2_Denatran_IAV_Activate_Secure_Mode *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.IavDenatran.u.secureMode;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIAVDenatranCustomOp(msg, &i, 0, 0, args->mode, args->payload, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_DENATRAN_IAV_AUTHENTICATEOBU:
+      {
+        TMR_TagOp_GEN2_Denatran_IAV_Authenticate_OBU *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.IavDenatran.u.authenticateOBU;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIAVDenatranCustomOp(msg, &i, 0, 0, args->mode, args->payload, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_ACTIVATE_SINIAV_MODE:
+      {
+        TMR_TagOp_GEN2_Denatran_IAV_Activate_Siniav_Mode *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.IavDenatran.u.activateSiniavMode;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIAVDenatranCustomActivateSiniavMode(msg, &i, 0, 0, args->mode, args->payload, NULL, args->isTokenDesc, args->token);
+        break;
+      }
+    case TMR_TAGOP_GEN2_OBU_AUTH_ID:
+      {
+        TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_ID *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthId;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIAVDenatranCustomOp(msg, &i, 0, 0, args->mode, args->payload, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_AUTHENTICATE_OBU_FULL_PASS1:
+      {
+        TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass1 *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthFullPass1;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIAVDenatranCustomOp(msg, &i, 0, 0, args->mode, args->payload, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_AUTHENTICATE_OBU_FULL_PASS2:
+      {
+        TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass2 *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthFullPass2;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIAVDenatranCustomOp(msg, &i, 0, 0, args->mode, args->payload, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_OBU_READ_FROM_MEM_MAP:
+      {
+        TMR_TagOp_GEN2_Denatran_IAV_OBU_ReadFromMemMap *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.IavDenatran.u.obuReadFromMemMap;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIAVDenatranCustomReadFromMemMap(msg, &i, 0, 0, args->mode, args->payload, NULL, args->readPtr);
+        break;
+      }
+    case TMR_TAGOP_GEN2_DENATRAN_IAV_READ_SEC:
+      {
+        TMR_TagOp_GEN2_Denatran_IAV_Read_Sec *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.IavDenatran.u.readSec;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+              | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIAVDenatranCustomReadSec(msg, &i, 0, 0, args->mode, args->payload, NULL, args->readPtr);
+        break;
+      }
+ 
+    case TMR_TAGOP_GEN2_OBU_WRITE_TO_MEM_MAP:
+      {
+        TMR_TagOp_GEN2_Denatran_IAV_OBU_WriteToMemMap *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.IavDenatran.u.obuWriteToMemMap;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+            | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIAVDenatranCustomWriteToMemMap(msg, &i, 0, 0, args->mode, args->payload, NULL, args->writePtr, args->wordData, args->tagIdentification, args->dataBuf);
+        break;
+      }
+
+    case TMR_TAGOP_GEN2_DENATRAN_IAV_WRITE_SEC:
+      {
+        TMR_TagOp_GEN2_Denatran_IAV_Write_Sec *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.IavDenatran.u.writeSec;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+              | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIAVDenatranCustomWriteSec(msg, &i, 0, 0, args->mode, args->payload, NULL, args->dataWords, args->dataBuf);
+        break;
+      }
+ 
+    case TMR_TAGOP_GEN2_DENATRAN_IAV_GET_TOKEN_ID:
+      {
+        TMR_TagOp_GEN2_Denatran_IAV_Get_Token_Id *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.IavDenatran.u.getTokenId;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+              | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIAVDenatranCustomGetTokenId(msg, &i, 0, 0, args->mode, NULL);
+        break;
+      }
+    case TMR_TAGOP_GEN2_DENATRAN_IAV_AUTHENTICATE_OBU_FULL_PASS:
+      {
+        TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthFullPass;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+              | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIAVDenatranCustomOp(msg, &i, 0, 0, args->mode, args->payload, NULL);
+        break;
+
+      }
+    case TMR_TAGOP_GEN2_DENATRAN_IAV_G0_PA_OBU_AUTHENTICATE_ID:
+      {
+        TMR_TagOp_GEN2_Denatran_IAV_G0_PA_OBU_Auth_ID *args;
+        args = &rp->u.simple.tagop->u.gen2.u.custom.u.IavDenatran.u.g0paobuauthid;
+
+        prepEmbReadTagMultiple(reader, msg, &i, (uint16_t)readTimeMs, (TMR_SR_SearchFlag)(TMR_SR_SEARCH_FLAG_CONFIGURED_LIST
+              | TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND|TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT),
+            rp->u.simple.filter, rp->u.simple.protocol, sr->gen2AccessPassword, &lenbyte);
+
+        TMR_SR_msgAddIAVDenatranCustomOp(msg, &i, 0, 0, args->mode, args->payload, NULL);
+        break;
+      }
+#endif /* TMR_ENABLE_GEN2_CUSTOM_TAGOPS */
+    case TMR_TAGOP_LIST:
+      return TMR_ERROR_UNIMPLEMENTED; /* Module doesn't implement these */
+    default:
+      return TMR_ERROR_INVALID; /* Unknown tagop - internal error */
+  }
+  *j = i;
+  *byte = lenbyte;
+  return ret;
+
+}
+/* Internal method used to update the base times stamp */
+void TMR_SR_updateBaseTimeStamp(TMR_Reader *reader)
+{
+  /* update the base time stamp to current host time */
+  uint32_t starttimeLow, starttimeHigh;
+
+  starttimeHigh = 0;
+  starttimeLow = 0;
+  tm_gettime_consistent(&starttimeHigh, &starttimeLow);
+  reader->u.serialReader.readTimeHigh = starttimeHigh;
+  reader->u.serialReader.readTimeLow = starttimeLow;
+  reader->u.serialReader.lastSentTagTimestampHigh = starttimeHigh;
+  reader->u.serialReader.lastSentTagTimestampLow = starttimeLow;
+}
+#endif /* TMR_ENABLE_SERIAL_READER */
diff --git a/cbits/api/serial_reader_imp.h b/cbits/api/serial_reader_imp.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/serial_reader_imp.h
@@ -0,0 +1,1011 @@
+#ifndef _SERIAL_READER_IMP_H
+#define _SERIAL_READER_IMP_H
+
+/**
+ *  @file serial_reader_imp.h
+ *  @brief Serial reader internal implementation header
+ *  @author Nathan Williams
+ *  @date 10/28/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.
+ */
+#include "tm_reader.h"
+#include "tmr_status.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+  
+/* This is used to enable the Gen2 secure readdata option */
+
+#ifndef BARE_METAL
+  extern bool isSecureAccessEnabled ;
+#else
+  static bool isSecureAccessEnabled;	
+#endif
+
+typedef enum TMR_SR_OpCode
+{
+  TMR_SR_OPCODE_WRITE_FLASH             = 0x01,
+  TMR_SR_OPCODE_READ_FLASH              = 0x02,
+  TMR_SR_OPCODE_VERSION                 = 0x03,
+  TMR_SR_OPCODE_BOOT_FIRMWARE           = 0x04,
+  TMR_SR_OPCODE_SET_BAUD_RATE           = 0x06,
+  TMR_SR_OPCODE_ERASE_FLASH             = 0x07,
+  TMR_SR_OPCODE_VERIFY_IMAGE_CRC        = 0x08,
+  TMR_SR_OPCODE_BOOT_BOOTLOADER         = 0x09,
+  TMR_SR_OPCODE_HW_VERSION              = 0x10,
+  TMR_SR_OPCODE_MODIFY_FLASH            = 0x0A,
+  TMR_SR_OPCODE_GET_DSP_SILICON_ID      = 0x0B,
+  TMR_SR_OPCODE_GET_CURRENT_PROGRAM     = 0x0C,
+  TMR_SR_OPCODE_WRITE_FLASH_SECTOR      = 0x0D,
+  TMR_SR_OPCODE_GET_SECTOR_SIZE         = 0x0E,
+  TMR_SR_OPCODE_MODIFY_FLASH_SECTOR     = 0x0F,
+  TMR_SR_OPCODE_READ_TAG_ID_SINGLE      = 0x21,
+  TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE    = 0x22,
+  TMR_SR_OPCODE_WRITE_TAG_ID            = 0x23,
+  TMR_SR_OPCODE_WRITE_TAG_DATA          = 0x24,
+  TMR_SR_OPCODE_LOCK_TAG                = 0x25,
+  TMR_SR_OPCODE_KILL_TAG                = 0x26,
+  TMR_SR_OPCODE_READ_TAG_DATA           = 0x28,
+  TMR_SR_OPCODE_GET_TAG_ID_BUFFER       = 0x29,
+  TMR_SR_OPCODE_CLEAR_TAG_ID_BUFFER     = 0x2A,
+  TMR_SR_OPCODE_WRITE_TAG_SPECIFIC      = 0x2D,
+  TMR_SR_OPCODE_ERASE_BLOCK_TAG_SPECIFIC= 0x2E,
+  TMR_SR_OPCODE_MULTI_PROTOCOL_TAG_OP   = 0x2F,
+  TMR_SR_OPCODE_GET_ANTENNA_PORT        = 0x61,
+  TMR_SR_OPCODE_GET_READ_TX_POWER       = 0x62,
+  TMR_SR_OPCODE_GET_TAG_PROTOCOL        = 0x63,
+  TMR_SR_OPCODE_GET_WRITE_TX_POWER      = 0x64,
+  TMR_SR_OPCODE_GET_FREQ_HOP_TABLE      = 0x65,
+  TMR_SR_OPCODE_GET_USER_GPIO_INPUTS    = 0x66,
+  TMR_SR_OPCODE_GET_REGION              = 0x67,
+  TMR_SR_OPCODE_GET_POWER_MODE          = 0x68,
+  TMR_SR_OPCODE_GET_USER_MODE           = 0x69,
+  TMR_SR_OPCODE_GET_READER_OPTIONAL_PARAMS=0x6A,
+  TMR_SR_OPCODE_GET_PROTOCOL_PARAM      = 0x6B,
+  TMR_SR_OPCODE_GET_READER_STATS        = 0x6C,
+  TMR_SR_OPCODE_GET_USER_PROFILE        = 0x6D,
+  TMR_SR_OPCODE_GET_AVAILABLE_PROTOCOLS = 0x70,
+  TMR_SR_OPCODE_GET_AVAILABLE_REGIONS   = 0x71,
+  TMR_SR_OPCODE_GET_TEMPERATURE         = 0x72,
+  TMR_SR_OPCODE_SET_ANTENNA_PORT        = 0x91,
+  TMR_SR_OPCODE_SET_READ_TX_POWER       = 0x92,
+  TMR_SR_OPCODE_SET_TAG_PROTOCOL        = 0x93,
+  TMR_SR_OPCODE_SET_WRITE_TX_POWER      = 0x94,
+  TMR_SR_OPCODE_SET_FREQ_HOP_TABLE      = 0x95,
+  TMR_SR_OPCODE_SET_USER_GPIO_OUTPUTS   = 0x96,
+  TMR_SR_OPCODE_SET_REGION              = 0x97,
+  TMR_SR_OPCODE_SET_POWER_MODE          = 0x98,
+  TMR_SR_OPCODE_SET_USER_MODE           =  0x99,
+  TMR_SR_OPCODE_SET_READER_OPTIONAL_PARAMS=0x9a,
+  TMR_SR_OPCODE_SET_PROTOCOL_PARAM      = 0x9B,
+  TMR_SR_OPCODE_SET_USER_PROFILE        = 0x9D,
+  TMR_SR_OPCODE_SET_PROTOCOL_LICENSEKEY = 0x9E,
+  TMR_SR_OPCODE_SET_OPERATING_FREQ      = 0xC1,
+  TMR_SR_OPCODE_TX_CW_SIGNAL            = 0xC3,
+}TMR_SR_OpCode;
+
+typedef enum TMR_SR_Gen2SingulationOptions
+{
+  TMR_SR_GEN2_SINGULATION_OPTION_SELECT_DISABLED         = 0x00,
+  TMR_SR_GEN2_SINGULATION_OPTION_SELECT_ON_EPC           = 0x01,
+  TMR_SR_GEN2_SINGULATION_OPTION_SELECT_ON_TID           = 0x02,
+  TMR_SR_GEN2_SINGULATION_OPTION_SELECT_ON_USER_MEM      = 0x03,
+  TMR_SR_GEN2_SINGULATION_OPTION_SELECT_ON_ADDRESSED_EPC = 0x04,
+  TMR_SR_GEN2_SINGULATION_OPTION_USE_PASSWORD            = 0x05,
+  TMR_SR_GEN2_SINGULATION_OPTION_SELECT_ON_LENGTH_OF_EPC = 0x06,
+  TMR_SR_GEN2_SINGULATION_OPTION_SELECT_GEN2TRUNCATE	 = 0x07,
+  TMR_SR_GEN2_SINGULATION_OPTION_INVERSE_SELECT_BIT      = 0x08,
+  TMR_SR_GEN2_SINGULATION_OPTION_FLAG_METADATA           = 0x10,
+  TMR_SR_GEN2_SINGULATION_OPTION_EXTENDED_DATA_LENGTH    = 0x20,
+  TMR_SR_GEN2_SINGULATION_OPTION_SECURE_READ_DATA        = 0x40
+}TMR_SR_Gen2SingulationOptions;
+
+typedef enum TMR_SR_TagidOption
+{
+  TMR_SR_TAG_ID_OPTION_NONE    = 0x00,
+  TMR_SR_TAG_ID_OPTION_REWIND  = 0x01
+}TMR_SR_TagidOption;
+
+typedef enum TMR_SR_ModelHardwareID
+{
+  TMR_SR_MODEL_M5E         = 0x00,
+  TMR_SR_MODEL_M5E_COMPACT = 0x01,
+  TMR_SR_MODEL_M5E_I       = 0x02,
+  TMR_SR_MODEL_M4E         = 0x03,
+  TMR_SR_MODEL_M6E         = 0x18,
+  TMR_SR_MODEL_M6E_I	   = 0x19,
+  TMR_SR_MODEL_MICRO       = 0x20,
+  TMR_SR_MODEL_M6E_NANO    = 0x30,
+  TMR_SR_MODEL_UNKNOWN     = 0xFF,
+} TMR_SR_ModelHardwareID;
+
+typedef enum TMR_SR_ModelMicro
+{
+  TMR_SR_MODEL_M6E_MICRO     = 0x01,
+  TMR_SR_MODEL_M6E_MICRO_USB = 0x02,
+  TMR_SR_MODEL_M6E_MICRO_USB_PRO = 0x03,
+}TMR_SR_ModelMicro;
+
+typedef enum TMR_SR_ModelM6E_I
+{
+  TMR_SR_MODEL_M6E_I_REV1 = 0x01,
+  TMR_SR_MODEL_M6E_I_PRC  = 0x02,
+  TMR_SR_MODEL_M6E_I_JIC  = 0x03,
+}TMR_SR_ModelM6E_I;
+
+typedef enum TMR_SR_ModelM5EInternational
+{
+  TMR_SR_MODEL_M5E_I_REV_EU  = 0x01,
+  TMR_SR_MODEL_M5E_I_REV_NA  = 0x02,
+  TMR_SR_MODEL_M5E_I_REV_JP  = 0x03,
+  TMR_SR_MODEL_M5E_I_REV_PRC = 0x04,
+}TMR_SR_ModelM5EInternational;
+
+typedef enum TMR_SR_ProductGroupID
+{
+  TMR_SR_PRODUCT_MODULE = 0,
+  TMR_SR_PRODUCT_RUGGEDIZED_READER = 1,
+  TMR_SR_PRODUCT_USB_READER = 2,
+  TMR_SR_PRODUCT_INVALID = 0xFFFF,
+}TMR_SR_ProductGroupID;
+
+TMR_Status TMR_SR_sendTimeout(TMR_Reader *reader, uint8_t *data,
+                              uint32_t timeoutMs);
+TMR_Status TMR_SR_send(TMR_Reader *reader, uint8_t *data);
+TMR_Status TMR_SR_sendMessage(TMR_Reader *reader, uint8_t *data,
+                              uint8_t *opcode, uint32_t timeoutMs);
+TMR_Status TMR_SR_receiveMessage(TMR_Reader *reader, uint8_t *data,
+                                 uint8_t opcode, uint32_t timeoutMs);
+TMR_Status TMR_SR_receiveAutonomousReading(struct TMR_Reader *reader, TMR_TagReadData *trd, TMR_Reader_StatsValues *stats);
+
+void TMR_SR_parseMetadataFromMessage(TMR_Reader *reader, TMR_TagReadData *read, uint16_t flags,
+                                     uint8_t *i, uint8_t msg[]);
+
+void
+TMR_SR_parseMetadataOnly(TMR_Reader *reader, TMR_TagReadData *read, uint16_t flags,
+                                uint8_t *i, uint8_t msg[]);
+void TMR_SR_postprocessReaderSpecificMetadata(TMR_TagReadData *read,
+                                              TMR_SR_SerialReader *sr);
+bool isContinuousReadParamSupported(TMR_Reader *reader);
+
+/**
+ * This structure is returned from read tag multiple embedded commands.
+ */
+typedef struct TMR_SR_MultipleStatus
+{
+  /** The number of tags found during the read. */
+  uint16_t tagsFound;
+  /** The number of tags for which the embedded operation succeeded. */
+  uint16_t successCount;
+  /** The number of tags for which the embedded operation failed. */
+  uint16_t failureCount;
+}TMR_SR_MultipleStatus;
+
+/**
+ * This structure is returned from TMR_SR_cmdGetTxRxPorts and
+ * TMR_SR_cmdGetAntennaSearchList, and passed as a parameter to
+ * TMR_SR_cmdSetAntennaSearchList.
+ */
+typedef struct TMR_SR_PortPair
+{
+  /** The transmit port. */
+  uint8_t txPort;
+  /** The receive port. */
+  uint8_t rxPort;
+}TMR_SR_PortPair;
+
+/**
+ * This structure is returned from TMR_SR_cmdAntennaDetect.
+ */
+typedef struct TMR_SR_PortDetect
+{
+  /** The port number. */
+  uint8_t port;
+  /** Whether an antenna was detected on the port. */
+  bool detected;
+}TMR_SR_PortDetect;
+
+/**
+ * Reader statistics options enum
+ */ 
+typedef enum TMR_SR_ReaderStatsOption
+{
+  /* Get statistics specified by the statistics flag */
+  TMR_SR_READER_STATS_OPTION_GET=   0x00,
+  /* Reset the specified statistic */
+  TMR_SR_READER_STATS_OPTION_RESET= 0x01,
+  /* Get the per-port statistics specified by the statistics flag*/
+  TMR_SR_READER_STATS_OPTION_GET_PER_PORT = 0x02,
+}TMR_SR_ReaderStatsOption;
+  
+
+/**
+ *  Reader Statistics Flag Enum
+ */
+typedef enum TMR_SR_ReaderStatisticsFlag
+{
+  /* Total time the port has been transmitting, in milliseconds. Resettable */
+  TMR_SR_READER_STATS_FLAG_RF_ON_TIME     = (1<<0),
+  /* Detected noise floor with transmitter off. Recomputed when requested, not resettable.*/
+  TMR_SR_READER_STATS_FLAG_NOISE_FLOOR    = (1<<1),
+  /* Detected noise floor with transmitter on. Recomputed when requested, not resettable. */
+  TMR_SR_READER_STATS_FLAG_NOISE_FLOOR_TX_ON = (1<<3),
+  /* ALL */
+  TMR_SR_READER_STATS_ALL = (TMR_SR_READER_STATS_FLAG_RF_ON_TIME | 
+      TMR_SR_READER_STATS_FLAG_NOISE_FLOOR |
+      TMR_SR_READER_STATS_FLAG_NOISE_FLOOR_TX_ON),
+}TMR_SR_ReaderStatisticsFlag;
+
+/**
+ * Antenna Configuration. Returned by TMR_SR_cmdGetAntennaConfiguration.
+ */
+typedef struct TMR_SR_AntennaPort
+{
+  /** The number of physical antenna ports. */
+  uint8_t numPorts;
+  /** The current logical Transmit port. */
+  uint8_t txPort;
+  /** The current logical Recieve port. */
+  uint8_t rxPort;
+  /** List specifying what ports are terminated. */
+  TMR_uint8List portTerminatedList;
+}TMR_SR_AntennaPort;
+
+/** Per-port power levels. Used by TMR_SR_cmd{Get,Set}AntennaPortPowers */
+typedef struct TMR_SR_PortPower
+{
+  /** The port number. */
+  uint8_t port;
+  /** The power level to use for read operations, in centidBm. */
+  uint16_t readPower;
+  /** The power level to use for write operations, in centidBm. */
+  uint16_t writePower;
+} TMR_SR_PortPower;
+
+/**
+ * Per-port power levels and settling times. Used by
+ * TMR_SR_cmd{Get,Set}AntennaPortPowersAndSettlingTime.
+ */
+typedef struct TMR_SR_PortPowerAndSettlingTime
+{
+  /** The port number. */
+  uint8_t port;
+  /** The power level to use for read operations, in centidBm. */
+  int16_t readPower;
+  /** The power level to use for write operations, in centidBm. */
+  int16_t writePower;
+  /** The duration to wait after switching to this port, in microseconds. */
+  uint16_t settlingTime;
+} TMR_SR_PortPowerAndSettlingTime;
+
+/** The current power level and the bounds of the power level range. */
+typedef struct TMR_SR_PowerWithLimits
+{
+  /** The current power level, in centidBm. */
+  uint16_t setPower;
+  /** The maximum power level, in centidBm. */
+  uint16_t maxPower;
+  /** The minimum power level, in centidBm. */
+  uint16_t minPower;
+} TMR_SR_PowerWithLimits;
+
+
+void TMR_hexDottedQuad(const uint8_t bytes[4], char buf[12]);
+TMR_Status TMR_hexDottedQuadToUint32(const char bytes[12], uint32_t *result);
+
+
+/**
+ * This type enumerates the serial reader configuration parameters for
+ * TMR_SR_cmdSetReaderConfiguration and
+ * TMR_SR_cmdGetReaderConfiguration.  Each value is
+ * associated with a particular data type for the setting.
+ */
+typedef enum TMR_SR_Configuration
+{
+  /**
+   *  Key tag buffer records off of antenna ID as well as EPC;
+   *  i.e., keep separate records for the same EPC read on different antennas
+   *  0: Disable -- Different antenna overwrites previous record.
+   *  1: Enable -- Different Antenna creates a new record.
+   */
+  TMR_SR_CONFIGURATION_UNIQUE_BY_ANTENNA        = 0,
+  /**
+   *  Run transmitter in lower-performance, power-saving mode.
+   *  0: Disable -- Higher transmitter bias for improved reader sensitivity
+   *  1: Enable -- Lower transmitter bias sacrifices sensitivity for power consumption
+   */
+  TMR_SR_CONFIGURATION_TRANSMIT_POWER_SAVE      = 1,
+  /**
+   *  Support 496-bit EPCs (vs normal max 96 bits)
+   *  0: Disable (max max EPC length = 96)
+   *  1: Enable 496-bit EPCs
+   */
+  TMR_SR_CONFIGURATION_EXTENDED_EPC             = 2,
+  /**
+   *  Configure GPOs to drive antenna switch.
+   *  0: No switch
+   *  1: Switch on GPO1
+   *  2: Switch on GPO2
+   *  3: Switch on GPO1,GPO2
+   */
+  TMR_SR_CONFIGURATION_ANTENNA_CONTROL_GPIO     = 3,
+  /**
+   *  Refuse to transmit if antenna is not detected
+   */
+  TMR_SR_CONFIGURATION_SAFETY_ANTENNA_CHECK     = 4,
+  /**
+   *  Refuse to transmit if overtemperature condition detected
+   */
+  TMR_SR_CONFIGURATION_SAFETY_TEMPERATURE_CHECK = 5,
+  /**
+   *  If tag read duplicates an existing tag buffer record (key is the same),
+   *  update the record's timestamp if incoming read has higher RSSI reading.
+   *  0: Keep timestamp of record's first read
+   *  1: Keep timestamp of read with highest RSSI
+   */
+  TMR_SR_CONFIGURATION_RECORD_HIGHEST_RSSI      = 6,
+  /**
+   *  Key tag buffer records off tag data as well as EPC;
+   *  i.e., keep separate records for the same EPC read with different data
+   *  0: Disable -- Different data overwrites previous record.
+   *  1: Enable -- Different data creates new record.
+   */
+  TMR_SR_CONFIGURATION_UNIQUE_BY_DATA           = 8,
+  /**
+   *  Whether RSSI values are reported in dBm, as opposed to
+   *  arbitrary uncalibrated units.
+   */
+  TMR_SR_CONFIGURATION_RSSI_IN_DBM              = 9,
+  /**
+   *  Self jammer cancellation
+   *  User can enable/disable through level2 API
+   */
+  TMR_SR_CONFIGURATION_SELF_JAMMER_CANCELLATION = 0x0A,
+  /**
+   *  Key tag buffer records off of protocol as well as EPC;
+   *  i.e., keep separate records for the same EPC read on different protocols
+   *  0: Disable -- Different protocol overwrites previous record.
+   *  1: Enable -- Different protocol creates a new record.
+   */
+  TMR_SR_CONFIGURATION_UNIQUE_BY_PROTOCOL       = 0x0B,
+  /**
+   *  Enable read filtering
+   */
+  TMR_SR_CONFIGURATION_ENABLE_READ_FILTER         = 0x0C,
+  /**
+   *  Tag buffer entry timeout
+   */
+  TMR_SR_CONFIGURATION_READ_FILTER_TIMEOUT        = 0x0D,
+  /**
+    * Transport (bus) type
+    **/ 
+  TMR_SR_CONFIGURATION_CURRENT_MSG_TRANSPORT      = 0x0E,
+  /**
+   * Enable the CRC calculation
+   */
+  TMR_SR_CONFIGURATION_SEND_CRC               = 0x1B,
+  /**
+   *  General category of finished reader into which module is integrated; e.g.,
+   *  0: bare module
+   *  1: In-vehicle Reader (e.g., Tool Link, Vega)
+   *  2: USB Reader
+   */
+  TMR_SR_CONFIGURATION_PRODUCT_GROUP_ID         = 0x12,
+  /**
+   * Product ID (Group ID 0x0002 ) information
+   * 0x0001 :M5e-C USB reader
+   * 0x0002 :Backback NA antenna
+   * 0x0003 :Backback EU antenna
+   **/
+  TMR_SR_CONFIGURATION_PRODUCT_ID              = 0x13,
+  /**
+   *  Configure GPIs to drive trigger read.
+   *  0: No switch
+   *  1: Switch on GPI1
+   *  2: Switch on GPI2
+   *  3: Switch on GPI3 (if supported)
+   *  4: Switch on GOI4 (if supported)
+   */
+  TMR_SR_CONFIGURATION_TRIGGER_READ_GPIO                     = 0x1E,
+} TMR_SR_Configuration;
+
+
+/**
+ * This type enumerates the region configuration parameters for
+ * the TMR_SR_cmdGetRegionConfiguration() command.
+ */
+typedef enum TMR_SR_RegionConfiguration
+{
+  TMR_SR_REGION_CONFIGURATION_LBT_ENABLED = 0x40,
+} TMR_SR_RegionConfiguration;
+
+/**
+ * This is the enumeration of Gen2-specific configuration values. Each
+ * enumerated value is associated with a particular data type for the
+ * setting value.
+ */
+typedef enum TMR_SR_Gen2Configuration
+{
+  TMR_SR_GEN2_CONFIGURATION_SESSION = 0x00,
+  TMR_SR_GEN2_CONFIGURATION_TARGET  = 0x01,
+  TMR_SR_GEN2_CONFIGURATION_TAGENCODING = 0x02,
+  TMR_SR_GEN2_CONFIGURATION_LINKFREQUENCY = 0x10,
+  TMR_SR_GEN2_CONFIGURATION_TARI    = 0x11,
+  TMR_SR_GEN2_CONFIGURATION_Q       = 0x12,
+  TMR_SR_GEN2_CONFIGURATION_BAP    = 0x13,
+  TMR_SR_GEN2_CONFIGURATION_PROTCOLEXTENSION = 0x14
+} TMR_SR_Gen2Configuration;
+
+/**
+ * This struture is retuned from TMR_SR_Gen2ReaderResponseTimeOut
+ */
+typedef struct TMR_SR_Gen2ReaderWriteTimeOut
+{
+  /* Status of reader timeout */
+  bool earlyexit;
+
+  /* Timeout value used for write operation */
+  uint16_t writetimeout;
+}TMR_SR_Gen2ReaderWriteTimeOut;
+/**
+ * This is the enumeration of ISO 18000-6B-specific configuration
+ * values. Each enumerated value is associated with a particular data
+ * type for the setting value.
+ */
+typedef enum TMR_SR_Iso180006bConfiguration
+{
+  TMR_SR_ISO180006B_CONFIGURATION_LINKFREQUENCY = 0x10,
+  TMR_SR_ISO180006B_CONFIGURATION_MODULATION_DEPTH = 0x11,
+  TMR_SR_ISO180006B_CONFIGURATION_DELIMITER = 0x12
+} TMR_SR_Iso180006bConfiguration;
+
+/**
+ * This is the enumeration of iPx-specific configuration
+ * values. Each enumerated value is associated with a particular data
+ * type for the setting value.
+ */
+typedef enum TMR_SR_iPxConfiguration
+{
+  TMR_SR_IPX_CONFIGURATION_LINKFREQUENCY = 0x10
+} TMR_SR_iPxConfiguration;
+
+
+/**
+ * This type selects the protocol configuration option for
+ * TMR_SR_cmdSetProtocolConfiguration() and
+ * TMR_SR_cmdGetProtocolConfiguration().  Each value is associated
+ * with a particular data type for the setting.
+ */
+typedef struct TMR_SR_ProtocolConfiguration
+{
+  /** The protocol to configure. Determines which union member is valid. */
+  TMR_TagProtocol protocol;
+  union
+  {
+    /** The configuration key for a Gen2 option. */
+    TMR_SR_Gen2Configuration gen2;
+    /** The configuration key for an ISO18000-6B option. */
+    TMR_SR_Iso180006bConfiguration iso180006b;
+    TMR_SR_iPxConfiguration ipx;
+  }u;
+} TMR_SR_ProtocolConfiguration;
+
+
+/**
+ * Defines the values for search flags for TMR_SR_cmdReadTagMultiple.
+ */
+typedef enum TMR_SR_SearchFlag
+{
+  TMR_SR_SEARCH_FLAG_CONFIGURED_ANTENNA = 0,
+  TMR_SR_SEARCH_FLAG_ANTENNA_1_THEN_2   = 1,
+  TMR_SR_SEARCH_FLAG_ANTENNA_2_THEN_1   = 2,
+  TMR_SR_SEARCH_FLAG_CONFIGURED_LIST    = 3,
+  TMR_SR_SEARCH_FLAG_ANTENNA_MASK       = 3,
+  TMR_SR_SEARCH_FLAG_EMBEDDED_COMMAND   = 4,
+  TMR_SR_SEARCH_FLAG_TAG_STREAMING      = 8,
+  TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT = 16,
+  TMR_SR_SEARCH_FLAG_STATUS_REPORT_STREAMING = 32,
+  TMR_SR_SEARCH_FLAG_RETURN_ON_N_TAGS = 64,
+  TMR_SR_SEARCH_FLAG_READ_MULTIPLE_FAST_SEARCH = 128,
+  TMR_SR_SEARCH_FLAG_STATS_REPORT_STREAMING = 256,
+  TMR_SR_SEARCH_FLAG_GPI_TRIGGER_READ = 512,
+  TMR_SR_SEARCH_FLAG_DUTY_CYCLE_CONTROL = 1024,
+}TMR_SR_SearchFlag;
+
+typedef enum TMR_SR_ISO180006BCommands
+{
+  TMR_SR_ISO180006B_COMMAND_DATA_READ           = 0x0B,
+  TMR_SR_ISO180006B_COMMAND_READ                = 0x0C,
+  TMR_SR_ISO180006B_COMMAND_WRITE               = 0x0D,
+  TMR_SR_ISO180006B_COMMAND_WRITE_MULTIPLE      = 0x0E,
+  TMR_SR_ISO180006B_COMMAND_WRITE4BYTE          = 0x1B,
+  TMR_SR_ISO180006B_COMMAND_WRITE4BYTE_MULTIPLE = 0x1C,
+} TMR_SR_ISO180006BCommands;
+
+typedef enum TMR_SR_ISO180006BCommandOptions
+{
+  TMR_SR_ISO180006B_WRITE_OPTION_READ_AFTER           = 0x00,
+  TMR_SR_ISO180006B_WRITE_OPTION_NO_VERIFY            = 0x01,
+  TMR_SR_ISO180006B_WRITE_OPTION_READ_VERIFY_AFTER    = 0x02,
+  TMR_SR_ISO180006B_WRITE_OPTION_GROUP_SELECT         = 0x03,
+  TMR_SR_ISO180006B_WRITE_OPTION_COUNT_PROVIDED       = 0x08,
+  TMR_SR_ISO180006B_WRITE_LOCK_NO                     = 0x00,
+  TMR_SR_ISO180006B_WRITE_LOCK_YES                    = 0x01,
+  TMR_SR_ISO180006B_LOCK_OPTION_TYPE_FOLLOWS          = 0x01,
+  TMR_SR_ISO180006B_LOCK_TYPE_QUERYLOCK_THEN_LOCK     = 0x01,
+} TMR_SR_ISO180006BCommandOptions;
+
+TMR_Status TMR_SR_cmdRaw(TMR_Reader *reader, uint32_t timeout, uint8_t msgLen,
+            uint8_t msg[]);
+TMR_Status TMR_SR_setSerialBaudRate(TMR_Reader *reader, uint32_t rate);
+TMR_Status TMR_SR_cmdVersion(TMR_Reader *reader, TMR_SR_VersionInfo *info);
+TMR_Status TMR_SR_cmdBootFirmware(TMR_Reader *reader);
+TMR_Status TMR_SR_cmdSetBaudRate(TMR_Reader *reader, uint32_t rate);
+TMR_Status TMR_SR_cmdVerifyImage(TMR_Reader *reader, bool *status);
+TMR_Status TMR_SR_cmdEraseFlash(TMR_Reader *reader, uint8_t sector, 
+            uint32_t password);
+TMR_Status TMR_SR_cmdWriteFlashSector(TMR_Reader *reader, uint8_t sector, 
+            uint32_t address, uint32_t password, uint8_t length,
+            const uint8_t data[], uint32_t offset);
+TMR_Status TMR_SR_cmdGetSectorSize(TMR_Reader *reader, uint8_t sector,
+            uint32_t *size);
+TMR_Status TMR_SR_cmdModifyFlashSector(TMR_Reader *reader, uint8_t sector, 
+            uint32_t address, uint32_t password, uint8_t length,
+            const uint8_t data[], uint32_t offset);
+TMR_Status TMR_SR_cmdBootBootloader(TMR_Reader *reader);
+TMR_Status TMR_SR_cmdGetHardwareVersion(TMR_Reader *reader, uint8_t option,
+            uint8_t flags, uint8_t* count, uint8_t data[]);
+TMR_Status TMR_SR_cmdGetCurrentProgram(TMR_Reader *reader, uint8_t *program);
+TMR_Status TMR_SR_cmdReadTagSingle(TMR_Reader *reader, uint16_t timeout, 
+            uint16_t metadataFlags, const TMR_TagFilter *filter, 
+            TMR_TagProtocol protocol, TMR_TagReadData *tagData);
+TMR_Status TMR_SR_cmdReadTagMultiple(TMR_Reader *reader, uint16_t timeout,
+            TMR_SR_SearchFlag flags, const TMR_TagFilter *filter,
+            TMR_TagProtocol protocol, uint32_t *tagCount);
+TMR_Status TMR_SR_cmdWriteGen2TagEpc(TMR_Reader *reader, const TMR_TagFilter *filter, TMR_GEN2_Password accessPassword,
+			uint16_t timeout, uint8_t count, const uint8_t *id, bool lock);
+TMR_Status TMR_SR_cmdGEN2WriteTagData(TMR_Reader *reader,
+            uint16_t timeout, TMR_GEN2_Bank bank, uint32_t address,
+            uint8_t count, const uint8_t data[],
+            TMR_GEN2_Password accessPassword, const TMR_TagFilter *filter);
+TMR_Status TMR_SR_cmdGEN2LockTag(TMR_Reader *reader, uint16_t timeout, 
+            uint16_t mask, uint16_t action, TMR_GEN2_Password accessPassword, 
+            const TMR_TagFilter *filter);
+TMR_Status TMR_SR_cmdKillTag(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password killPassword, const TMR_TagFilter *filter);
+TMR_Status TMR_SR_cmdGEN2ReadTagData(TMR_Reader *reader,
+            uint16_t timeout, TMR_GEN2_Bank bank,
+            uint32_t address, uint8_t length, uint32_t accessPassword,
+            const TMR_TagFilter *filter, TMR_TagReadData *data);
+TMR_Status TMR_SR_cmdGetTagsRemaining(TMR_Reader *reader, uint16_t *remaining);
+TMR_Status TMR_SR_cmdGetTagBuffer(TMR_Reader *reader, uint16_t count, bool epc496,
+            TMR_TagProtocol protocol, TMR_TagData tagData[]);
+TMR_Status TMR_SR_cmdClearTagBuffer(TMR_Reader *reader);
+TMR_Status TMR_SR_cmdHiggs2PartialLoadImage(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword, 
+            uint8_t len, const uint8_t epc[], TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdHiggs2FullLoadImage(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword,
+            uint16_t lockBits, uint16_t pcWord, uint8_t count,
+            const uint8_t epc[], TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdHiggs3FastLoadImage(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password currentAccessPassword, 
+            TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword,
+            uint16_t pcWord, uint8_t count, const uint8_t epc[], TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdHiggs3LoadImage(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password currentAccessPassword,
+            TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword,
+            uint16_t pcWord, uint8_t len, const uint8_t epcAndUserData[], TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdHiggs3BlockReadLock(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password accessPassword, uint8_t lockBits, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdNxpSetReadProtect(TMR_Reader *reader, uint16_t timeout,
+            TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdNxpResetReadProtect(TMR_Reader *reader, uint16_t timeout,
+            TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdNxpChangeEas(TMR_Reader *reader, uint16_t timeout,
+            TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, bool reset, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdNxpEasAlarm(TMR_Reader *reader, uint16_t timeout,
+            TMR_SR_GEN2_SiliconType chip, TMR_GEN2_DivideRatio dr, TMR_GEN2_TagEncoding m, TMR_GEN2_TrExt trExt,
+            TMR_uint8List *data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdNxpCalibrate(TMR_Reader *reader, uint16_t timeout,
+            TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, TMR_uint8List *data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdNxpChangeConfig(TMR_Reader *reader, uint16_t timeout,
+            TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, TMR_NXP_ConfigWord configWord, TMR_uint8List *data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdGen2v2NXPUntraceable(TMR_Reader *reader, uint16_t timeout,TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, uint16_t configWord,
+			TMR_TagOp_GEN2_NXP_Untraceable op,TMR_uint8List *data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdGen2v2NXPAuthenticate(TMR_Reader *reader, uint16_t timeout,TMR_SR_GEN2_SiliconType chip,
+	         TMR_GEN2_Password accessPassword, TMR_TagOp_GEN2_NXP_Authenticate op, TMR_uint8List *data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdGen2v2NXPReadBuffer(TMR_Reader *reader, uint16_t timeout,TMR_SR_GEN2_SiliconType chip,
+					TMR_GEN2_Password accessPassword, TMR_TagOp_GEN2_NXP_Readbuffer op, TMR_uint8List *data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdMonza4QTReadWrite(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+            TMR_Monza4_ControlByte controlByte, TMR_Monza4_Payload payload, TMR_uint8List *data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aGetSensorValue(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+            uint8_t CommandCode, uint32_t password, PasswordLevel level, Sensor sensortype, TMR_uint8List *data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aGetMeasurementSetup(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+            uint8_t CommandCode, uint32_t password, PasswordLevel level,TMR_uint8List *data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aGetCalibrationData(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+            uint8_t CommandCode, uint32_t password, PasswordLevel level, TMR_uint8List *data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aSetCalibrationData(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+            uint8_t CommandCode, uint32_t password, PasswordLevel level, uint64_t calibration, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aSetSfeParameters(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+            uint8_t CommandCode, uint32_t password, PasswordLevel level, uint16_t sfe, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aGetLogState(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+            uint8_t CommandCode, uint32_t password, PasswordLevel level, TMR_uint8List *data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aSetLogMode(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+           uint8_t CommandCode, uint32_t password, PasswordLevel level, LoggingForm form, StorageRule rule, bool Ext1Enable,
+           bool Ext2Enable, bool TempEnable, bool BattEnable, uint16_t LogInterval, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aSetLogLimit(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+           uint8_t CommandCode, uint32_t password, PasswordLevel level, uint16_t exLower,
+           uint16_t lower, uint16_t upper, uint16_t exUpper, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aSetShelfLife(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                             uint8_t CommandCode, uint32_t password, PasswordLevel level, uint32_t block0, uint32_t block1,
+                             TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aInitialize(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                      uint8_t CommandCode, uint32_t password, PasswordLevel level, uint16_t delayTime,
+                                      uint16_t applicatioData, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aStartLog(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t CommandCode,
+                                    uint32_t password, PasswordLevel level, uint32_t time, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aEndLog(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+           uint8_t CommandCode, uint32_t password, PasswordLevel level, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aSetPassword(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+           uint8_t CommandCode, uint32_t password, PasswordLevel level, uint32_t newPassword,
+           PasswordLevel newPasswordLevel, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aGetBatteryLevel(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                           uint8_t CommandCode, uint32_t password, PasswordLevel level,BatteryType type,
+                                           TMR_uint8List *data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aAccessFifoStatus(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t CommandCode,
+           uint32_t password, PasswordLevel level, AccessFifoOperation operation, TMR_uint8List * data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aAccessFifoRead(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t CommandCode,
+            uint32_t password, PasswordLevel level, AccessFifoOperation operation, uint8_t length,TMR_uint8List * data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdSL900aAccessFifoWrite(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t CommandCode,
+           uint32_t password, PasswordLevel level, AccessFifoOperation operation, TMR_uint8List *payLoad, TMR_uint8List * data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdHibikiReadLock(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password accessPassword, uint16_t mask, uint16_t action);
+TMR_Status TMR_SR_cmdHibikiGetSystemInformation(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password accessPassword,
+            TMR_GEN2_HibikiSystemInformation *info);
+TMR_Status TMR_SR_cmdHibikiSetAttenuate(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password accessPassword, uint8_t level, bool lock);
+TMR_Status TMR_SR_cmdHibikiBlockLock(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password accessPassword, uint8_t block,
+            TMR_GEN2_Password blockPassword, uint8_t mask, uint8_t action);
+TMR_Status TMR_SR_cmdHibikiBlockReadLock(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password accessPassword, uint8_t block,
+            TMR_GEN2_Password blockPassword, uint8_t mask, uint8_t action);
+TMR_Status TMR_SR_cmdHibikiWriteMultipleWords(TMR_Reader *reader,
+            uint16_t timeout, TMR_GEN2_Password accessPassword,
+            TMR_GEN2_Bank bank, uint32_t wordOffset, uint8_t count,
+            const uint8_t data[]);
+TMR_Status TMR_SR_cmdEraseBlockTagSpecific(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Bank bank, uint32_t address, uint8_t count);
+TMR_Status TMR_SR_cmdGetTxRxPorts(TMR_Reader *reader, TMR_SR_PortPair *ant);
+TMR_Status TMR_SR_cmdGetAntennaConfiguration(TMR_Reader *reader,
+            TMR_SR_AntennaPort *config);
+TMR_Status TMR_SR_cmdGetAntennaSearchList(TMR_Reader *reader, uint8_t *count,
+            TMR_SR_PortPair *ants);
+TMR_Status TMR_SR_cmdGetAntennaPortPowers(TMR_Reader *reader, uint8_t *count,
+            TMR_SR_PortPower *ports);
+TMR_Status TMR_SR_cmdGetAntennaPortPowersAndSettlingTime(TMR_Reader *reader,
+            uint8_t *count, TMR_SR_PortPowerAndSettlingTime *ports);
+TMR_Status TMR_SR_cmdGetAntennaReturnLoss(TMR_Reader *reader, TMR_PortValueList *ports);
+TMR_Status TMR_SR_cmdAntennaDetect(TMR_Reader *reader, uint8_t *count,
+            TMR_SR_PortDetect *ports);
+TMR_Status TMR_SR_cmdGetReadTxPower(TMR_Reader *reader, int32_t *power);
+TMR_Status TMR_SR_cmdGetReadTxPowerWithLimits(TMR_Reader *reader,
+            TMR_SR_PowerWithLimits *power);
+TMR_Status TMR_SR_cmdGetWriteTxPower(TMR_Reader *reader, int32_t *power);
+TMR_Status TMR_SR_cmdGetWriteTxPowerWithLimits(TMR_Reader *reader,
+            TMR_SR_PowerWithLimits *power);
+TMR_Status TMR_SR_cmdGetCurrentProtocol(TMR_Reader *reader,
+            TMR_TagProtocol *protocol);
+TMR_Status TMR_SR_cmdMultipleProtocolSearch(TMR_Reader *reader,TMR_SR_OpCode op,TMR_TagProtocolList *protocols, TMR_TRD_MetadataFlag metadataFlags,TMR_SR_SearchFlag antennas, TMR_TagFilter **filter, uint16_t timeout, uint32_t *tagsFound);
+TMR_Status TMR_SR_cmdGetFrequencyHopTable(TMR_Reader *reader, uint8_t *count,
+            uint32_t *hopTable);
+TMR_Status TMR_SR_cmdGetFrequencyHopTime(TMR_Reader *reader, uint32_t *hopTime);
+TMR_Status TMR_SR_cmdGetGPIO(TMR_Reader *reader, uint8_t *count, TMR_GpioPin *state);
+TMR_Status TMR_SR_cmdGetGPIODirection(TMR_Reader *reader, uint8_t pin,
+            bool *out);
+TMR_Status TMR_SR_cmdGetRegion(TMR_Reader *reader, TMR_Region *region);
+TMR_Status TMR_SR_cmdGetRegionConfiguration(TMR_Reader *reader,
+            TMR_SR_RegionConfiguration key, void *value);
+TMR_Status TMR_SR_cmdGetPowerMode(TMR_Reader *reader, TMR_SR_PowerMode *mode);
+TMR_Status TMR_SR_cmdGetUserMode(TMR_Reader *reader, TMR_SR_UserMode *mode);
+TMR_Status TMR_SR_cmdGetReaderConfiguration(TMR_Reader *reader,
+            TMR_SR_Configuration key, void *value);
+TMR_Status TMR_SR_cmdIAVDenatranCustomOp(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t mode, uint8_t rfu,
+           TMR_uint8List *data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdIAVDenatranCustomActivateSiniavMode(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t mode, uint8_t payload,
+           TMR_uint8List *data, TMR_TagFilter* target, bool tokenDesc, uint8_t *token);
+TMR_Status TMR_SR_cmdIAVDenatranCustomReadFromMemMap(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t mode, uint8_t payload,
+            TMR_uint8List *data, TMR_TagFilter* target, uint16_t wordAddress);
+TMR_Status TMR_SR_cmdIAVDenatranCustomWriteToMemMap(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t mode, uint8_t payload,
+            TMR_uint8List *data, TMR_TagFilter* target, uint16_t wordPtr, uint16_t wordData, uint8_t* tagId, uint8_t* dataBuf);
+TMR_Status TMR_SR_cmdIAVDenatranCustomWriteSec(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t mode, uint8_t payload,
+            TMR_uint8List *data, TMR_TagFilter* target, uint8_t* dataWords, uint8_t* dataBuf);
+TMR_Status TMR_SR_cmdIAVDenatranCustomGetTokenId(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t mode,
+           TMR_uint8List *data, TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdIAVDenatranCustomReadSec(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t mode, uint8_t payload,
+            TMR_uint8List *data, TMR_TagFilter* target, uint16_t wordAddress);
+TMR_Status TMR_SR_cmdGetProtocolConfiguration(TMR_Reader *reader, TMR_TagProtocol protocol,
+            TMR_SR_ProtocolConfiguration key, void *value);
+TMR_Status TMR_SR_cmdGetReaderStats(TMR_Reader *reader,
+           TMR_Reader_StatsFlag statFlags,
+           TMR_Reader_StatsValues *stats);
+TMR_Status TMR_SR_cmdGetReaderStatistics(TMR_Reader *reader,
+            TMR_SR_ReaderStatisticsFlag statFlags,
+            TMR_SR_ReaderStatistics *stats);
+TMR_Status TMR_SR_cmdGetAvailableProtocols(TMR_Reader *reader,
+            TMR_TagProtocolList *protocols);
+TMR_Status TMR_SR_cmdGetAvailableRegions(TMR_Reader *reader,
+            TMR_RegionList *regions);
+TMR_Status TMR_SR_cmdGetTemperature(TMR_Reader *reader, int8_t *temp);
+TMR_Status TMR_SR_cmdSetTxRxPorts(TMR_Reader *reader, uint8_t txPrt,
+            uint8_t rxPort);
+TMR_Status TMR_SR_cmdSetAntennaSearchList(TMR_Reader *reader,
+            uint8_t count, const TMR_SR_PortPair *ports);
+TMR_Status TMR_SR_cmdSetAntennaPortPowers(TMR_Reader *reader,
+            uint8_t count, const TMR_SR_PortPower *ports);
+TMR_Status TMR_SR_cmdSetAntennaPortPowersAndSettlingTime(TMR_Reader *reader,
+            uint8_t count, const TMR_SR_PortPowerAndSettlingTime *ports);
+TMR_Status TMR_SR_cmdSetReadTxPower(TMR_Reader *reader, int32_t power);
+TMR_Status TMR_SR_cmdSetWriteTxPower(TMR_Reader *reader, int32_t power);
+TMR_Status TMR_SR_cmdSetProtocol(TMR_Reader *reader, TMR_TagProtocol protocol);
+TMR_Status TMR_SR_cmdSetFrequencyHopTable(TMR_Reader *reader, uint8_t count,
+            const uint32_t *table);
+TMR_Status TMR_SR_cmdSetFrequencyHopTime(TMR_Reader *reader, uint32_t hopTime);
+TMR_Status TMR_SR_cmdSetGPIO(TMR_Reader *reader, uint8_t gpio, bool high);
+TMR_Status TMR_SR_cmdSetGPIODirection(TMR_Reader *reader, uint8_t pin,
+            bool out);
+TMR_Status TMR_SR_cmdSetRegion(TMR_Reader *reader, TMR_Region region);
+TMR_Status TMR_SR_cmdSetRegionLbt(TMR_Reader *reader, TMR_Region region, bool lbt);
+TMR_Status TMR_SR_cmdSetPowerMode(TMR_Reader *reader, TMR_SR_PowerMode mode);
+TMR_Status TMR_SR_cmdSetUserMode(TMR_Reader *reader, TMR_SR_UserMode mode);
+TMR_Status TMR_SR_cmdSetReaderConfiguration(TMR_Reader *reader, 
+            TMR_SR_Configuration key, const void *value);
+TMR_Status TMR_SR_cmdSetProtocolLicenseKey(TMR_Reader *reader, TMR_SR_SetProtocolLicenseOption option, uint8_t key[], int key_len,uint32_t *retData);
+TMR_Status TMR_SR_cmdSetProtocolConfiguration(TMR_Reader *reader,
+            TMR_TagProtocol protocol, TMR_SR_ProtocolConfiguration key,
+            const void *value);
+TMR_Status TMR_SR_cmdResetReaderStats(TMR_Reader *reader,
+           TMR_Reader_StatsFlag statFlags);
+TMR_Status TMR_SR_cmdResetReaderStatistics(TMR_Reader *reader,
+            TMR_SR_ReaderStatisticsFlag statFlags);
+TMR_Status TMR_SR_cmdTestSetFrequency(TMR_Reader *reader, uint32_t frequency);
+TMR_Status TMR_SR_cmdTestSendCw(TMR_Reader *reader, bool on);
+TMR_Status TMR_SR_cmdTestSendPrbs(TMR_Reader *reader, uint16_t duration);
+TMR_Status TMR_SR_cmdSetUserProfile(TMR_Reader *reader,
+                                    TMR_SR_UserConfigOperation op,TMR_SR_UserConfigCategory category, TMR_SR_UserConfigType type);
+TMR_Status TMR_SR_cmdGetUserProfile(TMR_Reader *reader, 
+                                    uint8_t byte[], uint8_t length, uint8_t response[], uint8_t* response_length);
+TMR_Status TMR_SR_cmdBlockWrite(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Bank bank, uint32_t wordPtr, 
+                                 uint32_t wordCount, const uint16_t* data, uint32_t accessPassword, const TMR_TagFilter* target);
+TMR_Status TMR_SR_cmdBlockErase(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Bank bank, uint32_t wordPtr,
+                                 uint8_t wordCount, uint32_t accessPassword, TMR_TagFilter *target);
+TMR_Status TMR_SR_cmdBlockPermaLock(TMR_Reader *reader, uint16_t timeout,uint32_t readLock, TMR_GEN2_Bank bank, 
+                         uint32_t blockPtr, uint32_t blockRange, uint16_t* mask, uint32_t accessPassword, TMR_TagFilter* target, TMR_uint8List *data);
+TMR_Status TMR_SR_msgSetupReadTagMultiple(TMR_Reader *reader, uint8_t *msg, uint8_t *i,
+            uint16_t timeout, TMR_SR_SearchFlag searchFlag,
+            const TMR_TagFilter *filter, TMR_TagProtocol protocol,
+            TMR_GEN2_Password accessPassword);
+
+TMR_Status
+TMR_SR_msgSetupReadTagMultipleWithMetadata(TMR_Reader *reader, uint8_t *msg, uint8_t *i, uint16_t timeout,
+                               TMR_SR_SearchFlag searchFlag,
+							                 TMR_TRD_MetadataFlag metadataFlag,
+                               const TMR_TagFilter *filter,
+                               TMR_TagProtocol protocol,
+                               TMR_GEN2_Password accessPassword);
+
+TMR_Status TMR_SR_msgSetupReadTagSingle(uint8_t *msg, uint8_t *i, TMR_TagProtocol protocol,TMR_TRD_MetadataFlag metadataFlags, const TMR_TagFilter *filter,uint16_t timeout);
+void TMR_SR_msgAddGEN2WriteTagEPC(uint8_t *msg, uint8_t *i, uint16_t timeout, uint8_t *epc, uint8_t count);
+void TMR_SR_msgAddGEN2DataRead(uint8_t *msg, uint8_t *i, uint16_t timeout,
+      TMR_GEN2_Bank bank, uint32_t wordAddress, uint8_t len, uint8_t option, bool withMetaData);
+void TMR_SR_msgAddGEN2DataWrite(uint8_t *msg, uint8_t *i, uint16_t timeout,
+      TMR_GEN2_Bank bank, uint32_t address);
+void TMR_SR_msgAddGEN2LockTag(uint8_t *msg, uint8_t *i, uint16_t timeout,
+      uint16_t mask, uint16_t action, TMR_GEN2_Password password);
+void TMR_SR_msgAddGEN2KillTag(uint8_t *msg, uint8_t *i, uint16_t timeout,
+      TMR_GEN2_Password password);
+void
+TMR_SR_msgAddGEN2BlockWrite(uint8_t *msg, uint8_t *i, uint16_t timeout,TMR_GEN2_Bank bank, uint32_t wordPtr, uint32_t wordCount, uint16_t* data, uint32_t accessPassword,TMR_TagFilter* target);
+
+void
+TMR_SR_msgAddGEN2BlockPermaLock(uint8_t *msg, uint8_t *i, uint16_t timeout, uint32_t readLock, TMR_GEN2_Bank bank, uint32_t blockPtr, uint32_t blockRange, uint16_t* mask, uint32_t accessPassword,TMR_TagFilter* target);
+
+void
+TMR_SR_msgAddGEN2BlockErase(uint8_t *msg, uint8_t *i, uint16_t timeout, uint32_t wordPtr, TMR_GEN2_Bank bank,
+                            uint8_t wordCount, uint32_t accessPassword, TMR_TagFilter* target);
+
+void 
+TMR_SR_msgAddHiggs2PartialLoadImage(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword, 
+                                    TMR_GEN2_Password killPassword, uint8_t len, const uint8_t *epc, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddHiggs2FullLoadImage(uint8_t *msg, uint8_t *i, uint16_t timeout,
+      TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword, uint16_t lockBits, uint16_t pcWord, uint8_t len, const uint8_t *epc, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddHiggs3FastLoadImage(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password currentAccessPassword,
+      TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword, uint16_t pcWord, uint8_t len, const uint8_t *epc, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddHiggs3LoadImage(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password currentAccessPassword,
+      TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword, uint16_t pcWord, uint8_t len, const uint8_t *epcAndUserData, TMR_TagFilter* target);
+
+void 
+TMR_SR_msgAddHiggs3BlockReadLock(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t lockBits, TMR_TagFilter* target);
+
+void 
+TMR_SR_msgAddNXPSetReadProtect(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_SR_GEN2_SiliconType chip,
+                            TMR_GEN2_Password accessPassword, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddNXPResetReadProtect(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_SR_GEN2_SiliconType chip,
+                            TMR_GEN2_Password accessPassword, TMR_TagFilter* target);
+void
+TMR_SR_msgAddNXPChangeEAS(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_SR_GEN2_SiliconType chip,
+                          TMR_GEN2_Password accessPassword, bool reset, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddNXPEASAlarm(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_SR_GEN2_SiliconType chip,
+                         TMR_GEN2_DivideRatio dr, TMR_GEN2_TagEncoding m, TMR_GEN2_TrExt trExt, TMR_TagFilter* target);
+void
+TMR_SR_msgAddIAVDenatranCustomOp(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                         uint8_t mode, uint8_t rfu, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddIAVDenatranCustomActivateSiniavMode(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                         uint8_t mode, uint8_t payload, TMR_TagFilter* target, bool tokenDesc, uint8_t *token);
+void 
+TMR_SR_msgAddIAVDenatranCustomReadFromMemMap(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                        uint8_t mode, uint8_t payload, TMR_TagFilter* target, uint16_t wordAddress);
+void 
+TMR_SR_msgAddIAVDenatranCustomWriteToMemMap(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                        uint8_t mode, uint8_t payload, TMR_TagFilter* target, uint16_t wordPtr, uint16_t wordData, uint8_t* tagId, uint8_t* dataBuf);
+void
+TMR_SR_msgAddIAVDenatranCustomWriteSec(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                        uint8_t mode, uint8_t payload, TMR_TagFilter* target, uint8_t* data, uint8_t* dataBuf);
+void 
+TMR_SR_msgAddIAVDenatranCustomGetTokenId(uint8_t *msg, uint8_t *i, uint16_t timeout,
+                        TMR_GEN2_Password accessPassword, uint8_t mode, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddIAVDenatranCustomReadSec(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                        uint8_t mode, uint8_t payload, TMR_TagFilter* target, uint16_t wordAddress);
+void 
+TMR_SR_msgAddNXPCalibrate(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_SR_GEN2_SiliconType chip,
+                         TMR_GEN2_Password accessPassword, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddNXPChangeConfig(uint8_t *msg, uint8_t *i, uint16_t timeout,
+                         TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, TMR_NXP_ConfigWord configword, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddMonza4QTReadWrite(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                               TMR_Monza4_ControlByte controlByte, TMR_Monza4_Payload payload, TMR_TagFilter* target);
+
+void 
+TMR_SR_msgAddIdsSL900aGetSensorValue(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                     uint8_t CommandCode, uint32_t password, PasswordLevel level, Sensor sensortype,
+                                     TMR_TagFilter* target);
+void 
+TMR_SR_msgAddIdsSL900aGetMeasurementSetup(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                          uint8_t CommandCode, uint32_t password, PasswordLevel level, TMR_TagFilter* target);
+
+void 
+TMR_SR_msgAddIdsSL900aGetCalibrationData(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                     uint8_t CommandCode, uint32_t password, PasswordLevel level, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddIdsSL900aSetCalibrationData(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                          uint8_t CommandCode, uint32_t password, PasswordLevel level, uint64_t calibration, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddIdsSL900aSetSfeParameters(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                          uint8_t CommandCode, uint32_t password, PasswordLevel level, uint16_t sfe,
+                                          TMR_TagFilter* target);
+void 
+TMR_SR_msgAddIdsSL900aGetLogState(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, TMR_TagFilter* target);
+void
+TMR_SR_msgAddIdsSL900aSetLogMode(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                 uint8_t CommandCode, uint32_t password, PasswordLevel level, LoggingForm form,
+                                 StorageRule rule, bool Ext1Enable, bool Ext2Enable, bool TempEnable, bool BattEnable,
+                                 uint16_t LogInterval, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddIdsSL900aSetLogLimit(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, uint16_t exLower,
+                                  uint16_t lower, uint16_t upper, uint16_t exUpper, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddIdsSL900aSetShelfLife(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                   uint8_t CommandCode, uint32_t password, PasswordLevel level, uint32_t block0, uint32_t block1,
+                                   TMR_TagFilter* target);
+void
+TMR_SR_msgAddIdsSL900aInitialize(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                 uint8_t CommandCode, uint32_t password, PasswordLevel level, uint16_t delayTime,
+                                 uint16_t applicatioData, TMR_TagFilter* target);
+void
+TMR_SR_msgAddIdsSL900aEndLog(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                             uint8_t CommandCode, uint32_t password, PasswordLevel level, TMR_TagFilter* target);
+void
+TMR_SR_msgAddIdsSL900aSetPassword(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, uint32_t newPassword,
+                                  PasswordLevel newPasswordLevel, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddIdsSL900aAccessFifoStatus(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, AccessFifoOperation operation,
+                                  TMR_TagFilter* target);
+void 
+TMR_SR_msgAddIdsSL900aGetBatteryLevel(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                      uint8_t CommandCode, uint32_t password, PasswordLevel level, BatteryType batteryType,
+                                      TMR_TagFilter* target);
+void 
+TMR_SR_msgAddIdsSL900aAccessFifoRead(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, AccessFifoOperation operation,
+                                  uint8_t length, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddIdsSL900aAccessFifoWrite(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, AccessFifoOperation operation,
+                                  TMR_uint8List *payLoad, TMR_TagFilter* target);
+void 
+TMR_SR_msgAddIdsSL900aStartLog(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                               uint8_t CommandCode, uint32_t password, PasswordLevel level, uint32_t time, TMR_TagFilter* target);
+
+TMR_Status TMR_SR_executeEmbeddedRead(TMR_Reader *reader, uint8_t *msg,
+            uint16_t timeout, TMR_SR_MultipleStatus *status);
+
+TMR_Status TMR_SR_cmdISO180006BWriteTagData(TMR_Reader *reader,
+      uint16_t timeout, uint8_t address, uint8_t count, const uint8_t data[],
+      const TMR_TagFilter *filter);
+TMR_Status TMR_SR_cmdISO180006BReadTagData(TMR_Reader *reader,
+      uint16_t timeout, uint8_t address, uint8_t length,
+      const TMR_TagFilter *filter, TMR_TagReadData *read);
+TMR_Status TMR_SR_cmdISO180006BLockTag(TMR_Reader *reader, uint16_t timeout,
+      uint8_t address, const TMR_TagFilter *filter);
+TMR_Status TMR_iso18000BBLFValToInt(int val, void *lf);
+TMR_Status TMR_SR_cmdStopReading(struct TMR_Reader *reader);
+TMR_Status TMR_SR_cmdGetReaderWriteTimeOut (struct TMR_Reader *reader, TMR_TagProtocol protocol,
+																						TMR_SR_Gen2ReaderWriteTimeOut *value);
+TMR_Status TMR_SR_cmdSetReaderWriteTimeOut (struct TMR_Reader *reader, TMR_TagProtocol protocol,
+																						TMR_SR_Gen2ReaderWriteTimeOut *value);
+TMR_Status TMR_SR_cmdAuthReqResponse(struct TMR_Reader *reader, TMR_TagAuthentication *auth);
+
+TMR_Status TMR_SR_addTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop,TMR_ReadPlan *rp, uint8_t *msg, uint8_t *i, uint32_t readTimeMs, uint8_t *lenbyte);
+
+TMR_Status
+TMR_fillReaderStats(TMR_Reader *reader, TMR_Reader_StatsValues* stats, uint16_t flag, uint8_t* msg, uint8_t offset);
+bool compareAntennas(TMR_MultiReadPlan *multi);
+bool compareVersion(TMR_Reader *reader, uint8_t firstByte, uint8_t secondByte, uint8_t thirdByte, uint8_t fourthByte);
+TMR_Status
+TMR_SR_cmdrebootReader(TMR_Reader *reader);
+TMR_Status
+prepForSearch(TMR_Reader *reader, TMR_uint8List *antennaList);
+TMR_Status 
+TMR_SR_msgSetupMultipleProtocolSearch(TMR_Reader *reader, uint8_t *msg, TMR_SR_OpCode op, TMR_TagProtocolList *protocols, TMR_TRD_MetadataFlag metadataFlags, TMR_SR_SearchFlag antennas, TMR_TagFilter **filter, uint16_t timeout);
+TMR_Status TMR_SR_cmdProbeBaudRate(TMR_Reader *reader, uint32_t *currentBaudRate);
+void TMR_SR_updateBaseTimeStamp(TMR_Reader *reader);
+TMR_Status verifySearchStatus(TMR_Reader *reader);
+
+
+#ifdef TMR_ENABLE_BACKGROUND_READS
+void notify_authreq_listeners(TMR_Reader *reader, TMR_TagReadData *trd, TMR_TagAuthentication *auth);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SERIAL_READER_IMP_H */
diff --git a/cbits/api/serial_reader_l3.c b/cbits/api/serial_reader_l3.c
new file mode 100644
--- /dev/null
+++ b/cbits/api/serial_reader_l3.c
@@ -0,0 +1,7295 @@
+/**
+ *  @file serial_reader_l3.c
+ *  @brief Mercury API - serial reader low level implementation
+ *  @author Nathan Williams
+ *  @date 11/2/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.
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tm_reader.h"
+#include "serial_reader_imp.h"
+#include "tmr_utils.h"
+
+#ifndef BARE_METAL
+bool isSecureAccessEnabled;
+#endif
+
+void
+notify_read_listeners(TMR_Reader *reader, TMR_TagReadData *trd);
+#ifdef TMR_ENABLE_SERIAL_READER
+
+static TMR_Status filterbytes(TMR_TagProtocol protocol,
+                              const TMR_TagFilter *filter, 
+                              uint8_t *option, uint8_t *i, uint8_t *msg,
+                              uint32_t accessPassword, bool usePassword);
+TMR_Status
+TMR_SR_sendBytes(TMR_Reader *reader, uint8_t len, uint8_t *data, uint32_t timeoutMs);
+
+/*
+ * ThingMagic-mutated CRC used for messages.
+ * Notably, not a CCITT CRC-16, though it looks close.
+ */
+static uint16_t crctable[] = 
+{
+  0x0000, 0x1021, 0x2042, 0x3063,
+  0x4084, 0x50a5, 0x60c6, 0x70e7,
+  0x8108, 0x9129, 0xa14a, 0xb16b,
+  0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+};
+
+static uint16_t
+tm_crc(uint8_t *u8Buf, uint8_t len)
+{
+  uint16_t crc;
+  int i;
+
+  crc = 0xffff;
+
+  for (i = 0; i < len ; i++)
+  {
+    crc = ((crc << 4) | (u8Buf[i] >> 4))  ^ crctable[crc >> 12];
+    crc = ((crc << 4) | (u8Buf[i] & 0xf)) ^ crctable[crc >> 12];
+  }
+
+  return crc;
+}
+
+
+/**
+ * Send a byte string
+ *
+ * @param reader The reader
+ * @param[in] len Number of bytes to send
+ * @param[in] data Bytes to send, with length in byte 1. Byte 0 is reserved for the SOF character, and two characters at the end are reserved for the CRC.
+ * @param timeoutMs Timeout value.
+ */
+TMR_Status
+TMR_SR_sendBytes(TMR_Reader *reader, uint8_t len, uint8_t *data, uint32_t timeoutMs)
+{
+  TMR_SR_SerialTransport *transport;
+  TMR_Status ret;
+
+  transport = &reader->u.serialReader.transport;
+
+  if (NULL != reader->transportListeners)
+  {
+    TMR__notifyTransportListeners(reader, true, len, data, timeoutMs);
+  }
+
+  ret = transport->sendBytes(transport, len, data, timeoutMs);
+  return ret;
+}
+
+/**
+ * Send a message to the reader
+ *
+ * @param reader The reader
+ * @param[in] data Message to send, with length in byte 1. Byte 0 is reserved for the SOF character, and two characters at the end are reserved for the CRC.
+ * @param[out] opcode Opcode sent with message (pass this value to receiveMessage to match against response)
+ * @param timeoutMs Timeout value.
+ */
+TMR_Status
+TMR_SR_sendMessage(TMR_Reader *reader, uint8_t *data, uint8_t *opcode, uint32_t timeoutMs)
+{
+  TMR_SR_SerialReader *sr;
+  TMR_Status ret;
+  uint16_t crc;
+  uint8_t len;
+  uint8_t j;
+  //uint8_t byteLen;
+
+  sr = &reader->u.serialReader;
+  timeoutMs += sr->transportTimeout;
+/*  if (reader->u.serialReader.crcEnabled)
+  {
+    byteLen = 5;
+  }
+  else
+  {
+    byteLen = 3;
+  }*/
+
+  /* Wake up processor from deep sleep.  Tickle the RS-232 line, then
+   * wait a fixed delay while the processor spins up communications again. */
+  if (sr->supportsPreamble && ((sr->powerMode == TMR_SR_POWER_MODE_INVALID) ||
+                              (sr->powerMode == TMR_SR_POWER_MODE_SLEEP)) )
+  {
+    uint8_t flushBytes[] = {
+      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
+    };
+
+    TMR_SR_sendBytes(reader, sizeof(flushBytes)/sizeof(uint8_t), flushBytes, timeoutMs);
+    {
+      uint32_t bytesper100ms;
+      uint32_t bytesSent;
+
+      /* Calculate fixed delay in terms of byte-lengths at current speed */
+      /* @todo Optimize delay length.  This value (100 bytes at 9600bps) is taken
+       * directly from arbser, which was itself using a hastily-chosen value. */
+      bytesper100ms = sr->baudRate / 50;
+      for (bytesSent=0; bytesSent<bytesper100ms;
+         bytesSent += (sizeof(flushBytes)/sizeof(uint8_t)))
+      {
+        TMR_SR_sendBytes(reader, sizeof(flushBytes)/sizeof(uint8_t), flushBytes, timeoutMs);
+      }
+    }
+  }    
+
+  /* Layout of message in data array: 
+   * [0] [1] [2] [3] [4]  ... [LEN+2] [LEN+3] [LEN+4]
+   * FF  LEN OP  xx  xx   ... xx      CRCHI   CRCLO
+   */
+  data[0] = 0xff;
+  len = data[1];
+  *opcode = data[2];
+
+  if (isContinuousReadParamSupported(reader))
+  {
+	  for (j = 0; j <= len; j++)
+	  {
+		  reader->paramMessage[j] = data[2 + j];
+	  }
+	  data[1] = 5 + len;
+	  data[2] = 0x2f;
+	  data[3] = 0x00;
+	  data[4] = 0x00;
+	  data[5] = 0x04;
+	  data[6] = len;
+	  for (j = 0; j <= len ; j++)
+	  {
+		  data[7 + j] = reader->paramMessage[j];
+	  }
+	  len = data[1];
+	  reader->paramWait = true;
+  }
+
+ // if (reader->u.serialReader.crcEnabled)
+  {
+  crc = tm_crc(&data[1], len + 2);
+  data[len + 3] = crc >> 8;
+  data[len + 4] = crc & 0xff;
+  }
+  
+  ret = TMR_SR_sendBytes(reader, len+5, data, timeoutMs);
+  return ret;
+}
+
+
+bool
+isContinuousReadParamSupported(TMR_Reader *reader)
+{
+	uint16_t i; 
+	uint8_t *readerVersion = reader->u.serialReader.versionInfo.fwVersion ;
+	uint8_t checkVersion[4];
+
+	if (reader->hasContinuousReadStarted == false || reader->continuousReading == false)
+		return false;
+
+	switch (reader->u.serialReader.versionInfo.hardware[0])
+	{
+		case TMR_SR_MODEL_M6E:
+		case TMR_SR_MODEL_M6E_I:
+			checkVersion[0] = 0x01; checkVersion[1] = 0x21; checkVersion[2] = 0x01; checkVersion[3] = 0x19;
+			break;
+		case TMR_SR_MODEL_MICRO:
+			checkVersion[0] = 0x01; checkVersion[1] = 0x09; checkVersion[2] = 0x00; checkVersion[3] = 0x14;
+			break;
+		case TMR_SR_MODEL_M6E_NANO:
+			checkVersion[0] = 0x01; checkVersion[1] = 0x07; checkVersion[2] = 0x00; checkVersion[3] = 0x0E;
+			break;
+		default:
+			checkVersion[0] = 0xFF; checkVersion[1] = 0xFF; checkVersion[2] = 0xFF; checkVersion[3] = 0xFF;
+	}
+	for (i = 0; i < 4; i++)
+	{
+		if (readerVersion[i] < checkVersion[i])
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+/**
+ * Receive a response.
+ *
+ * @param reader The reader
+ * @param[in] data Message to send, with length in byte 1. Byte 0 is reserved for the SOF character, and two characters at the end are reserved for the CRC.
+ * @param[out] data Message received.
+ * @param opcode Opcode that was sent with message that elicited this response, to be matched against incoming response opcode.
+ * @param timeoutMs Timeout value.
+ */
+TMR_Status
+TMR_SR_receiveMessage(TMR_Reader *reader, uint8_t *data, uint8_t opcode, uint32_t timeoutMs)
+{
+  TMR_Status ret;
+  uint16_t crc, status;
+  uint8_t len,headerOffset;
+  uint8_t receiveBytesLen;
+  uint32_t inlen;
+  int i;
+  TMR_SR_SerialTransport *transport;
+  uint8_t retryCount = 0;
+
+  transport = &reader->u.serialReader.transport;
+  timeoutMs += reader->u.serialReader.transportTimeout;
+
+  /**
+   * Initialize the receive bytes length based on
+   * sr->expectCRC option
+   **/
+  if (reader->u.serialReader.crcEnabled)
+  {
+    receiveBytesLen = 7;
+  }
+  else
+  {
+    receiveBytesLen = 5;
+  }
+
+  headerOffset = 0;
+retryHeader:
+  inlen = 0;
+  retryCount++;
+  ret = transport->receiveBytes(transport, receiveBytesLen - headerOffset, &inlen, data + headerOffset, timeoutMs);
+  if (TMR_SUCCESS != ret)
+  {
+    /* @todo Figure out how many bytes were actually obtained in a failed receive */
+    TMR__notifyTransportListeners(reader, false, inlen, data, timeoutMs);
+    return ret;
+  }
+
+  if (data[0] != (uint8_t)0xFF)
+  {
+    for (i = 1; i < receiveBytesLen; i++) 
+    {
+      if (data[i] == 0xFF)
+      {
+        /* An SOH has been found, so we won't enter the "NO SOH" section of code again */
+        headerOffset = receiveBytesLen - i;
+        memmove(data, data + i, headerOffset);
+        goto retryHeader;
+      }
+    }
+    if (retryCount < 20)
+    {
+      /* Retry to get SOH */
+      goto retryHeader;
+    }
+    return TMR_ERROR_TIMEOUT;
+  }
+
+  /* After this point, we have the the bare minimum (5 or 7)  of bytes in the buffer */
+
+  /* Layout of response in data array: 
+   * [0] [1] [2] [3]      [4]      [5] [6]  ... [LEN+4] [LEN+5] [LEN+6]
+   * FF  LEN OP  STATUSHI STATUSLO xx  xx   ... xx      CRCHI   CRCLO
+   */
+  len = data[1];
+
+  if (0 == len)
+  {
+    inlen = 0;
+  }
+  else if ((TMR_SR_MAX_PACKET_SIZE - receiveBytesLen) < len)
+  {
+    /**
+     * packet data size is overflowing the buffer size. This could be a
+     * corrupted packet. Discard it and move on. Return back with TMR_ERROR_TOO_BIG
+     * error.
+     **/
+    return TMR_ERROR_TOO_BIG;
+  }
+  else
+  {
+    ret = transport->receiveBytes(transport, len, &inlen, data + receiveBytesLen, timeoutMs);
+  }
+
+  if (NULL != reader->transportListeners)
+  {
+    TMR__notifyTransportListeners(reader, false, inlen + receiveBytesLen, data, timeoutMs);
+  }
+
+  if (TMR_SUCCESS != ret)
+  {
+    /* before we can actually process the message, we have to properly receive the message */
+    return ret;
+  }
+
+  /**
+   * Calculate the CRC only if expectCRC option
+   * is enabled
+   **/
+  if (reader->u.serialReader.crcEnabled)
+  {
+  crc = tm_crc(&data[1], len + 4);
+  if ((data[len + 5] != (crc >> 8)) ||
+      (data[len + 6] != (crc & 0xff)))
+  {
+    return TMR_ERROR_CRC_ERROR;
+  }
+  }
+
+  if ((data[2] != opcode) && ((data[2] != 0x2F) || (!reader->continuousReading)))
+  {
+    if(data[2] == 0x9D)
+     {
+       return TMR_ERROR_AUTOREAD_ENABLED;
+     }
+
+    /* We got a response for a different command than the one we
+     * sent. This usually means we received the boot-time message from
+     * a M6e, and thus that the device was rebooted somewhere between
+     * the previous command and this one. Report this as a problem.
+     */
+    return TMR_ERROR_DEVICE_RESET;
+ }
+
+  status = GETU16AT(data, 3);
+  if (status != 0)
+  {
+    ret = TMR_ERROR_CODE(status);
+    if (ret == TMR_ERROR_TM_ASSERT_FAILED)
+    {
+	  uint32_t line;
+	  uint8_t *assert = (uint8_t *) (data + 5);
+
+	  memset(reader->u.serialReader.errMsg, 0 ,TMR_SR_MAX_PACKET_SIZE);
+	  line = GETU32AT(assert, 0);
+	  sprintf(reader->u.serialReader.errMsg, "Assertion failed at line %"PRId32" in file ", line);
+	  memcpy(reader->u.serialReader.errMsg + strlen(reader->u.serialReader.errMsg), assert + 4, len - 4);
+  }
+  }  
+  return ret;
+}
+
+/**
+ * Send a message and receive a response.
+ *
+ * @param reader The reader
+ * @param[in] data Message to send, with length in byte 1. Byte 0 is reserved for the SOF character, and two characters at the end are reserved for the CRC.
+ * @param[out] data Message received.
+ * @param timeoutMs Timeout value.
+ */
+TMR_Status
+TMR_SR_sendTimeout(TMR_Reader *reader, uint8_t *data, uint32_t timeoutMs)
+{
+  TMR_Status ret;
+  uint8_t opcode;
+  ret = TMR_SR_sendMessage(reader, data, &opcode, timeoutMs);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  if (isContinuousReadParamSupported(reader))
+  {
+	  while(reader->paramWait)
+	  {
+#ifdef SINGLE_THREAD_ASYNC_READ
+		TMR_TagReadData trd;
+		ret = TMR_hasMoreTags(reader);
+		if (TMR_SUCCESS == ret)
+		{
+			TMR_getNextTag(reader, &trd);
+			notify_read_listeners(reader, &trd);
+		}
+#endif
+	  }
+
+	  reader->paramWait = false;	  
+	  memcpy(data , &reader->paramMessage[5], reader->paramMessage[1] * sizeof(uint8_t));
+	  data[0] = 0xFF;
+	  ret = (TMR_Status) GETU16AT(&reader->paramMessage[0], 3);
+	  if (TMR_SUCCESS != ret)
+	  {
+		  return TMR_ERROR_CODE(ret);
+	  }
+	  ret = (TMR_Status) GETU16AT(data, 3);
+	  if (TMR_SUCCESS != ret)
+	  {
+		  return TMR_ERROR_CODE(ret);
+	  }
+  }
+  else
+  {
+    ret = TMR_SR_receiveMessage(reader, data, opcode, timeoutMs);
+    if (TMR_SUCCESS != ret)
+    {
+		return ret;
+	}
+  }
+  return ret;
+}
+
+
+TMR_Status
+TMR_SR_send(TMR_Reader *reader, uint8_t *data)
+{
+  return TMR_SR_sendTimeout(reader, data,
+                            reader->u.serialReader.commandTimeout);
+}
+
+/**
+ * Set the operating frequency of the device.
+ * Testing command.
+ *
+ * @param reader The reader
+ * @param frequency the frequency to set, in kHz
+ */ 
+TMR_Status 
+TMR_SR_cmdTestSetFrequency(TMR_Reader *reader, uint32_t frequency)
+{
+  
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+  SETU8(msg, i,TMR_SR_OPCODE_SET_OPERATING_FREQ);
+  SETU32(msg, i, frequency);
+  msg[1] = i - 3; /* Install length */
+  return TMR_SR_send(reader, msg);
+}
+
+/**
+ * Turn CW transmission on or off.
+ * Testing command.
+ *
+ * @param reader The reader
+ * @param on whether to turn CW on or off
+ */ 
+TMR_Status 
+TMR_SR_cmdTestSendCw(TMR_Reader *reader, bool on)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+  SETU8(msg, i,TMR_SR_OPCODE_TX_CW_SIGNAL);
+  if(on)
+    SETU8(msg, i,1);
+  else
+    SETU8(msg, i,0);
+  msg[1] = i - 3; /* Install length */
+  return TMR_SR_send(reader, msg);
+}
+
+/**
+ * Turn on pseudo-random bit stream transmission for a particular
+ * duration.  
+ * Testing command.
+ *
+ * @param reader The reader
+ * @param duration the duration to transmit the PRBS signal.
+ */ 
+TMR_Status 
+TMR_SR_cmdTestSendPrbs(TMR_Reader *reader, uint16_t duration)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+  SETU8(msg, i,TMR_SR_OPCODE_TX_CW_SIGNAL);
+  SETU8(msg, i,2);
+  SETU16(msg, i,duration);
+  msg[1] = i - 3; /* Install length */
+  return TMR_SR_send(reader, msg);
+}
+
+/**
+ * Setting user profile on the basis of operation, category and type parameter
+ *
+ * @param reader The reader
+ * @param op operation to be performed on configuration (Save,restore,verify and reset)
+ * @param category Which category of configuration to operate on -- only TMR_SR_ALL is currently supported
+ * @param type Type of configuration value to use (default, custom...)
+ */
+
+TMR_Status 
+TMR_SR_cmdSetUserProfile(TMR_Reader *reader,TMR_SR_UserConfigOperation op,TMR_SR_UserConfigCategory category, TMR_SR_UserConfigType type)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  TMR_Status ret;
+  TMR_Status ret1;
+  uint16_t readTime = 250;
+  TMR_SR_SerialReader *sr;
+  TMR_SR_SerialTransport *transport;
+
+  sr = &reader->u.serialReader;
+  transport = &reader->u.serialReader.transport;
+
+  i = 2;
+  SETU8(msg,i,TMR_SR_OPCODE_SET_USER_PROFILE);
+  SETU8(msg,i,op);
+  SETU8(msg,i,category);
+  SETU8(msg,i,type);
+
+#ifdef TMR_ENABLE_BACKGROUND_READS
+  readTime = (uint16_t)reader->readParams.asyncOnTime; 
+#endif
+
+  if (op == TMR_USERCONFIG_CLEAR)
+  {
+    /* Resrt the Autonomous option if enabled */
+    sr->enableAutonomousRead = false;
+  }
+
+  if (op == TMR_USERCONFIG_SAVE_WITH_READPLAN)
+  {
+    /** 
+     * extract the read plan configuration form API read plan object, frame
+     * the serial command for read by using existing parser methods in read
+     * operation and append that to save configuration command.
+     **/
+    TMR_uint8List *antennaList = NULL;
+    TMR_ReadPlan *rp;
+    uint8_t tempMsg[TMR_SR_MAX_PACKET_SIZE];
+
+    rp = reader->readParams.readPlan;    
+
+    /**
+     * Currently Mercury API supports only true continuous read as a part of
+     * save configuration with read plan.
+     * TODO: Add support for other read types as well if needed in future.
+     **/
+
+    /* Add the Autonomous read option */
+    sr->enableAutonomousRead = rp->enableAutonomousRead;
+    SETU8(msg,i,rp->enableAutonomousRead);
+
+    if (TMR_READ_PLAN_TYPE_MULTI == rp->type)
+    {
+      /* The Multi read plan */
+      uint8_t i; 
+      TMR_TagProtocolList p;
+      TMR_TagProtocolList *protocolList = &p;
+      TMR_TagFilter *filters[TMR_MAX_SERIAL_MULTIPROTOCOL_LENGTH];
+      TMR_TagProtocol protocols[TMR_MAX_SERIAL_MULTIPROTOCOL_LENGTH];
+
+      if (TMR_MAX_SERIAL_MULTIPROTOCOL_LENGTH < rp->u.multi.planCount)
+      {
+        return TMR_ERROR_TOO_BIG ;
+      }
+      protocolList->len = rp->u.multi.planCount;
+      protocolList->max = rp->u.multi.planCount;
+      protocolList->list = protocols;
+
+      for (i = 0; i < rp->u.multi.planCount; i++)
+      {
+        protocolList->list[i] = rp->u.multi.plans[i]->u.simple.protocol;
+        filters[i]= rp->u.multi.plans[i]->u.simple.filter; 
+      }
+
+      if ((0 < rp->u.multi.planCount) &&
+        (rp->u.multi.plans[0]->type == TMR_READ_PLAN_TYPE_SIMPLE) &&
+        (compareAntennas(&rp->u.multi)))
+      {        
+        TMR_SR_SearchFlag antennas = TMR_SR_SEARCH_FLAG_CONFIGURED_LIST;
+
+        reader->continuousReading = true;
+        antennas |= ((reader->continuousReading)? TMR_SR_SEARCH_FLAG_TAG_STREAMING : 0);
+        antennaList = &(rp->u.multi.plans[0]->u.simple.antennas);
+        ret = prepForSearch(reader, antennaList);
+        if (TMR_SUCCESS != ret)
+        {
+          return ret;
+        }
+
+        if (reader->continuousReading)
+        {
+          bool value = false;
+          ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_ENABLE_READ_FILTER, &value);
+          if (TMR_SUCCESS != ret)
+          {
+            return ret;
+          }
+        }
+        
+        /* Call the helper function to frame the multi protocol read command */
+        ret = TMR_SR_msgSetupMultipleProtocolSearch(reader, tempMsg, TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE, protocolList,
+          reader->userMetadataFlag, antennas, filters, (uint16_t)readTime);
+        if (TMR_SUCCESS != ret)
+        {
+          return ret;
+        }
+      }
+      else
+      {
+        /**
+         * Coming here means the requested read plan is not for true continuous read.
+         * Throw error back to user.
+         * TODO:Remove this validation, if we need to support for other type of read
+         * operation in future.
+         */
+        return TMR_ERROR_UNSUPPORTED;
+      }
+    }
+    else
+    {
+      /* The Simple Read Plan */
+      TMR_TagProtocolList p;
+      TMR_TagProtocolList *protocolList = &p;
+      TMR_TagFilter *filters[TMR_MAX_SERIAL_MULTIPROTOCOL_LENGTH];
+      TMR_TagProtocol protocols[TMR_MAX_SERIAL_MULTIPROTOCOL_LENGTH];
+      TMR_SR_SearchFlag antennas;
+
+      antennaList = &rp->u.simple.antennas;
+      reader->continuousReading = true;
+      reader->fastSearch = rp->u.simple.useFastSearch;
+      reader->triggerRead = rp->u.simple.triggerRead.enable;
+      protocolList->len = 1;
+      protocolList->max = 1;
+      protocolList->list = protocols;
+
+      ret = prepForSearch(reader, antennaList);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      if (reader->continuousReading)
+      {
+        bool value = false;
+        ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_ENABLE_READ_FILTER, &value);
+        if (TMR_SUCCESS != ret)
+        {
+          return ret;
+        }
+      }
+
+      protocolList->list[0] = rp->u.simple.protocol;
+      filters[0]= rp->u.simple.filter;
+
+      antennas = TMR_SR_SEARCH_FLAG_CONFIGURED_LIST;
+      antennas |= ((reader->continuousReading)? TMR_SR_SEARCH_FLAG_TAG_STREAMING : 0);
+      antennaList = &(rp->u.simple.antennas);
+
+      ret = TMR_SR_msgSetupMultipleProtocolSearch(reader, tempMsg, TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE, protocolList,
+        reader->userMetadataFlag, antennas, filters, (uint16_t)readTime);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }      
+    }
+
+    /* Append the serial read command to save configuration command */
+    memcpy((msg + i), tempMsg+1, tempMsg[1]+2);
+    /* Add two bytes for Opcode and header */
+    i = (i + tempMsg[1] + 2);    
+    reader->continuousReading = false;
+  }
+
+  msg[1] = i - 3; /* Install length */
+  ret1 = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret1)
+  {
+    return ret1;
+  }
+
+  /* If Autonomous read is enabled skip this */
+  if (!sr->enableAutonomousRead)
+  {
+    if ((op == TMR_USERCONFIG_RESTORE)||(op == TMR_USERCONFIG_CLEAR))  //reprobe the baudrate
+    {
+      uint32_t rate;
+      if (reader->connected == false)
+      {
+        ret = transport->open(transport);
+        if (TMR_SUCCESS != ret)
+        {
+          return ret;
+        }
+      }
+
+      ret = TMR_SR_cmdProbeBaudRate(reader, &rate);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+      reader->connected = true;
+    }
+
+    /* Restore the region and protocol*/
+    if ((op == TMR_USERCONFIG_RESTORE) || (op == TMR_USERCONFIG_CLEAR))
+    {
+      ret = TMR_SR_cmdGetRegion(reader, &sr->regionId);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      ret = TMR_SR_cmdGetCurrentProtocol(reader, &reader->tagOpParams.protocol);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+      sr->currentProtocol = reader->tagOpParams.protocol;
+    }
+  }
+  return ret1;
+}
+
+/**
+ * Get Save/Restore Configuration 
+ *
+ * @param reader The reader
+ * @param byte array consists of a opcode option(s)
+ * @param length Length of byte array
+ * @param response Response of the operation
+ * @param response_length Length of response array
+ */
+
+TMR_Status TMR_SR_cmdGetUserProfile(TMR_Reader *reader, uint8_t byte[], uint8_t length, uint8_t response[], uint8_t* response_length)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i,j;
+  i = 2;
+  SETU8(msg,i,TMR_SR_OPCODE_GET_USER_PROFILE);
+  for(j=0;j<length;j++)
+  {
+    SETU8(msg,i,byte[j]);
+  }
+  msg[1] = i - 3;
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  for(j=0;j<msg[1];j++)
+  {
+    response[j]=msg[5+j];
+  }
+  *response_length=msg[1];
+  return ret;
+}
+
+TMR_Status TMR_SR_cmdBlockWrite(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Bank bank, uint32_t wordPtr, 
+                                 uint32_t wordCount, const uint16_t* data, uint32_t accessPassword, const TMR_TagFilter* target)
+        {   
+            uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+            uint8_t i, option=0,rec;
+            i = 2;        
+            SETU8(msg,i,TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+            SETU16(msg, i,timeout);
+            SETU8(msg,i,0x00);//chip type
+            rec=i;
+            SETU8(msg,i,0x40);//option
+            SETU8(msg,i,0x00);
+            SETU8(msg,i,0xC7);
+            filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, &i, msg,accessPassword,true);
+            msg[rec]=msg[rec]|option;
+            SETU8(msg,i,0x00);
+            SETU8(msg,i,bank);
+            SETU32(msg,i,wordPtr);
+            SETU8(msg,i,(uint8_t)wordCount);
+            {
+              uint32_t iWord;
+              for (iWord = 0; iWord < wordCount; iWord++)
+              {
+                SETU8(msg, i, ((data[iWord]>>8)&0xFF));
+                SETU8(msg, i, ((data[iWord]>>0)&0xFF));
+              }
+            }
+            msg[1] = i - 3;
+            return TMR_SR_send(reader, msg);
+         }
+
+TMR_Status 
+TMR_SR_cmdBlockErase(TMR_Reader *reader, uint16_t timeout,
+                     TMR_GEN2_Bank bank, uint32_t wordPtr,
+                     uint8_t wordCount, uint32_t accessPassword,
+                     TMR_TagFilter *target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddGEN2BlockErase(msg, &i, timeout, wordPtr, bank, wordCount, accessPassword, target);
+
+  msg[1] = i - 3;
+  return TMR_SR_send(reader, msg);
+}
+
+TMR_Status
+TMR_SR_cmdBlockPermaLock(TMR_Reader *reader, uint16_t timeout,uint32_t readLock, TMR_GEN2_Bank bank, uint32_t blockPtr, uint32_t blockRange, uint16_t* mask, uint32_t accessPassword, TMR_TagFilter* target, TMR_uint8List* data)
+        { 
+            TMR_Status ret;
+            uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+            uint8_t i, option=0,rec;
+            unsigned int j;
+            i = 2;    
+            SETU8(msg,i,TMR_SR_OPCODE_ERASE_BLOCK_TAG_SPECIFIC);
+            SETU16(msg,i,timeout);
+            SETU8(msg,i,0x00);
+            rec=i;
+            SETU8(msg,i,0x40);
+            SETU8(msg,i,0x01);
+            filterbytes(TMR_TAG_PROTOCOL_GEN2,target, &option, &i, msg,accessPassword,true);
+            msg[rec]=msg[rec]|option;
+            SETU8(msg,i,0x00);
+            SETU8(msg,i,(uint8_t)readLock);
+            
+            SETU8(msg,i,bank);
+            SETU32(msg,i,blockPtr);
+            SETU8(msg,i,(uint8_t)blockRange);
+            
+            if (readLock==0x01)
+            {
+              for(j=0;j<blockRange;j++)
+              {
+               SETU8(msg,i,(mask[j]>>8)&(0xff));
+               SETU8(msg,i,(mask[j]>>0) & (0xff));
+              }
+            }
+            msg[1] = i - 3;
+            ret =  TMR_SR_send(reader, msg);
+            if (TMR_SUCCESS != ret)
+            {
+              return ret;
+            }
+            if ((0 == readLock) && (NULL != data))
+            {
+              data->len = msg[1]-2;
+              if (data->len > data->max)
+              {
+                data->len = data->max;
+            }
+              memcpy(data->list, msg+7, data->len);
+            }
+            return ret;
+        }  
+TMR_Status
+TMR_SR_cmdVersion(TMR_Reader *reader, TMR_SR_VersionInfo *info)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i, j;
+  uint32_t tTimeout = 0;
+
+  tTimeout = reader->u.serialReader.transportTimeout;
+
+  /**
+   * If user not set any trasportTimeout value.
+   * Use the default value.
+   */
+  if (false == reader->u.serialReader.usrTimeoutEnable)
+  {
+  reader->u.serialReader.transportTimeout = 100;
+  }
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_VERSION);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, 0);
+  if (TMR_SUCCESS != ret)
+  {
+    reader->u.serialReader.transportTimeout = tTimeout;
+    return ret;    
+  }
+  if (NULL != info)
+  {
+    i = 5;
+    for (j = 0; j < 4 ; j++)
+    {
+      info->bootloader[j] = GETU8(msg, i);
+    }
+    for (j = 0; j < 4 ; j++)
+    {
+      info->hardware[j] = GETU8(msg, i);
+    }
+    for (j = 0; j < 4 ; j++)
+    {
+      info->fwDate[j] = GETU8(msg, i);
+    }
+    for (j = 0; j < 4 ; j++)
+    {
+      info->fwVersion[j] = GETU8(msg, i);
+    }
+    info->protocols = GETU32(msg, i);
+  }
+
+  reader->u.serialReader.transportTimeout = tTimeout;
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_cmdBootFirmware(TMR_Reader *reader)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i, j;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_BOOT_FIRMWARE);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, 1000);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  i = 5;
+  for (j = 0; j < 4 ; j++)
+  {
+    reader->u.serialReader.versionInfo.bootloader[j] = GETU8(msg, i);
+  }
+  for (j = 0; j < 4 ; j++)
+  {
+    reader->u.serialReader.versionInfo.hardware[j] = GETU8(msg, i);
+  }
+  for (j = 0; j < 4 ; j++)
+  {
+    reader->u.serialReader.versionInfo.fwDate[j] = GETU8(msg, i);
+  }
+  for (j = 0; j < 4 ; j++)
+  {
+    reader->u.serialReader.versionInfo.fwVersion[j] = GETU8(msg, i);
+  }
+  reader->u.serialReader.versionInfo.protocols = GETU32(msg, i);
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_cmdSetBaudRate(TMR_Reader *reader, uint32_t rate)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_BAUD_RATE);
+  SETU32(msg, i, rate);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status
+TMR_SR_cmdEraseFlash(TMR_Reader *reader, uint8_t sector, uint32_t password)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_ERASE_FLASH);
+  SETU32(msg, i, password);
+  SETU8(msg, i, sector);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, 30000);
+}
+
+
+TMR_Status
+TMR_SR_cmdWriteFlashSector(TMR_Reader *reader, uint8_t sector, uint32_t address,
+                           uint32_t password, uint8_t length, const uint8_t data[],
+                           uint32_t offset)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_WRITE_FLASH_SECTOR);
+  SETU32(msg, i, password);
+  SETU32(msg, i, address);
+  SETU8(msg, i, sector);
+  memcpy(&msg[i], data + offset, length);
+  i += length;
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, 3000);
+}
+
+
+
+TMR_Status
+TMR_SR_cmdModifyFlashSector(TMR_Reader *reader, uint8_t sector, uint32_t address,
+                            uint32_t password, uint8_t length, const uint8_t data[],
+                            uint32_t offset)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_MODIFY_FLASH_SECTOR);
+  SETU32(msg, i, password);
+  SETU32(msg, i, address);
+  SETU8(msg, i, sector);
+  memcpy(&msg[i], data + offset, length);
+  i += length;
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, 3000);
+}
+
+TMR_Status
+TMR_SR_cmdBootBootloader(TMR_Reader *reader)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_BOOT_BOOTLOADER);
+  msg[1] = i - 3; /* Install length */
+
+  reader->u.serialReader.crcEnabled = true;
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status
+TMR_SR_cmdGetHardwareVersion(TMR_Reader *reader, uint8_t option, uint8_t flags,
+                             uint8_t* count, uint8_t data[])
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_HW_VERSION);
+  SETU8(msg, i, option);
+  SETU8(msg, i, flags);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  for (i = 0 ; i < msg[1] && i < *count; i++)
+  {
+    data[i] = msg[5 + i];
+  }
+
+  *count = msg[1];
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_cmdGetCurrentProgram(TMR_Reader *reader, uint8_t *program)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_CURRENT_PROGRAM);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  *program = msg[5];
+
+  return ret;
+}
+
+TMR_Status TMR_SR_msgSetupReadTagSingle(uint8_t *msg, uint8_t *i, TMR_TagProtocol protocol,TMR_TRD_MetadataFlag metadataFlags, const TMR_TagFilter *filter,uint16_t timeout)
+{
+  uint8_t optbyte;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_READ_TAG_ID_SINGLE);
+  SETU16(msg, *i, timeout);
+  optbyte = *i;
+  SETU8(msg, *i, 0); /* Initialize option byte */
+  msg[optbyte] |= TMR_SR_GEN2_SINGULATION_OPTION_FLAG_METADATA;
+  SETU16(msg,*i, metadataFlags);
+  filterbytes(protocol, filter, &msg[optbyte], i, msg,0, true);
+  msg[optbyte] |= TMR_SR_GEN2_SINGULATION_OPTION_FLAG_METADATA;
+  return TMR_SUCCESS;
+
+}
+
+TMR_Status
+TMR_SR_msgSetupReadTagMultiple(TMR_Reader *reader, uint8_t *msg, uint8_t *i, uint16_t timeout,
+                               TMR_SR_SearchFlag searchFlag,
+                               const TMR_TagFilter *filter,
+                               TMR_TagProtocol protocol,
+                               TMR_GEN2_Password accessPassword)
+{
+  return TMR_SR_msgSetupReadTagMultipleWithMetadata(reader, msg, i, timeout,
+    searchFlag, reader->userMetadataFlag, filter, protocol,accessPassword);
+}
+
+
+TMR_Status
+TMR_SR_msgSetupReadTagMultipleWithMetadata(TMR_Reader *reader, uint8_t *msg, uint8_t *i, uint16_t timeout,
+                               TMR_SR_SearchFlag searchFlag,
+							                 TMR_TRD_MetadataFlag metadataFlag,
+                               const TMR_TagFilter *filter,
+                               TMR_TagProtocol protocol,
+                               TMR_GEN2_Password accessPassword)
+{
+  TMR_Status ret;
+  TMR_SR_SerialReader *sr;
+  uint8_t optbyte;
+  
+  sr = &reader->u.serialReader;
+  sr->opCode = TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE;
+  ret = TMR_SUCCESS;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE);
+
+  /**
+   * we need to add the option for bap parameters if enabled
+   * 
+   * for adding the bap parameter option, and EBV technique is used
+   * raising the lowest order bit of the high opder byte signals the
+   * use of new Gen2 Bap support parameters.
+   **/
+  if (sr->isBapEnabled)
+  {
+    SETU8(msg,*i,0x81);
+  }
+
+  optbyte = *i;
+  SETU8(msg, *i, 0); /* Initialize option byte */
+
+  /* add the large tag population support */
+  searchFlag= (TMR_SR_SearchFlag)(searchFlag | TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT);
+
+  if (reader->continuousReading)
+  {
+    msg[optbyte] |= TMR_SR_GEN2_SINGULATION_OPTION_FLAG_METADATA;
+    searchFlag = (TMR_SR_SearchFlag)(searchFlag
+        | TMR_SR_SEARCH_FLAG_TAG_STREAMING);
+
+    /**
+     * We need to send a different flag for the new reader stats,
+     * Both these options are mutually exclusive in nature,
+     * Hence can not be raised at once.
+     **/
+    if (TMR_SR_STATUS_NONE != reader->streamStats)
+    {
+      searchFlag |= TMR_SR_SEARCH_FLAG_STATUS_REPORT_STREAMING;
+    }
+    else
+    {
+      if (TMR_READER_STATS_FLAG_NONE != reader->statsFlag)
+      {
+        searchFlag |= TMR_SR_SEARCH_FLAG_STATS_REPORT_STREAMING;
+      }
+    }
+  }
+
+  /**
+   * Add the fast search flag depending on the user choice
+   */
+  if (reader->fastSearch)
+  {
+    searchFlag = (TMR_SR_SearchFlag)(searchFlag
+      |TMR_SR_SEARCH_FLAG_READ_MULTIPLE_FAST_SEARCH);
+    reader->fastSearch = false;
+  }
+
+  /**
+   * Add the trigger read flag depending on the user choice
+   */
+  if (reader->triggerRead)
+  {
+    searchFlag = (TMR_SR_SearchFlag)(searchFlag
+      |TMR_SR_SEARCH_FLAG_GPI_TRIGGER_READ);
+    reader->triggerRead = false;
+  }
+
+  /**
+   * Add the duty cycle flag depending on the user choice
+   */
+  if (reader->dutyCycle)
+  {
+    searchFlag = (TMR_SR_SearchFlag)(searchFlag
+		|TMR_SR_SEARCH_FLAG_DUTY_CYCLE_CONTROL);
+  }
+
+  if (reader->isStopNTags && !reader->continuousReading)
+  {
+    /**
+     * Currently stop N Trigger is only supported for
+     * sync read.
+     **/ 
+    searchFlag = (TMR_SR_SearchFlag)(searchFlag
+        |TMR_SR_SEARCH_FLAG_RETURN_ON_N_TAGS);
+  }
+
+  SETU16(msg, *i, searchFlag);
+  SETU16(msg, *i, timeout);
+  if(reader->dutyCycle)
+  {
+	  uint32_t offtime;
+	  ret = TMR_paramGet(reader,TMR_PARAM_READ_ASYNCOFFTIME,&offtime);
+	  SETU16(msg, *i, (uint16_t)offtime);
+  }
+  reader->dutyCycle = false;
+  if (reader->continuousReading)
+  {
+    SETU16(msg, *i, metadataFlag);
+
+    if (TMR_READER_STATS_FLAG_NONE != reader->statsFlag)
+    {
+      /**
+       * To extend the flag byte, an EBV technique is to be used.
+       * When the highest order bit of the flag byte is used,
+       * it signals the reader’s parser, that another flag byte is to follow
+       */
+      if ((0x80) > reader->statsFlag)
+      {
+        SETU16(msg, *i, (uint16_t)reader->statsFlag);
+      }
+      else
+      {
+        SETU16(msg, *i, ((uint16_t)reader->statsFlag));
+      }
+    }
+    else
+    {
+      if (TMR_SR_STATUS_NONE != reader->streamStats)
+      {
+        /* Add status report flags, so that the status stream responses are received */
+        SETU16(msg, *i, (uint16_t)reader->streamStats);
+      }
+    }
+  }
+
+  /**
+   * Add the no of tags to be read requested by user
+   * in stop N tag reads.Currently only supported for
+   * sync read.
+   **/
+  if (reader->isStopNTags && !reader->continuousReading)
+  {
+    SETU32(msg ,*i, (uint32_t)reader->numberOfTagsToRead);
+  }
+
+  /*
+   * Earlier, this filter bytes were skipped for a null filter and gen2 0 access password.
+   * as the filterbytes it self has the checks internally, these were removed.
+   * for some protocols (such as ISO180006B) the "null" filter is not zero-length, but we don't need to send
+   * that with this command.
+   */
+  if (TMR_TAG_PROTOCOL_ISO180006B == protocol && NULL == filter)
+  {
+    /* ISO18000-6B should not include any filter arg bytes if null */
+  }
+  else
+  {
+    ret = filterbytes(protocol, filter, &msg[optbyte], i, msg,
+        accessPassword, true);
+  }
+
+  if (reader->continuousReading)
+  {
+    msg[optbyte] |= TMR_SR_GEN2_SINGULATION_OPTION_FLAG_METADATA;
+  }
+	if (isSecureAccessEnabled)
+  {
+    msg[optbyte] |= TMR_SR_GEN2_SINGULATION_OPTION_SECURE_READ_DATA;
+  }
+
+  return ret;
+}
+
+TMR_Status
+TMR_SR_cmdReadTagMultiple(TMR_Reader *reader, uint16_t timeout,
+                          TMR_SR_SearchFlag searchFlag,
+                          const TMR_TagFilter *filter, TMR_TagProtocol protocol,
+                          uint32_t *tagCount)
+{
+  TMR_Status ret;
+  TMR_SR_SerialReader *sr;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  ret = TMR_SR_msgSetupReadTagMultiple(reader, msg, &i, timeout, searchFlag,
+                                       filter, protocol, 0);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  msg[1] = i - 3; /* Install length */
+
+  sr = &reader->u.serialReader;
+  sr->opCode = TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE;
+  if (reader->continuousReading)
+  {
+    uint8_t opcode;
+    ret = TMR_SR_sendMessage(reader, msg, &opcode, timeout);
+    *tagCount = (uint32_t)0;
+    return ret;
+  }
+  else
+  {
+    ret = TMR_SR_sendTimeout(reader, msg, timeout);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+
+    if (NULL != tagCount)
+    {
+      if (4 == msg[1])
+      {
+        /* Plain 1-byte count: Reader without large-tag-population support */
+        *tagCount = GETU8AT(msg, 8);
+      }
+      else if (5 == msg[1])
+      {
+        /* Later 1-byte count: ISO18k select option included in reply */
+        *tagCount = GETU8AT(msg, 9);
+      }
+      else if (7 == msg[1])
+      {
+        /* Plain 4-byte count: Reader with large-tag-population support */
+        *tagCount = GETU32AT(msg, 8);
+      }
+      else if (8 == msg[1])
+      {
+        /* Later 4-byte count: Large-tag-population support and ISO18k
+         * select option included in reply.
+         */
+        *tagCount = GETU32AT(msg, 9);
+      }
+      else
+      {
+        return TMR_ERROR_PARSE;
+      }
+    }
+
+    return TMR_SUCCESS;
+  }
+}
+
+
+TMR_Status
+TMR_SR_executeEmbeddedRead(TMR_Reader *reader, uint8_t *msg, uint16_t timeout,
+                           TMR_SR_MultipleStatus *status)
+{
+  TMR_Status ret;
+  uint8_t i, len, index;
+  uint8_t newMsg[TMR_SR_MAX_PACKET_SIZE];
+    
+  if (reader->continuousReading)
+  {
+    uint8_t opcode = TMR_SR_OPCODE_MULTI_PROTOCOL_TAG_OP;
+    i = 2;
+    SETU8(newMsg, i, opcode);  /* Opcode */
+    
+    /* Timeout should be zero for true continuous reading */
+    SETU16(newMsg, i, 0);
+    SETU8(newMsg, i, (uint8_t)0x1); /* TM Option 1, for continuous reading */
+    SETU8(newMsg, i, (uint8_t)TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE); /* sub command opcode */
+    SETU16(newMsg, i, (uint16_t)0x0000); /* search flags, only 0x0001 is supported */
+    SETU8(newMsg, i, (uint8_t)TMR_TAG_PROTOCOL_GEN2); /* protocol ID */
+
+    len = msg[1];
+    index = i;
+    SETU8(newMsg, i, 0); /* Protocol command length (initialize to 0)*/
+
+    /* Copy the protocol command including the command opcode (len + 1)*/
+    memcpy(&newMsg[i], &msg[2], (size_t)(len + 1));
+    i += len + 1;
+
+    /* Insert the exact protocol command length */
+    newMsg[index] = i - index - 2;
+
+    /* Install the total packet length*/
+    newMsg[1]=i - 3;    
+
+    ret = TMR_SR_sendMessage(reader, newMsg, &opcode, timeout);
+    status->tagsFound = status->successCount = status->failureCount = 0;
+
+    return ret;
+  }
+  else
+  {
+    uint16_t searchFlags = GETU16AT(msg, 4);
+
+    ret = TMR_SR_sendTimeout(reader, msg, timeout);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+
+    if (NULL != status)
+    {
+      int readIdx = 8;
+      if ((TMR_SR_SEARCH_FLAG_LARGE_TAG_POPULATION_SUPPORT & searchFlags) &&
+          ((TMR_SR_MODEL_M6E == reader->u.serialReader.versionInfo.hardware[0]) ||
+           (TMR_SR_MODEL_M6E_I == reader->u.serialReader.versionInfo.hardware[0]) ||
+           (TMR_SR_MODEL_M6E_NANO == reader->u.serialReader.versionInfo.hardware[0]) ||
+          (TMR_SR_MODEL_MICRO == reader->u.serialReader.versionInfo.hardware[0])))
+	    {
+        /* Only in case of M6e, the tag length will be 4 bytes */
+		    status->tagsFound = (uint16_t)GETU32AT(msg, readIdx);
+		    readIdx += 4;
+      }
+	    else
+	    {
+		    status->tagsFound = GETU8AT(msg, readIdx);
+		    readIdx += 1;
+	    }
+      readIdx += 2;
+      status->successCount = GETU16AT(msg, readIdx);
+      readIdx += 2;
+      status->failureCount = GETU16AT(msg, readIdx);
+      readIdx += 2;
+    }
+  }
+
+  return TMR_SUCCESS;
+}
+
+void
+TMR_SR_msgAddGEN2WriteTagEPC(uint8_t *msg, uint8_t *i, uint16_t timeout, uint8_t *epc, uint8_t count)
+{
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_ID);
+  SETU16(msg, *i, timeout); /* timeout */
+  SETU16(msg, *i, 0); /* RFU 2 bytes */
+  memcpy(&msg[*i], epc, count);
+  *i += count;
+}
+
+void
+TMR_SR_msgAddGEN2DataRead(uint8_t *msg, uint8_t *i, uint16_t timeout,
+                      TMR_GEN2_Bank bank, uint32_t wordAddress, uint8_t len, uint8_t option, bool withMetaData)
+{
+
+  SETU8(msg, *i, TMR_SR_OPCODE_READ_TAG_DATA);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, option);  /* Options - initialize */
+  if (withMetaData)
+  {
+    SETU16(msg, *i, 0x0000);  /* metadata flags - initialize */
+  }
+  SETU8(msg, *i, bank);
+  SETU32(msg, *i, wordAddress);
+  SETU8(msg, *i, len);
+}
+
+
+void
+TMR_SR_msgAddGEN2DataWrite(uint8_t *msg, uint8_t *i, uint16_t timeout,
+                       TMR_GEN2_Bank bank, uint32_t address)
+{
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_DATA);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, 0); /* Option - initialize */
+  SETU32(msg, *i, address);
+  SETU8(msg, *i, bank);
+}
+
+
+void
+TMR_SR_msgAddGEN2LockTag(uint8_t *msg, uint8_t *i, uint16_t timeout, uint16_t mask,
+                         uint16_t action, TMR_GEN2_Password accessPassword)
+{
+
+  SETU8(msg, *i, TMR_SR_OPCODE_LOCK_TAG);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, 0);  /* Option - initialize */
+  SETU32(msg, *i, accessPassword);
+  SETU16(msg, *i, mask);
+  SETU16(msg, *i, action);
+}
+
+
+void
+TMR_SR_msgAddGEN2KillTag(uint8_t *msg, uint8_t *i, uint16_t timeout,
+                         TMR_GEN2_Password password)
+{
+
+  SETU8(msg, *i, TMR_SR_OPCODE_KILL_TAG);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, 0);  /* Option - initialize */
+  SETU32(msg, *i, password);
+  SETU8(msg, *i, 0);  /* RFU */
+}
+
+void
+TMR_SR_msgAddGEN2BlockWrite(uint8_t *msg, uint8_t *i, uint16_t timeout,TMR_GEN2_Bank bank, uint32_t wordPtr, uint32_t wordCount, uint16_t* data, uint32_t accessPassword, TMR_TagFilter* target)
+{
+  uint8_t option=0,rec;      
+  SETU8(msg,*i,TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i,timeout);
+  SETU8(msg,*i,0x00);//chip type
+  rec=*i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg,*i,0x00);
+  SETU8(msg,*i,0xC7);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg,accessPassword,true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg,*i,0x00);
+  SETU8(msg,*i,bank);
+  SETU32(msg,*i,wordPtr);
+  SETU8(msg,*i,(uint8_t)wordCount);
+  {
+    uint32_t iWord;
+    for (iWord=0; iWord<wordCount; iWord++)
+    {
+      SETU8(msg, *i, ((data[iWord]>>8)&0xFF));
+      SETU8(msg, *i, ((data[iWord]>>0)&0xFF));
+    }
+  }
+}
+
+void
+TMR_SR_msgAddGEN2BlockPermaLock(uint8_t *msg, uint8_t *i, uint16_t timeout, uint32_t readLock, TMR_GEN2_Bank bank, uint32_t blockPtr, uint32_t blockRange, uint16_t* mask, uint32_t accessPassword,TMR_TagFilter* target)
+{
+  uint8_t option=0,rec;    
+  SETU8(msg,*i,TMR_SR_OPCODE_ERASE_BLOCK_TAG_SPECIFIC);
+  SETU16(msg,*i,timeout);
+  SETU8(msg,*i,0x00);
+  rec=*i;
+  SETU8(msg,*i,0x40);
+  SETU8(msg,*i,0x01);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2,target, &option, i, msg,accessPassword,true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg,*i,0x00);
+  SETU8(msg,*i,(uint8_t)readLock);
+
+  SETU8(msg,*i,bank);
+  SETU32(msg,*i,blockPtr);
+  SETU8(msg,*i,(uint8_t)blockRange);
+  if (readLock==0x01)
+  {
+   SETU16(msg, *i, *mask);
+  }
+
+}
+
+void
+TMR_SR_msgAddGEN2BlockErase(uint8_t *msg, uint8_t *i, uint16_t timeout,
+                            uint32_t wordPtr, TMR_GEN2_Bank bank, uint8_t wordCount,
+                            uint32_t accessPassword, TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_ERASE_BLOCK_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, 0x00);
+
+  rec = *i;
+  SETU8(msg, *i, 0x40);
+  SETU8(msg, *i, 0x00); /* Block erase */
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec] = msg[rec] | option;
+
+  SETU32(msg, *i, wordPtr);
+  SETU8(msg, *i, bank);
+  SETU8(msg,*i, wordCount);
+}
+
+TMR_Status
+TMR_SR_cmdWriteGen2TagEpc(TMR_Reader *reader, const TMR_TagFilter *filter, TMR_GEN2_Password accessPassword, 
+					  uint16_t timeout, uint8_t count, const uint8_t *id, bool lock)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i, optbyte;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_WRITE_TAG_ID);
+  SETU16(msg, i, timeout);
+  optbyte = i;
+  SETU8(msg, i, 0);
+  
+
+  ret = filterbytes(TMR_TAG_PROTOCOL_GEN2, filter, &msg[optbyte], &i, msg,
+                    accessPassword, true);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  if (0 == msg[optbyte])
+  {
+	  SETU8(msg, i, 0);  // Initialize second RFU byte to zero
+  }
+
+  if (i + count + 1 > TMR_SR_MAX_PACKET_SIZE)
+  {
+    return TMR_ERROR_TOO_BIG;
+  }
+
+  memcpy(&msg[i], id, count);
+  i += count;
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+
+TMR_Status
+TMR_SR_cmdClearTagBuffer(TMR_Reader *reader)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_CLEAR_TAG_ID_BUFFER);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+TMR_Status TMR_SR_cmdGetTagsRemaining(TMR_Reader *reader, uint16_t *tagCount)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  TMR_Status ret;
+	
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_TAG_ID_BUFFER);
+  msg[1] = i-3; /* Install length */
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  
+  *tagCount = GETU16AT(msg, 7) - GETU16AT(msg, 5);
+  return TMR_SUCCESS;
+}
+
+void
+TMR_SR_parseMetadataFromMessage(TMR_Reader *reader, TMR_TagReadData *read, uint16_t flags,
+                                uint8_t *i, uint8_t msg[])
+{
+  int msgEpcLen;
+
+  read->metadataFlags = flags;
+  read->tag.protocol = TMR_TAG_PROTOCOL_NONE;
+  read->readCount = 0;
+  read->rssi = 0;
+  read->antenna = 0;
+  read->phase = 0;
+  read->frequency = 0;
+  read->dspMicros = 0;
+  read->timestampLow = 0;
+  read->timestampHigh = 0;
+  read->isAsyncRead = false;
+
+  switch(reader->u.serialReader.versionInfo.hardware[0])
+  {
+  case TMR_SR_MODEL_M5E:
+    read->gpioCount = 2;
+    break;
+  case TMR_SR_MODEL_M6E:
+    read->gpioCount = 4;
+    break;
+  default:
+    read->gpioCount = 4;
+    break;
+  }
+    
+
+  /* Fill in tag data from response */
+  if (flags & TMR_TRD_METADATA_FLAG_READCOUNT)
+  {
+    read->readCount = GETU8(msg, *i);
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_RSSI)
+  {
+    read->rssi = (int8_t)GETU8(msg, *i);
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_ANTENNAID)
+  {
+    read->antenna = GETU8(msg, *i);
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_FREQUENCY)
+  {
+    read->frequency = GETU24(msg, *i);
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_TIMESTAMP)
+  {
+    read->dspMicros = GETU32(msg, *i);
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_PHASE)
+  {
+    read->phase = GETU16(msg, *i);
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_PROTOCOL)
+  {
+    read->tag.protocol = (TMR_TagProtocol)GETU8(msg, *i);
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_DATA)
+  {
+    int msgDataLen, copyLen;
+    
+    msgDataLen = tm_u8s_per_bits(GETU16(msg, *i));
+    read->data.len = msgDataLen;
+    copyLen = msgDataLen;
+    if (copyLen > read->data.max)
+    {
+      copyLen = read->data.max;
+    }
+	if (NULL != read->data.list)
+	{
+      memcpy(read->data.list, &msg[*i], copyLen);
+	}
+
+  /**
+   * if the gen2AllMemoryBankEnabled is enabled,
+   * extract the values
+   **/
+  if (reader->u.serialReader.gen2AllMemoryBankEnabled)
+  {
+    uint16_t dataLength = read->data.len;
+    uint8_t readOffSet = 0;
+    uint8_t bank;
+    uint16_t epcDataLength;
+    while (dataLength != 0)
+    {
+      if (readOffSet >= dataLength)
+        break;
+      bank = ((read->data.list[readOffSet] >> 4) & 0x1F);
+      epcDataLength = (read->data.list[readOffSet + 1] * 2);
+      switch (bank)
+      {
+        case TMR_GEN2_BANK_EPC:
+          {
+            read->epcMemData.len = epcDataLength;
+            if (epcDataLength > read->epcMemData.max)
+            {
+              epcDataLength = read->epcMemData.max;
+            }
+            if (NULL != read->epcMemData.list)
+            {
+              memcpy(read->epcMemData.list, (read->data.list + readOffSet + 2), epcDataLength);
+            }
+            readOffSet += (epcDataLength + 2);
+            break;
+
+          }
+        case TMR_GEN2_BANK_RESERVED:
+          {
+            read->reservedMemData.len = epcDataLength;
+            if (epcDataLength > read->epcMemData.max)
+            {
+              epcDataLength = read->reservedMemData.max;
+            }
+            if (NULL != read->reservedMemData.list)
+            {
+              memcpy(read->reservedMemData.list, (read->data.list + readOffSet + 2), epcDataLength);
+            }
+            readOffSet += (epcDataLength + 2);
+            break;
+
+          }
+        case TMR_GEN2_BANK_TID:
+          {
+            read->tidMemData.len = epcDataLength;
+            if (epcDataLength > read->tidMemData.max)
+            {
+              epcDataLength = read->tidMemData.max;
+            }
+            if (NULL != read->tidMemData.list)
+            {
+              memcpy(read->tidMemData.list, (read->data.list + readOffSet + 2), epcDataLength);
+            }
+            readOffSet += (epcDataLength + 2);
+            break;
+
+          }
+        case TMR_GEN2_BANK_USER:
+          {
+            read->userMemData.len = epcDataLength;
+            if (epcDataLength > read->userMemData.max)
+            {
+              epcDataLength = read->userMemData.max;
+            }
+            if (NULL != read->userMemData.list)
+            {
+              memcpy(read->userMemData.list, (read->data.list + readOffSet + 2), epcDataLength);
+            }
+            readOffSet += (epcDataLength + 2);
+            break;
+
+          }
+        default:
+          break;
+      }
+    }
+  }
+  /**
+   * Now, we extracted all the values,
+   * Disable the gen2AllMemoryBankEnabled option.
+   **/
+  reader->u.serialReader.gen2AllMemoryBankEnabled = false;
+
+	*i += msgDataLen;
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_GPIO_STATUS)
+  {
+    int j;
+    uint8_t gpioByte=GETU8(msg, *i);
+    for (j=0;j<read->gpioCount;j++) 
+    {
+      read->gpio[j].id = j+1;
+      read->gpio[j].high = (((gpioByte >> j)&0x1)== 1);
+    }
+  }
+
+  msgEpcLen = tm_u8s_per_bits(GETU16(msg, *i));  
+  if (TMR_TAG_PROTOCOL_ATA != read->tag.protocol)
+  {
+    /* ATA protocol does not have TAG CRC */
+    msgEpcLen -= 2; /* Remove 2 bytes CRC*/
+  }
+  if (TMR_TAG_PROTOCOL_GEN2 == read->tag.protocol)
+  {    
+    read->tag.u.gen2.pc[0] = GETU8(msg, *i);
+    read->tag.u.gen2.pc[1] = GETU8(msg, *i);
+    msgEpcLen -= 2;
+    read->tag.u.gen2.pcByteCount = 2;
+
+    /* Add support for XPC bits
+     * XPC_W1 is present, when the 6th most significant bit of PC word is set
+     */
+    if ((read->tag.u.gen2.pc[0] & 0x02) == 0x02)
+    {
+      /* When this bit is set, the XPC_W1 word will follow the PC word
+       * Our TMR_Gen2_TagData::pc has enough space, so copying to the same.
+       */
+      read->tag.u.gen2.pc[2] = GETU8(msg, *i);
+      read->tag.u.gen2.pc[3] = GETU8(msg, *i);
+      msgEpcLen -= 2;                           /* EPC length will be length - 4(PC + XPC_W1)*/
+      read->tag.u.gen2.pcByteCount += 2;        /* PC bytes are now 4*/
+
+      if ((read->tag.u.gen2.pc[2] & 0x80) == 0x80)
+      {
+        /*
+         * If the most siginificant bit of XPC_W1 is set, then there exists
+         * XPC_W2. A total of 6  (PC + XPC_W1 + XPC_W2 bytes)
+         */
+        read->tag.u.gen2.pc[4] = GETU8(msg, *i);
+        read->tag.u.gen2.pc[5] = GETU8(msg, *i);
+        msgEpcLen -= 2;                       /* EPC length will be length - 6 (PC + XPC_W1 + XPC_W2)*/
+        read->tag.u.gen2.pcByteCount += 2;    /* PC bytes are now 6 */
+      }
+    }    
+  }
+  read->tag.epcByteCount = msgEpcLen;
+  if (read->tag.epcByteCount > TMR_MAX_EPC_BYTE_COUNT)
+  {
+    read->tag.epcByteCount = TMR_MAX_EPC_BYTE_COUNT;
+  }
+
+  memcpy(read->tag.epc, &msg[*i], read->tag.epcByteCount);
+  *i += msgEpcLen;
+  if (TMR_TAG_PROTOCOL_ATA != read->tag.protocol)
+  {  
+    read->tag.crc = GETU16(msg, *i);
+  }
+  else
+  {
+	read->tag.crc = 0xffff;
+  }
+
+  if(reader->continuousReading)
+  {
+    read->isAsyncRead = true;
+  }
+  else
+  {
+    read->isAsyncRead = false;
+  }
+
+}
+
+void
+TMR_SR_parseMetadataOnly(TMR_Reader *reader, TMR_TagReadData *read, uint16_t flags,
+                                uint8_t *i, uint8_t msg[])
+{
+  read->metadataFlags = flags;
+  read->tag.protocol = TMR_TAG_PROTOCOL_NONE;
+  read->readCount = 0;
+  read->rssi = 0;
+  read->antenna = 0;
+  read->phase = 0;
+  read->frequency = 0;
+  read->dspMicros = 0;
+  read->timestampLow = 0;
+  read->timestampHigh = 0;
+  read->isAsyncRead = false;
+
+  switch(reader->u.serialReader.versionInfo.hardware[0])
+  {
+  case TMR_SR_MODEL_M5E:
+    read->gpioCount = 2;
+    break;
+  case TMR_SR_MODEL_M6E:
+    read->gpioCount = 4;
+    break;
+  default:
+    read->gpioCount = 4;
+    break;
+  }
+
+  /* Fill in tag data from response */
+  if (flags & TMR_TRD_METADATA_FLAG_READCOUNT)
+  {
+    read->readCount = GETU8(msg, *i);
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_RSSI)
+  {
+    read->rssi = GETU8(msg, *i);
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_ANTENNAID)
+  {
+    read->antenna = GETU8(msg, *i);
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_FREQUENCY)
+  {
+    read->frequency = GETU24(msg, *i);
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_TIMESTAMP)
+  {
+    read->dspMicros = GETU32(msg, *i);
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_PHASE)
+  {
+    read->phase = GETU16(msg, *i);
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_PROTOCOL)
+  {
+    read->tag.protocol = (TMR_TagProtocol)GETU8(msg, *i);
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_DATA)
+  {
+    int msgDataLen, copyLen;
+
+    msgDataLen = tm_u8s_per_bits(GETU16(msg, *i));
+    read->data.len = msgDataLen;
+    copyLen = msgDataLen;
+    if (copyLen > read->data.max)
+    {
+      copyLen = read->data.max;
+    }
+    memcpy(read->data.list, &msg[*i], copyLen);
+    *i += msgDataLen;
+  }
+  if (flags & TMR_TRD_METADATA_FLAG_GPIO_STATUS)
+  {
+    int j;
+    uint8_t gpioByte=GETU8(msg, *i);
+    for (j=0;j<read->gpioCount ;j++) 
+    {
+      read->gpio[j].id = j+1;
+      read->gpio[j].high = (((gpioByte >> j)&0x1)== 1);
+    }
+  }
+}
+
+void
+TMR_SR_postprocessReaderSpecificMetadata(TMR_TagReadData *read, TMR_SR_SerialReader *sr)
+{
+  uint16_t j;
+  uint32_t timestampLow;
+  uint64_t currTime64, lastSentTagTime64; /*for comparison*/
+  int32_t tempDiff;
+
+  timestampLow = sr->readTimeLow;
+  read->timestampHigh = sr->readTimeHigh;
+
+  timestampLow = timestampLow + read->dspMicros;
+  currTime64 = ((uint64_t)read->timestampHigh << 32) | timestampLow;
+  lastSentTagTime64 = ((uint64_t)sr->lastSentTagTimestampHigh << 32) | sr->lastSentTagTimestampLow;
+  if (lastSentTagTime64 >= currTime64)
+  {
+    tempDiff = (int32_t)(currTime64 - lastSentTagTime64);
+    timestampLow = timestampLow - tempDiff + 1;
+    if (timestampLow < sr->lastSentTagTimestampLow) /*account for overflow*/
+    {
+      read->timestampHigh++;
+    }
+  }
+  if (timestampLow < sr->readTimeLow) /* Overflow */
+  {
+    read->timestampHigh++;
+  }
+  read->timestampLow = timestampLow;
+  sr->lastSentTagTimestampHigh = read->timestampHigh;
+  sr->lastSentTagTimestampLow = read->timestampLow;
+
+  {
+    uint8_t tx;
+    uint8_t rx;
+    tx = (read->antenna >> 4) & 0xF;
+    rx = (read->antenna >> 0) & 0xF;
+
+    // Due to limited space, Antenna 16 wraps around to 0
+    if (0 == tx) { tx = 16; }
+    if (0 == rx) { rx = 16; }
+
+    for (j = 0; j < sr->txRxMap->len; j++)
+    {
+      if (rx == sr->txRxMap->list[j].rxPort &&
+          tx == sr->txRxMap->list[j].txPort)
+      {
+        read->antenna = sr->txRxMap->list[j].antenna;
+		if (read->gpioCount > 2)
+		{
+			if (read->gpio[2].high)
+				read->antenna += 16;
+		}
+        break;
+      }
+    }
+  }
+}
+
+#ifdef TMR_ENABLE_ISO180006B
+TMR_Status
+TMR_SR_cmdISO180006BReadTagData(TMR_Reader *reader,
+                                uint16_t timeout, uint8_t address,
+                                uint8_t length, const TMR_TagFilter *filter,
+                                TMR_TagReadData *read)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t copylen, i;
+
+  if (length > 8
+      || filter == NULL
+      || TMR_FILTER_TYPE_TAG_DATA != filter->type
+      || filter->u.tagData.epcByteCount != 8)
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_READ_TAG_DATA);
+  SETU16(msg, i, timeout);
+  SETU8(msg, i, 0x01); /* Standard read operations */
+  SETU8(msg, i, TMR_SR_ISO180006B_COMMAND_READ);
+  SETU8(msg, i, 0x00); /* RFU */
+  SETU8(msg, i, length);
+  SETU8(msg, i, address);
+  memcpy(&msg[i], filter->u.tagData.epc, 8);
+  i += 8;
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  read->metadataFlags = TMR_TRD_METADATA_FLAG_DATA;
+  read->tag.protocol = TMR_TAG_PROTOCOL_ISO180006B;
+  read->tag.epcByteCount = 0;
+
+  read->data.len = msg[1];
+  copylen = (uint8_t)read->data.len;
+  if (copylen > read->data.max)
+  {
+    copylen = (uint8_t)read->data.max;
+  }
+  if (NULL != read->data.list)
+  {
+    memcpy(read->data.list, &msg[5], copylen);
+  }
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_SR_cmdISO180006BWriteTagData(TMR_Reader *reader,
+                                 uint16_t timeout, uint8_t address,
+                                 uint8_t count, const uint8_t data[],
+                                 const TMR_TagFilter *filter)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+
+  SETU8(msg, i, TMR_SR_OPCODE_WRITE_TAG_DATA);
+  SETU16(msg, i, timeout);
+  if (NULL != filter
+    && TMR_FILTER_TYPE_TAG_DATA == filter->type
+    && filter->u.tagData.epcByteCount == 8)
+  {
+    SETU8(msg, i, 
+          TMR_SR_ISO180006B_WRITE_OPTION_READ_VERIFY_AFTER
+          | TMR_SR_ISO180006B_WRITE_OPTION_COUNT_PROVIDED); 
+    SETU8(msg, i, TMR_SR_ISO180006B_COMMAND_WRITE4BYTE);
+    SETU8(msg, i, TMR_SR_ISO180006B_WRITE_LOCK_NO);
+    SETU8(msg, i, address);
+    memcpy(&msg[i], filter->u.tagData.epc, 8);
+    i += 8;
+  }
+  else
+  {
+    SETU8(msg, i, TMR_SR_ISO180006B_WRITE_OPTION_GROUP_SELECT 
+                  | TMR_SR_ISO180006B_WRITE_OPTION_COUNT_PROVIDED);
+    SETU8(msg, i, TMR_SR_ISO180006B_COMMAND_WRITE4BYTE_MULTIPLE);
+    SETU8(msg, i, TMR_SR_ISO180006B_WRITE_LOCK_NO);
+    SETU8(msg, i, address);
+    /* 
+     * Actually, we don't use password in case of iso.
+     * passing 1, instead of '0' fixes the crash.
+     */
+    ret = filterbytes(TMR_TAG_PROTOCOL_ISO180006B, filter, NULL,
+                      &i, msg, 1, false);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+  }
+  SETU16(msg, i, count);
+  memcpy(&msg[i], data, count);
+  i += count;
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+
+}
+
+
+TMR_Status
+TMR_SR_cmdISO180006BLockTag(TMR_Reader *reader, uint16_t timeout,
+                            uint8_t address, const TMR_TagFilter *filter)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  if (filter == NULL
+      || TMR_FILTER_TYPE_TAG_DATA != filter->type
+      || filter->u.tagData.epcByteCount != 8)
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_LOCK_TAG);
+  SETU16(msg, i, timeout);
+  SETU8(msg, i, TMR_SR_ISO180006B_LOCK_OPTION_TYPE_FOLLOWS);
+  SETU8(msg, i, TMR_SR_ISO180006B_LOCK_TYPE_QUERYLOCK_THEN_LOCK);
+  SETU8(msg, i, address);
+  memcpy(&msg[i], filter->u.tagData.epc, 8);
+  i += 8;
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+#endif /* TMR_ENABLE_ISO180006B */
+
+TMR_Status
+TMR_SR_cmdGEN2WriteTagData(TMR_Reader *reader,
+                           uint16_t timeout, TMR_GEN2_Bank bank,
+                           uint32_t address, uint8_t count,
+                           const uint8_t data[],
+                           TMR_GEN2_Password accessPassword,
+                           const TMR_TagFilter *filter)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t optbyte, i;
+
+  i = 2;
+  TMR_SR_msgAddGEN2DataWrite(msg, &i, timeout, bank, address);
+  optbyte = 5;
+  ret = filterbytes(TMR_TAG_PROTOCOL_GEN2, filter, &msg[optbyte], &i, msg,
+                    accessPassword, true);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  if (i + count + 1 > TMR_SR_MAX_PACKET_SIZE)
+  {
+    return TMR_ERROR_TOO_BIG;
+  }
+  memcpy(&msg[i], data, count);
+  i += count;
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+TMR_Status
+TMR_SR_cmdGEN2LockTag(TMR_Reader *reader, uint16_t timeout,
+                      uint16_t mask, uint16_t action, 
+                      TMR_GEN2_Password accessPassword, 
+                      const TMR_TagFilter *filter)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t optbyte, i;
+
+  i = 2;
+  TMR_SR_msgAddGEN2LockTag(msg, &i, timeout, mask, action, accessPassword);
+  optbyte = 5;
+  ret = filterbytes(TMR_TAG_PROTOCOL_GEN2, filter, &msg[optbyte], &i, msg,
+                    0, false);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+TMR_Status
+TMR_SR_cmdrebootReader(TMR_Reader *reader)
+{
+  TMR_Status ret;
+  TMR_SR_SerialReader *sr;
+  TMR_SR_SerialTransport *transport;
+
+  sr = &reader->u.serialReader;
+  transport = &sr->transport;
+
+  /*
+   * Drop baud to 9600 so we know for sure what it will be after going
+   * back to the bootloader.  (Older firmwares always revert to 9600.
+   * Newer ones keep the current baud rate.)
+   */
+  if (NULL != transport->setBaudRate)
+  {
+    /**
+     * some transport layer does not support baud rate settings.
+     * for ex: TCP transport. In that case skip the baud rate
+     * settings.
+     */ 
+
+    ret = TMR_SR_cmdSetBaudRate(reader, 9600);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+    ret = transport->setBaudRate(transport, 9600);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+  }
+  ret = TMR_SR_cmdBootBootloader(reader);
+  if ((TMR_SUCCESS != ret)
+      /* Invalid Opcode okay -- means "already in bootloader" */
+      && (TMR_ERROR_INVALID_OPCODE != ret))
+  {
+    return ret;
+  }
+
+  /*
+   * Wait for the bootloader to be entered. 200ms is enough.
+   */
+  tmr_sleep(200);
+
+  return ret;
+}
+
+TMR_Status
+TMR_SR_cmdKillTag(TMR_Reader *reader, uint16_t timeout,
+                  TMR_GEN2_Password killPassword, 
+                  const TMR_TagFilter *filter)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t optbyte, i;
+
+  i = 2;
+  TMR_SR_msgAddGEN2KillTag(msg, &i, timeout, killPassword);
+  optbyte = 5;
+  ret = filterbytes(TMR_TAG_PROTOCOL_GEN2, filter, &msg[optbyte], &i, msg, 
+                    0, false);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+
+TMR_Status
+TMR_SR_cmdGEN2ReadTagData(TMR_Reader *reader,
+                          uint16_t timeout, TMR_GEN2_Bank bank,
+                          uint32_t address, uint8_t length,
+                          uint32_t accessPassword, const TMR_TagFilter *filter,
+                          TMR_TagReadData *read)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t optbyte, i, mdfbyte;
+  uint32_t starttimeHigh, starttimeLow;
+
+  i = 2;
+  TMR_SR_msgAddGEN2DataRead(msg, &i, timeout, bank, address, length, 0x00, true);
+  optbyte = 5;
+  ret = filterbytes(TMR_TAG_PROTOCOL_GEN2, filter, &msg[optbyte], &i, msg, 
+                    accessPassword, true);
+
+
+  msg[optbyte] |= 0x10;
+  mdfbyte = 6;
+  read->metadataFlags |= TMR_TRD_METADATA_FLAG_DATA | TMR_TRD_METADATA_FLAG_PROTOCOL;
+  SETU16(msg, mdfbyte, read->metadataFlags);
+
+
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  msg[1] = i - 3; /* Install length */
+
+  /* Cache the read time so it can be put in tag read data later */
+  tm_gettime_consistent(&starttimeHigh, &starttimeLow);
+  reader->u.serialReader.readTimeHigh = starttimeHigh;
+  reader->u.serialReader.readTimeLow = starttimeLow;
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  if (NULL != read->data.list)
+  {
+  i = 8;
+   
+  TMR_SR_parseMetadataOnly(reader, read, read->metadataFlags , &i, msg);
+  TMR_SR_postprocessReaderSpecificMetadata(read, &reader->u.serialReader);
+
+  /* Read Tag Data doesn't put actual tag data inside the metadata fields.
+   * Read the actual data here (remainder of response.) */
+  {
+    uint16_t dataLength;
+    uint16_t copyLength;
+    
+    copyLength = dataLength = msg[1] + 5 - i;
+    if (copyLength > read->data.max)
+    {
+      copyLength = read->data.max;
+  }
+    read->data.len = copyLength;
+    memcpy(read->data.list, &msg[i], copyLength);
+    i += dataLength;
+  }
+  }
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_SR_cmdSetTxRxPorts(TMR_Reader *reader, uint8_t txPort, uint8_t rxPort)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_ANTENNA_PORT);
+  SETU8(msg, i, txPort);
+  SETU8(msg, i, rxPort);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status
+TMR_SR_cmdSetAntennaSearchList(TMR_Reader *reader, uint8_t count,
+                               const TMR_SR_PortPair *ports)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  uint8_t j;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_ANTENNA_PORT);
+  SETU8(msg, i, 2); /* logical antenna list option */
+  for (j = 0; j < count ; j++)
+  {
+    SETU8(msg, i, ports[j].txPort);
+    SETU8(msg, i, ports[j].rxPort);
+  }
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+TMR_Status
+TMR_SR_cmdSetAntennaPortPowersAndSettlingTime(
+  TMR_Reader *reader, uint8_t count, const TMR_SR_PortPowerAndSettlingTime *ports)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t j, i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_ANTENNA_PORT);
+  SETU8(msg, i, 4); /* power and settling time option */
+
+  for (j = 0; j < count; j++)
+  {
+    SETU8(msg, i, ports[j].port);
+    SETS16(msg, i, (int16_t) ports[j].readPower);
+    SETS16(msg, i, (int16_t)ports[j].writePower);
+    SETU16(msg, i, ports[j].settlingTime);
+  }
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status
+TMR_SR_cmdSetReadTxPower(TMR_Reader *reader, int32_t power)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_READ_TX_POWER);
+
+  /** The read power should always be a 16 bit value */
+  if (power > 32767 || power < -32768)
+  {
+    return TMR_ERROR_ILLEGAL_VALUE;
+  }
+
+  SETS16(msg,i, (int16_t)power);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status
+TMR_SR_cmdSetProtocol(TMR_Reader *reader, TMR_TagProtocol protocol)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_TAG_PROTOCOL);
+  SETU16(msg, i, protocol);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status
+TMR_SR_cmdSetWriteTxPower(TMR_Reader *reader, int32_t power)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_WRITE_TX_POWER);
+
+  /** The write power should always be a 16 bit value */
+  if (power > 32767 || power < -32768)
+  {
+    return TMR_ERROR_ILLEGAL_VALUE;
+  }
+
+  SETS16(msg, i, (int16_t)power);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status
+TMR_SR_cmdSetFrequencyHopTable(TMR_Reader *reader, uint8_t count,
+                               const uint32_t *table)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i, j;
+
+  i = 2;
+
+  if (count > 62)
+  {
+    return TMR_ERROR_TOO_BIG;
+  }
+
+  SETU8(msg, i, TMR_SR_OPCODE_SET_FREQ_HOP_TABLE);
+  for (j = 0; j < count; j++)
+  {
+    SETU32(msg, i, table[j]);
+  }
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status
+TMR_SR_cmdSetFrequencyHopTime(TMR_Reader *reader, uint32_t hopTime)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_FREQ_HOP_TABLE);
+  SETU8(msg, i, 1); /* hop time option */
+  SETU32(msg, i, hopTime);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status
+TMR_SR_cmdSetGPIO(TMR_Reader *reader, uint8_t gpio, bool high)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_USER_GPIO_OUTPUTS);
+  SETU8(msg, i, gpio);
+  SETU8(msg, i, (high == true));
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status
+TMR_SR_cmdSetRegion(TMR_Reader *reader, TMR_Region region)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_REGION);
+  SETU8(msg, i, region);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status
+TMR_SR_cmdSetRegionLbt(TMR_Reader *reader, TMR_Region region, bool lbt)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_REGION);
+  SETU8(msg, i, region);
+  SETU8(msg, i, lbt ? 1 : 0);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status
+TMR_SR_cmdSetPowerMode(TMR_Reader *reader, TMR_SR_PowerMode mode)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_POWER_MODE);
+  SETU8(msg, i, mode);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status
+TMR_SR_cmdSetUserMode(TMR_Reader *reader, TMR_SR_UserMode mode)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_USER_MODE);
+  SETU8(msg, i, mode);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status
+TMR_SR_cmdSetReaderConfiguration(TMR_Reader *reader, TMR_SR_Configuration key,
+                                 const void *value)
+{
+	TMR_SR_SerialReader *sr = &reader->u.serialReader;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_READER_OPTIONAL_PARAMS);
+  SETU8(msg, i, 1); /* key-value form of command */
+  SETU8(msg, i, key);
+
+  switch (key)
+  {
+  case TMR_SR_CONFIGURATION_ANTENNA_CONTROL_GPIO:
+    SETU8(msg, i, *(uint8_t *)value);
+    break;
+  case TMR_SR_CONFIGURATION_TRIGGER_READ_GPIO:
+    SETU8(msg, i, *(uint8_t *)value);
+    break;
+
+
+  case TMR_SR_CONFIGURATION_UNIQUE_BY_ANTENNA:
+  case TMR_SR_CONFIGURATION_UNIQUE_BY_DATA:
+  case TMR_SR_CONFIGURATION_UNIQUE_BY_PROTOCOL:
+    SETU8(msg, i, *(bool *)value ? 0 : 1);
+    break;
+  case TMR_SR_CONFIGURATION_TRANSMIT_POWER_SAVE:
+		if(TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0])
+		{
+			// Open loop power calibration
+			SETU8(msg, i, *(bool *)value ? 2 : 1);
+		}
+		else
+		{
+			// Closed loop power calibration
+			SETU8(msg, i, *(bool *)value ? 1 : 0);
+		}
+		break;
+  case TMR_SR_CONFIGURATION_EXTENDED_EPC:
+  case TMR_SR_CONFIGURATION_SAFETY_ANTENNA_CHECK:
+  case TMR_SR_CONFIGURATION_SAFETY_TEMPERATURE_CHECK:
+  case TMR_SR_CONFIGURATION_RECORD_HIGHEST_RSSI:
+  case TMR_SR_CONFIGURATION_RSSI_IN_DBM:
+  case TMR_SR_CONFIGURATION_SELF_JAMMER_CANCELLATION:
+  case TMR_SR_CONFIGURATION_ENABLE_READ_FILTER:
+  case TMR_SR_CONFIGURATION_SEND_CRC:
+    SETU8(msg, i, *(bool *)value ? 1 : 0);
+    break;
+
+  case TMR_SR_CONFIGURATION_READ_FILTER_TIMEOUT:
+    SETS32(msg, i, *(int32_t *)value);
+    break;
+
+  default:
+    return TMR_ERROR_NOT_FOUND;
+  }
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_send(reader, msg);
+}
+
+/**
+ * Handles license key to enable protocol 
+ *
+ * @param reader The reader
+ * @param option Option to set or erase the license key
+ * @param key license key
+ * @param key_len Length of license key or the key array
+ * @param retData The response data
+*/
+
+
+TMR_Status TMR_SR_cmdSetProtocolLicenseKey(TMR_Reader *reader, 
+										   TMR_SR_SetProtocolLicenseOption option, 
+										   uint8_t key[], int key_len,uint32_t *retData)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  TMR_Status ret;
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_PROTOCOL_LICENSEKEY);
+  SETU8(msg, i, option);
+
+  if(TMR_SR_SET_LICENSE_KEY == option)
+  {
+  memcpy(msg+i, key, key_len);
+  i+= key_len;
+  }
+
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (ret != TMR_SUCCESS)
+  {
+	  return ret;
+  }
+
+  reader->u.serialReader.versionInfo.protocols = 0x00;
+  for (i = 0; i < msg[1] - 2 ; i += 2)
+  {
+	reader->u.serialReader.versionInfo.protocols |= (1 << (GETU8AT(msg, 7 + i) - 1)); 
+  }
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_SR_cmdSetProtocolConfiguration(TMR_Reader *reader, TMR_TagProtocol protocol,
+                                   TMR_SR_ProtocolConfiguration key,
+                                   const void *value)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  uint8_t BLF = 0;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_PROTOCOL_PARAM);
+  SETU8(msg, i, protocol);
+  if (TMR_TAG_PROTOCOL_GEN2 == key.protocol)
+  {
+    SETU8(msg, i, key.u.gen2);
+    switch (key.u.gen2)
+    {
+    case TMR_SR_GEN2_CONFIGURATION_SESSION:
+      SETU8(msg, i, *(TMR_GEN2_Session *)value);
+      break;
+
+    case TMR_SR_GEN2_CONFIGURATION_TAGENCODING:
+      SETU8(msg, i, *(TMR_GEN2_TagEncoding *)value);
+      break;
+
+    case TMR_SR_GEN2_CONFIGURATION_LINKFREQUENCY:
+	#ifndef	BARE_METAL
+      switch (*(int *)value)
+	#else
+	  switch (*(TMR_GEN2_LinkFrequency *)value)
+    #endif
+      {
+      case 40:
+        BLF = 0x03;
+        break;
+      case 250:
+        BLF = 0x00;
+        break;
+      case 320:
+        BLF = 0x02;
+        break;
+      case 400:
+        BLF = 0x02;
+        break;
+      case 640:
+        BLF = 0x04;
+        break;
+      default:
+        return TMR_ERROR_INVALID;
+      }
+      SETU8(msg, i, BLF);
+      break;
+
+    case TMR_SR_GEN2_CONFIGURATION_TARI:
+      SETU8(msg, i, *(TMR_GEN2_Tari *)value);
+      break;
+
+	case TMR_SR_GEN2_CONFIGURATION_PROTCOLEXTENSION:
+	  SETU8(msg, i, *(TMR_GEN2_ProtocolExtension *)value);
+      break;
+      
+    case TMR_SR_GEN2_CONFIGURATION_TARGET:
+      switch (*(TMR_GEN2_Target *)value)
+      {
+      case TMR_GEN2_TARGET_A:
+        SETU16(msg, i, 0x0100);
+        break;
+      case TMR_GEN2_TARGET_B:
+        SETU16(msg, i, 0x0101);
+        break;
+      case TMR_GEN2_TARGET_AB:
+        SETU16(msg, i, 0x0000);
+        break;
+      case TMR_GEN2_TARGET_BA:
+        SETU16(msg, i, 0x0001);
+        break;
+      default:
+        return TMR_ERROR_INVALID;
+      }
+      break;
+      
+    case TMR_SR_GEN2_CONFIGURATION_Q:
+    {
+      const TMR_SR_GEN2_Q *q = value;
+      if (q->type == TMR_SR_GEN2_Q_DYNAMIC)
+      {
+        SETU8(msg, i, 0);
+      }
+      else if (q->type == TMR_SR_GEN2_Q_STATIC)
+      {
+        SETU8(msg, i, 1);
+        SETU8(msg, i, q->u.staticQ.initialQ);
+      }
+      else
+      {
+        return TMR_ERROR_INVALID;
+      }
+      break;
+    }
+
+    case TMR_SR_GEN2_CONFIGURATION_BAP:
+    {
+      TMR_GEN2_Bap *bap;
+      bap = (TMR_GEN2_Bap *)value;
+
+      SETU8(msg, i, 0x01); //version
+      SETU16(msg, i, 0x03);// currently we supports only this enable bits.
+      SETU32(msg, i, bap->powerUpDelayUs);
+      SETU32(msg, i, bap->freqHopOfftimeUs);
+      /**
+       * Currently support for M value and FlexQueryPayload has been disabled
+       * TO DO: add support for these parameters when firmware support has added for this.
+       **/ 
+      break;
+    }
+
+    default:
+      return TMR_ERROR_NOT_FOUND;
+    }
+  }
+#ifdef TMR_ENABLE_ISO180006B
+  else if (TMR_TAG_PROTOCOL_ISO180006B == key.protocol 
+           || TMR_TAG_PROTOCOL_ISO180006B_UCODE == key.protocol)
+  {
+    switch (key.u.iso180006b)
+    {
+    case TMR_SR_ISO180006B_CONFIGURATION_LINKFREQUENCY:
+      {
+      switch (*(int *)value)
+      {
+      case 40:
+        BLF = 0x01;
+        break;
+      case 160:
+        BLF = 0x00;
+        break;
+      default:
+        return TMR_ERROR_INVALID;
+      }
+        break;
+      }
+    case TMR_SR_ISO180006B_CONFIGURATION_MODULATION_DEPTH:
+      {
+        switch (*(int *)value)
+        {
+        case 0:
+          BLF = TMR_ISO180006B_Modulation99percent;
+          break;
+        case 1:
+          BLF = TMR_ISO180006B_Modulation11percent;
+          break;
+        default:
+          return TMR_ERROR_INVALID;
+        }
+        break;
+      }
+    case TMR_SR_ISO180006B_CONFIGURATION_DELIMITER:
+      {
+        switch (*(int *)value)
+        {
+        case 1:
+          BLF = TMR_ISO180006B_Delimiter1;
+          break;
+        case 4:
+          BLF = TMR_ISO180006B_Delimiter4;
+          break;
+        default:
+          return  TMR_ERROR_INVALID;
+        }
+        break;
+      }
+    default:
+      return TMR_ERROR_NOT_FOUND;
+    }
+
+    SETU8(msg, i, key.u.iso180006b);
+    SETU8(msg, i, BLF);
+  }
+#endif /* TMR_ENABLE_ISO180006B */
+  else
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  msg[1] = i - 3; /* Install length */
+  return TMR_SR_send(reader, msg);
+}
+
+
+TMR_Status TMR_SR_cmdGetTxRxPorts(TMR_Reader *reader, TMR_SR_PortPair *ant)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+
+  SETU8(msg, i, TMR_SR_OPCODE_GET_ANTENNA_PORT);
+  SETU8(msg, i, 0); /* just configured ports */
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  ant->txPort = msg[5];
+  ant->rxPort = msg[6];
+  
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_SR_cmdAntennaDetect(TMR_Reader *reader, uint8_t *count,
+                        TMR_SR_PortDetect *ports)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i, j; 
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_ANTENNA_PORT);
+  SETU8(msg, i, 5); /* antenna detect option */
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  
+  for (i = 1, j = 0; i < msg[1] && j < *count; i += 2, j++)
+  {
+    ports[j].port = msg[i + 5];
+    ports[j].detected = (msg[i + 6] == 1);
+  }
+  *count = j;
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_cmdGetAntennaPortPowersAndSettlingTime(
+  TMR_Reader *reader, uint8_t *count, TMR_SR_PortPowerAndSettlingTime *ports)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i, j;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_ANTENNA_PORT);
+  SETU8(msg, i, 4); /* power and settling time option */
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  
+  for (i = 1, j = 0; i < msg[1] && j < *count; i += 7, j++)
+  {
+    ports[j].port = GETU8AT(msg, i + 5);
+    ports[j].readPower = (int16_t)GETS16AT(msg, i + 6);
+    ports[j].writePower = (int16_t)GETS16AT(msg, i + 8);
+    ports[j].settlingTime = GETU16AT(msg, i + 10);
+  }
+  *count = j;
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_SR_cmdGetAntennaReturnLoss(TMR_Reader *reader, TMR_PortValueList *ports)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i, j, count;
+
+  count = TMR_SR_MAX_ANTENNA_PORTS;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_ANTENNA_PORT);
+  SETU8(msg, i, 6); /* antenna return loss option */
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  
+  for (i = 1, j = 0; i < msg[1] && j < count; i += 2, j++)
+  {
+    if (j < ports->max)
+    {
+      ports->list[j].port = (uint8_t)GETU8AT(msg, i + 5);
+      ports->list[j].value = (int16_t)GETU8AT(msg, i + 6);
+    }
+    else
+    {
+      /* no sufficent memory, break from here */
+      break;
+    }
+  }
+  ports->len = (uint8_t)j;
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_SR_cmdGetReadTxPower(TMR_Reader *reader, int32_t *power)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_READ_TX_POWER);
+  SETU8(msg, i, 0); /* just return power */
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  *power = (int32_t)GETS16AT(msg, 6);
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_cmdGetReadTxPowerWithLimits(TMR_Reader *reader,
+                                   TMR_SR_PowerWithLimits *power)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_READ_TX_POWER);
+  SETU8(msg, i, 1); /* return limits */
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  power->setPower = GETU16AT(msg, 6);
+  power->maxPower = GETU16AT(msg, 8);
+  power->minPower = GETU16AT(msg, 10);
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_cmdGetWriteTxPower(TMR_Reader *reader, int32_t *power)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_WRITE_TX_POWER);
+  SETU8(msg, i, 0); /* just return power */
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  *power = (int32_t)GETS16AT(msg, 6);
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_cmdGetFrequencyHopTable(TMR_Reader *reader, uint8_t *count,
+                               uint32_t *hopTable)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i, j, len;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_FREQ_HOP_TABLE);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  len = msg[1] / 4;
+  for (j = 0; i < *count && j < len ; j++)
+  {
+    hopTable[j] = GETU32AT(msg, 5 + 4*j);
+  }
+  *count = len;
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_cmdGetFrequencyHopTime(TMR_Reader *reader, uint32_t *hopTime)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_FREQ_HOP_TABLE);
+  SETU8(msg, i, 1); /* get time */
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  *hopTime = GETU32AT(msg, 6);
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_cmdGetGPIO(TMR_Reader *reader, uint8_t *count, TMR_GpioPin *state)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE] = {0};
+  uint8_t i, j, len, offset;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_USER_GPIO_INPUTS);
+  SETU8(msg, i, 0x01);  // option
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, reader->u.serialReader.commandTimeout);
+  if (TMR_SUCCESS != ret)
+    return ret;
+
+  len = (msg[1] - 1)/3;
+  if (len > *count)
+  {
+    len = *count;
+  }
+
+  offset = 6;
+  for (j = 0; j < len ; j++)
+  {
+    state[j].id = msg[offset++];
+    state[j].output = (1 == msg[offset++]) ? true : false;
+    state[j].high = (1 == msg[offset++]) ? true : false;
+  }
+  *count = len;
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_SR_cmdGetGPIODirection(TMR_Reader *reader, uint8_t pin, bool *out)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_USER_GPIO_OUTPUTS);
+  SETU8(msg, i, pin);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+    return ret;
+
+  *out = (msg[6] == 1);
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_cmdSetGPIODirection(TMR_Reader *reader, uint8_t pin, bool out)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_USER_GPIO_OUTPUTS);
+  SETU8(msg, i, 1); /* Option flag */
+  SETU8(msg, i, pin);
+  SETU8(msg, i, (out == true) ? 1 : 0);
+  SETU8(msg, i, 0); /* New value if output */
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+    return ret;
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status 
+TMR_SR_cmdGetCurrentProtocol(TMR_Reader *reader, TMR_TagProtocol *protocol)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_TAG_PROTOCOL);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  *protocol = (TMR_TagProtocol)GETU16AT(msg, 5);
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_SR_cmdGetRegion(TMR_Reader *reader, TMR_Region *region)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_REGION);
+  msg[1] = i - 3; /* Install length */
+  
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  *region = (TMR_Region)GETU8AT(msg, 5);
+  
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_SR_cmdGetRegionConfiguration(TMR_Reader *reader,
+                                 TMR_SR_RegionConfiguration key,
+                                 void *value)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_REGION);
+  SETU8(msg, i, 1);
+  SETU8(msg, i, key);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  switch (key)
+  {
+  case TMR_SR_REGION_CONFIGURATION_LBT_ENABLED:
+    *(bool *)value = (GETU8AT(msg, 8) == 1);
+    break;
+  default:
+    return TMR_ERROR_NOT_FOUND;
+  }
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_cmdGetPowerMode(TMR_Reader *reader, TMR_SR_PowerMode *mode)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_POWER_MODE);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  *mode = (TMR_SR_PowerMode)GETU8AT(msg, 5);
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_cmdGetUserMode(TMR_Reader *reader, TMR_SR_UserMode *mode)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_USER_MODE);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  *mode = (TMR_SR_UserMode)GETU8AT(msg, 5);
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_cmdGetReaderConfiguration(TMR_Reader *reader, TMR_SR_Configuration key,
+                                 void *value)
+{
+	TMR_SR_SerialReader *sr = &reader->u.serialReader;
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_READER_OPTIONAL_PARAMS);
+  SETU8(msg, i, 1); /* key-value form of command */
+  SETU8(msg, i, key);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  switch (key)
+  {
+  case TMR_SR_CONFIGURATION_ANTENNA_CONTROL_GPIO:
+    *(uint8_t *)value = GETU8AT(msg, 7);
+    break;
+  case TMR_SR_CONFIGURATION_TRIGGER_READ_GPIO:
+    *(uint8_t *)value = GETU8AT(msg, 7);
+    break;
+
+  case TMR_SR_CONFIGURATION_UNIQUE_BY_ANTENNA:
+  case TMR_SR_CONFIGURATION_UNIQUE_BY_DATA:
+  case TMR_SR_CONFIGURATION_UNIQUE_BY_PROTOCOL:
+    *(bool *)value = (GETU8AT(msg, 7) == 0);
+    break;
+  case TMR_SR_CONFIGURATION_TRANSMIT_POWER_SAVE:
+		if(TMR_SR_MODEL_MICRO == sr->versionInfo.hardware[0])
+		{
+			if(GETU8AT(msg, 7) == 2)
+			{
+				//Open loop power calibration
+				*(bool *)value = 1;
+			}
+			else
+			{
+				//Closed loop power calibration
+				*(bool *)value = 0;
+			}
+		}
+		else
+		{
+			*(bool *)value = (GETU8AT(msg, 7) == 1);
+		}
+		break;
+  case TMR_SR_CONFIGURATION_EXTENDED_EPC:
+  case TMR_SR_CONFIGURATION_SAFETY_ANTENNA_CHECK:
+  case TMR_SR_CONFIGURATION_SAFETY_TEMPERATURE_CHECK:
+  case TMR_SR_CONFIGURATION_RECORD_HIGHEST_RSSI:
+  case TMR_SR_CONFIGURATION_RSSI_IN_DBM:
+  case TMR_SR_CONFIGURATION_SELF_JAMMER_CANCELLATION:
+  case TMR_SR_CONFIGURATION_ENABLE_READ_FILTER:
+  case TMR_SR_CONFIGURATION_SEND_CRC:
+    *(bool *)value = (GETU8AT(msg, 7) == 1);
+    break;
+  case TMR_SR_CONFIGURATION_CURRENT_MSG_TRANSPORT:
+    *(uint8_t *)value = GETU8AT(msg, 7) ;
+    break;
+  case TMR_SR_CONFIGURATION_READ_FILTER_TIMEOUT:
+    *(uint32_t *)value = GETU32AT(msg, 7);
+    break;
+
+  case TMR_SR_CONFIGURATION_PRODUCT_GROUP_ID:
+    *(uint16_t *)value = GETU16AT(msg, 7);
+    break;
+
+  case TMR_SR_CONFIGURATION_PRODUCT_ID:
+    *(uint16_t *)value = GETU16AT(msg, 7);
+    break;
+
+  default:
+    return TMR_ERROR_NOT_FOUND;
+  }
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_SR_cmdGetProtocolConfiguration(TMR_Reader *reader, TMR_TagProtocol protocol,
+                                   TMR_SR_ProtocolConfiguration key,
+                                   void *value)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_PROTOCOL_PARAM);
+  SETU8(msg, i, protocol);
+  if (TMR_TAG_PROTOCOL_GEN2 == key.protocol)
+  {
+    SETU8(msg, i, key.u.gen2);
+  }
+#ifdef TMR_ENABLE_ISO180006B
+  else if (TMR_TAG_PROTOCOL_ISO180006B == key.protocol 
+           || TMR_TAG_PROTOCOL_ISO180006B_UCODE == key.protocol)
+  {
+    SETU8(msg, i, key.u.iso180006b);
+  }
+#endif
+  else
+  {
+    return TMR_ERROR_INVALID;
+  }
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  if (TMR_TAG_PROTOCOL_GEN2 == key.protocol)
+  {
+    switch (key.u.gen2)
+    {
+    case TMR_SR_GEN2_CONFIGURATION_SESSION:
+      *(TMR_GEN2_Session *)value = (TMR_GEN2_Session)GETU8AT(msg, 7);
+      break;
+
+    case TMR_SR_GEN2_CONFIGURATION_TAGENCODING:
+      *(TMR_GEN2_TagEncoding *)value = (TMR_GEN2_TagEncoding)GETU8AT(msg, 7);
+      break;
+
+    case TMR_SR_GEN2_CONFIGURATION_LINKFREQUENCY:
+      *(TMR_GEN2_LinkFrequency *)value = (TMR_GEN2_LinkFrequency)GETU8AT(msg, 7);
+      break;
+
+    case TMR_SR_GEN2_CONFIGURATION_TARI:
+      *(TMR_GEN2_Tari *)value = (TMR_GEN2_Tari)GETU8AT(msg, 7);
+      break;
+
+	case TMR_SR_GEN2_CONFIGURATION_PROTCOLEXTENSION:
+	  *(TMR_GEN2_ProtocolExtension *)value = (TMR_GEN2_ProtocolExtension)GETU8AT(msg, 7);
+      break;
+
+    case TMR_SR_GEN2_CONFIGURATION_BAP:
+      {
+        TMR_GEN2_Bap *b = value;
+
+        i = 10;
+        b->powerUpDelayUs = GETU32(msg,i);
+        b->freqHopOfftimeUs = GETU32(msg,i);
+        break;
+      }
+
+    case TMR_SR_GEN2_CONFIGURATION_TARGET:
+      {
+        uint16_t target;
+
+        target = GETU16AT(msg, 7);
+        switch (target)
+        {
+        case 0x0100:
+          *(TMR_GEN2_Target *)value = TMR_GEN2_TARGET_A;
+          break;
+        case 0x0101:
+          *(TMR_GEN2_Target *)value = TMR_GEN2_TARGET_B;
+          break;
+        case 0x0000:
+          *(TMR_GEN2_Target *)value = TMR_GEN2_TARGET_AB;
+          break;
+        case 0x0001:
+          *(TMR_GEN2_Target *)value = TMR_GEN2_TARGET_BA;
+          break;
+        default:
+          *(TMR_GEN2_Target *)value = TMR_GEN2_TARGET_INVALID;
+        }
+        break;
+      }
+
+    case TMR_SR_GEN2_CONFIGURATION_Q:
+      {
+        TMR_SR_GEN2_Q *q = value;
+
+        q->type = (TMR_SR_GEN2_QType)GETU8AT(msg, 7);
+        if (q->type == TMR_SR_GEN2_Q_DYNAMIC)
+        {
+          ; /* No further data to get */
+        }
+        else if (q->type == TMR_SR_GEN2_Q_STATIC)
+        {
+          q->u.staticQ.initialQ = GETU8AT(msg, 8);
+        }
+        break;
+      }
+
+    default:
+      return TMR_ERROR_NOT_FOUND;
+    }
+  }
+#ifdef TMR_ENABLE_ISO180006B
+  else if (TMR_TAG_PROTOCOL_ISO180006B == key.protocol 
+    || TMR_TAG_PROTOCOL_ISO180006B_UCODE == key.protocol)
+  {
+    switch (key.u.iso180006b)
+    {
+    case TMR_SR_ISO180006B_CONFIGURATION_LINKFREQUENCY:
+      {
+    TMR_iso18000BBLFValToInt(GETU8AT(msg, 7), value);
+        break;
+  }
+    case TMR_SR_ISO180006B_CONFIGURATION_MODULATION_DEPTH:
+      {
+        uint8_t val;
+        val = GETU8AT(msg, 7);
+        switch (val)
+        {
+        case 0:
+          *(TMR_ISO180006B_ModulationDepth *)value = TMR_ISO180006B_Modulation99percent;
+          break;
+        case 1:
+          *(TMR_ISO180006B_ModulationDepth *)value = TMR_ISO180006B_Modulation11percent;
+          break;
+        default:
+          return TMR_ERROR_NOT_FOUND;
+        }
+        break;
+      }
+    case TMR_SR_ISO180006B_CONFIGURATION_DELIMITER:
+      {
+        uint8_t val;
+        val = GETU8AT(msg, 7);
+        switch (val)
+        {
+        case 1:
+          *(TMR_ISO180006B_Delimiter *)value = TMR_ISO180006B_Delimiter1;
+          break;
+        case 4:
+          *(TMR_ISO180006B_Delimiter *)value = TMR_ISO180006B_Delimiter4;
+          break;
+        default:
+          return TMR_ERROR_NOT_FOUND;
+        }
+        break;
+      }
+    default:
+      return TMR_ERROR_NOT_FOUND;
+      }
+    }  
+#endif /* TMR_ENABLE_ISO180006B */
+  else
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status TMR_iso18000BBLFValToInt(int val, void *lf)
+{
+  switch (val)
+  {
+    case 1:
+	  *(TMR_ISO180006B_LinkFrequency *)lf = TMR_ISO180006B_LINKFREQUENCY_40KHZ;
+	  break;
+	case 0:
+	  *(TMR_ISO180006B_LinkFrequency *)lf = TMR_ISO180006B_LINKFREQUENCY_160KHZ;
+	  break;
+	default:
+      return TMR_ERROR_NOT_FOUND;
+  }
+  return TMR_SUCCESS;
+}
+
+/* Helper function to frame the multiple protocol search command */
+TMR_Status 
+TMR_SR_msgSetupMultipleProtocolSearch(TMR_Reader *reader, uint8_t *msg, TMR_SR_OpCode op, TMR_TagProtocolList *protocols, TMR_TRD_MetadataFlag metadataFlags, TMR_SR_SearchFlag antennas, TMR_TagFilter **filter, uint16_t timeout)
+{
+  TMR_Status ret;
+  uint8_t i;
+  uint32_t j;
+  uint16_t subTimeout;
+
+  ret = TMR_SUCCESS;
+  i=2;
+
+  SETU8(msg, i, TMR_SR_OPCODE_MULTI_PROTOCOL_TAG_OP);  //Opcode
+  if(reader->continuousReading)
+  {
+    /* Timeout should be zero for true continuous reading */
+    SETU16(msg, i, 0);
+    SETU8(msg, i, (uint8_t)0x1);//TM Option 1, for continuous reading
+  }
+  else
+  {
+    SETU16(msg, i, timeout); //command timeout
+    SETU8(msg, i, (uint8_t)0x11);//TM Option, turns on metadata
+    SETU16(msg, i, (uint16_t)metadataFlags);
+  }
+
+  SETU8(msg, i, (uint8_t)op);//sub command opcode
+
+  if (TMR_READ_PLAN_TYPE_MULTI == reader->readParams.readPlan->type)
+  {
+    reader->isStopNTags = false;
+    /**
+    * in case of multi read plan look for the stop N trigger option
+    **/
+    for (j = 0; j < reader->readParams.readPlan->u.multi.planCount; j++)
+    {
+      if (reader->readParams.readPlan->u.multi.plans[j]->u.simple.stopOnCount.stopNTriggerStatus)
+      {
+        reader->numberOfTagsToRead += reader->readParams.readPlan->u.multi.plans[j]->u.simple.stopOnCount.noOfTags;
+        reader->isStopNTags = true;
+      }
+    }
+  }
+  else
+  {
+    reader->numberOfTagsToRead += reader->readParams.readPlan->u.simple.stopOnCount.noOfTags;
+  }
+
+  if (reader->isStopNTags && !reader->continuousReading)
+  {
+    /**
+    * True means atlest one sub read plan has the requested for stop N trigger.
+    * Enable the flag and add the total tag count. This is only supported for sync read
+    * case.
+    */
+    SETU16(msg, i, (uint16_t)TMR_SR_SEARCH_FLAG_RETURN_ON_N_TAGS);
+    SETU32(msg, i, reader->numberOfTagsToRead);
+  }
+  else
+  {
+    SETU16(msg, i, (uint16_t)0x0000);//search flags, only 0x0001 is supported
+  }
+
+  /**
+  * TODO:add the timeout as requested by the user
+  **/
+  subTimeout =(uint16_t)(timeout/(protocols->len));
+  for (j=0;j<protocols->len;j++) // iterate through the protocol search list
+  {
+    int PLenIdx;
+
+
+    TMR_TagProtocol subProtocol=protocols->list[j];
+    SETU8(msg, i, (uint8_t)(subProtocol)); //protocol ID
+    PLenIdx = i;
+    SETU8(msg, i, 0); //PLEN
+
+    /**
+    * in case of multi readplan and the total weight is not zero,
+    * we should use the weight as provided by the user.
+    **/
+    if (TMR_READ_PLAN_TYPE_MULTI == reader->readParams.readPlan->type)
+    {
+      if (0 != reader->readParams.readPlan->u.multi.totalWeight)
+      {
+        subTimeout = (uint16_t)(reader->readParams.readPlan->u.multi.plans[j]->weight * timeout
+          / reader->readParams.readPlan->u.multi.totalWeight);
+      }
+    }
+
+    /**
+    * In case of Multireadplan, check each simple read plan FastSearch option and
+    * stop N trigger option.
+    */
+    if (TMR_READ_PLAN_TYPE_MULTI == reader->readParams.readPlan->type)
+    {
+      reader->fastSearch = reader->readParams.readPlan->u.multi.plans[j]->u.simple.useFastSearch;
+      reader->triggerRead = reader->readParams.readPlan->u.multi.plans[j]->u.simple.triggerRead.enable;
+      reader->isStopNTags = false;
+      reader->isStopNTags = reader->readParams.readPlan->u.multi.plans[j]->u.simple.stopOnCount.stopNTriggerStatus;
+      reader->numberOfTagsToRead = reader->readParams.readPlan->u.multi.plans[j]->u.simple.stopOnCount.noOfTags;
+    }
+
+    switch(op)
+    {
+    case TMR_SR_OPCODE_READ_TAG_ID_SINGLE :
+      {
+        ret = TMR_SR_msgSetupReadTagSingle(msg, &i, subProtocol,metadataFlags, filter[j], subTimeout);
+        break;
+      }
+    case TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE:
+      {
+        /**
+        * simple read plan uses this function, only when tagop is NULL,
+        * s0, need to check for simple read plan tagop.
+        **/
+        if (TMR_READ_PLAN_TYPE_MULTI == reader->readParams.readPlan->type)
+        {
+          /* check for the tagop */
+          if (NULL != reader->readParams.readPlan->u.multi.plans[j]->u.simple.tagop)
+          {
+            uint32_t readTimeMs = (uint32_t)subTimeout;
+            uint8_t lenbyte = 0;
+            //add the tagoperation here
+            ret = TMR_SR_addTagOp(reader,reader->readParams.readPlan->u.multi.plans[j]->u.simple.tagop,
+              reader->readParams.readPlan->u.multi.plans[j], msg, &i, readTimeMs, &lenbyte);
+          }
+          else
+          {
+            ret = TMR_SR_msgSetupReadTagMultipleWithMetadata(reader, msg, &i, subTimeout, antennas, metadataFlags ,filter[j], subProtocol, 0);
+          }
+        }
+        else
+        {
+          if (NULL != reader->readParams.readPlan->u.simple.tagop)
+          {
+            uint32_t readTimeMs = (uint32_t)subTimeout;
+            uint8_t lenbyte = 0;
+            //add the tagoperation here
+            ret = TMR_SR_addTagOp(reader, reader->readParams.readPlan->u.simple.tagop,
+              reader->readParams.readPlan, msg, &i, readTimeMs, &lenbyte);
+          }
+          else
+          {
+            ret = TMR_SR_msgSetupReadTagMultipleWithMetadata(reader, msg, &i, subTimeout, antennas, metadataFlags ,filter[j], subProtocol, 0);
+          }
+        }
+        break;
+      }
+    default :
+      {
+        return TMR_ERROR_INVALID_OPCODE;          
+      }
+    }
+
+    msg[PLenIdx]= i - PLenIdx - 2; //PLEN
+    msg[1]=i - 3;
+  }
+  return ret;
+}
+
+TMR_Status TMR_SR_cmdMultipleProtocolSearch(TMR_Reader *reader,TMR_SR_OpCode op,TMR_TagProtocolList *protocols, TMR_TRD_MetadataFlag metadataFlags,TMR_SR_SearchFlag antennas, TMR_TagFilter **filter, uint16_t timeout, uint32_t *tagsFound)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  TMR_SR_SerialReader *sr;
+
+  sr = &reader->u.serialReader;
+  *tagsFound = 0 ;
+
+  ret = TMR_SR_msgSetupMultipleProtocolSearch(reader, msg, op, protocols, metadataFlags, antennas, filter, timeout);
+  if (ret != TMR_SUCCESS)
+  {
+    return ret;
+  }
+
+  if (op == TMR_SR_OPCODE_READ_TAG_ID_SINGLE)
+  {
+    uint8_t opcode;
+
+    sr->opCode = op;
+    ret = TMR_SR_sendMessage(reader, msg, &opcode, timeout);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+    sr->tagsRemaining = 1;
+  }
+
+  if (op == TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE)
+  {
+    sr->opCode = op;
+    if(reader->continuousReading)
+    {
+      uint8_t opcode;
+      ret = TMR_SR_sendMessage(reader, msg, &opcode, timeout);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+	  reader->hasContinuousReadStarted = true;
+      sr->tagsRemaining=1;
+    }
+    else
+    {
+      ret = TMR_SR_sendTimeout(reader, msg, timeout);
+      if (TMR_ERROR_NO_TAGS_FOUND == ret)
+      {
+        sr->tagsRemaining = *tagsFound = 0;
+        return ret;
+      }
+      else if ((TMR_ERROR_TM_ASSERT_FAILED == ret) ||
+        (TMR_ERROR_TIMEOUT == ret))
+      {
+        return ret;
+      }
+      else if (TMR_SUCCESS != ret)
+      {
+        uint16_t remainingTagsCount;
+        TMR_Status ret1;
+
+        /* Check for the tag count (in case of module error)*/
+        ret1 = TMR_SR_cmdGetTagsRemaining(reader, &remainingTagsCount);
+        if (TMR_SUCCESS != ret1)
+        {
+          return ret1;
+        }
+
+        *tagsFound = remainingTagsCount;
+        sr->tagsRemaining = *tagsFound;
+        return ret;
+      }
+
+      *tagsFound = GETU32AT(msg , 9);
+      sr->tagsRemaining = *tagsFound;
+    }
+  }
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_SR_cmdGetAvailableProtocols(TMR_Reader *reader,
+                                TMR_TagProtocolList *protocols)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_AVAILABLE_PROTOCOLS);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  protocols->len = 0;
+  for (i = 0; i < msg[1] ; i += 2)
+  {
+    LISTAPPEND(protocols, (TMR_TagProtocol)GETU16AT(msg, 5 + i)); 
+  }
+
+  reader->u.serialReader.versionInfo.protocols = 0x0000;
+  for (i = 0 ; i < protocols->len; i ++)
+  {
+    reader->u.serialReader.versionInfo.protocols |= (1 << (protocols->list[i] - 1)); 
+  }
+  
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_SR_cmdGetAvailableRegions(TMR_Reader *reader, TMR_RegionList *regions)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_AVAILABLE_REGIONS);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  regions->len = 0;
+  for (i = 0; i < msg[1] ; i++)
+  {
+    LISTAPPEND(regions, (TMR_Region)GETU8AT(msg, 5 + i)); 
+  }
+
+  return TMR_SUCCESS;
+}
+
+
+
+TMR_Status
+TMR_SR_cmdGetTemperature(TMR_Reader *reader, int8_t *temp)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_GET_TEMPERATURE);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  *temp = msg[5];
+  return TMR_SUCCESS;
+}
+
+
+static TMR_Status
+filterbytes(TMR_TagProtocol protocol, const TMR_TagFilter *filter, 
+            uint8_t *option, uint8_t *i, uint8_t *msg,
+            uint32_t accessPassword, bool usePassword)
+{
+  int j;
+  if (isSecureAccessEnabled)
+  {
+    *option = TMR_SR_GEN2_SINGULATION_OPTION_SECURE_READ_DATA;
+  }
+
+  if (NULL == filter && 0 == accessPassword)
+  {
+    *option = 0x00;
+    return TMR_SUCCESS;
+  }
+
+  if (TMR_TAG_PROTOCOL_GEN2 == protocol)
+  {
+    if (usePassword)
+    {
+		if (filter && TMR_FILTER_TYPE_GEN2_SELECT == filter->type)
+		{
+			if (filter->u.gen2Select.bank != TMR_GEN2_EPC_LENGTH_FILTER)
+				SETU32(msg, *i, accessPassword);
+		}
+		else
+		{
+			SETU32(msg, *i, accessPassword);
+		}
+    }
+    if (NULL == filter)
+    {
+      *option |= TMR_SR_GEN2_SINGULATION_OPTION_USE_PASSWORD;
+    }
+    else if (TMR_FILTER_TYPE_GEN2_SELECT == filter->type)
+    {
+      const TMR_GEN2_Select *fp;
+
+      fp = &filter->u.gen2Select;
+
+      if (1 == fp->bank)
+      {
+        *option |= TMR_SR_GEN2_SINGULATION_OPTION_SELECT_ON_ADDRESSED_EPC;
+      }
+      else /* select based on the bank */
+      {
+        *option |= fp->bank;
+      }
+
+	  if (fp->bank == TMR_GEN2_EPC_LENGTH_FILTER)
+	  {
+		  SETU16(msg, *i, fp->maskBitLength);
+	  }
+	  else
+	  {
+		  if(true == fp->invert)
+		  {
+			*option |= TMR_SR_GEN2_SINGULATION_OPTION_INVERSE_SELECT_BIT;
+		  }
+
+		  if (fp->maskBitLength > 255)
+		  {
+			*option |= TMR_SR_GEN2_SINGULATION_OPTION_EXTENDED_DATA_LENGTH;
+		  }
+
+		  SETU32(msg, *i, fp->bitPointer);
+
+		  if (fp->maskBitLength > 255)
+		  {
+			SETU8(msg, *i, (fp->maskBitLength >> 8) & 0xFF);
+		  }
+		  SETU8(msg, *i, fp->maskBitLength & 0xFF);
+
+		  if (*i + 1 + tm_u8s_per_bits(fp->maskBitLength) > TMR_SR_MAX_PACKET_SIZE)
+		  {
+			return TMR_ERROR_TOO_BIG;
+		  }
+
+		  for(j = 0; j < tm_u8s_per_bits(fp->maskBitLength) ; j++)
+		  {
+			SETU8(msg, *i, fp->mask[j]);
+		  }
+	  }
+    }
+    else if (TMR_FILTER_TYPE_TAG_DATA == filter->type)
+    {
+      const TMR_TagData *fp;
+      int bitCount;
+
+      fp = &filter->u.tagData;
+      bitCount = fp->epcByteCount * 8;
+
+      /* select on the EPC */
+      *option |= 1;
+      if (bitCount > 255)
+      {
+        *option |= TMR_SR_GEN2_SINGULATION_OPTION_EXTENDED_DATA_LENGTH;
+        SETU8(msg, *i, (bitCount>>8) & 0xFF);
+      }
+      SETU8(msg, *i, (bitCount & 0xFF));
+
+      if (*i + 1 + fp->epcByteCount > TMR_SR_MAX_PACKET_SIZE)
+      {
+        return TMR_ERROR_TOO_BIG;
+      }
+
+      for(j = 0 ; j < fp->epcByteCount ; j++)
+      {
+        SETU8(msg, *i, fp->epc[j]);
+      }
+    }
+    else
+    {
+      return TMR_ERROR_INVALID;
+    }
+  }
+#ifdef TMR_ENABLE_ISO180006B
+  else if (TMR_TAG_PROTOCOL_ISO180006B == protocol)
+  {
+    if (option)
+    {
+      *option = 1;
+    }
+    
+    if (NULL == filter)
+    {
+       /* Set up a match-anything filter, since it isn't the default */
+      SETU8(msg, *i, TMR_ISO180006B_SELECT_OP_EQUALS);
+      SETU8(msg, *i, 0); /* address */
+      SETU8(msg, *i, 0); /* mask - don't compare anything */
+      SETU32(msg, *i, 0); /* dummy tag ID bytes 0-3, not compared */
+      SETU32(msg, *i, 0); /* dummy tag ID bytes 4-7, not compared */
+      return TMR_SUCCESS;
+    }
+    else if (TMR_FILTER_TYPE_ISO180006B_SELECT == filter->type)
+    {
+      const TMR_ISO180006B_Select *fp;
+      
+      fp = &filter->u.iso180006bSelect;
+      if (false == fp->invert)
+      {
+        SETU8(msg, *i, fp->op);
+      }
+      else
+      {
+        SETU8(msg, *i, fp->op | 4);
+      }
+      SETU8(msg, *i, fp->address);
+      SETU8(msg, *i, fp->mask);
+      for (j = 0 ; j < 8 ; j++)
+      {
+        SETU8(msg, *i, fp->data[j]);
+      }
+    }
+    else if (TMR_FILTER_TYPE_TAG_DATA == filter->type)
+    {
+      const TMR_TagData *fp;
+      uint8_t mask;
+
+      fp = &filter->u.tagData;
+
+      if (fp->epcByteCount > 8)
+      {
+        return TMR_ERROR_INVALID;
+      }
+
+      /* Convert the byte count to a MSB-based bit mask */
+      mask = (0xff00 >> fp->epcByteCount) & 0xff;
+
+      SETU8(msg, *i, TMR_ISO180006B_SELECT_OP_EQUALS);
+      SETU8(msg, *i, 0); /* Address - EPC is at the start of memory */
+      SETU8(msg, *i, mask);
+      for (j = 0 ; j < fp->epcByteCount; j++)
+      {
+        SETU8(msg, *i, fp->epc[j]);
+      }
+      for ( ; j < 8 ; j++)
+      {
+        SETU8(msg, *i, 0); /* EPC data must be 8 bytes */
+      }
+    }
+    else
+    {
+      return TMR_ERROR_INVALID;
+    }
+    
+  }
+#endif /* TMR_ENABLE_ISO180006B */
+  else
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  return TMR_SUCCESS;
+}
+
+/** 
+ *  Alien Higgs2 and Higgs3 Specific Commands
+ **/
+
+/** Helper routine to form the Higgs2 Partial Load Image command **/
+void TMR_SR_msgAddHiggs2PartialLoadImage(uint8_t *msg, uint8_t *i, uint16_t timeout,
+      TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword, uint8_t len, const uint8_t *epc, TMR_TagFilter* target)
+{
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_ALIEN_HIGGS_SILICON);  /* Chip - type*/
+  SETU8(msg, *i, (uint8_t)0x01);  /* Sub command, partial load image */
+  SETU32(msg, *i, killPassword);
+  SETU32(msg, *i, accessPassword);
+  memcpy(&msg[*i], epc, len);
+  *i += len;
+}
+/**
+ * Partial Load Image (only 96-bit EPC with no user memory versions)
+ * Chip type = 0x01
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to write on the tag
+ * @param killPassword The kill password to write on the tag
+ * @param len Length of the EPC
+ * @param epc The EPC to write to the tag. Maximum of 12 bytes (96 bits)
+ * @param target Filter to be applied.
+ */
+TMR_Status TMR_SR_cmdHiggs2PartialLoadImage(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword, 
+            uint8_t len, const uint8_t epc[], TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  if(NULL != target)
+  {
+    return TMR_ERROR_UNSUPPORTED;
+  }
+  TMR_SR_msgAddHiggs2PartialLoadImage(msg, &i, timeout, accessPassword, killPassword, len, epc, target);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+
+/** Helper routine to form the Higgs2 Full Load Image command **/
+void TMR_SR_msgAddHiggs2FullLoadImage(uint8_t *msg, uint8_t *i, uint16_t timeout,
+      TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword, uint16_t lockBits, uint16_t pcWord, uint8_t len, const uint8_t *epc, TMR_TagFilter* target)
+{
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_ALIEN_HIGGS_SILICON);  /* Chip - type*/
+  SETU8(msg, *i, (uint8_t)0x03);  /* Sub command, full load image */
+  SETU32(msg, *i, killPassword);
+  SETU32(msg, *i, accessPassword);
+  SETU16(msg, *i, lockBits);
+  SETU16(msg, *i, pcWord);
+  memcpy(&msg[*i], epc, len);
+  *i += len;
+}
+/**
+ * Full Load Image (only 96-bit EPC with no user memory versions)
+ * Chip type = 0x01
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to write on the tag
+ * @param killPassword The kill password to write on the tag
+ * @param lockBits locking the tag according to the Alien Higgs LockBits
+ * @param pcWord PC Word in the Tag EPC memBank defined in the Gen2 Specification
+ * @param len Length of the EPC
+ * @param epc The EPC to write to the tag. Maximum of 12 bytes (96 bits)
+ * @param target Filter to be applied.
+ */
+TMR_Status TMR_SR_cmdHiggs2FullLoadImage(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword,
+            uint16_t lockBits, uint16_t pcWord, uint8_t len,
+            const uint8_t epc[], TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  if(NULL != target)
+  {
+    return TMR_ERROR_UNSUPPORTED;
+  }
+  TMR_SR_msgAddHiggs2FullLoadImage(msg, &i, timeout, accessPassword, killPassword, lockBits, pcWord, len, epc, target);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/** Helper routine to form the Higgs3 Fast Load Image command **/
+void TMR_SR_msgAddHiggs3FastLoadImage(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password currentAccessPassword,
+      TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword, uint16_t pcWord, uint8_t len, const uint8_t *epc, TMR_TagFilter* target)
+{
+  uint8_t option=0,rec; 
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_ALIEN_HIGGS3_SILICON);  /* Chip - type*/
+  
+  rec=*i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)0x01);  /* Sub command, fast load image */
+  
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, 0, false); 
+  msg[rec]=msg[rec]|option;
+
+  SETU32(msg, *i, currentAccessPassword);
+  SETU32(msg, *i, killPassword);
+  SETU32(msg, *i, accessPassword);
+  SETU16(msg, *i, pcWord);
+  memcpy(&msg[*i], epc, len);
+  *i += len;
+}
+/**
+ * Higgs3 Fast Load Image (only 96-bit EPC)
+ * Chip type = 0x05
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param currentAccessPassword The access password to use to write to the tag
+ * @param accessPassword The access password to write on the tag
+ * @param killPassword The kill password to write on the tag
+ * @param pcWord PC Word in the Tag EPC memBank defined in the Gen2 Specification
+ * @param len Length of the EPC
+ * @param epc The EPC to write to the tag. Maximum of 12 bytes (96 bits)
+ * @param target Filter to be applied.
+ */
+TMR_Status 
+TMR_SR_cmdHiggs3FastLoadImage(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password currentAccessPassword, TMR_GEN2_Password accessPassword, 
+            TMR_GEN2_Password killPassword, uint16_t pcWord, uint8_t len, const uint8_t epc[], TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddHiggs3FastLoadImage(msg, &i, timeout, currentAccessPassword, accessPassword, killPassword, pcWord, len, epc, target);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/** Helper routine to form the Higgs3 Load Image command **/
+void TMR_SR_msgAddHiggs3LoadImage(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password currentAccessPassword,
+      TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword, uint16_t pcWord, uint8_t len, const uint8_t *epcAndUserData, TMR_TagFilter* target)
+{
+  uint8_t option=0,rec; 
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_ALIEN_HIGGS3_SILICON);  /* Chip - type*/
+  
+  rec=*i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)0x03);  /* Sub command, Load image */
+
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, 0, false); 
+  msg[rec]=msg[rec]|option;
+
+  SETU32(msg, *i, currentAccessPassword);
+  SETU32(msg, *i, killPassword);
+  SETU32(msg, *i, accessPassword);
+  SETU16(msg, *i, pcWord);
+  memcpy(&msg[*i], epcAndUserData, len);
+  *i += len;
+}
+
+/**
+ * Higgs3 Load Image 
+ * Chip type = 0x05
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param currentAccessPassword The access password to use to write to the tag
+ * @param accessPassword The access password to write on the tag
+ * @param killPassword The kill password to write on the tag
+ * @param pcWord PC Word in the Tag EPC memBank defined in the Gen2 Specification
+ * @param len Length of epcAndUserData
+ * @param epcAndUserData The EPC and user data to write to the tag. Must be exactly 76 bytes. 
+ *                       The pcWord specifies which of this is EPC and which is user data.
+ * @param target Filter to be applied.
+ */
+TMR_Status TMR_SR_cmdHiggs3LoadImage(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password currentAccessPassword,
+            TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword,
+            uint16_t pcWord, uint8_t len, const uint8_t epcAndUserData[], TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddHiggs3LoadImage(msg, &i, timeout, currentAccessPassword, accessPassword, 
+                                killPassword, pcWord, len, epcAndUserData, target);  /* Length of epcAndUserData must be 76 */
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/** Helper routine to form the Higgs3 Block Read Lock command**/
+void TMR_SR_msgAddHiggs3BlockReadLock(uint8_t *msg, uint8_t *i, uint16_t timeout, 
+          TMR_GEN2_Password accessPassword, uint8_t lockBits, TMR_TagFilter* target)
+{
+  uint8_t option=0,rec; 
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_ALIEN_HIGGS3_SILICON);  /* Chip - type*/
+  
+  rec=*i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)0x09);  /* Sub command, Block Read Lock */
+  
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, 0, false); 
+  msg[rec]=msg[rec]|option;
+
+  SETU32(msg, *i, accessPassword);
+  SETU8(msg, *i, lockBits);
+}
+
+/**
+ * Higgs3 Block Read Lock 
+ * Chip type = 0x05
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param lockBits A bitmask of bits to lock. Valid range 0-255
+ * @param target Filter to be applied.
+ */
+TMR_Status TMR_SR_cmdHiggs3BlockReadLock(TMR_Reader *reader, uint16_t timeout,
+            TMR_GEN2_Password accessPassword, uint8_t lockBits, TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddHiggs3BlockReadLock(msg, &i, timeout, accessPassword, lockBits, target);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/** 
+ *  NXP Silicon (G2xL and G2iL) Specific Commands
+ *  Chip Type = 0x02 and 0x07
+ **/
+
+/** Helper routine to form the NXP Set Read Protect command**/
+void TMR_SR_msgAddNXPSetReadProtect(uint8_t *msg, uint8_t *i, uint16_t timeout,
+                TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, TMR_TagFilter* target)
+{
+  uint8_t option=0,rec; 
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)chip);  /* Chip - type*/
+  
+  rec=*i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)0x01);  /* Sub command, Set Read Protect */
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, 0, false);
+  msg[rec]=msg[rec]|option;
+  
+  SETU32(msg, *i, accessPassword);
+}
+
+/** Helper routine to form the NXP Set Read Protect command**/
+void TMR_SR_msgAddNXPResetReadProtect(uint8_t *msg, uint8_t *i, uint16_t timeout,
+                TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, TMR_TagFilter* target)
+{
+  uint8_t option=0,rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)chip);  /* Chip - type*/
+  
+  rec=*i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)0x02);  /* Sub command, Reset Read Protect */
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, 0, false); 
+  msg[rec]=msg[rec]|option;
+  
+  SETU32(msg, *i, accessPassword);
+}
+
+/**
+ * NXP Set Read Protect
+ * Chip type = 0x02 or 0x07, Command = 0x01
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param chip The NXP Chip type (G2iL or G2xL)
+ * @param accessPassword The access password to use to write on the tag
+ * @param target Filter to be applied.
+ */
+TMR_Status TMR_SR_cmdNxpSetReadProtect(TMR_Reader *reader, uint16_t timeout,
+            TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+  
+  TMR_SR_msgAddNXPSetReadProtect(msg, &i, timeout, chip, accessPassword, target);  /* set read protect */
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/**
+ * NXP Reset Read Protect
+ * Chip type = 0x02 or 0x07, Command = 0x02
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param chip The NXP Chip type (G2iL or G2xL)
+ * @param accessPassword The access password to use to write on the tag
+ * @param target Filter to be applied.
+ */
+TMR_Status TMR_SR_cmdNxpResetReadProtect(TMR_Reader *reader, uint16_t timeout,
+            TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddNXPResetReadProtect(msg, &i, timeout, chip, accessPassword, target);  /* Reset read protect */
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/** Helper routine to form the NXP Change EAS command**/
+void TMR_SR_msgAddNXPChangeEAS(uint8_t *msg, uint8_t *i, uint16_t timeout, 
+                TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, bool reset, TMR_TagFilter* target)
+{
+  uint8_t option=0,rec; 
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)chip);  /* Chip - type*/
+  
+  rec=*i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)0x03);  /* Sub command, Change EAS */
+  
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, 0, false); 
+  msg[rec]=msg[rec]|option;
+    
+  SETU32(msg, *i, accessPassword);  
+  if(reset)
+  {
+    SETU8(msg, *i, (uint8_t)0x02);  /* reset EAS */
+  }
+  else
+  {
+    SETU8(msg, *i, (uint8_t)0x01);  /* set EAS */
+  }  
+}
+
+/**
+ * NXP Change EAS
+ * Chip type = 0x02 or 0x07, Command = 0x03
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param chip The NXP Chip type (G2iL or G2xL)
+ * @param accessPassword The access password to use to write on the tag
+ * @param reset Reset or set EAS bit
+ * @param target Filter to be applied.
+ */
+TMR_Status TMR_SR_cmdNxpChangeEas(TMR_Reader *reader, uint16_t timeout,
+            TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, bool reset, TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddNXPChangeEAS(msg, &i, timeout, chip, accessPassword, reset, target);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/** Helper routine to form the NXP EAS Alarm command **/
+void TMR_SR_msgAddNXPEASAlarm(uint8_t *msg, uint8_t *i, uint16_t timeout, 
+                TMR_SR_GEN2_SiliconType chip, TMR_GEN2_DivideRatio dr, TMR_GEN2_TagEncoding m, TMR_GEN2_TrExt trExt, TMR_TagFilter* target)
+{
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)chip);  /* Chip - type*/
+  
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);  
+  SETU8(msg, *i, (uint8_t)0x04);  /* Sub command, EAS Alarm */
+
+  SETU8(msg, *i, (uint8_t)dr);    
+  SETU8(msg, *i, (uint8_t)m);
+  SETU8(msg, *i, (uint8_t)trExt);
+}
+
+/**
+ * NXP EAS Alarm
+ * Chip type = 0x02 or 0x07, Command = 0x04
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param chip The NXP Chip type (G2iL or G2xL)
+ * @param dr Gen2 divide ratio to use
+ * @param m Gen2 M(tag encoding) parameter to use
+ * @param trExt Gen2 TrExt value to use
+ * @param data 8 bytes of EAS alarm data will be returned, on successful operation
+ * @param target Filter to be applied.
+ */
+TMR_Status TMR_SR_cmdNxpEasAlarm(TMR_Reader *reader, uint16_t timeout,
+            TMR_SR_GEN2_SiliconType chip, TMR_GEN2_DivideRatio dr, TMR_GEN2_TagEncoding m, TMR_GEN2_TrExt trExt,
+            TMR_uint8List *data, TMR_TagFilter* target)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  if (NULL != target)
+  {  /* EAS Alarm command is sent without any singulation of the tag*/
+    return TMR_ERROR_UNSUPPORTED;
+  }
+  TMR_SR_msgAddNXPEASAlarm(msg, &i, timeout, chip, dr, m, trExt, target);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  
+  
+  /* Alarm data always starts at position 9 */
+  /*  FF    0A    2D   00 00    xx        40         00 04            [8 bytes]       ?? ??
+   *  SOH Length OpCode Status ChipType  option     SubCommand      [EAS AlarmData]      CRC
+   */
+  i = 9;
+  if (NULL != data)
+  {
+    uint16_t copyLength;
+    
+    copyLength = msg[1] + 5 - i;
+    memcpy(data->list, &msg[i], copyLength);    
+    data->len = copyLength;    
+  }
+
+  return TMR_SUCCESS;
+}
+
+/** Helper routine to form the NXP Calibrate command **/
+void TMR_SR_msgAddNXPCalibrate(uint8_t *msg, uint8_t *i, uint16_t timeout, 
+                               TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, TMR_TagFilter* target)
+{
+  uint8_t option=0,rec; 
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)chip);  /* Chip - type*/
+  
+  rec=*i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)0x05);  /* Sub command, Calibrate */
+
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, 0, false); 
+  msg[rec]=msg[rec]|option;
+  
+  SETU32(msg, *i, accessPassword);
+}
+/**
+ * NXP Calibrate (only for G2xL)
+ * Chip type = 0x02, Command = 0x05
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param chip The NXP Chip type (G2iL or G2xL)
+ * @param accessPassword The access password to use to write on the tag
+ * @param data  64 bytes of calibration data will be returned on a successful operation
+ * @param target Filter to be applied.
+ */
+TMR_Status TMR_SR_cmdNxpCalibrate(TMR_Reader *reader, uint16_t timeout,
+                                  TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, TMR_uint8List *data, TMR_TagFilter* target)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddNXPCalibrate(msg, &i, timeout, chip, accessPassword, target);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  
+  
+  /* Calibration data always starts at position 9 */
+  /* FF    42     2D    00 00     xx     40       00 05         [64 bytes]     ?? ??
+   * SOH Length OpCode Status  ChipType  option  SubCommand   [CalibrateData]     CRC
+   */
+  i = 9;
+  if (NULL != data)
+  {    
+    uint16_t copyLength;
+    
+    copyLength = msg[1] + 5 - i;
+    memcpy(data->list, &msg[i], copyLength);    
+    data->len = copyLength;
+  }
+
+  return TMR_SUCCESS;
+}
+
+/** Helper routine to form the NXP ChangeConfig command **/
+void TMR_SR_msgAddNXPChangeConfig(uint8_t *msg, uint8_t *i, uint16_t timeout,
+        TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, TMR_NXP_ConfigWord configWord, TMR_TagFilter* target)
+{
+  //uint16_t configData;
+  uint8_t option=0,rec; 
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)chip);  /* Chip - type*/
+  rec=*i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)0x07);  /* Sub command, ChangeConfig */
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true); 
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)0x00); //RFU  
+  SETU16(msg, *i, configWord.data);
+}
+
+/**
+ * NXP ChangeConfig (only for G2iL)
+ * Chip type = 0x07, Command = 0x07
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param chip The NXP Chip type (G2iL or G2xL)
+ * @param accessPassword The access password to use to write on the tag
+ * @param configWord (I/O)The config word to write on the tag. 
+ * @param data If the operation is success, this data contains the current configword setting on the tag.
+ * @param target Filter to be applied.
+ */
+TMR_Status TMR_SR_cmdNxpChangeConfig(TMR_Reader *reader, uint16_t timeout,
+            TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, TMR_NXP_ConfigWord configWord,
+            TMR_uint8List *data, TMR_TagFilter* target)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  if (chip == TMR_SR_GEN2_NXP_G2X_SILICON)
+  {
+    /* ChangeConfig works only for G2iL tags*/
+    return TMR_ERROR_UNSUPPORTED;  
+  }
+  
+  TMR_SR_msgAddNXPChangeConfig(msg, &i, timeout, chip, accessPassword, configWord, target);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the config data from response back to the user */
+  i = 9;  
+  /* FF    06     2d    00 00      07     40     00 07         80 46        59 2f
+   * SOH Length OpCode Status  ChipType  option  SubCommand  [ConfigData]     CRC
+   */
+  {
+    uint16_t copyLength;
+    
+    copyLength = msg[1] + 5 - i;
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+void TMR_SR_msgAddGen2v2NxpUntraceable(uint8_t *msg, uint8_t *i, uint16_t timeout,
+									   TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, uint16_t configWord, 
+									   TMR_TagOp_GEN2_NXP_Untraceable op ,TMR_TagFilter* target)
+{
+	uint8_t option=0,rec; 
+	SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+	SETU16(msg, *i, timeout);
+	SETU8(msg, *i, (uint8_t)chip);  /* Chip - type*/
+	rec=*i;
+	SETU8(msg,*i,0x00);//option
+	SETU8(msg, *i, (uint8_t)op.subCommand);  /* Sub command, Untraceable */
+	filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, false); 
+	msg[rec]=msg[rec]|option;
+	SETU16(msg, *i, configWord);
+	if(op.subCommand == 0x02)// Untraceable with Authentication
+	{
+		SETU8(msg,*i, op.auth.tam1Auth.Authentication);
+		SETU8(msg,*i,op.auth.tam1Auth.CSI);
+		SETU8(msg,*i,op.auth.tam1Auth.keyID);
+		SETU8(msg,*i,op.auth.tam1Auth.KeyLength);	
+		{
+			uint32_t iWord;
+			for (iWord = 0; iWord < op.auth.tam1Auth.Key.len; iWord++)
+			{
+				SETU8(msg, *i, (op.auth.tam1Auth.Key.list[iWord]));
+				// SETU8(msg, *i, ((op.auth.tam1Auth.Key.list[iWord]>>0)&0xFF));
+			}
+		}
+		SETU8(msg,*i,op.auth.tam1Auth.IchallengeLength);
+		{
+			uint32_t iWord;
+			for (iWord = 0; iWord < op.auth.tam1Auth.Ichallenge.len; iWord++)
+			{
+				SETU8(msg, *i, (op.auth.tam1Auth.Ichallenge.list[iWord]));
+				//SETU8(msg, *i, ((op.auth.tam1Auth.Ichallenge.list[iWord]>>0)&0xFF));
+			}
+		}
+	}
+	else //Untraceable with Access 
+	{
+		SETU32(msg, *i,op.auth.accessPassword);
+	}
+}
+
+TMR_Status TMR_SR_cmdGen2v2NXPUntraceable(TMR_Reader *reader, uint16_t timeout,
+										  TMR_SR_GEN2_SiliconType chip, TMR_GEN2_Password accessPassword, uint16_t configWord,
+										  TMR_TagOp_GEN2_NXP_Untraceable op,TMR_uint8List *data, TMR_TagFilter* target)
+{
+	TMR_Status ret;
+	uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+	uint8_t i;
+	i = 2;
+
+	TMR_SR_msgAddGen2v2NxpUntraceable(msg, &i, timeout, chip, accessPassword, configWord, op ,target);
+	msg[1] = i - 3; /* Install length */
+
+	ret = TMR_SR_sendTimeout(reader, msg, timeout);
+	if (TMR_SUCCESS != ret)
+	{
+		return ret;
+	}
+	return TMR_SUCCESS;
+}
+uint8_t getCmdProtModeBlockCount(uint8_t protMode, uint8_t blockCount)
+{
+	uint8_t protModeBlockCount = 0x01; //The UCODE AES Tag only supports ProtMode = "0001b" (CBC encryption)
+	uint16_t mask = 0x0F;
+	int pos = 4;
+	protModeBlockCount |= ((blockCount & mask) << pos);
+
+	return protModeBlockCount;
+}
+uint16_t getCmdProfileOffset(uint16_t profile, uint16_t offset)
+{
+	uint16_t profileOffset = 0x0000;
+	uint16_t mask;
+	int pos;
+
+	mask = 0xF;
+	pos = 12;
+	profileOffset |= ((profile & mask) << pos);
+
+	mask = 0xFFF;
+	pos = 0;
+	profileOffset |= ((offset & mask) << pos);
+
+	return profileOffset;
+}
+void TMR_SR_msgAddGen2v2NxpAuthenticate(uint8_t *msg, uint8_t *i, uint16_t timeout,TMR_SR_GEN2_SiliconType chip,
+										TMR_GEN2_Password accessPassword,TMR_TagOp_GEN2_NXP_Authenticate op ,TMR_TagFilter* target)
+{
+	uint8_t option=0,rec; 
+	SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+	SETU16(msg, *i, timeout);
+	SETU8(msg, *i, (uint8_t)chip);  /* Chip - type*/
+	rec=*i;
+	SETU8(msg,*i,0x00);//option
+	SETU8(msg, *i, (uint8_t)op.subCommand);  /* Sub command, Untraceable */
+	filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, false); 
+	msg[rec]=msg[rec]|option;
+	SETU8(msg,*i, op.tam1Auth.Authentication);
+	SETU8(msg,*i,op.tam1Auth.CSI);
+	SETU8(msg,*i,op.tam1Auth.keyID);
+	SETU8(msg,*i,op.tam1Auth.KeyLength);	
+	{
+		uint8_t iWord;
+		for (iWord = 0; iWord < op.tam1Auth.Key.len; iWord++)
+		{
+			SETU8(msg, *i, (op.tam1Auth.Key.list[iWord]));
+		}
+	}
+	SETU8(msg,*i,op.tam1Auth.IchallengeLength);
+	{
+		uint8_t iWord;
+		for (iWord = 0; iWord < op.tam1Auth.Ichallenge.len; iWord++)
+		{
+			SETU8(msg, *i, (op.tam1Auth.Ichallenge.list[iWord]));
+		}
+	}
+	if(op.type == TAM2_AUTHENTICATION)
+	{
+		SETU16(msg, *i, getCmdProfileOffset(op.tam2Auth.profile,op.tam2Auth.Offset));
+		SETU8(msg, *i, getCmdProtModeBlockCount(op.tam2Auth.ProtMode,op.tam2Auth.BlockCount));
+	}
+}
+
+TMR_Status TMR_SR_cmdGen2v2NXPAuthenticate(TMR_Reader *reader, uint16_t timeout,TMR_SR_GEN2_SiliconType chip,
+										   TMR_GEN2_Password accessPassword, TMR_TagOp_GEN2_NXP_Authenticate op, TMR_uint8List *data, TMR_TagFilter* target)
+{
+	TMR_Status ret;
+	uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+	uint8_t i;
+	i = 2;
+
+	TMR_SR_msgAddGen2v2NxpAuthenticate(msg, &i, timeout, chip, accessPassword, op ,target);
+	msg[1] = i - 3; /* Install length */
+
+	ret = TMR_SR_sendTimeout(reader, msg, timeout);
+
+	if (TMR_SUCCESS != ret)
+	{
+		return ret;
+	}
+
+	if (NULL != data->list)
+	{
+		i = 8;
+		{
+			uint16_t dataLength;
+			uint16_t copyLength;
+
+			copyLength = dataLength = msg[1] + 5 - i;
+			if (copyLength > data->max)
+			{
+				copyLength = data->max;
+			}
+			data->len = copyLength;
+			memcpy(data->list, &msg[i], copyLength);
+			i += dataLength;
+		}
+	}
+	return TMR_SUCCESS;
+}
+uint16_t getCmdWordPointer(uint16_t wordPointer)
+{
+	uint16_t rdBufferWordPointer = 0x0000;
+	if (wordPointer > 0)
+	{
+		uint16_t mask = 0x0FFF;
+		int pos = 0;
+		rdBufferWordPointer |= ((wordPointer & mask) << pos);
+	}
+	return rdBufferWordPointer;
+}
+uint16_t getCmdBitCount(uint16_t bitCount)
+{
+	uint16_t rdBufferBitCount = 0x0000;
+	if (bitCount > 0)
+	{
+		uint16_t mask = 0x0FFF;
+		int pos = 0;
+		rdBufferBitCount |= ((bitCount & mask) << pos);
+	}
+	return rdBufferBitCount;
+}
+void TMR_SR_msgAddGen2v2NxpReadBuffer(uint8_t *msg, uint8_t *i, uint16_t timeout,TMR_SR_GEN2_SiliconType chip,
+									  TMR_GEN2_Password accessPassword,TMR_TagOp_GEN2_NXP_Readbuffer op ,TMR_TagFilter* target)
+{
+	uint8_t option=0,rec; 
+	SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+	SETU16(msg, *i, timeout);
+	SETU8(msg, *i, (uint8_t)chip);  /* Chip - type*/
+	rec=*i;
+	SETU8(msg,*i,0x00);//option
+	SETU8(msg, *i, (uint8_t)op.authenticate.subCommand);  /* Sub command, Untraceable */
+	filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, false); 
+	msg[rec]=msg[rec]|option;
+	SETU16(msg, *i, getCmdWordPointer(op.wordPointer));
+	SETU16(msg, *i, getCmdBitCount(op.bitCount));
+	SETU8(msg,*i, op.authenticate.tam1Auth.Authentication);
+	SETU8(msg,*i,op.authenticate.tam1Auth.CSI);
+	SETU8(msg,*i,op.authenticate.tam1Auth.keyID);
+	SETU8(msg,*i,op.authenticate.tam1Auth.KeyLength);	
+	{
+		uint8_t iWord;
+		for (iWord = 0; iWord < op.authenticate.tam1Auth.Key.len; iWord++)
+		{
+			SETU8(msg, *i, (op.authenticate.tam1Auth.Key.list[iWord]));
+		}
+	}
+	SETU8(msg,*i,op.authenticate.tam1Auth.IchallengeLength);
+	{
+		uint8_t iWord;
+		for (iWord = 0; iWord < op.authenticate.tam1Auth.Ichallenge.len; iWord++)
+		{
+			SETU8(msg, *i, (op.authenticate.tam1Auth.Ichallenge.list[iWord]));
+		}
+	}
+	if(op.authenticate.type == TAM2_AUTHENTICATION)
+	{
+		SETU16(msg, *i, getCmdProfileOffset(op.authenticate.tam2Auth.profile,op.authenticate.tam2Auth.Offset));
+		SETU8(msg, *i, getCmdProtModeBlockCount(op.authenticate.tam2Auth.ProtMode,op.authenticate.tam2Auth.BlockCount));
+	}
+}
+
+TMR_Status TMR_SR_cmdGen2v2NXPReadBuffer(TMR_Reader *reader, uint16_t timeout,TMR_SR_GEN2_SiliconType chip,
+										 TMR_GEN2_Password accessPassword, TMR_TagOp_GEN2_NXP_Readbuffer op, TMR_uint8List *data, TMR_TagFilter* target)
+{
+	TMR_Status ret;
+	uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+	uint8_t i;
+	i = 2;
+
+	TMR_SR_msgAddGen2v2NxpReadBuffer(msg, &i, timeout, chip, accessPassword, op ,target);
+	msg[1] = i - 3; /* Install length */
+
+	ret = TMR_SR_sendTimeout(reader, msg, timeout);
+	if (TMR_SUCCESS != ret)
+	{
+		return ret;
+	}
+	if (NULL != data->list)
+	{
+		i = 8;
+		{
+			uint16_t dataLength;
+			uint16_t copyLength;
+
+			copyLength = dataLength = msg[1] + 5 - i;
+			if (copyLength > data->max)
+			{
+				copyLength = data->max;
+			}
+			data->len = copyLength;
+			memcpy(data->list, &msg[i], copyLength);
+			i += dataLength;
+		}
+	}
+	return TMR_SUCCESS;
+}
+/** 
+ *  Monza4 Silicon Specific Commands
+ *  Chip Type = 0x08
+ **/
+
+/** Helper routine to form the Monza4 QT Read/Write command **/
+void TMR_SR_msgAddMonza4QTReadWrite(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                TMR_Monza4_ControlByte controlByte, TMR_Monza4_Payload payload, TMR_TagFilter* target)
+{
+  uint8_t option=0,rec; 
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IMPINJ_MONZA4_SILICON);  /* Chip - type*/
+  rec=*i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)0x00);  /* Sub command, QT Read/Write */
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true); 
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, controlByte.data);
+  SETU16(msg, *i, payload.data);
+}
+
+/**
+ * Impinj Monza4 QT Read/Write
+ * Chip type = 0x08, command = 0x00
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param controlByte The control byte to write on the tag
+ * @param payload The payload 
+ * @param data If the operation is success, this data contains the payload
+ *             When Read/Write (bit) = 0, then the payload is the value read,
+ *             When Read/Write (bit) = 1, then the payload is the value written.
+ * @param target Filter to be applied.
+ */
+TMR_Status TMR_SR_cmdMonza4QTReadWrite(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, 
+                                       TMR_Monza4_ControlByte controlByte, TMR_Monza4_Payload payload, TMR_uint8List *data, TMR_TagFilter* target)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddMonza4QTReadWrite(msg, &i, timeout, accessPassword, controlByte, payload, target);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  
+  /* Parse the payload data from response back to the user */
+  i = 9;  
+  /* FF    06     2d    00 00      08     40     00 00         xx xx        xx xx
+   * SOH Length OpCode Status  ChipType  option  SubCommand  [payload]      CRC
+   */
+  {
+    uint16_t copyLength;
+    
+    copyLength = msg[1] + 5 - i;
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+
+}
+
+/**
+ * IDS SL900A specific commands
+ * chip type 0A
+ */
+
+/**
+ * Helper routine to form the IDS SL900A get battery level command
+ */
+void TMR_SR_msgAddIdsSL900aGetBatteryLevel(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                           uint8_t CommandCode, uint32_t password, PasswordLevel level, BatteryType batteryType,
+                                           TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+  SETU8(msg, *i, batteryType);
+}
+
+/**
+ * IDS SL900A  Get Battery Level
+ * Chip type = 0x0A, command = 0x00 AA
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param data If the operation is success, this data contains the requested value
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aGetBatteryLevel(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                uint8_t CommandCode, uint32_t password, PasswordLevel level,BatteryType type,
+                                TMR_uint8List *data, TMR_TagFilter* target)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aGetBatteryLevel(msg, &i, timeout, accessPassword, CommandCode, password, level, type, target);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the battery level data from response back to the user */
+  i = 9;
+  /* FF    06     2d    00 00      0A     42     00 AD         xx xx        xx xx
+   * SOH Length OpCode Status  ChipType  option  SubCommand    [level]       CRC
+   */
+  {
+    uint16_t copyLength;
+    
+    copyLength = msg[1] + 5 - i;
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/**
+ *  Helper routine to form the IDS SL900A get sensor value command
+ */
+void TMR_SR_msgAddIdsSL900aGetSensorValue(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                          uint8_t CommandCode, uint32_t password, PasswordLevel level, Sensor sensortype,
+                                          TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+  SETU8(msg, *i, sensortype);
+}
+
+/**
+ * IDS SL900A  Get Sensor value
+ * Chip type = 0x0A, command = 0x00 AD
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param data If the operation is success, this data contains the requested value
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aGetSensorValue(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                               uint8_t CommandCode, uint32_t password, PasswordLevel level,Sensor sensortype,
+                                TMR_uint8List *data, TMR_TagFilter* target)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aGetSensorValue(msg, &i, timeout, accessPassword, CommandCode, password, level, sensortype, target);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the sensor type data from response back to the user */
+  i = 9;
+  /* FF    06     2d    00 00      0A     42     00 AD         xx xx        xx xx
+   * SOH Length OpCode Status  ChipType  option  SubCommand    [type]       CRC
+   */
+  {
+    uint16_t copyLength;
+    
+    copyLength = msg[1] + 5 - i;
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/**
+ *  Helper routine to form the IDS SL900A get measurment setup command
+ */
+void TMR_SR_msgAddIdsSL900aGetMeasurementSetup(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                          uint8_t CommandCode, uint32_t password, PasswordLevel level, TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+}
+
+/**
+ * IDS SL900A  Get Sensor value
+ * Chip type = 0x0A, command = 0x00 A3
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param data If the operation is success, this data contains the requested value
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aGetMeasurementSetup(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                               uint8_t CommandCode, uint32_t password, PasswordLevel level,
+                                TMR_uint8List *data, TMR_TagFilter* target)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aGetMeasurementSetup(msg, &i, timeout, accessPassword, CommandCode, password, level, target);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the measurment data from response back to the user */
+  i = 9;
+  /* FF    06     2d    00 00      0A     42     00 AD         xx xx    xx xx
+   * SOH Length OpCode Status  ChipType  option  SubCommand    [data]   CRC
+   */
+  {
+    uint16_t copyLength;
+    
+    copyLength = msg[1] + 5 - i;
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/**
+ *  Helper routine to form the IDS SL900A get log state command
+ */
+void TMR_SR_msgAddIdsSL900aGetLogState(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                       uint8_t CommandCode, uint32_t password, PasswordLevel level, TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+}
+
+/**
+ * IDS SL900A  Get log State
+ * Chip type = 0x0A, command = 0x00 AD
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param to specify SL900A sensor type
+ * @param data If the operation is success, this data contains the requested value
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aGetLogState(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                            uint8_t CommandCode, uint32_t password, PasswordLevel level,TMR_uint8List *data,
+                            TMR_TagFilter* target)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aGetLogState(msg, &i, timeout, accessPassword, CommandCode, password, level, target);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the sensor type data from response back to the user */
+  i = 9;
+  /* FF    06     2d    00 00      0A     42     00 AD         xx xx        xx xx
+  * SOH Length OpCode Status  ChipType  option  SubCommand    [type]       CRC
+  */
+  {
+    uint16_t copyLength;
+
+    copyLength = msg[1] + 5 - i;
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/**
+ *  Helper routine to form the IDS SL900A set log mode command
+ */
+void TMR_SR_msgAddIdsSL900aSetLogMode(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                      uint8_t CommandCode, uint32_t password, PasswordLevel level, LoggingForm form,
+                                      StorageRule rule, bool Ext1Enable, bool Ext2Enable, bool TempEnable, bool BattEnable,
+                                      uint16_t LogInterval, TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+  uint32_t logmode = 0;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+
+  logmode |= (uint32_t)form << 21;
+  logmode |= (uint32_t)rule << 20;
+  logmode |= (uint32_t)(Ext1Enable ? 1 : 0) << 19;
+  logmode |= (uint32_t)(Ext2Enable ? 1 : 0) << 18;
+  logmode |= (uint32_t)(TempEnable ? 1 : 0) << 17;
+  logmode |= (uint32_t)(BattEnable ? 1 : 0) << 16;
+  logmode |= (uint32_t)LogInterval << 1;
+  SETU8(msg, *i, (uint8_t)((logmode >> 16) & 0xFF));
+  SETU8(msg, *i, (uint8_t)((logmode >> 8) & 0xFF));
+  SETU8(msg, *i, (uint8_t)((logmode >> 0) & 0xFF));
+}
+
+/**
+ * IDS SL900A  Get log State
+ * Chip type = 0x0A, command = 0x00 AD
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param level IDS password level
+ * @param form IDS logging form
+ * @param rule IDS storage rule
+ * @param Ext1Enable to Enable log for EXT1 external sensor
+ * @param Ext2Enable to Enable log for EXT2 external sensor
+ * @param TempEnable to Enable log for temperature sensor
+ * @param BattEnable to Enable log for battery sensor
+ * @param LogInterval to Time (seconds) between log readings
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aSetLogMode(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                           uint8_t CommandCode, uint32_t password, PasswordLevel level, LoggingForm form,
+                           StorageRule rule, bool Ext1Enable, bool Ext2Enable, bool TempEnable, bool BattEnable,
+                           uint16_t LogInterval, TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aSetLogMode(msg, &i, timeout, accessPassword, CommandCode, password, level, form,
+    rule, Ext1Enable, Ext2Enable, TempEnable, BattEnable, LogInterval, target);
+
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/* Helper routine to form the IDS SL900A initialize command */
+void TMR_SR_msgAddIdsSL900aInitialize(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                      uint8_t CommandCode, uint32_t password, PasswordLevel level, uint16_t delayTime,
+                                      uint16_t applicatioData, TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+  SETU16(msg, *i, delayTime);
+  SETU16(msg, *i, applicatioData);
+}
+
+/**
+ * IDS SL900A  initialize command
+ * Chip type = 0x0A, command = 0x00 AC
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param delayTime to secify delayTime
+ * @param applicatioData to specify applicationData
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aInitialize(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                           uint8_t CommandCode, uint32_t password, PasswordLevel level, uint16_t delayTime,
+                           uint16_t applicationData, TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aInitialize(msg, &i, timeout, accessPassword, CommandCode, password, level, delayTime,
+    applicationData, target);
+
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/**
+ *  Helper routine to form the IDS SL900A end log command
+ */
+void TMR_SR_msgAddIdsSL900aEndLog(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);  
+}
+
+/**
+ * IDS SL900A Initialize command
+ * Chip type = 0x0A, command = 0x00 A6
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param data If the operation is success, this data contains the requested value
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aEndLog(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                               uint8_t CommandCode, uint32_t password, PasswordLevel level, TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aEndLog(msg, &i, timeout, accessPassword, CommandCode, password, level, target);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/**
+ * Helper function to form the IDS SL900A SetPassword command
+ */ 
+void TMR_SR_msgAddIdsSL900aSetPassword(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                       uint8_t CommandCode, uint32_t password, PasswordLevel level, uint32_t newPassword,
+                                       PasswordLevel newPasswordLevel, TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+  SETU8(msg, *i, (uint8_t)newPasswordLevel);
+  SETU32(msg, *i, newPassword);
+}
+
+/**
+ * IDS SL900A SetPassword command
+ * Chip type = 0x0A, command = 0x00 A0
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param data If the operation is success, this data contains the requested value
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aSetPassword(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                            uint8_t CommandCode, uint32_t password, PasswordLevel level, uint32_t newPassword,
+                            PasswordLevel newPasswordLevel, TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aSetPassword(msg, &i, timeout, accessPassword, CommandCode, password, level, newPassword, newPasswordLevel, target);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/**
+ *  Helper routine to form the IDS SL900A AccessFifo Status command
+ */
+void TMR_SR_msgAddIdsSL900aAccessFifoStatus(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, AccessFifoOperation operation,
+                                  TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+  SETU8(msg, *i, (uint8_t)operation);
+}
+
+/**
+ * IDS SL900A AccessFifo status command
+ * Chip type = 0x0A, command = 0x00 AF
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param data If the operation is success, this data contains the requested value
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aAccessFifoStatus(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t CommandCode,
+                                 uint32_t password, PasswordLevel level, AccessFifoOperation operation,TMR_uint8List *data, TMR_TagFilter* target)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aAccessFifoStatus(msg, &i, timeout, accessPassword, CommandCode, password, level, operation, target);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the sensor type data from response back to the user */
+  i = 9;
+  /* FF    06     2d    00 00      0A     42     00 AF         xx xx        xx xx
+  * SOH Length OpCode Status  ChipType  option  SubCommand    [type]       CRC
+  */
+  {
+    uint16_t copyLength;
+
+    copyLength = msg[1] + 5 - i;
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/**
+ *  Helper routine to form the IDS SL900A AccessFifo Read command
+ */
+void TMR_SR_msgAddIdsSL900aAccessFifoRead(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, AccessFifoOperation operation,
+                                  uint8_t length, TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+  SETU8(msg, *i, (uint8_t)(operation | length));
+}
+
+/**
+ * IDS SL900A AccessFifo read command
+ * Chip type = 0x0A, command = 0x00 AF
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param data If the operation is success, this data contains the requested value
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aAccessFifoRead(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t CommandCode,
+                               uint32_t password, PasswordLevel level, AccessFifoOperation operation, uint8_t length, TMR_uint8List *data,
+                               TMR_TagFilter* target)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aAccessFifoRead(msg, &i, timeout, accessPassword, CommandCode, password, level, operation, length, target);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the sensor type data from response back to the user */
+  i = 9;
+  /* FF    06     2d    00 00      0A     42     00 AF         xx xx        xx xx
+  * SOH Length OpCode Status  ChipType  option  SubCommand    [type]       CRC
+  */
+  {
+    uint16_t copyLength;
+
+    copyLength = msg[1] + 5 - i;
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/**
+ *  Helper routine to form the IDS SL900A AccessFifo Write command
+ */
+void TMR_SR_msgAddIdsSL900aAccessFifoWrite(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                  uint8_t CommandCode, uint32_t password, PasswordLevel level, AccessFifoOperation operation,
+                                  TMR_uint8List *payLoad, TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+  SETU8(msg, *i, (uint8_t)(operation | payLoad->len));
+  memcpy(&msg[*i], payLoad->list, payLoad->len);
+  *i += payLoad->len;
+}
+
+/**
+ * IDS SL900A AccessFifo Write command
+ * Chip type = 0x0A, command = 0x00 AF
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param data If the operation is success, this data contains the requested value
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aAccessFifoWrite(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t CommandCode,
+                                uint32_t password, PasswordLevel level, AccessFifoOperation operation, TMR_uint8List *payLoad, TMR_uint8List *data,
+                                TMR_TagFilter* target)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aAccessFifoWrite(msg, &i, timeout, accessPassword, CommandCode, password, level, operation, payLoad, target);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the sensor type data from response back to the user */
+  i = 9;
+  /* FF    06     2d    00 00      0A     42     00 AF         xx xx        xx xx
+  * SOH Length OpCode Status  ChipType  option  SubCommand    [type]       CRC
+  */
+  {
+    uint16_t copyLength;
+
+    copyLength = msg[1] + 5 - i;
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/**
+ *  Helper routine to form the IDS SL900A Start Log command
+ */
+void TMR_SR_msgAddIdsSL900aStartLog(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                    uint8_t CommandCode, uint32_t password, PasswordLevel level, uint32_t time, TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+  SETU32(msg, *i, time);
+}
+
+/**
+ * IDS SL900A StartLog command
+ * Chip type = 0x0A, command = 0x00 A7
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param startTime to specify count start time
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aStartLog(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t CommandCode,
+                         uint32_t password, PasswordLevel level, uint32_t time, TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aStartLog(msg, &i, timeout, accessPassword, CommandCode, password, level, time, target);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/**
+ *  Helper routine to form the IDS SL900A get calibration data  command
+ */
+void TMR_SR_msgAddIdsSL900aGetCalibrationData(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                          uint8_t CommandCode, uint32_t password, PasswordLevel level, TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+}
+
+/**
+ * IDS SL900A  Get Calibration Data
+ * Chip type = 0x0A, command = 0x00 A9
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param data If the operation is success, this data contains the requested value
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aGetCalibrationData(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                               uint8_t CommandCode, uint32_t password, PasswordLevel level,
+                                TMR_uint8List *data, TMR_TagFilter* target)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aGetCalibrationData(msg, &i, timeout, accessPassword, CommandCode, password, level, target);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the  calibration  data from response back to the user */
+  i = 9;
+  /* FF    06     2d    00 00      0A     42     00 A9         xx xx        xx xx
+   * SOH Length OpCode Status  ChipType  option  SubCommand    [data]       CRC
+   */
+  {
+    uint16_t copyLength;
+
+    copyLength = msg[1] + 5 - i;
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/**
+ *  Helper routine to form the IDS SL900A set calibration data  command
+ */
+void TMR_SR_msgAddIdsSL900aSetCalibrationData(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                          uint8_t CommandCode, uint32_t password, PasswordLevel level, uint64_t calibration, 
+                                          TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+  uint8_t calBytes[8];
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+
+  calBytes[0] = (uint8_t) (calibration >> 56);
+  calBytes[1] = (uint8_t) (calibration >> 48);
+  calBytes[2] = (uint8_t) (calibration >> 40);
+  calBytes[3] = (uint8_t) (calibration >> 32);
+  calBytes[4] = (uint8_t) (calibration >> 24);
+  calBytes[5] = (uint8_t) (calibration >> 16);
+  calBytes[6] = (uint8_t) (calibration >> 8);
+  calBytes[7] = (uint8_t) (calibration >> 0);
+
+  memcpy(&msg[*i], calBytes + 1, 7);
+  *i += 7;
+
+}
+
+/**
+ * IDS SL900A  Set Calibration Data
+ * Chip type = 0x0A, command = 0x00 A5
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param calibration to spcify the calibration data
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aSetCalibrationData(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, 
+    uint8_t CommandCode, uint32_t password, PasswordLevel level, uint64_t calibration,
+    TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aSetCalibrationData(msg, &i, timeout, accessPassword, CommandCode, password, level, calibration, target);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/**
+ *  Helper routine to form the IDS SL900A set sfe parameters command
+ */
+void TMR_SR_msgAddIdsSL900aSetSfeParameters(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                          uint8_t CommandCode, uint32_t password, PasswordLevel level, uint16_t sfe,
+                                          TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+  SETU16(msg, *i, sfe);
+}
+
+/**
+ * IDS SL900A  Set Calibration Data
+ * Chip type = 0x0A, command = 0x00 A4
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param sfe to spcify the sfe parameters
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aSetSfeParameters(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, 
+    uint8_t CommandCode, uint32_t password, PasswordLevel level, uint16_t sfe,
+    TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aSetSfeParameters(msg, &i, timeout, accessPassword, CommandCode, password, level, sfe, target);
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/**
+ * Helper routine to form the IDS Sl900A set log mode command
+ */
+void TMR_SR_msgAddIdsSL900aSetLogLimit(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                       uint8_t CommandCode, uint32_t password, PasswordLevel level, uint16_t exLower,
+                                       uint16_t lower, uint16_t upper, uint16_t exUpper, TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+  uint64_t temp = 0;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+
+  temp |= (uint64_t)exLower << 30;
+  temp |= (uint64_t)lower << 20;
+  temp |= (uint64_t)upper << 10;
+  temp |= (uint64_t)exUpper << 0;
+
+  SETU8(msg, *i, (uint8_t)((temp >> 32) & 0xFF));
+  SETU8(msg, *i, (uint8_t)((temp >> 24) & 0xFF));
+  SETU8(msg, *i, (uint8_t)((temp >> 16) & 0xFF));
+  SETU8(msg, *i, (uint8_t)((temp >> 8) & 0xFF));
+  SETU8(msg, *i, (uint8_t)((temp >> 0) & 0xFF));
+}
+
+/**
+ * IDS SL90A SetLogLimit
+ * Chip type = 0x0A, command = 0x00 A2
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in millisecondds. Valid range 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param level IDS password level
+ * @param exLoweer IDS extreamLower limit
+ * @param lower IDS lower limit
+ * @param upper IDS upper limit
+ * @param exUpper IDS extreamUpper limit
+ */
+TMR_Status
+TMR_SR_cmdSL900aSetLogLimit(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                            uint8_t CommandCode, uint32_t password, PasswordLevel level, uint16_t exLower,
+                            uint16_t lower, uint16_t upper, uint16_t exUpper, TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aSetLogLimit(msg, &i, timeout, accessPassword, CommandCode, password, level, exLower,
+      lower, upper, exUpper, target);
+
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/**
+ *  Helper routine to form the IDS SL900A SetShelfLife command
+ */
+void TMR_SR_msgAddIdsSL900aSetShelfLife(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                        uint8_t CommandCode, uint32_t password, PasswordLevel level, uint32_t block0, uint32_t block1,
+                                        TMR_TagFilter* target)
+{
+  uint8_t option = 0, rec;
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_IDS_SL900A_SILICON); /* chip type */
+  rec = *i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)CommandCode);
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true);
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)level);
+  SETU32(msg, *i, password);
+  SETU32(msg, *i, block0);
+  SETU32(msg, *i, block1);
+}
+
+/**
+ * IDS SL900A  SetShelfLife
+ * Chip type = 0x0A, command = 0x00 AB
+ *
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param commandcode to specify the operation
+ * @param password to specify SL900A password access level values
+ * @param data If the operation is success, this data contains the requested value
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdSL900aSetShelfLife(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                             uint8_t CommandCode, uint32_t password, PasswordLevel level, uint32_t block0, uint32_t block1,
+                             TMR_TagFilter* target)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIdsSL900aSetShelfLife(msg, &i, timeout, accessPassword, CommandCode, password, level, block0, block1, target);
+
+  msg[1] = i - 3; /* Install length */
+
+  return TMR_SR_sendTimeout(reader, msg, timeout);
+}
+
+/** 
+ *  Gen2 IAVDenatran Custom Commands
+ *  Chip Type = 0x0B
+ **/
+ 
+/** Helper routine to form the Gen2 IAVDenatran Custom commands **/
+void TMR_SR_msgAddIAVDenatranCustomOp(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                              uint8_t mode, uint8_t payload, TMR_TagFilter* target)
+{
+  uint8_t option=0,rec; 
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_DENATRAN_IAV_SILICON);  /* Chip - type*/
+  rec=*i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)mode);  /* Sub command */
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true); 
+  msg[rec]=msg[rec]|option;
+  SETU8(msg, *i, (uint8_t)payload);
+}
+
+ /**
+ * IAV Denatran Custom Commands
+ * Chip type = 0x0B, command = 0x00
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param target Filter to be applied.
+ */
+TMR_Status
+TMR_SR_cmdIAVDenatranCustomOp(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t mode, uint8_t payload,
+                      TMR_uint8List *data, TMR_TagFilter* target)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIAVDenatranCustomOp(msg, &i, timeout, accessPassword, mode, payload, target);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the  response back to the user */
+  i = 9;  
+  /* FF    06     2d    00 00      08     40     00 00         xx xx        xx xx
+   * SOH Length OpCode Status  ChipType  option  SubCommand  [payload]      CRC
+   */
+  {
+    uint16_t copyLength;
+
+    copyLength = msg[1] + 5 - i;
+
+    if (copyLength > data->max)
+    {
+      copyLength = data->max;
+    }
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/** Helper routine to form the Gen2 IAVDenatran Custom commad readFromMemMap */
+void TMR_SR_msgAddIAVDenatranCustomReadFromMemMap(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+    uint8_t mode, uint8_t payload, TMR_TagFilter* target, uint16_t wordAddress)
+{
+
+  TMR_SR_msgAddIAVDenatranCustomOp(msg, i, timeout, accessPassword, mode, payload, target);
+  /* Add the address to be read from user bank */
+  SETU16(msg, *i, wordAddress);
+}
+
+/** * IAV Denatran Custom Command Read From MemMap
+ * Chip type = 0x0B, command = 0x06
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param target Filter to be applied.
+ * @param wordAddress address to be read from USER bank
+ */
+TMR_Status
+TMR_SR_cmdIAVDenatranCustomReadFromMemMap(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t mode, uint8_t payload,
+                      TMR_uint8List *data, TMR_TagFilter* target, uint16_t wordAddress)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIAVDenatranCustomReadFromMemMap(msg, &i, timeout, accessPassword, mode, payload, target, wordAddress);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the  response back to the user */
+  i = 9;
+  /* FF    06     2d    00 00      08     40     00 00         xx xx        xx xx
+   * SOH Length OpCode Status  ChipType  option  SubCommand  [payload]      CRC
+   */
+  {
+    uint16_t copyLength;
+
+    copyLength = msg[1] + 5 - i;
+
+    if (copyLength > data->max)
+    {
+      copyLength = data->max;
+    }
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/** Helper routine to form the Gen2 IAVDenatran Custom commad read sec */
+void TMR_SR_msgAddIAVDenatranCustomReadSec(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+    uint8_t mode, uint8_t payload, TMR_TagFilter* target, uint16_t wordAddress)
+{
+
+  TMR_SR_msgAddIAVDenatranCustomOp(msg, i, timeout, accessPassword, mode, payload, target);
+  /* Add the address to be read from user bank */
+  SETU16(msg, *i, wordAddress);
+}
+
+/** * IAV Denatran Custom Command Read Sec
+ * Chip type = 0x0B, command = 0x0A
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param target Filter to be applied.
+ * @param wordAddress address to be read from USER bank
+ */
+TMR_Status
+TMR_SR_cmdIAVDenatranCustomReadSec(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t mode, uint8_t payload,
+                      TMR_uint8List *data, TMR_TagFilter* target, uint16_t wordAddress)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIAVDenatranCustomReadSec(msg, &i, timeout, accessPassword, mode, payload, target, wordAddress);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the  response back to the user */
+  i = 9;
+  /* FF    06     2d    00 00      08     40     00 00         xx xx        xx xx
+   * SOH Length OpCode Status  ChipType  option  SubCommand  [payload]      CRC
+   */
+  {
+    uint16_t copyLength;
+
+    copyLength = msg[1] + 5 - i;
+
+    if (copyLength > data->max)
+    {
+      copyLength = data->max;
+    }
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/** Helper routine to form the Gen2 IAVDenatran Custom commad Activate Siniav Mode */
+void TMR_SR_msgAddIAVDenatranCustomActivateSiniavMode(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+                                                      uint8_t mode, uint8_t payload, TMR_TagFilter* target, bool tokenDesc, uint8_t *token)
+{
+  uint8_t j;
+
+  TMR_SR_msgAddIAVDenatranCustomOp(msg, i, timeout, accessPassword, mode, payload, target);
+  /* add the token field */
+  if (tokenDesc)
+  {
+    for (j = 0; j < 8; j++)
+    {
+      SETU8(msg, *i, token[j]);
+    }
+  }
+}
+
+ /**
+ * IAV Denatran Custom Commands Activate Siniav Mode
+ * Chip type = 0x0B, command = 0x02
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param target Filter to be applied.
+ * @param token 64bit value to active the tag
+ */
+TMR_Status
+TMR_SR_cmdIAVDenatranCustomActivateSiniavMode(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t mode, uint8_t payload,
+                              TMR_uint8List *data, TMR_TagFilter* target, bool tokenDesc, uint8_t *token)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIAVDenatranCustomActivateSiniavMode(msg, &i, timeout, accessPassword, mode, payload, target, tokenDesc, token);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the  response back to the user */
+  i = 9;  
+  /* FF    06     2d    00 00      08     40     00 00         xx xx        xx xx
+   * SOH Length OpCode Status  ChipType  option  SubCommand  [payload]      CRC
+   */
+  {
+    uint16_t copyLength;
+
+    copyLength = msg[1] + 5 - i;
+
+    if (copyLength > data->max)
+    {
+      copyLength = data->max;
+    }
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/** Helper routine to form the Gen2 IAVDenatran Custom commad writeToMemMap */
+void TMR_SR_msgAddIAVDenatranCustomWriteToMemMap(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+    uint8_t mode, uint8_t payload, TMR_TagFilter* target, uint16_t wordPtr, uint16_t wordData, uint8_t* tagId, uint8_t* dataBuf)
+{
+  uint8_t j;
+
+  TMR_SR_msgAddIAVDenatranCustomOp(msg, i, timeout, accessPassword, mode, payload, target);
+  /* Add the address to be read from user bank */
+  SETU16(msg, *i, wordPtr);
+  SETU16(msg, *i, wordData);
+  for (j = 0; j < 8; j++)
+  {
+    SETU8(msg, *i, tagId[j]);
+  }
+  for (j = 0; j < 16; j++)
+  {
+    SETU8(msg, *i, dataBuf[j]);
+  }
+}
+
+/** Helper routine to form the Gne2 IAVDenatran Custom command get token Id */
+void TMR_SR_msgAddIAVDenatranCustomGetTokenId(uint8_t *msg, uint8_t *i, uint16_t timeout, 
+    TMR_GEN2_Password accessPassword, uint8_t mode, TMR_TagFilter* target)
+{
+  uint8_t option = 0,rec; 
+
+  SETU8(msg, *i, TMR_SR_OPCODE_WRITE_TAG_SPECIFIC);
+  SETU16(msg, *i, timeout);
+  SETU8(msg, *i, (uint8_t)TMR_SR_GEN2_DENATRAN_IAV_SILICON);  /* Chip - type*/
+  rec=*i;
+  SETU8(msg,*i,0x40);//option
+  SETU8(msg, *i, (uint8_t)0x00);
+  SETU8(msg, *i, (uint8_t)mode);  /* Sub command */
+  filterbytes(TMR_TAG_PROTOCOL_GEN2, target, &option, i, msg, accessPassword, true); 
+  msg[rec]=msg[rec]|option;
+}
+
+/**
+ * IAV Denatran Custom Command write to MemMap
+ * Chip type = 0x0B, command = 0x06
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param target Filter to be applied.
+ * @param wordPtr pointer to the USER data
+ * @param wordData data to be written
+ * @param dataBuf credentials written word
+ */
+TMR_Status
+TMR_SR_cmdIAVDenatranCustomWriteToMemMap(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t mode, uint8_t payload,
+                      TMR_uint8List *data, TMR_TagFilter* target, uint16_t wordPtr, uint16_t wordData, uint8_t* tagId, uint8_t* dataBuf)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIAVDenatranCustomWriteToMemMap(msg, &i, timeout, accessPassword, mode, payload, target, wordPtr, wordData, tagId, dataBuf);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the  response back to the user */
+  i = 9;
+  /* FF    06     2d    00 00      08     40     00 00         xx xx        xx xx
+   * SOH Length OpCode Status  ChipType  option  SubCommand  [payload]      CRC
+   */
+  {
+    uint16_t copyLength;
+
+    copyLength = msg[1] + 5 - i;
+
+    if (copyLength > data->max)
+    {
+      copyLength = data->max;
+    }
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/** Helper routine to form the Gen2 IAVDenatran Custom commad write Sec */
+void TMR_SR_msgAddIAVDenatranCustomWriteSec(uint8_t *msg, uint8_t *i, uint16_t timeout, TMR_GEN2_Password accessPassword,
+    uint8_t mode, uint8_t payload, TMR_TagFilter* target, uint8_t* data, uint8_t* dataBuf)
+{
+  uint8_t j;
+
+  TMR_SR_msgAddIAVDenatranCustomOp(msg, i, timeout, accessPassword, mode, payload, target);
+
+  for (j = 0; j < 6; j++)
+  {
+    SETU8(msg, *i, data[j]);
+  }
+  for (j = 0; j < 16; j++)
+  {
+    SETU8(msg, *i, dataBuf[j]);
+  }
+}
+
+/**
+ * IAV Denatran Custom Command write sec
+ * Chip type = 0x0B, command = 0x0B
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag
+ * @param target Filter to be applied.
+ * @param wordPtr pointer to the USER data
+ * @param data data words
+ * @param dataBuf credentials written word
+ */
+TMR_Status
+TMR_SR_cmdIAVDenatranCustomWriteSec(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t mode, uint8_t payload,
+                      TMR_uint8List *data, TMR_TagFilter* target, uint8_t* dataWords, uint8_t* dataBuf)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIAVDenatranCustomWriteSec(msg, &i, timeout, accessPassword, mode, payload, target, dataWords, dataBuf);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the  response back to the user */
+  i = 9;
+  /* FF    06     2d    00 00      08     40     00 00         xx xx        xx xx
+   * SOH Length OpCode Status  ChipType  option  SubCommand  [payload]      CRC
+   */
+  {
+    uint16_t copyLength;
+
+    copyLength = msg[1] + 5 - i;
+
+    if (copyLength > data->max)
+    {
+      copyLength = data->max;
+    }
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/**
+ * IAV Denatran Custom Command Get Token Id
+ * Chip type = 0x0B, command = 0x09
+ *  
+ * @param reader The reader
+ * @param timeout The timeout of the operation, in milliseconds. Valid range is 0-65535.
+ * @param accessPassword The access password to use to write on the tag 
+ * @param target Filter to be applied.
+ */ 
+TMR_Status
+TMR_SR_cmdIAVDenatranCustomGetTokenId(TMR_Reader *reader, uint16_t timeout, TMR_GEN2_Password accessPassword, uint8_t mode, 
+                      TMR_uint8List *data, TMR_TagFilter* target)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  TMR_SR_msgAddIAVDenatranCustomGetTokenId(msg, &i, timeout, accessPassword, mode, target);
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, timeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the  response back to the user */
+  i = 9;
+  /* FF    06     2d    00 00      08     40     00 00         xx xx        xx xx
+   * SOH Length OpCode Status  ChipType  option  SubCommand  [payload]      CRC
+   */
+  {
+    uint16_t copyLength;
+
+    copyLength = msg[1] + 5 - i;
+
+    if (copyLength > data->max)
+    {
+      copyLength = data->max;
+    }
+    if (NULL != data)
+    {
+      memcpy(data->list, &msg[i], copyLength);
+      data->len = copyLength;
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/**
+ * TMR_SR_cmdGetReaderStatistics
+ * Get the current per-port statistics.
+ *
+ * @param reader [in]The reader
+ * @param statFlags [in]The set of statistics together
+ * @param stats [out]The ReaderStatistics structure populated with requested per-port values
+ */
+TMR_Status
+TMR_SR_cmdGetReaderStatistics(TMR_Reader *reader, TMR_SR_ReaderStatisticsFlag statFlags,
+                                         TMR_SR_ReaderStatistics *stats)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i, length, offset;
+  i = 2;
+
+  SETU8(msg, i, TMR_SR_OPCODE_GET_READER_STATS);
+  SETU8(msg, i, (uint8_t)TMR_SR_READER_STATS_OPTION_GET_PER_PORT); /* Option byte */
+  SETU8(msg, i, (uint8_t)statFlags);
+
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, reader->u.serialReader.commandTimeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the statistics from response */
+  if (NULL != stats)
+  {
+    uint8_t  port = 0;
+    offset = 7;
+
+    length = reader->u.serialReader.txRxMap->len;
+
+    while (offset < (msg[1] + 2))
+    {
+      if (0 != (msg[offset] & TMR_SR_READER_STATS_FLAG_RF_ON_TIME))
+      {
+        offset += 2;
+
+        for (i = 0; i < length; i++)
+        {
+          port = msg[offset];
+          if (i == (port-1))
+          {
+            offset ++;
+            stats->rfOnTime[i] = GETU32(msg, offset);
+          }
+          else
+          {
+            stats->rfOnTime[i] = 0;
+          }
+        }
+        stats->numPorts = length;
+      }
+      else if (0 != (msg[offset] & TMR_SR_READER_STATS_FLAG_NOISE_FLOOR))
+      {
+        offset += 2;
+
+        for (i = 0; i < length; i++)
+        {
+          port = msg[offset];
+          if (i == (port-1))
+          {
+            offset ++;
+            stats->noiseFloor[i] = msg[offset++];
+          }
+          else
+          {
+            stats->noiseFloor[i] = 0;
+          }
+        }
+        stats->numPorts = length;
+      }
+      else if (0 != (msg[offset] & TMR_SR_READER_STATS_FLAG_NOISE_FLOOR_TX_ON))
+      {
+        offset += 2;
+
+        for (i = 0; i < length; i++)
+        {
+          port = msg[offset];
+          if (i == (port-1))
+          {
+            offset ++;
+            stats->noiseFloorTxOn[i] = msg[offset++];
+          }
+          else
+          {
+            stats->noiseFloorTxOn[i] = 0;
+          }
+        }
+        stats->numPorts = length;
+      }
+    }
+  }
+  return TMR_SUCCESS;
+}
+
+/**
+ * TMR_SR_cmdResetReaderStatistics
+ * Reset the per-port statistics.
+ *
+ * @param reader [in]The reader
+ * @param statFlags [in]The set of statistics to reset. Only the RF on time statistic may be reset.
+ */
+TMR_Status
+TMR_SR_cmdResetReaderStatistics(TMR_Reader *reader, TMR_SR_ReaderStatisticsFlag statFlags)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  i = 2;
+
+  SETU8(msg, i, TMR_SR_OPCODE_GET_READER_STATS);
+  SETU8(msg, i, (uint8_t)TMR_SR_READER_STATS_OPTION_RESET); /* Option byte */
+  SETU8(msg, i, (uint8_t)statFlags);
+
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, reader->u.serialReader.commandTimeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  return TMR_SUCCESS;
+}
+
+
+/**
+ * Helper function to be used in GetReaderStats
+ */ 
+TMR_Status
+TMR_fillReaderStats(TMR_Reader *reader, TMR_Reader_StatsValues* stats, uint16_t flag, uint8_t* msg, uint8_t offset)
+{
+  uint8_t i;
+  while (offset < (msg[1] + 2))
+  {
+    if ((0x80) > msg[offset])
+    {
+      flag = msg[offset];
+    }
+    else
+    {
+      /**
+       * the response flag will be in EBV format,
+       * convert that to the api enum values
+       */
+      flag = ((msg[offset] << 8) | (msg[offset + 1]));
+      flag &= 0x7fff;
+      flag = ((flag >> 1) | (flag & 0x7f));
+    }
+
+
+    if (flag & TMR_READER_STATS_FLAG_RF_ON_TIME)
+    {
+      uint8_t tx;
+
+      offset += 2;
+
+      for (i = 0; i < reader->u.serialReader.txRxMap->len; i++)
+      {
+        tx = GETU8(msg, offset);
+        if (tx == reader->u.serialReader.txRxMap->list[i].txPort)
+        {
+          stats->perAntenna.list[i].antenna = reader->u.serialReader.txRxMap->list[i].antenna;
+          stats->perAntenna.list[i].rfOnTime = GETU32(msg, offset);
+        }
+      }
+    }
+
+    else if (flag & TMR_READER_STATS_FLAG_NOISE_FLOOR_SEARCH_RX_TX_WITH_TX_ON)
+    {
+      uint8_t tx,rx, len;
+
+      offset++;
+      len = GETU8(msg, offset);
+      while (len)
+      {
+        tx = GETU8(msg, offset);
+        rx = GETU8(msg, offset);
+        for (i = 0; i < reader->u.serialReader.txRxMap->len; i++)
+        {
+          if ((rx == reader->u.serialReader.txRxMap->list[i].rxPort) && (tx == reader->u.serialReader.txRxMap->list[i].txPort))
+          {
+            stats->perAntenna.list[i].antenna = reader->u.serialReader.txRxMap->list[i].antenna;
+            stats->perAntenna.list[i].noiseFloor = GETU8(msg, offset);
+            len -= 3;
+          }
+        }
+      }
+    }
+
+    else if (flag & TMR_READER_STATS_FLAG_FREQUENCY)
+    {
+      offset += 3;
+      stats->frequency = GETU24(msg, offset);
+    }
+
+    else if (flag & TMR_READER_STATS_FLAG_TEMPERATURE)
+    {
+      offset += 3;
+      stats->temperature = GETU8(msg, offset);
+    }
+
+    else if (flag & TMR_READER_STATS_FLAG_PROTOCOL)
+    {
+      offset += 3;
+      stats->protocol = (TMR_TagProtocol)GETU8(msg, offset);
+    }
+
+    else if (flag & TMR_READER_STATS_FLAG_ANTENNA_PORTS)
+    {
+      uint8_t tx, rx;
+
+      offset += 3;      
+      tx = GETU8(msg, offset);
+      rx = GETU8(msg, offset);
+
+      for (i = 0; i < reader->u.serialReader.txRxMap->len; i++)
+      {
+        if ((rx == reader->u.serialReader.txRxMap->list[i].rxPort) && (tx == reader->u.serialReader.txRxMap->list[i].txPort))
+        {
+          stats->antenna = reader->u.serialReader.txRxMap->list[i].antenna;
+          break;
+        }
+      }
+    }
+
+    else if (flag & TMR_READER_STATS_FLAG_CONNECTED_ANTENNAS)
+    {
+      offset += 3;
+      stats->connectedAntennas.len = msg[offset - 1];
+      for (i = 0; i < stats->connectedAntennas.len; i++)
+      {
+        stats->connectedAntennas.list[i] = msg[offset++];
+      }
+    }
+    else
+    {
+      return TMR_ERROR_INVALID;
+    }
+  }/* End of while loop */
+  return TMR_SUCCESS;
+}
+ 
+/**
+ * TMR_SR_cmdGetReaderStats
+ * Get the current per-port statistics.
+ *   
+ * @param reader [in]The reader
+ * @param statFlags [in]The set of statistics together
+ * @param stats [out]The ReaderStatistics structure populated with requested per-port values
+ */
+TMR_Status 
+TMR_SR_cmdGetReaderStats(TMR_Reader *reader, TMR_Reader_StatsFlag statFlags,
+                                         TMR_Reader_StatsValues *stats)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i, offset; 
+  uint16_t flag = 0, temp = 0;
+  i = 2;
+
+  SETU8(msg, i, TMR_SR_OPCODE_GET_READER_STATS);
+  SETU8(msg, i, (uint8_t)TMR_SR_READER_STATS_OPTION_GET_PER_PORT); /* Option byte */
+
+  /**
+   * To extend the flag byte, an EBV technique is to be used.
+   * When the highest order bit of the flag byte is used,
+   * it signals the reader’s parser, that another flag byte is to follow
+   */
+  if ((0x80) > statFlags)
+  {
+    SETU8(msg, i, (uint8_t)statFlags);
+  }
+  else
+  {
+    temp = statFlags & 0x7f;
+    statFlags &= 0xFFFE;
+    statFlags = (TMR_Reader_StatsFlag)((statFlags << 1) | temp);
+    statFlags &= 0xFF7F;
+    SETU16(msg, i, ((uint16_t)0x8000 | statFlags));
+  }
+
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, reader->u.serialReader.commandTimeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Parse the statistics from response */
+  if (NULL != stats)
+  {
+    uint8_t  j;
+    offset = 7;
+
+    /**
+     * preinitialize the rf ontime and the noise floor value to zero
+     * berfore getting the reader stats
+     */
+    for (i = 0; i < stats->perAntenna.max; i++)
+    {
+      stats->perAntenna.list[i].antenna = 0;
+      stats->perAntenna.list[i].rfOnTime = 0;
+      stats->perAntenna.list[i].noiseFloor = 0;
+    }
+
+    if ((0x80) > statFlags)
+    {
+      offset = 7;
+    }
+    else
+    {
+      offset = 8;
+    }
+
+    ret = TMR_fillReaderStats(reader, stats, flag, msg, offset);
+    if (TMR_SUCCESS != ret)
+    {
+      return ret;
+    }
+
+    /**
+     * iterate through the per antenna values,
+     * If found  any 0-antenna rows, copy the
+     * later rows down to compact out the empty space.
+     */
+    for (i = 0; i < reader->u.serialReader.txRxMap->len; i++)
+    {
+      if (!stats->perAntenna.list[i].antenna )
+      {
+        for (j = i + 1; j < reader->u.serialReader.txRxMap->len; j++)
+        {
+          if (stats->perAntenna.list[j].antenna) 
+          {
+            stats->perAntenna.list[i].antenna = stats->perAntenna.list[j].antenna;
+            stats->perAntenna.list[i].rfOnTime = stats->perAntenna.list[j].rfOnTime;
+            stats->perAntenna.list[i].noiseFloor = stats->perAntenna.list[j].noiseFloor;
+            stats->perAntenna.list[j].antenna = 0;
+            stats->perAntenna.list[j].rfOnTime = 0;
+            stats->perAntenna.list[j].noiseFloor = 0;
+
+            stats->perAntenna.len++;
+            break;
+          }
+        }
+      }
+      else
+      {
+        /* Increment the length */
+        stats->perAntenna.len++;
+      }
+    }
+  }/* end of outermost if block */
+
+  /* Store the requested flags for future validation */
+  stats->valid = reader->statsFlag;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * TMR_SR_cmdResetReaderStats
+ * Reset the per-port statistics.
+ *   
+ * @param reader [in]The reader
+ * @param statFlags [in]The set of statistics to reset. Only the RF on time statistic may be reset.
+ */
+TMR_Status 
+TMR_SR_cmdResetReaderStats(TMR_Reader *reader, TMR_Reader_StatsFlag statFlags)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  uint16_t temp = 0;
+  i = 2;
+
+  SETU8(msg, i, TMR_SR_OPCODE_GET_READER_STATS);
+  SETU8(msg, i, (uint8_t)TMR_SR_READER_STATS_OPTION_RESET); /* Option byte */
+
+ /**
+   * To extend the flag byte, an EBV technique is to be used.
+   * When the highest order bit of the flag byte is used,
+   * it signals the reader’s parser, that another flag byte is to follow
+   */
+  if ((0x80) > statFlags)
+  {
+    SETU8(msg, i, (uint8_t)statFlags);
+  }
+  else
+  {
+    temp = statFlags & 0x7f;
+    statFlags &= 0xFFFE;
+    statFlags = (TMR_Reader_StatsFlag)((statFlags << 1) | temp);
+    statFlags &= 0xFF7F;
+    SETU16(msg, i, ((uint16_t)0x8000 | statFlags));
+  }
+
+  msg[1] = i - 3; /* Install length */
+
+  ret = TMR_SR_sendTimeout(reader, msg, reader->u.serialReader.commandTimeout);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_SR_receiveAutonomousReading(struct TMR_Reader *reader, TMR_TagReadData *trd, TMR_Reader_StatsValues *stats)
+{
+  TMR_Status ret;
+
+  ret = TMR_SUCCESS;
+  reader->continuousReading = true;
+
+  ret = TMR_SR_hasMoreTags(reader);
+  if (TMR_SUCCESS == ret)
+  {        
+    uint16_t flags;
+
+    if (false == reader->isStatusResponse)
+    {
+      /* Ignore the fail cases and pass only valid messages */
+      flags = GETU16AT(reader->u.serialReader.bufResponse, 8);
+      TMR_SR_parseMetadataFromMessage(reader, trd, flags, &reader->u.serialReader.bufPointer, reader->u.serialReader.bufResponse);
+      TMR_SR_postprocessReaderSpecificMetadata(trd, &reader->u.serialReader);
+      trd->reader = reader;
+      reader->u.serialReader.tagsRemainingInBuffer--;
+    }
+    else
+    {
+      /* A status stream response */
+      uint8_t offset, i,j;
+      uint16_t flags = 0;                 
+
+      TMR_STATS_init(stats);
+      offset = reader->u.serialReader.bufPointer;
+
+      /* Get status content flags */
+      if ((0x80) > reader->statsFlag)
+      {
+        offset += 1;
+      }
+      else
+      {
+        offset += 2;
+      }
+
+      /**
+      * preinitialize the rf ontime and the noise floor value to zero
+      * berfore getting the reader stats
+      */
+      for (i = 0; i < stats->perAntenna.max; i++)
+      {
+        stats->perAntenna.list[i].antenna = 0;
+        stats->perAntenna.list[i].rfOnTime = 0;
+        stats->perAntenna.list[i].noiseFloor = 0;
+      }
+
+      TMR_fillReaderStats(reader, stats, flags, reader->u.serialReader.bufResponse, offset);
+
+      /**
+      * iterate through the per antenna values,
+      * If found  any 0-antenna rows, copy the
+      * later rows down to compact out the empty space.
+      */
+      for (i = 0; i < reader->u.serialReader.txRxMap->len; i++)
+      {
+        if (!stats->perAntenna.list[i].antenna)
+        {
+          for (j = i + 1; j < reader->u.serialReader.txRxMap->len; j++)
+          {
+            if (stats->perAntenna.list[j].antenna)
+            {
+              stats->perAntenna.list[i].antenna = stats->perAntenna.list[j].antenna;
+              stats->perAntenna.list[i].rfOnTime = stats->perAntenna.list[j].rfOnTime;
+              stats->perAntenna.list[i].noiseFloor = stats->perAntenna.list[j].noiseFloor;
+              stats->perAntenna.list[j].antenna = 0;
+              stats->perAntenna.list[j].rfOnTime = 0;
+              stats->perAntenna.list[j].noiseFloor = 0;
+
+              stats->perAntenna.len++;
+              break;
+            }
+          }
+        }
+        else
+        {
+          /* Increment the length */
+          stats->perAntenna.len++;
+        }
+      }
+
+      /* store the requested flags for future use */
+      stats->valid = reader->statsFlag;
+    }
+  }
+  
+  reader->continuousReading = false;
+  return ret;  
+}
+
+TMR_Status
+TMR_SR_cmdStopReading(struct TMR_Reader *reader)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i, op;
+  
+  reader->hasContinuousReadStarted = false;
+  i = 2;
+  op = TMR_SR_OPCODE_MULTI_PROTOCOL_TAG_OP;
+  SETU8(msg, i, op);
+  SETU16(msg, i, 0); /* Timeout, Currently ignored */
+  SETU8(msg, i, (uint8_t)0x02); /* option - stop continuous reading */
+
+  msg[1]=i - 3;  /* Install length */
+
+  /* No need to capture the response */
+  return TMR_SR_sendMessage(reader, msg, &op, reader->u.serialReader.commandTimeout);
+}
+
+TMR_Status
+TMR_SR_cmdGetReaderWriteTimeOut (struct TMR_Reader *reader, TMR_TagProtocol protocol,
+                                 TMR_SR_Gen2ReaderWriteTimeOut *value)
+{
+  TMR_Status ret;
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i, op;
+
+  i = 2;
+  op = TMR_SR_OPCODE_GET_PROTOCOL_PARAM;
+  SETU8(msg, i, op);
+  SETU8(msg, i, protocol); 
+  SETU8(msg, i, (uint8_t)0x3f); /* option - reader write timeout */
+
+  msg[1]=i - 3;  /* Install length */
+
+  ret = TMR_SR_send(reader, msg);
+  if (TMR_SUCCESS != ret)
+  {
+    return ret;
+  }
+
+  /* Get the values */
+  value->earlyexit =  GETU8AT(msg, 7);
+  value->writetimeout = GETU16AT(msg, 8);
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_SR_cmdSetReaderWriteTimeOut (struct TMR_Reader *reader, TMR_TagProtocol protocol,
+                                 TMR_SR_Gen2ReaderWriteTimeOut *value)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+
+  i = 2;
+  SETU8(msg, i, TMR_SR_OPCODE_SET_PROTOCOL_PARAM);
+  SETU8(msg, i, protocol);
+  SETU8(msg, i, (uint8_t)0x3f); /* option - reader write timeout */
+  SETU8(msg, i, (uint8_t)value->earlyexit);
+  SETU16(msg,i, value->writetimeout);
+
+  msg[1] = i - 3; /* Install length */
+  return TMR_SR_send(reader, msg);
+}
+
+TMR_Status
+TMR_SR_cmdAuthReqResponse(struct TMR_Reader *reader, TMR_TagAuthentication *auth)
+{
+  uint8_t msg[TMR_SR_MAX_PACKET_SIZE];
+  uint8_t i;
+  uint8_t opcode;
+
+  i = 2;
+  SETU8(msg, i, (uint8_t)TMR_SR_OPCODE_MULTI_PROTOCOL_TAG_OP);
+  SETU8(msg, i, (uint8_t)0x00);
+  SETU8(msg, i, (uint8_t)0x00);
+  SETU8(msg, i, (uint8_t)0x03);
+  SETU8(msg, i, (uint8_t)0x00);
+  SETU8(msg, i, (uint8_t)0x01);
+  SETU8(msg, i, (uint8_t)0x00);
+
+  switch (auth->type)
+  {
+  default:
+	return TMR_ERROR_UNSUPPORTED;
+
+  case TMR_AUTH_TYPE_GEN2_PASSWORD:
+	{
+	  TMR_GEN2_Password password = auth->u.gen2Password;
+	  SETU8(msg, i, (uint8_t)0x20);
+	  SETU8(msg, i, (uint8_t)(password>>24));
+	  SETU8(msg, i, (uint8_t)(password>>16));
+	  SETU8(msg, i, (uint8_t)(password>> 8));
+	  SETU8(msg, i, (uint8_t)(password>> 0));
+	}
+	break;
+  }
+
+  msg[1] = i - 3; /* Install length */
+  return TMR_SR_sendMessage(reader, msg, &opcode, 0);
+}
+
+#endif /* TMR_ENABLE_SERIAL_READER */
diff --git a/cbits/api/serial_transport_posix.c b/cbits/api/serial_transport_posix.c
new file mode 100644
--- /dev/null
+++ b/cbits/api/serial_transport_posix.c
@@ -0,0 +1,307 @@
+/**
+ *  @file serial_transport_posix.c
+ *  @brief Mercury API - POSIX serial transport implementation
+ *  @author Nathan Williams
+ *  @date 10/20/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.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include "tm_reader.h"
+
+#ifdef __APPLE__
+#include <sys/ioctl.h>
+#include <IOKit/serial/ioss.h>
+#endif
+
+#ifdef TMR_ENABLE_SERIAL_TRANSPORT_NATIVE
+
+static TMR_Status
+s_open(TMR_SR_SerialTransport *this)
+{
+  int ret;
+  struct termios t;
+#if TMR_MAX_READER_NAME_LENGTH > 0
+  TMR_SR_SerialPortNativeContext *c;
+
+  c = this->cookie;
+
+  c->handle = open(c->devicename, O_RDWR);
+  if (c->handle == -1)
+    return TMR_ERROR_COMM_ERRNO(errno);
+#endif
+
+  /*
+   * Set 8N1, disable high-bit stripping, soft flow control, and hard
+   * flow control (modem lines).
+   */
+  ret = tcgetattr(c->handle, &t);
+  if (-1 == ret)
+    return TMR_ERROR_COMM_ERRNO(errno);
+  t.c_iflag &= ~(ICRNL | IGNCR | INLCR | INPCK | ISTRIP | IXANY 
+                 | IXON | IXOFF | PARMRK);
+  t.c_oflag &= ~OPOST;
+  t.c_cflag &= ~(CRTSCTS | CSIZE | CSTOPB | PARENB);
+  t.c_cflag |= CS8 | CLOCAL | CREAD | HUPCL;
+  t.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+  t.c_cc[VMIN] = 0;
+  t.c_cc[VTIME] = 1;
+  ret = tcsetattr(c->handle, TCSANOW, &t);
+  if (-1 == ret)
+    return TMR_ERROR_COMM_ERRNO(errno);
+
+  return TMR_SUCCESS;
+}
+
+static TMR_Status
+s_sendBytes(TMR_SR_SerialTransport *this, uint32_t length, 
+            uint8_t* message, const uint32_t timeoutMs)
+{
+  TMR_SR_SerialPortNativeContext *c;
+  int ret;
+
+  c = this->cookie;
+  do 
+  {
+    ret = write(c->handle, message, length);
+    if (ret == -1)
+    {
+      if (ENXIO == errno)
+      {
+        return TMR_ERROR_TIMEOUT; 
+      }
+      else
+      {
+        return TMR_ERROR_COMM_ERRNO(errno);
+      }
+    }
+    length -= ret;
+    message += ret;
+  }
+  while (length > 0);
+
+  return TMR_SUCCESS;
+}
+
+static TMR_Status
+s_receiveBytes(TMR_SR_SerialTransport *this, uint32_t length, 
+               uint32_t *messageLength, uint8_t* message, const uint32_t timeoutMs)
+{
+  TMR_SR_SerialPortNativeContext *c;
+  int ret;
+  struct timeval tv;
+  fd_set set;
+  int status = 0;
+
+  *messageLength = 0;
+  c = this->cookie;
+
+  do
+  {
+    do
+    {
+      FD_ZERO(&set);
+      FD_SET(c->handle, &set);
+      tv.tv_sec = timeoutMs / 1000;
+      tv.tv_usec = (timeoutMs % 1000) * 1000;
+      /* Ideally should reset this timeout value every time through */
+      ret = select(c->handle + 1, &set, NULL, NULL, &tv);
+    } while (ret == -1 && errno == EINTR);
+    if (ret == -1)
+    {
+      return TMR_ERROR_COMM_ERRNO(errno);
+    }
+    if (ret < 1)
+    {
+      return TMR_ERROR_TIMEOUT;
+    }
+    ret = read(c->handle, message, length);
+    if (ret == -1)
+    {
+      if (ENXIO == errno)
+      {
+        return TMR_ERROR_TIMEOUT; 
+      }
+      else
+      {
+        return TMR_ERROR_COMM_ERRNO(errno);
+      }
+    }
+
+    if (0 == ret)
+    {
+      /**
+       * We should not be here, coming here means the select()
+       * is success , but we are not able to read the data.
+       * check the serial port connection status.
+       **/
+      ret = ioctl(c->handle, TIOCMGET, &status);
+      if (-1 == ret)
+      {
+        /* not success. check for errno */
+        if (EIO == errno)
+        {
+          /**
+           * EIO means I/O error, may serial port got disconnected,
+           * throw the error.
+           **/
+          return TMR_ERROR_TIMEOUT;
+        }
+      }
+    }
+
+    length -= ret;
+    *messageLength += ret;
+    message += ret;
+  }
+  while (length > 0);
+
+  return TMR_SUCCESS;
+}
+
+static TMR_Status
+s_setBaudRate(TMR_SR_SerialTransport *this, uint32_t rate)
+{
+  TMR_SR_SerialPortNativeContext *c;
+  
+  c = this->cookie;
+
+#if defined(__APPLE__)
+  {
+    speed_t speed = rate;
+
+    if (ioctl(c->handle, IOSSIOSPEED, &speed) == -1)
+      return TMR_ERROR_COMM_ERRNO(errno);
+  }
+#else
+  {
+    struct termios t;
+
+    tcgetattr(c->handle, &t);
+
+#define BCASE(t,n) case n: cfsetispeed((t),B##n); cfsetospeed((t),B##n); break;
+    switch (rate)
+    {
+      BCASE(&t, 9600);
+      BCASE(&t, 19200);
+      BCASE(&t, 38400);
+      // Believe it or not, speeds beyond 38400 aren't required by POSIX.
+#ifdef B57600
+      BCASE(&t, 57600);
+#endif
+#ifdef B115200
+      BCASE(&t, 115200);
+#endif
+#ifdef B230400
+      BCASE(&t, 230400);
+#endif
+#ifdef B460800
+      BCASE(&t, 460800);
+#endif
+#ifdef B921600
+      BCASE(&t, 921600);
+#endif
+    default:
+      return TMR_ERROR_INVALID;
+    }
+#undef BCASE
+    if (tcsetattr(c->handle, TCSANOW, &t) != 0)
+    {
+      return TMR_ERROR_COMM_ERRNO(errno);
+    }
+  }
+#endif /* __APPLE__ */
+
+  return TMR_SUCCESS;
+}
+
+static TMR_Status
+s_shutdown(TMR_SR_SerialTransport *this)
+{
+  TMR_SR_SerialPortNativeContext *c;
+
+  c = this->cookie;
+
+  close(c->handle);
+  /* What, exactly, would be the point of checking for an error here? */
+
+  return TMR_SUCCESS;
+}
+
+static TMR_Status
+s_flush(TMR_SR_SerialTransport *this)
+{
+  TMR_SR_SerialPortNativeContext *c;
+
+  c = this->cookie;
+
+  if (tcflush(c->handle, TCOFLUSH) == -1)
+  {
+    return TMR_ERROR_COMM_ERRNO(errno);
+  }
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_SR_SerialTransportNativeInit(TMR_SR_SerialTransport *transport,
+                                 TMR_SR_SerialPortNativeContext *context,
+                                 const char *device)
+{
+
+#if TMR_MAX_READER_NAME_LENGTH > 0
+  if (strlen(device) + 1 > TMR_MAX_READER_NAME_LENGTH)
+  {
+    return TMR_ERROR_INVALID;
+  }
+  strcpy(context->devicename, device);
+#else
+  /* No space to store the device name, so open it now */
+  context->handle = open(device, O_RDWR);
+  if (context->handle == -1)
+  {
+    return TMR_ERROR_COMM_ERRNO(errno);
+  }
+#endif
+
+  transport->cookie = context;
+  transport->open = s_open;
+  transport->sendBytes = s_sendBytes;
+  transport->receiveBytes = s_receiveBytes;
+  transport->setBaudRate = s_setBaudRate;
+  transport->shutdown = s_shutdown;
+  transport->flush = s_flush;
+
+  return TMR_SUCCESS;
+}
+
+#endif
diff --git a/cbits/api/serial_transport_win32.c b/cbits/api/serial_transport_win32.c
new file mode 100644
--- /dev/null
+++ b/cbits/api/serial_transport_win32.c
@@ -0,0 +1,234 @@
+/**
+ *  @file serial_transport_win32.c
+ *  @brief Mercury API - Serial transport over local serial port on Win32
+ *  @author Nathan Williams
+ *  @date 10/20/2009
+ */
+
+
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#include "tm_config.h"
+#include "tmr_status.h"
+
+#if defined(WIN32) || defined(WINCE)
+#if !defined(_WINSOCK2API_) && !defined(_WINSOCKAPI_)
+#include <winsock2.h>
+#endif
+#include <stdio.h>
+
+#  if defined(WINCE)
+#    define snprintf _snprintf
+#  elif !defined(__GNUC__)
+#    define snprintf sprintf_s
+#  endif
+
+#endif /* WIN32 */
+
+#include "tm_reader.h"
+
+__declspec(dllexport) TMR_Status
+s_open(TMR_SR_SerialTransport *this)
+{
+  TMR_SR_SerialPortNativeContext *c;
+  COMMTIMEOUTS timeOuts;
+  DCB dcb;
+
+  c = this->cookie;
+  
+  c->handle = CreateFile((TCHAR*)c->devicename,
+                         GENERIC_READ | GENERIC_WRITE,
+                         0,             /* not shared */
+                         NULL,          /* default security */
+                         OPEN_EXISTING, /* don't create a new file */
+                         0,             /* flags and attributes */
+                         NULL);         /* template file */
+                         
+  if (INVALID_HANDLE_VALUE == c->handle)
+    return TMR_ERROR_INVALID; /* @todo use GetLastError() */
+
+  timeOuts.ReadIntervalTimeout          = 0xFFFFFFFF;
+  timeOuts.ReadTotalTimeoutConstant     = 0;
+  timeOuts.ReadTotalTimeoutMultiplier   = 0;
+  timeOuts.WriteTotalTimeoutConstant    = 5000;
+  timeOuts.WriteTotalTimeoutMultiplier  = 0;
+  
+  SetCommTimeouts(c->handle, &timeOuts);
+
+  dcb.DCBlength = sizeof(DCB);
+  GetCommState(c->handle, &dcb);
+  dcb.fOutxCtsFlow = 0;
+  dcb.fOutxDsrFlow = 0;
+  dcb.fDtrControl = DTR_CONTROL_DISABLE;
+  dcb.fDsrSensitivity = 0;
+  dcb.fOutX = 0;
+  dcb.fInX = 0;
+  dcb.fNull = 0;
+  dcb.fRtsControl = RTS_CONTROL_DISABLE;
+  dcb.ByteSize  = 8;
+  dcb.fParity = NOPARITY;
+  dcb.StopBits = ONESTOPBIT;
+  if ((0 == SetCommState(c->handle, &dcb)) ||
+      (0 == SetupComm(c->handle, 10000, 10000)))
+  {
+    return TMR_ERROR_INVALID;  /* @todo use GetLastError() */
+  }
+  
+  return TMR_SUCCESS;
+}
+
+__declspec(dllexport) TMR_Status
+s_sendBytes(TMR_SR_SerialTransport *this, uint32_t length,
+            uint8_t* message, const uint32_t timeoutMs)
+{
+  TMR_SR_SerialPortNativeContext *c;
+  BOOL writeStatus;
+  COMMTIMEOUTS timeOuts;
+
+  c = this->cookie;
+  GetCommTimeouts(c->handle, &timeOuts);
+  timeOuts.WriteTotalTimeoutConstant = timeoutMs;
+  SetCommTimeouts(c->handle, &timeOuts);
+  
+  {
+	long numberOfBytesWritten;
+	writeStatus = WriteFile(c->handle, message, length, &numberOfBytesWritten, NULL);
+  }
+  if (0 == writeStatus)
+  {
+    return TMR_ERROR_TIMEOUT;  /* @todo use GetLastError() */
+  }
+  return TMR_SUCCESS;
+}
+
+__declspec(dllexport) TMR_Status
+s_receiveBytes(TMR_SR_SerialTransport *this, uint32_t length,
+              uint32_t* messageLength, uint8_t* message, const uint32_t
+timeoutMs)
+{
+ DWORD readLength;
+ DWORD errorFlags;
+ COMSTAT comStat;
+ TMR_SR_SerialPortNativeContext *c;
+ BOOL    readStatus;
+ COMMTIMEOUTS timeOuts;
+
+ c = this->cookie;
+ *messageLength=0;
+
+ GetCommTimeouts(c->handle, &timeOuts);
+ timeOuts.ReadTotalTimeoutConstant = timeoutMs;
+ SetCommTimeouts(c->handle, &timeOuts);
+
+ ClearCommError(c->handle, &errorFlags, &comStat);
+ while (length > 0)
+ {
+   readLength=0;
+   readStatus = ReadFile(c->handle, message, length, &readLength, NULL);
+   *messageLength += readLength;
+   if (0 == readStatus)
+   {
+     return TMR_ERROR_TIMEOUT;  /* @todo use GetLastError() */
+   }
+   if(readLength == 0)
+   {
+     return TMR_ERROR_TIMEOUT;
+   }
+   length -= readLength;
+   message += readLength;
+
+ }
+ return TMR_SUCCESS;
+}
+
+
+__declspec(dllexport) TMR_Status
+s_setBaudRate(TMR_SR_SerialTransport *this, uint32_t rate)
+{
+  TMR_SR_SerialPortNativeContext *c;
+  DCB   dcb;
+
+  c = this->cookie;
+
+  dcb.DCBlength = sizeof(DCB);
+  GetCommState(c->handle, &dcb);
+  dcb.BaudRate  = rate;
+
+  if (0 == SetCommState(c->handle, &dcb)) /* @todo use GetLastError() */
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  return TMR_SUCCESS;
+}
+
+static TMR_Status
+s_shutdown(TMR_SR_SerialTransport *this)
+{
+  TMR_SR_SerialPortNativeContext *c;
+
+  c = this->cookie;
+
+  CloseHandle(c->handle);
+  /* What, exactly, would be the point of checking for an error here? */
+
+  return TMR_SUCCESS;
+}
+
+static TMR_Status
+s_flush(TMR_SR_SerialTransport *this)
+{
+  TMR_SR_SerialPortNativeContext *c;
+
+  c = this->cookie;
+
+  if (PurgeComm(c->handle, PURGE_RXCLEAR) == 0)
+  {
+	  return TMR_ERROR_COMM_ERRNO(errno);
+  }
+  return TMR_SUCCESS;
+}
+
+__declspec(dllexport)TMR_Status
+TMR_SR_SerialTransportNativeInit(TMR_SR_SerialTransport *transport,
+                                 TMR_SR_SerialPortNativeContext *context,
+                                 const char *device)
+{
+  // Transform COM port name from "/COMnn" to "\\\\.\\COMnn"
+  if (strlen(device)-1 + 4 + 1 > TMR_MAX_READER_NAME_LENGTH)
+  {
+    return TMR_ERROR_INVALID;
+  }
+  snprintf(context->devicename, sizeof(context->devicename),
+    "\\\\.\\%s", device+1);
+
+  transport->cookie = context;
+  transport->open = s_open;
+  transport->sendBytes = s_sendBytes;
+  transport->receiveBytes = s_receiveBytes;
+  transport->setBaudRate = s_setBaudRate;
+  transport->shutdown = s_shutdown;
+  transport->flush = s_flush;
+
+  return TMR_SUCCESS;
+}
diff --git a/cbits/api/tm_config.h b/cbits/api/tm_config.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tm_config.h
@@ -0,0 +1,263 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TM_CONFIG_H
+#define _TM_CONFIG_H
+
+/**
+ *  @file tm_config.h
+ *  @brief Mercury API - Build Configuration
+ *  @author Nathan Williams
+ *  @date 10/20/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.
+ */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * API version number
+ */
+#define TMR_VERSION "1.29.3.34"
+
+/**
+ * Define this to enable support for devices that support the serial
+ * reader command set (M5e, M6e, Vega, etc.)
+ */
+#define TMR_ENABLE_SERIAL_READER
+
+/**
+ * Define this to enable support for local serial port access via
+ * native interfaces (COM1 on Windows, /dev/ttyS0, /dev/ttyUSB0 on
+ * Linux, etc.).
+ */
+#define TMR_ENABLE_SERIAL_TRANSPORT_NATIVE
+
+/**
+ * The longest possible name for a reader.
+ */
+#define TMR_MAX_READER_NAME_LENGTH 256
+
+/**
+ * The maximum number of protocols supported in a multiprotocol search command
+ */
+#define TMR_MAX_SERIAL_MULTIPROTOCOL_LENGTH 5
+
+/**
+ * The maximum size of the Queue, used to share the streamed messages
+ * between the do_background_reads thread and parse_tag_reads thread.
+ */
+#define TMR_MAX_QUEUE_SLOTS 20
+
+/** 
+ * Number of bytes to allocate for embedded data return
+ * in each TagReadData.
+ */
+#define TMR_MAX_EMBEDDED_DATA_LENGTH 128 
+
+/**
+ * The maximum length of the probe baudrate list. This list specifies the  
+ * baudrates which are used while connecting to the serial reader.
+ */
+#define TMR_MAX_PROBE_BAUDRATE_LENGTH 8
+
+/**
+ * Define this to enable support for LLRP readers.
+ * (Not yet available for Windows)
+ */
+#define TMR_ENABLE_LLRP_TRANSPORT
+#ifndef WIN32
+#define TMR_ENABLE_LLRP_SERIAL_TRANSPORT
+#endif
+
+/**
+ * LLRP reader keep alive timeout in milli seconds
+ */
+#define TMR_LLRP_KEEP_ALIVE_TIMEOUT 5000
+
+/**
+ * Define this to enable async read using single thread
+
+Note:To run readsync_baremetal codelet you have to 
+     define it.
+	 Otherwise keep it undefined.
+ */
+#undef SINGLE_THREAD_ASYNC_READ
+
+/**
+ * Define this to enable for BARE_METAL API 
+ */
+#ifndef BARE_METAL
+/**
+ * Define this to enable support for the GEN2 Custom Tag Operations parameters
+ * and access commands
+ */
+#define TMR_ENABLE_GEN2_CUSTOM_TAGOPS
+
+/**
+ * Define this to enable support for the ISO180006B protocol parameters
+ * and access commands
+ */
+#define TMR_ENABLE_ISO180006B
+
+/**
+ * Define this to enable support for small microcontrollers.
+ * Enabling this option will reduce the code which is not relevant to 
+ * serial readers in order to minimize the program footprint
+ * To compile for Serial Reader only.
+ *
+ * To compile for Serial Reader only, use one of the following options:
+ ** Uncomment the following define
+ ** Run make with TMR_ENABLE_SERIAL_READER_ONLY=1 defined
+ ** Add -DTMR_ENABLE_SERIAL_READER_ONLY=1 to your compiler flags
+ */ 
+//#define TMR_ENABLE_SERIAL_READER_ONLY
+
+/**
+ * Define this to enable support for background reads using native threads.
+ * This feature is also available for windows (using pthreads-win32)
+ */
+
+#define TMR_ENABLE_BACKGROUND_READS
+
+
+/**
+ * Define this to include TMR_strerror().
+ */
+#define TMR_ENABLE_ERROR_STRINGS
+
+/**
+ * Define this to include TMR_paramName() and TMR_paramID().
+ */
+#define TMR_ENABLE_PARAM_STRINGS
+
+/**
+ * Enabling  this option will enable the support for the parameters defined 
+ * in stdio.h header file like FILE *. This check is required as stdio.h does not
+ * exist in some of the embedded  architectures.
+ */
+#define  TMR_ENABLE_STDIO
+  
+/**
+ * Enabling  this option will enable the support for the parameters defined 
+ * in string.h header file like strerror(). This check is required as string.h does not
+ * exist in some of the embedded  architectures.
+ */
+#define  TMR_USE_STRERROR
+#if defined(WINCE)
+#undef TMR_USE_STRERROR
+#endif
+
+#else
+/**
+ * Define this to enable support for the GEN2 Custom Tag Operations parameters
+ * and access commands
+ */
+#undef TMR_ENABLE_GEN2_CUSTOM_TAGOPS
+
+/**
+ * Define this to enable support for the ISO180006B protocol parameters
+ * and access commands
+ */
+#undef TMR_ENABLE_ISO180006B
+
+/**
+ * Define this to enable support for small microcontrollers.
+ * Enabling this option will reduce the code which is not relevant to 
+ * serial readers in order to minimize the program footprint
+ * To compile for Serial Reader only.
+ *
+ * To compile for Serial Reader only, use one of the following options:
+ ** Uncomment the following define
+ ** Run make with TMR_ENABLE_SERIAL_READER_ONLY=1 defined
+ ** Add -DTMR_ENABLE_SERIAL_READER_ONLY=1 to your compiler flags
+ */ 
+#define TMR_ENABLE_SERIAL_READER_ONLY
+
+/**
+ * Define this to enable support for background reads using native threads.
+ * This feature is also available for windows (using pthreads-win32)
+ */
+
+#undef TMR_ENABLE_BACKGROUND_READS
+
+
+/**
+ * Define this to include TMR_strerror().
+ */
+#undef TMR_ENABLE_ERROR_STRINGS
+
+/**
+ * Define this to include TMR_paramName() and TMR_paramID().
+ */
+#undef TMR_ENABLE_PARAM_STRINGS
+
+/**
+ * Enabling  this option will enable the support for the parameters defined 
+ * in stdio.h header file like FILE *. This check is required as stdio.h does not
+ * exist in some of the embedded  architectures.
+ */
+#undef  TMR_ENABLE_STDIO
+  
+/**
+ * Enabling  this option will enable the support for the parameters defined 
+ * in string.h header file like strerror(). This check is required as string.h does not
+ * exist in some of the embedded  architectures.
+ */
+#undef  TMR_USE_STRERROR
+
+#endif    /*Bare_metal*/
+
+/**
+ * Define the largest number serial reader antenna ports that will be supported
+ */
+#define TMR_SR_MAX_ANTENNA_PORTS (32)
+
+/**
+ * Define when compiling on a big-endian host platform to enable some
+ * endian optimizations. Without this, no endianness will be assumed.
+ */ 
+#undef TMR_BIG_ENDIAN_HOST
+
+/**
+ * Define this to enable API-side tag read deduplication.  Under
+ * certain conditions, the module runs out of buffer space to detect
+ * reads of a previously-seen EPC.  
+ */
+#define TMR_ENABLE_API_SIDE_DEDUPLICATION
+
+/**
+ * Default read filter timeout.
+ */
+#define TMR_DEFAULT_READ_FILTER_TIMEOUT -1
+
+/**
+ * The max length of the custom transport scheme name
+ */
+#define TMR_MAX_TRANSPORT_SCHEME_NAME 50
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TM_CONFIG_H */
diff --git a/cbits/api/tm_reader.c b/cbits/api/tm_reader.c
new file mode 100644
--- /dev/null
+++ b/cbits/api/tm_reader.c
@@ -0,0 +1,3680 @@
+/**
+ *  @file tm_reader.c
+ *  @brief Mercury API - top level implementation
+ *  @author Nathan Williams
+ *  @date 10/28/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.
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tm_reader.h"
+#include "serial_reader_imp.h"
+#include "tmr_utils.h"
+
+#define EAPI_PREFIX "eapi://"
+#define EAPI_PREFIX_LEN (sizeof(EAPI_PREFIX)-1)
+
+#define TMR_PREFIX "tmr://"
+#define TMR_PREFIX_LEN (sizeof(TMR_PREFIX)-1)
+
+#define LLRP_EAPI_PREFIX "llrp+eapi://"
+#define LLRP_EAPI_PREFIX_LEN (sizeof(LLRP_EAPI_PREFIX)-1)
+
+#define LLRP_PREFIX "llrp://"
+#define LLRP_PREFIX_LEN (sizeof(LLRP_PREFIX)-1)
+
+TMR_Status restart_reading(struct TMR_Reader *reader);
+
+/**
+ * Private: Should not be used by user level application.
+ * structure containing the transport scheme name  and the
+ * pointer to the factory init function.
+ **/
+static void TMR_initSerialTransportTable();
+
+void* do_background_receiveAutonomousReading(void * arg);
+
+typedef struct TMR_SerialTransportDispatchTableData
+{
+  char transportScheme[TMR_MAX_TRANSPORT_SCHEME_NAME];
+  TMR_TransportNativeInit transportInit;
+}TMR_SerialTransportDispatchTableData;
+
+typedef struct TMR_SerialTransportDispatchTable
+{
+  TMR_SerialTransportDispatchTableData *list;
+  uint8_t max;
+  uint8_t len;
+}TMR_SerialTransportDispatchTable;
+
+static bool transportTableInitialized = false;
+static TMR_SerialTransportDispatchTableData tdTableData[10];
+static TMR_SerialTransportDispatchTable tdTable;
+
+static void TMR_initSerialTransportTable()
+{
+  if (false == transportTableInitialized)
+  {
+    /** 
+     * We did not get a chance to initialize the transport table.
+     * Initialize it now.
+     */
+    memset(tdTableData, 0, (sizeof(tdTableData)/sizeof(tdTableData[0])));
+    tdTable.list = tdTableData;
+    tdTable.max = sizeof(tdTableData)/sizeof(tdTableData[0]);
+    tdTable.len = 0;
+
+    /* Add default schemes to the table */
+    {
+      TMR_String str;
+
+      str.max = TMR_MAX_TRANSPORT_SCHEME_NAME;
+      str.value = tdTable.list[tdTable.len].transportScheme;
+      TMR_stringCopy(&str, "eapi", (int)strlen("eapi"));
+      tdTable.list[tdTable.len].transportInit = TMR_SR_SerialTransportNativeInit;
+      tdTable.len++;
+
+      str.value = tdTable.list[tdTable.len].transportScheme;
+      TMR_stringCopy(&str, "tmr", (int)strlen("tmr"));
+      tdTable.list[tdTable.len].transportInit = TMR_SR_SerialTransportNativeInit;
+      tdTable.len++;
+    }
+    transportTableInitialized = true;
+  }
+}
+
+TMR_Status
+TMR_create_alloc(TMR_Reader **reader, const char* deviceUri)
+{
+
+  *reader = malloc(sizeof(**reader));
+  if (NULL == *reader)
+    return TMR_ERROR_OUT_OF_MEMORY;
+  return TMR_create(*reader, deviceUri);
+}
+
+
+TMR_Status
+TMR_create(TMR_Reader *reader, const char* deviceUri)
+{
+  TMR_Status ret;
+
+  ret = TMR_ERROR_INVALID;
+
+#ifdef TMR_ENABLE_BACKGROUND_READS
+  /* Because destruction of the readers may rely on the locks, these must be
+   * created before any possible error can cause an early exit
+   */
+  pthread_mutex_init(&reader->backgroundLock, NULL);
+  pthread_mutex_init(&reader->parserLock, NULL);
+  pthread_cond_init(&reader->backgroundCond, NULL);
+  pthread_cond_init(&reader->parserCond, NULL);
+  pthread_cond_init(&reader->readCond, NULL);
+  pthread_mutex_init(&reader->listenerLock, NULL);
+  pthread_mutex_init(&reader->queue_lock, NULL);
+  reader->authReqListeners = NULL;
+  reader->readExceptionListeners = NULL;
+  reader->statsListeners = NULL;
+  reader->statusListeners = NULL;
+  reader->readState = TMR_READ_STATE_IDLE;
+  reader->backgroundSetup = false;
+  reader->parserSetup = false;
+#endif
+  reader->readListeners = NULL;
+  reader->dutyCycle = false;
+  reader->paramWait = false;
+  reader->hasContinuousReadStarted = false;
+
+#ifdef TMR_ENABLE_SERIAL_READER
+#ifdef TMR_ENABLE_SERIAL_TRANSPORT_NATIVE
+if ((strncmp(deviceUri, EAPI_PREFIX, EAPI_PREFIX_LEN) == 0)
+    || ((strncmp(deviceUri, TMR_PREFIX, TMR_PREFIX_LEN) == 0)
+      && *(deviceUri + TMR_PREFIX_LEN) == '/'))
+{
+  uint8_t i;
+  char  *scheme;
+  char devname[TMR_MAX_READER_NAME_LENGTH];
+  bool scheme_exists = false;
+
+  TMR_initSerialTransportTable();
+
+  strcpy(devname, deviceUri);
+  scheme = strtok((char *)devname, ":");
+
+  for (i = 0; i < tdTable.len; i++)
+  {
+    if (0 == strcmp(scheme, tdTable.list[i].transportScheme))
+    {
+      if ('e' == deviceUri[0])
+      {
+        scheme = (char *)deviceUri + EAPI_PREFIX_LEN;
+      }
+      else
+      {
+        scheme = (char *)deviceUri + TMR_PREFIX_LEN;
+      }
+      strncpy(reader->uri, deviceUri, TMR_MAX_READER_NAME_LENGTH);
+
+        /* Entry exists */
+        ret = tdTable.list[i].transportInit(&reader->u.serialReader.transport,
+            &reader->u.serialReader.
+            transportContext.nativeContext,
+            scheme);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      scheme_exists = true;
+      break;
+    }
+  }
+
+  if (false == scheme_exists)
+  {
+    /* No entry found */
+    return TMR_ERROR_INVALID;
+  }
+  return TMR_SR_SerialReader_init(reader);
+}
+else
+#endif /* TMR_ENABLE_SERIAL_TRANSPORT_NATIVE */
+  if ((strncmp(deviceUri, LLRP_PREFIX, LLRP_PREFIX_LEN) == 0)
+      || (strncmp(deviceUri, TMR_PREFIX, TMR_PREFIX_LEN) == 0))
+{
+#ifdef TMR_ENABLE_LLRP_READER
+  const char *host, *port;
+  char hostCopy[256];
+
+  if ('t' == deviceUri[0])
+  {
+    host = deviceUri + TMR_PREFIX_LEN;
+  }
+  else
+  {
+    host = deviceUri + LLRP_PREFIX_LEN;
+  }
+  port = strchr(host, ':');
+  strcpy(hostCopy, host);
+  if (port == NULL)
+  {
+    char *slash;
+    reader->u.llrpReader.portNum = TMR_LLRP_READER_DEFAULT_PORT;
+    slash = strchr(hostCopy, '/');
+    if (slash)
+    {
+      *slash = '\0';
+    }
+  }
+  else
+  {
+    reader->u.llrpReader.portNum = atoi(port + 1);
+    hostCopy[port - host] = '\0';
+  }
+
+  strncpy(reader->uri, hostCopy, TMR_MAX_READER_NAME_LENGTH); 
+  return TMR_LLRP_LlrpReader_init(reader);
+
+#else
+  return TMR_ERROR_UNSUPPORTED_READER_TYPE;
+#endif /* TMR_ENABLE_LLRP_READER */
+}
+else
+{
+  /**
+   * we are here means user requested for custom transport
+   * scheme.
+   **/
+  uint8_t i;
+  char* scheme;
+  bool scheme_exists = false;
+
+  scheme = strtok((char *)deviceUri, ":");
+
+  for (i = 0; i < tdTable.len; i++)
+  {
+    if (0 == strcmp(scheme, tdTable.list[i].transportScheme))
+    {
+      deviceUri += strlen(scheme) + 2;
+      strncpy(reader->uri, deviceUri, TMR_MAX_READER_NAME_LENGTH);
+
+      /* Entry exists */
+      ret = tdTable.list[i].transportInit(&reader->u.serialReader.transport,
+          &reader->u.serialReader.
+          transportContext.nativeContext,
+          reader->uri);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+
+      scheme_exists = true;
+      break;
+    }
+  }
+
+  if (false == scheme_exists)
+  {
+    /* No entry found */
+    return TMR_ERROR_INVALID;
+  }
+  return TMR_SR_SerialReader_init(reader);
+}
+
+
+#else /* TMR_ENABLE_SERIAL_READER */
+/* No readers supported! */
+return TMR_ERROR_INVALID;
+#endif
+}
+
+TMR_Status
+TMR_reader_init_internal(struct TMR_Reader *reader)
+{
+  reader->connected = false;
+  reader->pSupportsResetStats = NULL;
+  reader->transportListeners = NULL;
+
+
+  TMR_RP_init_simple(&reader->readParams.defaultReadPlan, 0, NULL, 
+                     TMR_TAG_PROTOCOL_GEN2, 1);
+  reader->readParams.readPlan = &reader->readParams.defaultReadPlan;
+#ifdef SINGLE_THREAD_ASYNC_READ
+  reader->readParams.asyncOnTime = 250;
+  reader->readParams.asyncOffTime = 0;
+#endif
+#ifdef TMR_ENABLE_BACKGROUND_READS
+  reader->readParams.asyncOnTime = 250;  
+  reader->readParams.asyncOffTime = 0;
+#if 0
+  pthread_mutex_init(&reader->backgroundLock, NULL);
+  pthread_mutex_init(&reader->parserLock, NULL);
+  pthread_cond_init(&reader->backgroundCond, NULL);
+  pthread_cond_init(&reader->parserCond, NULL);
+  pthread_cond_init(&reader->readCond, NULL);
+  pthread_mutex_init(&reader->listenerLock, NULL);
+  pthread_mutex_init(&reader->queue_lock, NULL);
+  reader->readListeners = NULL;
+  reader->authReqListeners = NULL;
+  reader->readExceptionListeners = NULL;
+  reader->statsListeners = NULL;
+  reader->statusListeners = NULL;
+  reader->readState = TMR_READ_STATE_IDLE;
+  reader->backgroundSetup = false;
+  reader->parserSetup = false;
+#endif
+  reader->backgroundEnabled = false;
+  reader->trueAsyncflag = false;
+  reader->parserEnabled = false;
+  reader->tagQueueHead = NULL;
+  reader->tagQueueTail = NULL;
+  reader->isStatusResponse = false;  
+  reader->statsFlag = TMR_READER_STATS_FLAG_NONE;
+  reader->streamStats = TMR_SR_STATUS_NONE;
+  reader->finishedReading = true;
+#endif
+  reader->continuousReading = false;
+  reader->searchStatus = false;
+  reader->fastSearch = false;
+  reader->backgroundThreadCancel = false;
+  reader->isStopNTags = false;
+  reader->numberOfTagsToRead = 0;
+  reader->userMetadataFlag = TMR_TRD_METADATA_FLAG_ALL;
+  reader->portmask = 0;
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_setSerialTransport(char* scheme, TMR_TransportNativeInit nativeInit)
+{
+  bool scheme_exists = false;
+  uint8_t i;
+
+  TMR_initSerialTransportTable();
+
+  if ((0 == strcmp("llrp", scheme))
+      || (0 == strcmp("llrp", scheme)))
+  {
+    /**
+     * Currently set serial transport is only supported for
+     * serial readers only.
+     **/
+    return TMR_ERROR_UNSUPPORTED;
+  }
+
+  for (i = 0; i < tdTable.len; i++)
+  {
+    if (0 == strcmp(scheme, tdTable.list[i].transportScheme))
+    {
+      /* Entry exists already, just update it */
+      if (NULL != nativeInit)
+      {
+        tdTable.list[i].transportInit = nativeInit;
+      }
+      scheme_exists = true;
+      break;
+    }
+  }
+
+  if (false == scheme_exists)
+  {
+
+    TMR_String str;
+    /* Its a new entry, add it to table */
+
+    str.max = TMR_MAX_TRANSPORT_SCHEME_NAME;
+    str.value = tdTable.list[tdTable.len].transportScheme;
+    TMR_stringCopy(&str, scheme, (int)strlen(scheme));
+    tdTable.list[tdTable.len].transportInit = nativeInit;
+    tdTable.len++;
+  }
+  return TMR_SUCCESS;
+}
+#ifdef TMR_ENABLE_API_SIDE_DEDUPLICATION
+
+static int
+TMR_findDupTag(TMR_Reader *reader,
+               TMR_TagReadData* newRead,
+               TMR_TagReadData oldReads[], int32_t oldLength,
+               bool uniqueByAntenna, bool uniqueByData, bool uniqueByProtocol)
+{
+  int i;
+
+  for (i=0; i<oldLength; i++)
+  {
+    TMR_TagReadData* oldRead = &oldReads[i];
+    TMR_TagData* oldTag = &oldRead->tag;
+    TMR_TagData* newTag = &newRead->tag;
+
+    if ((oldTag->epcByteCount != newTag->epcByteCount) ||
+        (0 != memcmp(oldTag->epc, newTag->epc,
+                     (oldTag->epcByteCount)*sizeof(uint8_t))))
+    {
+      continue;
+    }
+    if (uniqueByAntenna)
+    {
+      if (oldRead->antenna != newRead->antenna)
+      {
+        continue;
+      }
+    }
+    if (uniqueByData)
+    {
+      if ((oldRead->data.len != newRead->data.len) ||
+          (0 != memcmp(oldRead->data.list, newRead->data.list,
+                       (oldRead->data.len)*sizeof(uint8_t))))
+      {
+        continue;
+      }
+    }
+    if (uniqueByProtocol)
+    {
+      if (oldRead->tag.protocol != newRead->tag.protocol)
+      {
+        continue;
+      }
+    }
+    /* No fields mismatched; this tag is a match */
+    break;
+  }
+
+  return (i < oldLength) ? i : -1;
+}
+
+static void
+TMR_updateDupTag(TMR_Reader* reader,
+                 TMR_TagReadData* oldRead, TMR_TagReadData* newRead,
+                 bool highestRssi)
+{
+  oldRead->readCount += newRead->readCount;
+
+  if (highestRssi)
+  {
+    if (newRead->rssi > oldRead->rssi)
+    {
+      uint32_t saveCount = oldRead->readCount;
+
+      memcpy(oldRead, newRead, sizeof(TMR_TagReadData));
+      /* TODO: TagReadData.data field not yet supported, pending a
+       * comprehensive strategy for dynamic memory allocation. */
+
+      oldRead->readCount = saveCount;
+    }
+  }
+}
+
+#endif /* TMR_ENABLE_API_SIDE_DEDUPLICATION */
+
+TMR_Status
+TMR_readIntoArray(struct TMR_Reader *reader, uint32_t timeoutMs,
+                  int32_t *tagCount, TMR_TagReadData *result[])
+{
+  int32_t tagsRead, count, alloc;
+  TMR_TagReadData *results;
+  TMR_Status ret;
+  uint32_t startHi, startLo, nowHi, nowLo;
+#ifdef TMR_ENABLE_API_SIDE_DEDUPLICATION
+  bool uniqueByAntenna, uniqueByData, recordHighestRssi, uniqueByProtocol;
+#endif /* TMR_ENABLE_API_SIDE_DEDUPLICATION */
+
+#ifdef TMR_ENABLE_API_SIDE_DEDUPLICATION
+  {
+    bool bval;
+
+    ret = TMR_paramGet(reader, TMR_PARAM_TAGREADDATA_UNIQUEBYANTENNA, &bval);
+    if (TMR_ERROR_NOT_FOUND == ret) { bval = false; }
+    else if (TMR_SUCCESS != ret) { return ret; }
+    uniqueByAntenna = bval;
+
+    ret = TMR_paramGet(reader, TMR_PARAM_TAGREADDATA_UNIQUEBYDATA, &bval);
+    if (TMR_ERROR_NOT_FOUND == ret) { bval = false; }
+    else if (TMR_SUCCESS != ret) { return ret; }
+    uniqueByData = bval;
+
+    ret = TMR_paramGet(reader, TMR_PARAM_TAGREADDATA_UNIQUEBYPROTOCOL, &bval);
+    if (TMR_ERROR_NOT_FOUND == ret) { bval = false; }
+    else if (TMR_SUCCESS != ret) { return ret; }
+    uniqueByProtocol = bval;
+
+    ret = TMR_paramGet(reader, TMR_PARAM_TAGREADDATA_RECORDHIGHESTRSSI, &bval);
+    if (TMR_ERROR_NOT_FOUND == ret) { bval = false; }
+    else if (TMR_SUCCESS != ret) { return ret; }
+    recordHighestRssi = bval;
+  }
+#endif /* TMR_ENABLE_API_SIDE_DEDUPLICATION */
+
+  tagsRead = 0;
+  alloc = 0;
+  results = NULL;
+
+  tm_gettime_consistent(&startHi, &startLo);
+  do 
+  {
+
+    ret = TMR_read(reader, timeoutMs, &count);
+    if ((TMR_SUCCESS != ret) && (TMR_ERROR_TAG_ID_BUFFER_FULL != ret))
+    {
+      goto out;
+    }
+
+    if (0 == count)
+    {
+      goto out;
+    }
+    else if (-1 == count) /* Unknown - streaming */
+    {
+      alloc += 4;
+    }
+    else
+    {
+      alloc += count;
+    }
+
+    {
+      TMR_TagReadData *newResults;
+      newResults = realloc(results, alloc * sizeof(*results));
+      if (NULL == newResults)
+      {
+        ret = TMR_ERROR_OUT_OF_MEMORY;
+        goto out;
+      }
+      results = newResults;
+    }
+    while (TMR_SUCCESS == TMR_hasMoreTags(reader))
+    {
+      if (tagsRead == alloc)
+      {
+        TMR_TagReadData *newResults;
+        alloc *= 2;
+        newResults = realloc(results, alloc * sizeof(*results));
+        if (NULL == newResults)
+        {
+          ret = TMR_ERROR_OUT_OF_MEMORY;
+          goto out;
+        }
+        results = newResults;
+      }
+      TMR_TRD_init(&results[tagsRead]);
+      ret = TMR_getNextTag(reader, &results[tagsRead]);
+      if (TMR_SUCCESS != ret)
+      {
+        goto out;
+      }
+#ifndef TMR_ENABLE_API_SIDE_DEDUPLICATION
+      tagsRead++;
+#else
+      /* Search array for record duplicating the one just fetched.
+       * If no dup found, commit fetched tag by incrementing tag count.
+       * If dup found, copy last record to found position, don't advance count.
+       */
+      if (true == reader->u.serialReader.enableReadFiltering)
+      {
+        TMR_TagReadData* last = &results[tagsRead];
+        int dupIndex = TMR_findDupTag(reader, last, results, tagsRead,
+                        uniqueByAntenna, uniqueByData, uniqueByProtocol);
+        if (-1 == dupIndex)
+          {
+            tagsRead++;
+          }
+        else
+          {
+            TMR_updateDupTag(reader, &results[dupIndex], last,
+                             recordHighestRssi);
+          }
+      }
+      else
+      {
+        tagsRead++;
+      }
+#endif /* TMR_ENABLE_API_SIDE_DEDUPLICATION */
+    }
+
+    tm_gettime_consistent(&nowHi, &nowLo);
+  }
+  while (tm_time_subtract(nowLo, startLo) < timeoutMs);
+
+out:
+  if (NULL != tagCount)
+    *tagCount = tagsRead;
+  *result = results;
+  return ret;
+}
+
+TMR_Status
+validateReadPlan(TMR_Reader *reader, TMR_ReadPlan *plan,
+                  TMR_AntennaMapList *txRxMap, uint32_t protocols)
+{
+  TMR_Status ret;
+  int i, j;
+
+  if (TMR_READ_PLAN_TYPE_MULTI == plan->type)
+  {
+    plan->u.multi.totalWeight = 0;
+    for (i = 0; i < plan->u.multi.planCount; i++)
+    {
+      ret = validateReadPlan(reader, plan->u.multi.plans[i], txRxMap, protocols);
+      if (TMR_SUCCESS != ret)
+      {
+        return ret;
+      }
+      plan->u.multi.totalWeight += plan->u.multi.plans[i]->weight;
+    }
+    }
+  else if (TMR_READ_PLAN_TYPE_SIMPLE == plan->type)
+  {
+    if (0 == ((1 << (plan->u.simple.protocol - 1)) & protocols))
+    {
+      return TMR_ERROR_INVALID_PROTOCOL_SPECIFIED;
+    }
+    for (i = 0 ; i < plan->u.simple.antennas.len; i++)
+    {
+      for (j = 0; j < txRxMap->len; j++)
+      { 
+        if (plan->u.simple.antennas.list[i] == txRxMap->list[j].antenna)
+        {
+          break;
+        }
+      }
+      if (j == txRxMap->len)
+      {
+        return TMR_ERROR_INVALID_ANTENNA_CONFIG;
+      }
+    }
+    if (NULL != plan->u.simple.tagop)
+    {
+      if (TMR_TAGOP_LIST == plan->u.simple.tagop->type)
+        return TMR_ERROR_UNSUPPORTED; /* not yet supported */
+    }
+  }
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_paramSet(struct TMR_Reader *reader, TMR_Param key, const void *value)
+{
+  TMR_Status ret;
+
+  ret = TMR_SUCCESS;
+
+  switch (key)
+  {
+#if defined(TMR_ENABLE_BACKGROUND_READS)|| defined(SINGLE_THREAD_ASYNC_READ)
+  case TMR_PARAM_READ_ASYNCOFFTIME:
+      {
+        if (TMR_READER_TYPE_LLRP != reader->readerType)
+        {
+			if (reader->readParams.asyncOffTime != *(uint32_t *)value)
+			{
+				uint32_t asyncOffTime = reader->readParams.asyncOffTime;
+				reader->readParams.asyncOffTime = *(uint32_t *)value;
+				if (reader->continuousReading)
+				{
+					ret = restart_reading(reader);
+					if(ret != TMR_SUCCESS)
+					{
+						reader->readParams.asyncOffTime = asyncOffTime;
+					}
+				}
+			}
+        }
+        else
+        {
+          goto LEVEL1;
+        }
+      }
+    break;
+  case TMR_PARAM_READ_ASYNCONTIME:
+	  {
+		  if (reader->readParams.asyncOnTime != *(uint32_t *)value)
+		  {
+			  uint32_t asyncOnTime = reader->readParams.asyncOnTime;
+			  reader->readParams.asyncOnTime = *(uint32_t *)value;
+			  if (reader->continuousReading)
+			  {
+				  ret = restart_reading(reader);
+				  if(ret != TMR_SUCCESS)
+				  {
+					  reader->readParams.asyncOnTime = asyncOnTime;
+				  }
+			  }
+		  }
+	  }
+    break;
+LEVEL1:
+#endif
+  default:
+    ret = reader->paramSet(reader, key, value);
+  }
+  return ret;
+}
+
+
+TMR_Status
+TMR_paramGet(struct TMR_Reader *reader, TMR_Param key, void *value)
+{
+  TMR_Status ret;
+
+  ret = TMR_SUCCESS;
+
+  switch (key)
+  {
+  case TMR_PARAM_READ_PLAN:
+  {
+    TMR_ReadPlan *plan = value;
+    *plan = *reader->readParams.readPlan;
+    break;
+  }
+#if defined(TMR_ENABLE_BACKGROUND_READS)|| defined(SINGLE_THREAD_ASYNC_READ) 
+  case TMR_PARAM_READ_ASYNCOFFTIME:
+  {
+    if (TMR_READER_TYPE_LLRP != reader->readerType)
+    {
+    *(uint32_t *)value = reader->readParams.asyncOffTime;
+    }
+    else
+    {
+      goto LEVEL;
+    }
+    break;
+  }
+  case TMR_PARAM_READ_ASYNCONTIME:
+    *(uint32_t *)value = reader->readParams.asyncOnTime;
+    break;
+LEVEL:
+#endif
+  default:
+    ret = reader->paramGet(reader, key, value);
+  }
+  return ret;
+}
+
+
+TMR_Status
+TMR_addTransportListener(TMR_Reader *reader, TMR_TransportListenerBlock *b)
+{
+
+  b->next = reader->transportListeners;
+  reader->transportListeners = b;
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_removeTransportListener(TMR_Reader *reader, TMR_TransportListenerBlock *b)
+{
+  TMR_TransportListenerBlock *block, **prev;
+
+  prev = &reader->transportListeners;
+  block = reader->transportListeners;
+  while (NULL != block)
+  {
+    if (block == b)
+    {
+      *prev = block->next;
+      break;
+    }
+    prev = &block->next;
+    block = block->next;
+  }
+  if (block == NULL)
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  return TMR_SUCCESS;
+}
+
+
+void
+TMR__notifyTransportListeners(TMR_Reader *reader, bool tx, 
+                              uint32_t dataLen, uint8_t *data,
+                              int timeout)
+{
+  TMR_TransportListenerBlock *block;
+
+  block = reader->transportListeners;
+  while (NULL != block)
+  {
+    block->listener(tx, dataLen, data, timeout, block->cookie);
+    block = block->next;
+  }
+}
+
+bool
+TMR_memoryProvider(void *cookie, uint16_t *size, uint8_t *data)
+{
+  TMR_memoryCookie *mc;
+  int len;
+
+  mc = cookie;
+
+  if (0 == mc->firmwareSize)
+  {
+    return false;
+  }
+
+  if (*size > mc->firmwareSize)
+  {
+    *size =(uint16_t) mc->firmwareSize;
+  }
+
+  len = *size;
+
+  memcpy(data, mc->firmwareStart, len);
+  
+  mc->firmwareSize -= len;
+  mc->firmwareStart += len;
+
+  return true;
+}
+
+#ifdef TMR_ENABLE_STDIO
+bool
+TMR_fileProvider(void *cookie, uint16_t *size, uint8_t *data)
+{
+  FILE *fp;
+  size_t len;
+
+  fp = cookie;
+
+  len = fread(data, 1, *size, fp);
+  if (0 == len)
+  {
+    return false;
+  }
+  
+  *size = (uint16_t) len;
+  return true;
+}
+#endif
+
+/**
+ * Initialize TMR_TagReadData with default values.
+ * The tagData buffer will be initialized to TMR_MAX_EMBEDDED_DATA_LENGTH
+ * which can be found in tm_config.h.  
+ * If this value is zero, then the buffer is pointed to NULL.
+ * @param trd Pointer to the TMR_TagReadData structure to initialize
+ */
+TMR_Status
+TMR_TRD_init(TMR_TagReadData *trd)
+{
+  trd->tag.protocol = TMR_TAG_PROTOCOL_NONE;
+  trd->tag.epcByteCount = 0;
+  trd->tag.crc = 0;
+  trd->metadataFlags = 0;
+  trd->phase = 0;
+  memset(trd->gpio, 0, sizeof(trd->gpio));
+  trd->gpioCount = 0;
+  trd->readCount = 0;
+  trd->rssi = 0;
+  trd->frequency = 0;
+  trd->dspMicros = 0;
+  trd->timestampLow = 0;
+  trd->timestampHigh = 0;
+
+#if TMR_MAX_EMBEDDED_DATA_LENGTH
+  trd->data.list = trd->_dataList;
+  trd->epcMemData.list = trd->_epcMemDataList;
+  trd->tidMemData.list = trd->_tidMemDataList;
+  trd->userMemData.list = trd->_userMemDataList;
+  trd->reservedMemData.list = trd->_reservedMemDataList;
+
+  trd->data.max = TMR_MAX_EMBEDDED_DATA_LENGTH;
+  trd->epcMemData.max = TMR_MAX_EMBEDDED_DATA_LENGTH;
+  trd->userMemData.max = TMR_MAX_EMBEDDED_DATA_LENGTH;
+  trd->reservedMemData.max = TMR_MAX_EMBEDDED_DATA_LENGTH;
+  trd->tidMemData.max = TMR_MAX_EMBEDDED_DATA_LENGTH;
+#else
+  trd->data.list = NULL;
+  trd->epcMemData.list = NULL;
+  trd->userMemData.list = NULL;
+  trd->tidMemData.list = NULL;
+  trd->reservedMemData.list = NULL;
+
+  trd->data.max = 0;
+  trd->epcMemData.max = 0;
+  trd->userMemData.max = 0;
+  trd->reservedMemData.max = 0;
+  trd->tidMemData.max = 0;
+#endif
+  trd->data.len = 0;
+  trd->epcMemData.len = 0;
+  trd->userMemData.len = 0;
+  trd->tidMemData.len = 0;
+  trd->reservedMemData.len = 0;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagReadData with the provided data storage area.
+ *
+ * @param trd Pointer to the TMR_TagReadData structure to initialize
+ * @param size The number of bytes pointed to
+ * @param buf Pointer to the uint8_t storage area
+ */
+TMR_Status
+TMR_TRD_init_data(TMR_TagReadData *trd, uint16_t size, uint8_t *buf)
+{
+  trd->data.max = size;
+  trd->data.len = 0;
+  trd->data.list = buf;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagReadDataMemBank with provided data storage area
+ *
+ * @param data to the TMR_uint8List structure to initialize
+ * @param size The nuber of bytes pointed to
+ * @param buf pointer to the uint8_t storage area
+ **/
+TMR_Status
+TMR_TRD_MEMBANK_init_data(TMR_uint8List *data, uint16_t size, uint8_t *buf)
+{
+  data->max = size;
+  data->len = 0;
+  data->list = buf;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_GEN2_Bap with the provided parameters
+ *
+ * @param bapVal pointer to the TMR_GEN2_Bap structure
+ * @param powerUpDelayUs the power up delay time
+ * @param freqHopOfftimeUs the offtime for frequencyHop
+ **/
+TMR_Status
+TMR_GEN2_init_BapParams(TMR_GEN2_Bap *bapVal, int32_t powerUpDelayUs, int32_t freqHopOfftimeUs)
+{
+
+  bapVal->powerUpDelayUs = powerUpDelayUs;
+  bapVal->freqHopOfftimeUs=freqHopOfftimeUs;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_Filter structure as tag data (EPC) filter with the
+ * provided tag (which is copied).
+ * 
+ * @param filter Pointer to the filter structure to initialize
+ * @param tag TMR_TagData to use as the filter value
+ */
+TMR_Status
+TMR_TF_init_tag(TMR_TagFilter *filter, TMR_TagData *tag)
+{
+  
+  filter->type = TMR_FILTER_TYPE_TAG_DATA;
+  filter->u.tagData = *tag;
+  
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_Filter structure as a Gen2 select filter with the
+ * provided parameters.
+ * 
+ * @param filter Pointer to the filter structure to initialize
+ * @param invert Whether to invert the result of the select
+ * @param bank The memory bank on the tag to compare with the data
+ * @param bitPointer The bit address of the tag data to compare
+ * @param maskBitLength The length of the data to compare
+ * @param mask The data to compare
+ */
+TMR_Status
+TMR_TF_init_gen2_select(TMR_TagFilter *filter, bool invert, TMR_GEN2_Bank bank,
+                        uint32_t bitPointer, uint16_t maskBitLength,
+                        uint8_t *mask)
+{
+  
+  filter->type = TMR_FILTER_TYPE_GEN2_SELECT;
+  filter->u.gen2Select.invert = invert;
+  filter->u.gen2Select.bank = bank;
+  filter->u.gen2Select.bitPointer = bitPointer;
+  filter->u.gen2Select.maskBitLength = maskBitLength;
+  filter->u.gen2Select.mask = mask;
+
+  return TMR_SUCCESS;
+}
+
+
+#ifdef TMR_ENABLE_ISO180006B
+/**
+ * Initialize a TMR_Filter structure as an ISO180006B select filter with the
+ * provided parameters.
+ * 
+ * @param filter Pointer to the filter structure to initialize
+ * @param invert Whether to invert the result of the select
+ * @param op The operation to use to compare the provided data with the tag data
+ * @param address The address of the 8 bytes of data on the tag to compare 
+ * @param mask 8-bit mask of the bytes to compare
+ * @param wordData The data to compare to the tag data
+ */
+TMR_Status TMR_TF_init_ISO180006B_select(TMR_TagFilter *filter, bool invert,
+                                         TMR_ISO180006B_SelectOp op,
+                                         uint8_t address, uint8_t mask,
+                                         uint8_t wordData[8])
+{
+
+  filter->type = TMR_FILTER_TYPE_ISO180006B_SELECT;
+  filter->u.iso180006bSelect.invert = invert;
+  filter->u.iso180006bSelect.op = op;
+  filter->u.iso180006bSelect.address = address;
+  filter->u.iso180006bSelect.mask = mask;
+  memcpy(filter->u.iso180006bSelect.data, wordData, 8);
+  
+  return TMR_SUCCESS;
+}
+#endif /* TMR_ENABLE_ISO180006B */
+
+
+bool
+TMR_TF_match(TMR_TagFilter *filter, TMR_TagData *tag)
+{
+  int32_t i, bitAddr;
+  bool match;
+  TMR_GEN2_Select *sel;
+
+  if (TMR_FILTER_TYPE_GEN2_SELECT != filter->type)
+  {
+    return false;
+  }
+
+  if (TMR_TAG_PROTOCOL_GEN2 != tag->protocol)
+  {
+    return false;
+  }
+
+  sel = &filter->u.gen2Select;
+
+  if (TMR_GEN2_BANK_EPC != sel->bank)
+  {
+    /*
+     * Can't perform non-EPC matches, since we don't have the rest of
+     * the tag data.
+     */
+    return false;
+  }
+
+  i = 0;
+  bitAddr = sel->bitPointer;
+  /*
+   * Matching against the CRC and PC does not have defined
+   * behavior; see section 6.3.2.11.1.1 of Gen2 version 1.2.0.
+   * We choose to let it match, because that's simple.
+   */
+  bitAddr -= 32;
+  if (bitAddr < 0)
+  {
+    i -= bitAddr;
+    bitAddr = 0;
+  }
+
+  match = true;
+  for (; i < sel->maskBitLength; i++, bitAddr++)
+  {
+    if (bitAddr >(int32_t) (tag->epcByteCount * 8))
+    {
+      match = false;
+      break;
+    }
+    /* Extract the relevant bit from both the EPC and the mask. */
+    if (((tag->epc[bitAddr / 8] >> (7 - (bitAddr & 7))) & 1) !=
+        ((sel->mask[i / 8] >> (7 - (i & 7))) & 1))
+    {
+      match = false;
+      break;
+    }
+  }
+  if (sel->invert)
+    match = match ? false : true;
+
+  return match;
+}
+
+
+/**
+ * Initialize a TMR_TagAuthentication structure as a Gen2 password.
+ *
+ * @param auth Pointer to the structure to initialize.
+ * @param password The password 32-bit Gen2 password value.
+ */
+TMR_Status
+TMR_TA_init_gen2(TMR_TagAuthentication *auth, TMR_GEN2_Password password)
+{
+
+  auth->type = TMR_AUTH_TYPE_GEN2_PASSWORD;
+  auth->u.gen2Password = password;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagAuthentication structure as Denatran IAV write credential
+ *
+ * @param auth Pointer to the structure to initialize.
+ * @param data Gen2 Denatran IAV write credential
+ */
+TMR_Status
+TMR_TA_init_gen2_Denatran_IAV_writeCredentials(TMR_TagAuthentication *auth, uint8_t idLength, uint8_t* tagId, uint8_t len, uint8_t *data)
+{
+  uint8_t i;
+  auth->type = TMR_AUTH_TYPE_GEN2_DENATRAN_IAV_WRITE_CREDENTIALS;
+
+  /* The length should be 16 byte */
+  auth->u.writeCreds.credentialLength = len;
+  if (16 != auth->u.writeCreds.credentialLength)
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  /* The length for tag ID should be 8 bytes */
+  auth->u.writeCreds.tagIdLength = idLength;
+  if (8 != auth->u.writeCreds.tagIdLength)
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  /* Copy the data */
+  for (i = 0; i < auth->u.writeCreds.tagIdLength; i++)
+  {
+    memcpy(auth->u.writeCreds.tagId, tagId, auth->u.writeCreds.tagIdLength);
+  }
+
+  /* Copy the data */
+  for (i = 0; i < auth->u.writeCreds.credentialLength; i++)
+  {
+    memcpy(auth->u.writeCreds.value, data, auth->u.writeCreds.credentialLength);
+  }
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagAuthentication structure as Denatran IAV write credential
+ *
+ * @param auth Pointer to the structure to initialize.
+ * @param data Gen2 Denatran IAV write credential
+ */
+TMR_Status
+TMR_TA_init_gen2_Denatran_IAV_writeSecCredentials(TMR_TagAuthentication *auth, uint8_t length, uint8_t* data, uint8_t len, uint8_t* credentials)
+{
+  uint8_t i;
+  auth->type = TMR_AUTH_TYPE_GEN2_DENATRAN_IAV_WRITE_SEC_CREDENTIALS;
+
+  /* The length should be 16 byte */
+  auth->u.writeSecCreds.credentialLength = len;
+  if (16 != auth->u.writeSecCreds.credentialLength)
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  /* The length for data words should be 6 bytes */
+  auth->u.writeSecCreds.dataLength = length;
+  if (6 != auth->u.writeSecCreds.dataLength)
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  /* Copy the data */
+  for (i = 0; i < auth->u.writeSecCreds.dataLength; i++)
+  {
+    memcpy(auth->u.writeSecCreds.data, data, auth->u.writeSecCreds.dataLength);
+  }
+
+  /* Copy the data */
+  for (i = 0; i < auth->u.writeSecCreds.credentialLength; i++)
+  {
+    memcpy(auth->u.writeSecCreds.value, credentials, auth->u.writeSecCreds.credentialLength);
+  }
+
+  return TMR_SUCCESS;
+}
+
+/** Initialize a TMR_StatValues structure with the default vales
+ *
+ * @param stats Pointer to the TMR_StatValues structure to initialize.
+ */
+TMR_Status
+TMR_STATS_init(TMR_Reader_StatsValues *stats)
+{
+  if (NULL != stats)
+  {
+    stats->valid = TMR_READER_STATS_FLAG_NONE;
+    /* Allocate space for the parameters */
+    stats->connectedAntennas.len = 0;
+    stats->connectedAntennas.max = TMR_SR_MAX_ANTENNA_PORTS;
+    stats->connectedAntennas.list = stats->_connectedAntennasStorage;
+    stats->perAntenna.len = 0;
+    stats->perAntenna.max = TMR_SR_MAX_ANTENNA_PORTS;
+    stats->perAntenna.list = stats->_perAntStorage;
+  }
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_GPITriggerRead structure with default values.
+ *
+ * @param triggerRead Pointer to the read plan to initialize.
+ * @param enable Option to enable trigger read.
+ */
+TMR_Status
+TMR_GPITR_init_enable(TMR_GPITriggerRead *triggerRead, bool enable)
+{
+  triggerRead->enable = enable;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_ReadPlan structure as a simple read plan with the
+ * provided parameters.  
+ *
+ * Only the mandatory elements are parameters to
+ * this function. The optional elements, filters and tag operations,
+ * can be set with TMR_RP_set_filter() and TMR_RP_set_tagop().
+ *
+ * @param plan Pointer to the read plan to initialize.
+ * @param antennaCount Number of antennas in antenna list. A
+ * zero-length list requests the reader to use all antennas known to
+ * be connected at the time of the read operation.
+ * @param antennaList Pointer to antenna numbers.
+ * @param protocol Protocol
+ * @param weight Weight.
+ */
+TMR_Status
+TMR_RP_init_simple(TMR_ReadPlan *plan, uint8_t antennaCount,
+                   uint8_t *antennaList, TMR_TagProtocol protocol,
+                   uint32_t weight) 
+{
+  
+  plan->type = TMR_READ_PLAN_TYPE_SIMPLE;
+  plan->u.simple.antennas.max = antennaCount;
+  plan->u.simple.antennas.len = antennaCount;
+  plan->u.simple.antennas.list = antennaList;
+  plan->u.simple.protocol = protocol;
+  plan->u.simple.filter = NULL;
+  plan->u.simple.tagop = NULL;
+  plan->weight = weight;
+  plan->u.simple.useFastSearch = false;
+  plan->u.simple.stopOnCount.stopNTriggerStatus = false;
+  plan->u.simple.stopOnCount.noOfTags = 0;
+  plan->u.simple.triggerRead.enable = false;
+  plan->u.simple.triggerRead.gpiList.len = 0;
+  plan->u.simple.triggerRead.gpiList.list = NULL;
+  plan->u.simple.triggerRead.gpiList.max = 0;
+  plan->enableAutonomousRead = false;
+  
+  return TMR_SUCCESS;
+}
+
+/**
+ * Set the stop on N tags  option of a read plan
+ *
+ * @param plan Pointer to the read plan
+ * @param nCount the number of tags user requested to search.
+ */
+TMR_Status
+TMR_RP_set_stopTrigger(TMR_ReadPlan *plan, uint32_t nCount)
+{
+
+  if (TMR_READ_PLAN_TYPE_SIMPLE != plan->type)
+    return TMR_ERROR_INVALID;
+
+  plan->u.simple.stopOnCount.stopNTriggerStatus = true;
+  plan->u.simple.stopOnCount.noOfTags = nCount;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Set the filter of a simple read plan.
+ *
+ * @param plan Pointer to the read plan
+ * @param filter Pointer to the filter 
+ */
+TMR_Status
+TMR_RP_set_filter(TMR_ReadPlan *plan, TMR_TagFilter *filter)
+{
+
+  if (TMR_READ_PLAN_TYPE_SIMPLE != plan->type)
+    return TMR_ERROR_INVALID;
+
+  plan->u.simple.filter = filter;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Set the fast search option of a read plan
+ *
+ * @param plan Pointer to the read plan
+ * @param useFastSearch Option for FastSearch
+ */ 
+TMR_Status
+TMR_RP_set_useFastSearch(TMR_ReadPlan *plan, bool useFastSearch)
+{
+
+  if (TMR_READ_PLAN_TYPE_SIMPLE != plan->type)
+    return TMR_ERROR_INVALID;
+
+  plan->u.simple.useFastSearch = useFastSearch;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Set the autonomous read option of a read plan
+ *
+ * @param plan Pointer to the read plan
+ * @param autonomousRead Option for autonomous read.
+ */ 
+TMR_Status
+TMR_RP_set_enableAutonomousRead(TMR_ReadPlan *plan, bool autonomousRead)
+{
+  plan->enableAutonomousRead = autonomousRead;
+  return TMR_SUCCESS;
+}
+
+/**
+ * Set the trigger read option of a read plan
+ *
+ * @param plan Pointer to the read plan
+ * @param triggerRead Pointer for trigger read
+ */
+TMR_Status
+TMR_RP_set_enableTriggerRead(TMR_ReadPlan *plan, TMR_GPITriggerRead *triggerRead)
+{
+  if (TMR_READ_PLAN_TYPE_SIMPLE != plan->type)
+    return TMR_ERROR_INVALID;
+
+  plan->u.simple.triggerRead.enable = triggerRead->enable;
+  /*
+   * TODO: extent the set_enableTriggerRead() method to accept the GPI list directly
+           as a part of read plan. Current the GPI list can be set through TMR_paramSet().
+   */
+  plan->u.simple.triggerRead.gpiList.list = NULL;
+  plan->u.simple.triggerRead.gpiList.len = 0;
+  plan->u.simple.triggerRead.gpiList.max = 0;  
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Set the tagop of a simple read plan.
+ *
+ * @param plan Pointer to the read plan
+ * @param tagop Pointer to the tagop 
+ */
+TMR_Status
+TMR_RP_set_tagop(TMR_ReadPlan *plan, TMR_TagOp *tagop)
+{
+
+  if (TMR_READ_PLAN_TYPE_SIMPLE != plan->type)
+    return TMR_ERROR_INVALID;
+
+  plan->u.simple.tagop = tagop;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_ReadPlan structure as a multi-read plan with the
+ * provided parameters.
+ *
+ * @param plan Pointer to the read plan to initialize.
+ * @param plans Array of pointers to read plans to include
+ * @param planCount Number of elements in array
+ * @param weight Weight.
+ */
+TMR_Status
+TMR_RP_init_multi(TMR_ReadPlan *plan, TMR_ReadPlan **plans, uint8_t planCount,
+                  uint32_t weight)
+{
+  plan->type = TMR_READ_PLAN_TYPE_MULTI;
+  plan->u.multi.plans = plans;
+  plan->u.multi.planCount = planCount;
+  plan->u.multi.totalWeight = 0;
+  plan->weight = weight;
+
+  return TMR_SUCCESS;
+}
+
+
+/**
+ * Initialize a TMR_TagLockAction as a Gen2 lock action with the
+ * provided parameters.
+ *
+ * @param lockAction Pointer to the structure to initialize.
+ * @param mask mask
+ * @param action action
+ */
+TMR_Status
+TMR_TLA_init_gen2(TMR_TagLockAction *lockAction, uint16_t mask, uint16_t action)
+{
+
+  lockAction->type = TMR_LOCK_ACTION_TYPE_GEN2_LOCK_ACTION;
+  lockAction->u.gen2LockAction.mask = mask;
+  lockAction->u.gen2LockAction.action = action;
+
+  return TMR_SUCCESS;
+}
+
+
+#ifdef TMR_ENABLE_ISO180006B
+/**
+ * Initialize a TMR_TagLockAction as an ISO180006B lock action with the
+ * provided parameters.
+ *
+ * @param lockAction Pointer to the structure to initialize.
+ * @param address The byte to lock
+ */
+TMR_Status
+TMR_TLA_init_ISO180006B(TMR_TagLockAction *lockAction, uint8_t address)
+{
+
+  lockAction->type = TMR_LOCK_ACTION_TYPE_ISO180006B_LOCK_ACTION;
+  lockAction->u.iso180006bLockAction.address = address;
+
+  return TMR_SUCCESS;
+}
+
+#endif /* TMR_ENABLE_ISO180006B */
+
+
+/**
+ * Initialize a TMR_TagOp as a GEN2 EPC write operation with the
+ * provided parameters.
+ * 
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param epc EPC to write
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_WriteTag(TMR_TagOp *tagop, TMR_TagData* epc)
+{
+  tagop->type = TMR_TAGOP_GEN2_WRITETAG;
+  tagop->u.gen2.u.writeTag.epcptr = epc;  /* Takes pointer to EPC; doesn't make an actual copy */
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a GEN2 data read operation with the
+ * provided parameters.
+ * 
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param bank Memory bank from which to read
+ * @param wordAddress Word address of location in bank from which to read
+ * @param len Number of words to read
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_ReadData(TMR_TagOp *tagop, TMR_GEN2_Bank bank,
+                             uint32_t wordAddress, uint8_t len)
+{
+
+  tagop->type = TMR_TAGOP_GEN2_READDATA;
+  tagop->u.gen2.u.readData.bank = bank;
+  tagop->u.gen2.u.readData.wordAddress = wordAddress;
+  tagop->u.gen2.u.readData.len = len;
+
+  return TMR_SUCCESS;
+}
+
+/** 
+ * Initialize a TMR_TagOp as a GEN2 Secure data read operation with the
+ * provided parameters.
+ *
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param bank Memory bank from which to read
+ * @param wordAddress Word address of location in bank from which to read
+ * @param len Number of words to read
+ * @param tagtype to select Alien Higgs 3 secure access and Monza 4 secure access
+ * @param passwordType specifying the mode of password 
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_SecureReadData(TMR_TagOp *tagop, TMR_GEN2_Bank bank, uint32_t wordAddress,
+                                   uint8_t len, uint8_t tagtype, uint8_t passwordType)
+{
+  tagop->type = TMR_TAGOP_GEN2_SECURE_READDATA;
+  tagop->u.gen2.u.secureReadData.passwordType = (SecurePasswordType)passwordType;
+  tagop->u.gen2.u.secureReadData.readData.bank = bank;
+  tagop->u.gen2.u.secureReadData.readData.wordAddress = wordAddress;
+  tagop->u.gen2.u.secureReadData.readData.len = len;
+  tagop->u.gen2.u.secureReadData.type = (SecureTagType)tagtype;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Secure Password with the 
+ * provided parameters.
+ *
+ * @param tagop Pointer to the tagop structure to initialize
+ * @param passwordType specifying the mode of password 
+ * @param gen2PassWord Gen2 access password
+ * @param addressLength Number of bits used to address the AP list
+ * @param addressOffset EPC word offset
+ * @param flashOffset User flash offset
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_SecurePassWord(TMR_TagOp *tagop, uint8_t passwordType, uint32_t gen2PassWord,
+                                   uint8_t addressLength, uint8_t addressOffset, uint16_t flashOffset)
+{
+  
+  tagop->u.gen2.u.secureReadData.passwordType = (SecurePasswordType)passwordType;
+  tagop->u.gen2.u.secureReadData.password.gen2PassWord.u.gen2Password = gen2PassWord;
+  tagop->u.gen2.u.secureReadData.password.secureAddressLength = addressLength;
+  tagop->u.gen2.u.secureReadData.password.secureAddressOffset = addressOffset;
+  tagop->u.gen2.u.secureReadData.password.secureFlashOffset = flashOffset;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a ISO18000B data read operation with the
+ * provided parameters.
+ * 
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param byteAddress Address of location in bank from which to read
+ * @param len Number of bytes to read
+ */
+TMR_Status
+TMR_TagOp_init_ISO180006B_ReadData(TMR_TagOp *tagop, uint8_t byteAddress, uint8_t len)
+{
+
+  tagop->type = TMR_TAGOP_ISO180006B_READDATA;
+  tagop->u.iso180006b.u.readData.byteAddress = byteAddress;
+  tagop->u.iso180006b.u.readData.len = len;
+
+  return TMR_SUCCESS;
+}
+
+
+/**
+ * Initialize a TMR_TagOp as a GEN2 data write operation with the
+ * provided parameters.
+ * 
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param bank Memory bank to write into
+ * @param wordAddress Word address of location to begin write
+ * @param data Data to write
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_WriteData(TMR_TagOp *tagop, TMR_GEN2_Bank bank,
+                              uint32_t wordAddress, TMR_uint16List *data)
+{
+  tagop->type = TMR_TAGOP_GEN2_WRITEDATA;
+  tagop->u.gen2.u.writeData.bank = bank;
+  tagop->u.gen2.u.writeData.wordAddress = wordAddress;
+  tagop->u.gen2.u.writeData.data = *data; /* Copies pointer to the words adata but not data */
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a ISO180006B data write operation with the
+ * provided parameters.
+ * 
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param byteAddress  address of location to begin write
+ * @param data Data to write
+ */
+TMR_Status
+TMR_TagOp_init_ISO180006B_WriteData(TMR_TagOp *tagop, uint8_t byteAddress, TMR_uint8List *data)
+{
+  tagop->type = TMR_TAGOP_ISO180006B_WRITEDATA;
+  tagop->u.iso180006b.u.writeData.byteAddress = byteAddress;
+  tagop->u.iso180006b.u.writeData.data = *data;
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a GEN2 lock operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param mask mask
+ * @param action action
+ * @param accessPassword The password to use to lock the tag.
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Lock(TMR_TagOp *tagop, uint16_t mask, uint16_t action, TMR_GEN2_Password accessPassword)
+{
+
+  tagop->type = TMR_TAGOP_GEN2_LOCK;
+  tagop->u.gen2.u.lock.mask = mask;
+  tagop->u.gen2.u.lock.action = action;
+  tagop->u.gen2.u.lock.accessPassword = accessPassword;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a ISO180006B lock operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param address The memory address of the byte to lock.
+ */
+TMR_Status
+TMR_TagOp_init_ISO180006B_Lock(TMR_TagOp *tagop,  uint8_t address)
+{
+
+  tagop->type = TMR_TAGOP_ISO180006B_LOCK;
+  tagop->u.iso180006b.u.lock.address = address;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a GEN2 kill operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param killPassword tag kill password
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Kill(TMR_TagOp *tagop, TMR_GEN2_Password killPassword)
+{
+
+  tagop->type = TMR_TAGOP_GEN2_KILL;
+  tagop->u.gen2.u.kill.password = killPassword;
+
+  return TMR_SUCCESS;
+}
+
+
+/**
+ * Initialize a TMR_TagOp as a GEN2 BlockWrite operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param bank bank
+ * @param wordPtr word pointer
+ * @param data data (The length of the data specifies the word count)
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_BlockWrite(TMR_TagOp *tagop, TMR_GEN2_Bank bank, uint32_t wordPtr, TMR_uint16List *data)
+{
+  tagop->type = TMR_TAGOP_GEN2_BLOCKWRITE;
+  tagop->u.gen2.u.blockWrite.bank = bank;
+  tagop->u.gen2.u.blockWrite.wordPtr = wordPtr;
+  tagop->u.gen2.u.blockWrite.data.len = data->len;
+  tagop->u.gen2.u.blockWrite.data.list = data->list;
+  tagop->u.gen2.u.blockWrite.data.max = data->max;
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a GEN2 BlockPermaLock operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param readLock readLock
+ * @param bank bank
+ * @param blockPtr block pointer
+ * @param mask mask (The length of the mask specifies the block range)
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_BlockPermaLock(TMR_TagOp *tagop, uint8_t readLock, TMR_GEN2_Bank bank, uint32_t blockPtr, TMR_uint16List *mask)
+{
+  tagop->type = TMR_TAGOP_GEN2_BLOCKPERMALOCK;
+  tagop->u.gen2.u.blockPermaLock.readLock = readLock;
+  tagop->u.gen2.u.blockPermaLock.bank = bank;
+  tagop->u.gen2.u.blockPermaLock.blockPtr = blockPtr;
+  tagop->u.gen2.u.blockPermaLock.mask.len = mask->len;
+  tagop->u.gen2.u.blockPermaLock.mask.list = mask->list;
+  tagop->u.gen2.u.blockPermaLock.mask.max = mask->max;
+  return TMR_SUCCESS;
+
+}
+
+/**
+ * Initialize a TMR_TagOp as a GEN2 BlockErase operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param bank bank
+ * @param wordPtr The starting word address to erase
+ * @param wordCount Number of words to erase
+ */
+TMR_Status 
+TMR_TagOp_init_GEN2_BlockErase(TMR_TagOp *tagop, TMR_GEN2_Bank bank, uint32_t wordPtr, uint8_t wordCount)
+{
+  tagop->type = TMR_TAGOP_GEN2_BLOCKERASE;
+  tagop->u.gen2.u.blockErase.bank = bank;
+  tagop->u.gen2.u.blockErase.wordCount = wordCount;
+  tagop->u.gen2.u.blockErase.wordPtr = wordPtr;
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Higgs2 Partial Load Image operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param killPassword kill password
+ * @param accessPassword access password
+ * @param epc EPC to write
+ */
+
+#ifdef TMR_ENABLE_GEN2_CUSTOM_TAGOPS
+
+TMR_Status 
+TMR_TagOp_init_GEN2_Alien_Higgs2_PartialLoadImage(TMR_TagOp *tagop, TMR_GEN2_Password killPassword,
+                                       TMR_GEN2_Password accessPassword, TMR_TagData *epc)
+{
+  tagop->type = TMR_TAGOP_GEN2_ALIEN_HIGGS2_PARTIALLOADIMAGE;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_ALIEN_HIGGS_SILICON;
+  tagop->u.gen2.u.custom.u.alien.u.higgs2.u.partialLoadImage.accessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.alien.u.higgs2.u.partialLoadImage.killPassword = killPassword;
+  tagop->u.gen2.u.custom.u.alien.u.higgs2.u.partialLoadImage.epcptr = epc; /* Takes pointer to EPC; doesn't make an actual copy */
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Higgs2 Full Load Image operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param killPassword kill password
+ * @param accessPassword access password
+ * @param lockBits Lock bits to write to the tag
+ * @param pcWord PC word to write to the tag
+ * @param epc EPC to write
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Alien_Higgs2_FullLoadImage(TMR_TagOp *tagop, TMR_GEN2_Password killPassword,
+                                    TMR_GEN2_Password accessPassword, uint16_t lockBits, 
+                                    uint16_t pcWord, TMR_TagData *epc)
+{
+  tagop->type = TMR_TAGOP_GEN2_ALIEN_HIGGS2_FULLLOADIMAGE;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_ALIEN_HIGGS_SILICON;
+  tagop->u.gen2.u.custom.u.alien.u.higgs2.u.fullLoadImage.accessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.alien.u.higgs2.u.fullLoadImage.killPassword = killPassword;
+  tagop->u.gen2.u.custom.u.alien.u.higgs2.u.fullLoadImage.lockBits = lockBits;
+  tagop->u.gen2.u.custom.u.alien.u.higgs2.u.fullLoadImage.pcWord = pcWord;
+  tagop->u.gen2.u.custom.u.alien.u.higgs2.u.fullLoadImage.epcptr = epc; /* Takes pointer to EPC; doesn't make an actual copy */
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Higgs3 Fast Load Image operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param currentAccessPassword The access password used to write to the tag
+ * @param accessPassword access password
+ * @param killPassword kill password
+ * @param pcWord PC word to write to the tag
+ * @param epc EPC to write
+ */
+TMR_Status TMR_TagOp_init_GEN2_Alien_Higgs3_FastLoadImage(TMR_TagOp *tagop, TMR_GEN2_Password currentAccessPassword,
+                                    TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword, 
+                                    uint16_t pcWord, TMR_TagData *epc)
+{
+  tagop->type = TMR_TAGOP_GEN2_ALIEN_HIGGS3_FASTLOADIMAGE;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_ALIEN_HIGGS3_SILICON;
+  tagop->u.gen2.u.custom.u.alien.u.higgs3.u.fastLoadImage.currentAccessPassword = currentAccessPassword;
+  tagop->u.gen2.u.custom.u.alien.u.higgs3.u.fastLoadImage.killPassword = killPassword;
+  tagop->u.gen2.u.custom.u.alien.u.higgs3.u.fastLoadImage.accessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.alien.u.higgs3.u.fastLoadImage.pcWord = pcWord;
+  tagop->u.gen2.u.custom.u.alien.u.higgs3.u.fastLoadImage.epcptr = epc; /* Takes pointer to EPC; doesn't make an actual copy */
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Higgs3 Load Image operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param currentAccessPassword The access password used to write to the tag
+ * @param accessPassword access password
+ * @param killPassword kill password
+ * @param pcWord PC word to write to the tag
+ * @param epcAndUserData Tag EPC and user data to write to the tag (76 bytes)
+ */
+TMR_Status TMR_TagOp_init_GEN2_Alien_Higgs3_LoadImage(TMR_TagOp *tagop, TMR_GEN2_Password currentAccessPassword,
+                                    TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword, 
+                                    uint16_t pcWord, TMR_uint8List *epcAndUserData)
+{
+  tagop->type = TMR_TAGOP_GEN2_ALIEN_HIGGS3_LOADIMAGE;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_ALIEN_HIGGS3_SILICON;
+  tagop->u.gen2.u.custom.u.alien.u.higgs3.u.loadImage.currentAccessPassword = currentAccessPassword;
+  tagop->u.gen2.u.custom.u.alien.u.higgs3.u.loadImage.killPassword = killPassword;
+  tagop->u.gen2.u.custom.u.alien.u.higgs3.u.loadImage.accessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.alien.u.higgs3.u.loadImage.pcWord = pcWord;
+  tagop->u.gen2.u.custom.u.alien.u.higgs3.u.loadImage.epcAndUserData = epcAndUserData; /* Takes pointer epcAndUserData; doesn't make an actual copy */
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Higgs3 Block Read Lock operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword access password
+ * @param lockBits A bitmask of bits to lock
+ */
+TMR_Status TMR_TagOp_init_GEN2_Alien_Higgs3_BlockReadLock(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, uint8_t lockBits)
+{
+  tagop->type = TMR_TAGOP_GEN2_ALIEN_HIGGS3_BLOCKREADLOCK;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_ALIEN_HIGGS3_SILICON;
+  tagop->u.gen2.u.custom.u.alien.u.higgs3.u.blockReadLock.accessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.alien.u.higgs3.u.blockReadLock.lockBits = lockBits;
+  
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a NXP G2I set read protect operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword access password
+ */
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2I_SetReadProtect(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword)
+{
+  tagop->type = TMR_TAGOP_GEN2_NXP_SETREADPROTECT;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_G2I_SILICON;
+  tagop->u.gen2.u.custom.u.nxp.u.setReadProtect.accessPassword = accessPassword;
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a NXP G2X set read protect operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword access password
+ */
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2X_SetReadProtect(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword)
+{
+  tagop->type = TMR_TAGOP_GEN2_NXP_SETREADPROTECT;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_G2X_SILICON;
+  tagop->u.gen2.u.custom.u.nxp.u.setReadProtect.accessPassword = accessPassword;
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a NXP G2I reset read protect operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword access password
+ */
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2I_ResetReadProtect(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword)
+{
+  tagop->type = TMR_TAGOP_GEN2_NXP_RESETREADPROTECT;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_G2I_SILICON;
+  tagop->u.gen2.u.custom.u.nxp.u.resetReadProtect.accessPassword = accessPassword;
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a NXP G2X reset read protect operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword access password
+ */
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2X_ResetReadProtect(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword)
+{
+  tagop->type = TMR_TAGOP_GEN2_NXP_RESETREADPROTECT;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_G2X_SILICON;
+  tagop->u.gen2.u.custom.u.nxp.u.resetReadProtect.accessPassword = accessPassword;
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a NXP G2I Change EAS operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword access password
+ * @param resetEAS   -  if true, Reset EAS
+ *                      if false, Set EAS
+ */
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2I_ChangeEAS(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, bool resetEAS)
+{
+  tagop->type = TMR_TAGOP_GEN2_NXP_CHANGEEAS;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_G2I_SILICON;
+  tagop->u.gen2.u.custom.u.nxp.u.changeEAS.accessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.nxp.u.changeEAS.reset = resetEAS;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a NXP G2X Change EAS operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword access password
+ * @param resetEAS   -  if true, Reset EAS
+ *                      if false, Set EAS
+ */
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2X_ChangeEAS(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, bool resetEAS)
+{
+  tagop->type = TMR_TAGOP_GEN2_NXP_CHANGEEAS;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_G2X_SILICON;
+  tagop->u.gen2.u.custom.u.nxp.u.changeEAS.accessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.nxp.u.changeEAS.reset = resetEAS;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a NXP G2I EAS alarm operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param dr Gen2 divide ratio to use
+ * @param m Gen2 M(tag encoding) parameter to use
+ * @param trExt txExt Gen2 TrExt value to use
+ */
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2I_EASAlarm(TMR_TagOp *tagop, TMR_GEN2_DivideRatio dr, TMR_GEN2_TagEncoding m, TMR_GEN2_TrExt trExt)
+{
+  tagop->type = TMR_TAGOP_GEN2_NXP_EASALARM;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_G2I_SILICON;
+  tagop->u.gen2.u.custom.u.nxp.u.EASAlarm.dr = dr;
+  tagop->u.gen2.u.custom.u.nxp.u.EASAlarm.m = m;
+  tagop->u.gen2.u.custom.u.nxp.u.EASAlarm.trExt = trExt;
+  return TMR_SUCCESS;
+}
+
+TMR_Status TMR_TagOp_init_GEN2_NXP_AES_Untraceable(TMR_TagOp *tagop,TMR_GEN2_UNTRACEABLE_Epc epc, int epclen , TMR_GEN2_UNTRACEABLE_Tid tid, TMR_GEN2_UNTRACEABLE_UserMemory user,
+																									 TMR_GEN2_UNTRACEABLE_Range range, TMR_TagOp_GEN2_NXP_Untraceable *untraceable)
+{
+	tagop->type = TMR_TAGOP_GEN2_NXP_UNTRACEABLE;
+	tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_AES_UCODE;
+	tagop->u.gen2.u.custom.u.nxp.u.untraceable.epc = epc;
+	tagop->u.gen2.u.custom.u.nxp.u.untraceable.epcLength = epclen;
+	tagop->u.gen2.u.custom.u.nxp.u.untraceable.tid = tid;
+	tagop->u.gen2.u.custom.u.nxp.u.untraceable.userMemory = user;
+	tagop->u.gen2.u.custom.u.nxp.u.untraceable.range = range;
+	if(untraceable->auth.authType == UNTRACEABLE_WITH_AUTHENTICATION)
+	{
+		tagop->u.gen2.u.custom.u.nxp.u.untraceable.subCommand = 0x02;
+		tagop->u.gen2.u.custom.u.nxp.u.untraceable.auth.tam1Auth = untraceable->auth.tam1Auth;
+		tagop->u.gen2.u.custom.u.nxp.u.untraceable.auth.tam1Auth.Authentication |= 0x03;
+	}
+	else
+	{
+		tagop->u.gen2.u.custom.u.nxp.u.untraceable.subCommand = 0x03;
+		tagop->u.gen2.u.custom.u.nxp.u.untraceable.auth.accessPassword = untraceable->auth.accessPassword;
+	}
+	return TMR_SUCCESS;
+}
+
+TMR_Status TMR_TagOp_init_GEN2_NXP_AES_Authenticate(TMR_TagOp *tagop, TMR_TagOp_GEN2_NXP_Authenticate *authenticate)
+{
+	tagop->type = TMR_TAGOP_GEN2_NXP_AUTHENTICATE;
+	tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_AES_UCODE;
+	if(authenticate->type == TAM1_AUTHENTICATION)
+	{
+		tagop->u.gen2.u.custom.u.nxp.u.authenticate.type = authenticate->type;
+		tagop->u.gen2.u.custom.u.nxp.u.authenticate.subCommand = 0x01;
+		tagop->u.gen2.u.custom.u.nxp.u.authenticate.tam1Auth = authenticate->tam1Auth;
+		tagop->u.gen2.u.custom.u.nxp.u.authenticate.tam1Auth.Authentication |= 0x03;
+	}
+	else
+	{
+		tagop->u.gen2.u.custom.u.nxp.u.authenticate.tam1Auth = authenticate->tam2Auth.tam1Auth;
+		tagop->u.gen2.u.custom.u.nxp.u.authenticate.type = authenticate->type;
+		tagop->u.gen2.u.custom.u.nxp.u.authenticate.subCommand = 0x01;
+		tagop->u.gen2.u.custom.u.nxp.u.authenticate.tam2Auth = authenticate->tam2Auth;
+		tagop->u.gen2.u.custom.u.nxp.u.authenticate.tam1Auth.Authentication |= 0x07;
+	}
+	return TMR_SUCCESS;
+}
+
+TMR_Status TMR_TagOp_init_GEN2_NXP_AES_Tam2authentication(TMR_TagOp_GEN2_NXP_Tam2Authentication *auth, TMR_NXP_KeyId keyid, TMR_uint8List *key, 
+																		TMR_uint8List *ichallenge, TMR_NXP_Profile profile, uint16_t Offset,uint8_t blockCount,bool sendRawData)
+{
+	auth->tam1Auth.Authentication = sendRawData ? 0x80 : 0x00;
+	auth->tam1Auth.CSI = 0x00;
+	auth->tam1Auth.KeyLength = 0x10;
+	auth->tam1Auth.IchallengeLength = 0x0A;
+	auth->tam1Auth.Ichallenge.len = ichallenge->len;
+	auth->tam1Auth.Ichallenge.list = ichallenge->list;
+	auth->tam1Auth.Ichallenge.max = ichallenge->max;
+	auth->tam1Auth.Key.len = key->len;
+	auth->tam1Auth.Key.list = key->list;
+	auth->tam1Auth.Key.max = key->max;
+	auth->tam1Auth.keyID = keyid;
+	auth->Offset = Offset;
+	auth->BlockCount = blockCount;
+	auth->ProtMode = 0x0001;
+	auth->profile = profile;
+	return TMR_SUCCESS;
+}
+TMR_Status TMR_TagOp_init_GEN2_NXP_AES_ReadBuffer(TMR_TagOp *tagop, uint16_t wordPointer, uint16_t bitCount, TMR_TagOp_GEN2_NXP_Readbuffer *readbuffer)
+{
+	tagop->type = TMR_TAGOP_GEN2_NXP_READBUFFER;
+	tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_AES_UCODE;
+	tagop->u.gen2.u.custom.u.nxp.u.readBuffer.wordPointer = wordPointer;
+	tagop->u.gen2.u.custom.u.nxp.u.readBuffer.bitCount = bitCount;
+	if(readbuffer->authenticate.type == TAM1_AUTHENTICATION)
+	{
+		tagop->u.gen2.u.custom.u.nxp.u.readBuffer.authenticate.type = readbuffer->authenticate.type;
+		tagop->u.gen2.u.custom.u.nxp.u.readBuffer.authenticate.subCommand = 0x04;
+		tagop->u.gen2.u.custom.u.nxp.u.readBuffer.authenticate.tam1Auth = readbuffer->authenticate.tam1Auth;
+		tagop->u.gen2.u.custom.u.nxp.u.readBuffer.authenticate.tam1Auth.Authentication |= 0x00;
+	}
+	else
+	{
+		tagop->u.gen2.u.custom.u.nxp.u.readBuffer.authenticate.tam1Auth = readbuffer->authenticate.tam2Auth.tam1Auth;
+		tagop->u.gen2.u.custom.u.nxp.u.readBuffer.authenticate.type = readbuffer->authenticate.type;
+		tagop->u.gen2.u.custom.u.nxp.u.readBuffer.authenticate.subCommand = 0x04;
+		tagop->u.gen2.u.custom.u.nxp.u.readBuffer.authenticate.tam2Auth = readbuffer->authenticate.tam2Auth;
+		tagop->u.gen2.u.custom.u.nxp.u.readBuffer.authenticate.tam1Auth.Authentication |= 0x04;
+	}
+	return TMR_SUCCESS;
+}
+
+TMR_Status TMR_TagOp_init_GEN2_NXP_AES_Tam1authentication(TMR_TagOp_GEN2_NXP_Tam1Authentication *auth, TMR_NXP_KeyId keyid, TMR_uint8List *key, 
+																													TMR_uint8List *ichallenge ,bool sendRawData )
+{
+	auth->Authentication = sendRawData ? 0x80 : 0x00;
+	auth->CSI = 0x00;
+	auth->KeyLength = 0x10;
+	auth->IchallengeLength = 0x0A;
+	auth->Ichallenge.len = ichallenge->len;
+	auth->Ichallenge.list = ichallenge->list;
+	auth->Ichallenge.max = ichallenge->max;
+	auth->Key.len = key->len;
+	auth->Key.list = key->list;
+	auth->Key.max = key->max;
+	auth->keyID = keyid;
+	return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a NXP G2X EAS alarm operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param dr Gen2 divide ratio to use
+ * @param m Gen2 M(tag encoding) parameter to use
+ * @param trExt txExt Gen2 TrExt value to use
+ */
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2X_EASAlarm(TMR_TagOp *tagop, TMR_GEN2_DivideRatio dr, TMR_GEN2_TagEncoding m, TMR_GEN2_TrExt trExt)
+{
+  tagop->type = TMR_TAGOP_GEN2_NXP_EASALARM;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_G2X_SILICON;
+  tagop->u.gen2.u.custom.u.nxp.u.EASAlarm.dr = dr;
+  tagop->u.gen2.u.custom.u.nxp.u.EASAlarm.m = m;
+  tagop->u.gen2.u.custom.u.nxp.u.EASAlarm.trExt = trExt;
+  
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a NXP G2i Calibrate operation with the provided parameters.
+ *
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword access password
+ */
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2I_Calibrate(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword)
+{
+  tagop->type = TMR_TAGOP_GEN2_NXP_CALIBRATE;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_G2I_SILICON;
+  tagop->u.gen2.u.custom.u.nxp.u.calibrate.accessPassword = accessPassword;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a NXP G2x Calibrate operation with the provided parameters.
+ *
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword access password
+ */
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2X_Calibrate(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword)
+{
+  tagop->type = TMR_TAGOP_GEN2_NXP_CALIBRATE;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_G2X_SILICON;
+  tagop->u.gen2.u.custom.u.nxp.u.calibrate.accessPassword = accessPassword;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a NXP G2i Change Config operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword access password
+ * @param configWord ConfigWord to write to the tag.
+ */
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2I_ChangeConfig(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, TMR_NXP_ConfigWord configWord)
+{
+  tagop->type = TMR_TAGOP_GEN2_NXP_CHANGECONFIG;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_G2I_SILICON;
+  tagop->u.gen2.u.custom.u.nxp.u.changeConfig.accessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.nxp.u.changeConfig.configWord = configWord;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a NXP G2x Change Config operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword access password
+ * @param configWord ConfigWord to write to the tag.
+ */
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2X_ChangeConfig(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, TMR_NXP_ConfigWord configWord)
+{
+  tagop->type = TMR_TAGOP_GEN2_NXP_CHANGECONFIG;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_NXP_G2X_SILICON;
+  tagop->u.gen2.u.custom.u.nxp.u.changeConfig.accessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.nxp.u.changeConfig.configWord = configWord;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Monza4 QT Read/Write operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword access password
+ * @param controlByte The QT control Byte 
+ * @param payload The QT payload
+ */
+TMR_Status 
+TMR_TagOp_init_GEN2_Impinj_Monza4_QTReadWrite(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                  TMR_Monza4_ControlByte controlByte, TMR_Monza4_Payload payload)
+{
+  tagop->type = TMR_TAGOP_GEN2_IMPINJ_MONZA4_QTREADWRITE;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IMPINJ_MONZA4_SILICON;
+  tagop->u.gen2.u.custom.u.impinj.u.monza4.u.qtReadWrite.accessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.impinj.u.monza4.u.qtReadWrite.controlByte = controlByte;
+  tagop->u.gen2.u.custom.u.impinj.u.monza4.u.qtReadWrite.payload = payload;
+
+  return TMR_SUCCESS;
+}
+
+ /**
+ * Initialize a TMR_TagOp as a Gen2 IAVDenatran ActivateSecureMode operation with the provided parameter
+ * @param tagop Pointer to the tagop structure to initialize
+ * @param payload 1byte->[TC(Transmission Count) 1bit + RFFU(Reserved For Furture Use) 7bits]
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Denatran_IAV_Activate_Secure_Mode(TMR_TagOp *tagop, uint8_t payload)
+{
+  tagop->type = TMR_TAGOP_GEN2_DENATRAN_IAV_ACTIVATESECUREMODE;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_DENATRAN_IAV_SILICON; 
+  tagop->u.gen2.u.custom.u.IavDenatran.u.secureMode.mode = GEN2_ACTIVATE_SECURE_MODE;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.secureMode.payload = payload;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 IAVDenatran AuthenticateOBU operation with the provided parameter
+ * @param tagop Pointer to the tagop structure to initialize 
+ * @param payload 1byte->[TC(Transmission Count) 1bit + RFFU(Reserved For Furture Use) 7bits]
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Denatran_IAV_Authenticate_OBU(TMR_TagOp *tagop, uint8_t payload)
+{
+  tagop->type = TMR_TAGOP_GEN2_DENATRAN_IAV_AUTHENTICATEOBU;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_DENATRAN_IAV_SILICON; 
+  tagop->u.gen2.u.custom.u.IavDenatran.u.authenticateOBU.mode = GEN2_AUTHENTICATE_OBU;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.authenticateOBU.payload = payload;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 IAVDenatran ACTIVATE_SINIAV_MODE operation with the provided parameter
+ * @param tagop Pointer to the tagop structure to initialize 
+ * @param payload 1byte->[TC(Transmission Count) 1bit + RFFU(Reserved For Furture Use) 7bits]
+ * @param data 64 bits of token number to activate the tag
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Denatran_IAV_Activate_Siniav_Mode(TMR_TagOp *tagop, uint8_t payload, TMR_uint8List *token)
+{
+  uint8_t tokenDesc;
+
+  tagop->type = TMR_TAGOP_GEN2_ACTIVATE_SINIAV_MODE;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_DENATRAN_IAV_SILICON; 
+  tagop->u.gen2.u.custom.u.IavDenatran.u.activateSiniavMode.mode = GEN2_ACTIVATE_SINIAV_MODE;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.activateSiniavMode.payload = payload;
+
+  /**
+   * Currently last two bits of the payload is used as TokenDesc
+   * (Token Descriptor): 2 bits parameter indicating the presence and format of Token
+   * 00 : No Token.
+   * 01 : Token of 64 bits.
+   */
+  tokenDesc = 0x03 & payload;
+  if (0x01 == tokenDesc)
+  { 
+    /* the token field is always 64 bits in this case */    
+    if (0x08 != token->len)
+    {
+      return TMR_ERROR_INVALID;
+    }
+    memcpy(tagop->u.gen2.u.custom.u.IavDenatran.u.activateSiniavMode.token, token->list, token->len);
+    tagop->u.gen2.u.custom.u.IavDenatran.u.activateSiniavMode.isTokenDesc = true;  
+  }
+  else
+  {
+    tagop->u.gen2.u.custom.u.IavDenatran.u.activateSiniavMode.isTokenDesc = false;
+  }
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 IAVDenatran OBU_Auth_ID operation with the provided parameter
+ * @param tagop Pointer to the tagop structure to initialize 
+ * @param payload 1byte->[TC(Transmission Count) 1bit + RFFU(Reserved For Furture Use) 7bits] 
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Denatran_IAV_OBU_Auth_ID(TMR_TagOp *tagop, uint8_t payload)
+{
+  tagop->type = TMR_TAGOP_GEN2_OBU_AUTH_ID;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_DENATRAN_IAV_SILICON; 
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthId.mode = GEN2_OBU_AUTH_ID;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthId.payload = payload;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 IAVDenatran OBU_Auth_Full_Pass1 operation with the provided parameter
+ * @param tagop Pointer to the tagop structure to initialize 
+ * @param payload 1byte->[TC(Transmission Count) 1bit + RFFU(Reserved For Furture Use) 7bits] 
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Denatran_IAV_OBU_Auth_Full_Pass1(TMR_TagOp *tagop, uint8_t payload)
+{
+  tagop->type = TMR_TAGOP_GEN2_AUTHENTICATE_OBU_FULL_PASS1;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_DENATRAN_IAV_SILICON; 
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthFullPass1.mode = GEN2_AUTHENTICATE_OBU_FULL_PASS1;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthFullPass1.payload = payload;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 IAVDenatran OBU_Auth_Full_Pass2 operation with the provided parameter
+ * @param tagop Pointer to the tagop structure to initialize 
+ * @param payload 1byte->[TC(Transmission Count) 1bit + RFFU(Reserved For Furture Use) 7bits] 
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Denatran_IAV_OBU_Auth_Full_Pass2(TMR_TagOp *tagop, uint8_t payload)
+{
+  tagop->type = TMR_TAGOP_GEN2_AUTHENTICATE_OBU_FULL_PASS2;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_DENATRAN_IAV_SILICON; 
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthFullPass2.mode = GEN2_AUTHENTICATE_OBU_FULL_PASS2;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthFullPass2.payload = payload;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 IAVDenatran OBU_ReadFromMemMap operation with the provided parameter
+ * @param tagop Pointer to the tagop structure to initialize 
+ * @param payload The OBU_ReadFromMemMap Payload
+ * @param wordAddress pointer indicating the address to be read from USER memory bank
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Denatran_IAV_OBU_ReadFromMemMap(TMR_TagOp *tagop, uint8_t payload, uint16_t wordAddress)
+{
+  tagop->type = TMR_TAGOP_GEN2_OBU_READ_FROM_MEM_MAP;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_DENATRAN_IAV_SILICON;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuReadFromMemMap.mode = GEN2_OBU_READ_FROM_MEM_MAP;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuReadFromMemMap.payload = payload;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuReadFromMemMap.readPtr = wordAddress;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 IAVDenatran OBU_WriteToMemMap operation with the provided parameter
+ * @param tagop Pointer to the tagop structure to initialize 
+ * @param payload The OBU_WriteToMemMap Payload
+ * @param wordAddress pointer to the USER data
+ * @param word data to be written
+ * @param data credentials written word
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Denatran_IAV_OBU_WriteToMemMap(TMR_TagOp *tagop, uint8_t payload, uint16_t wordAddress, uint16_t word, uint8_t* tagId, uint8_t* data)
+{
+  tagop->type = TMR_TAGOP_GEN2_OBU_WRITE_TO_MEM_MAP;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_DENATRAN_IAV_SILICON;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuWriteToMemMap.mode = GEN2_OBU_WRITE_TO_MEM_MAP;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuWriteToMemMap.payload = payload;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuWriteToMemMap.writePtr = wordAddress;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuWriteToMemMap.wordData = word;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuWriteToMemMap.tagIdentification = tagId;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuWriteToMemMap.dataBuf = data;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 IAVDenatran Write Sec operation with the provided parameter
+ * @param tagop Pointer to the tagop structure to initialize 
+ * @param payload The OBU_WriteToMemMap Payload
+ * @param wordAddress pointer to the USER data
+ * @param dataWords 4 data words
+ * @param data credentials written word
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Denatran_IAV_WriteSec(TMR_TagOp *tagop, uint8_t payload, uint8_t* data, uint8_t* credentials)
+{
+  tagop->type = TMR_TAGOP_GEN2_DENATRAN_IAV_WRITE_SEC;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_DENATRAN_IAV_SILICON;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.writeSec.mode = GEN2_WRITE_SEC;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.writeSec.payload = payload;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.writeSec.dataWords = data;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.writeSec.dataBuf = credentials;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 IAVDenatran OBU_Auth_Full_Pass operation with the provided parameter
+ * @param tagop Pointer to the tagop structure to initialize 
+ * @param payload 1byte->[TC(Transmission Count) 1bit + RFFU(Reserved For Furture Use) 7bits] 
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Denatran_IAV_OBU_Auth_Full_Pass(TMR_TagOp *tagop, uint8_t payload)
+{
+  tagop->type = TMR_TAGOP_GEN2_DENATRAN_IAV_AUTHENTICATE_OBU_FULL_PASS;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_DENATRAN_IAV_SILICON; 
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthFullPass.mode = GEN2_AUTHENTICATE_OBU_FULL_PASS;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.obuAuthFullPass.payload = payload;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 IAVDenatran G0_PA_OBU_Auth_ID operation with the provided parameter
+ * @param tagop Pointer to the tagop structure to initialize 
+ * @param payload 1byte->[TC(Transmission Count) 1bit + RFFU(Reserved For Furture Use) 7bits] 
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Denatran_IAV_G0_PA_OBU_Auth(TMR_TagOp *tagop, uint8_t payload)
+{
+  tagop->type = TMR_TAGOP_GEN2_DENATRAN_IAV_G0_PA_OBU_AUTHENTICATE_ID;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_DENATRAN_IAV_SILICON; 
+  tagop->u.gen2.u.custom.u.IavDenatran.u.g0paobuauthid.mode = GEN2_PA_G0_AUTHENTICATE;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.g0paobuauthid.payload = payload;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 IAVDenatran Get Token Id operation with the provided parameter
+ * @param tagop Pointer to the tagop structure to initialize 
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Denatran_IAV_GetTokenId(TMR_TagOp *tagop)
+{
+  tagop->type = TMR_TAGOP_GEN2_DENATRAN_IAV_GET_TOKEN_ID;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_DENATRAN_IAV_SILICON;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.getTokenId.mode = GEN2_GET_TOKEN_ID;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 IAVDenatran read sec operation with the provided parameter
+ * @param tagop Pointer to the tagop structure to initialize
+ * @param payLoad 8 bits for future use
+ * @param wordAddress pointer indicating the sector to be read from USER memory bank
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_Denatran_IAV_ReadSec(TMR_TagOp *tagop, uint8_t payload, uint16_t wordAddress)
+{
+  tagop->type = TMR_TAGOP_GEN2_DENATRAN_IAV_READ_SEC;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_DENATRAN_IAV_SILICON;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.readSec.mode = GEN2_READ_SEC;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.readSec.payload = payload;
+  tagop->u.gen2.u.custom.u.IavDenatran.u.readSec.readPtr = wordAddress;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A GetCalibrationData value operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param password IDS password
+ * @param level IDS passwordlevel
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_GetCalibrationData(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                                  PasswordLevel level, uint32_t password)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_GETCALIBRATIONDATA;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.calibrationData.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.calibrationData.CommandCode = 0xA9;
+  tagop->u.gen2.u.custom.u.ids.u.calibrationData.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.calibrationData.sl900A.level = level;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize  a TMR_TagOp as a GEn2 IDs SL900A SetPassword value with
+ * @param tagop pointer to the tagop struture to SetPassword
+ * @param accessPassword Gen2 accessPassword
+ * @param level IDS passwordLevel
+ * @param password IDS password
+ * @param newPasswordLevel IDS NewPasswordLevel
+ * @param newPassword IDS NewPassword
+ */ 
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_SetPassword(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, PasswordLevel level,
+                                           uint32_t password, PasswordLevel newPasswordLevel, uint32_t newPassword)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_SETPASSWORD;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.setPassword.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.setPassword.CommandCode = 0xA0;
+  tagop->u.gen2.u.custom.u.ids.u.setPassword.sl900A.level = level;
+  tagop->u.gen2.u.custom.u.ids.u.setPassword.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.setPassword.NewPasswordLevel = newPasswordLevel;
+  tagop->u.gen2.u.custom.u.ids.u.setPassword.NewPassword = newPassword;
+  
+  return TMR_SUCCESS;
+}
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A SetCalibrationData value operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param password IDS password
+ * @param level IDS passwordlevel
+ * @param data IDS calibration data
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_SetCalibrationData(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, PasswordLevel level, 
+                                                  uint32_t password, TMR_TagOp_GEN2_IDS_SL900A_CalibrationData *data)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_SETCALIBRATIONDATA;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.setCalibration.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.setCalibration.CommandCode = 0xA5;
+  tagop->u.gen2.u.custom.u.ids.u.setCalibration.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.setCalibration.sl900A.level = level;
+  tagop->u.gen2.u.custom.u.ids.u.setCalibration.cal.raw = data->raw;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A SetSfeParameters value operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param password IDS password
+ * @param level IDS passwordlevel
+ * @param data IDS sfe parameters
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_SetSfeParameters(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, PasswordLevel level,
+                                                uint32_t password, TMR_TagOp_GEN2_IDS_SL900A_SfeParameters *data)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_SETSFEPARAMETERS;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.setSfeParameters.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.setSfeParameters.CommandCode = 0xA4;
+  tagop->u.gen2.u.custom.u.ids.u.setSfeParameters.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.setSfeParameters.sl900A.level = level;
+  tagop->u.gen2.u.custom.u.ids.u.setSfeParameters.sfe = data;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A GetSensor value operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param password IDS password
+ * @param level IDS passwordlevel
+ * @param type IDS sensor type
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_GetSensorValue(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                              PasswordLevel level, uint32_t password, Sensor type)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_GETSENSOR;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.sensor.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.sensor.CommandCode = 0xAD;
+  tagop->u.gen2.u.custom.u.ids.u.sensor.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.sensor.sl900A.level = level;
+  tagop->u.gen2.u.custom.u.ids.u.sensor.sl900A.sensortype = type;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A GetMeasurementSetup operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param password IDS password
+ * @param level IDS passwordlevel
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_GetMeasurementSetup(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                                   PasswordLevel level, uint32_t password)
+{
+  tagop->type =TMR_TAGOP_GEN2_IDS_SL900A_GETMEASUREMENTSETUP;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.measurementSetup.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.measurementSetup.CommandCode = 0xA3;
+  tagop->u.gen2.u.custom.u.ids.u.measurementSetup.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.measurementSetup.sl900A.level = level;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A GetLogState operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param password IDS password
+ * @param level IDS passwordlevel
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_GetLogState(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                           PasswordLevel level, uint32_t password)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_GETLOGSTATE;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.getLog.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.getLog.CommandCode = 0xA8;
+  tagop->u.gen2.u.custom.u.ids.u.getLog.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.getLog.sl900A.level = level;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A Set Log Mode operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param password IDS password
+ * @param level IDS passwordlevel
+ * @param form IDS logging form
+ * @param rule IDS storage rule
+ * @param Ext1Enable to Enable log for EXT1 external sensor
+ * @param Ext2Enable to Enable log for EXT2 external sensor
+ * @param TempEnable to Enable log for temperature sensor
+ * @param BattEnable to Enable log for battery sensor
+ * @param LogInterval to Time (seconds) between log readings
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_SetLogMode(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, PasswordLevel level,
+                                          uint32_t password, LoggingForm form, StorageRule rule, bool Ext1Enable,
+                                          bool Ext2Enable,  bool TempEnable, bool BattEnable, uint16_t LogInterval)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_SETLOGMODE;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.setLogMode.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.setLogMode.CommandCode = 0xA1;
+  tagop->u.gen2.u.custom.u.ids.u.setLogMode.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.setLogMode.sl900A.level = level;
+  tagop->u.gen2.u.custom.u.ids.u.setLogMode.sl900A.dataLog = form;
+  tagop->u.gen2.u.custom.u.ids.u.setLogMode.sl900A.rule = rule;
+  tagop->u.gen2.u.custom.u.ids.u.setLogMode.Ext1Enable = Ext1Enable;
+  tagop->u.gen2.u.custom.u.ids.u.setLogMode.Ext2Enable = Ext2Enable;
+  tagop->u.gen2.u.custom.u.ids.u.setLogMode.TempEnable = TempEnable;
+  tagop->u.gen2.u.custom.u.ids.u.setLogMode.BattEnable = BattEnable;
+  tagop->u.gen2.u.custom.u.ids.u.setLogMode.LogInterval = LogInterval;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A EndLog operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param password IDS password
+ * @param level IDS passwordlevel
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_EndLog(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                      PasswordLevel level, uint32_t password)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_ENDLOG;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.endLog.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.endLog.CommandCode = 0xA6;
+  tagop->u.gen2.u.custom.u.ids.u.endLog.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.endLog.sl900A.level = level;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A initialize operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param level IDS passwordlevel
+ * @param password IDS password
+ * @param delayMode IDS delaymode
+ * @param delayTime specifying IDS Delay time
+ * @param timeEnable IDS timeenable
+ * @param numberOfWords specifying Number of user bank memory words to reserve
+ * @param BrokenWordPointer IDS broken word pointer
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_Initialize(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                          PasswordLevel level, uint32_t password, uint8_t delayMode, 
+                                          uint16_t delayTime, bool timeEnable, uint16_t numberOfWords, 
+                                          uint8_t BrokenWordPointer)
+{
+  uint16_t mask = 0x1 << 1;
+
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_INITIALIZE;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.initialize.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.initialize.CommandCode = 0xAC;
+  tagop->u.gen2.u.custom.u.ids.u.initialize.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.initialize.sl900A.level = level;
+
+  if (TMR_GEN2_IDS_SL900A_DELAYMODE_TIMER == delayMode)
+  {   
+   uint16_t raw = 0;
+   raw &= (uint16_t)~mask;
+   tagop->u.gen2.u.custom.u.ids.u.initialize.delayTime.raw = raw;
+   tagop->u.gen2.u.custom.u.ids.u.initialize.delayTime.Mode = (DelayMode)delayMode;
+  }
+  else
+  {
+    tagop->u.gen2.u.custom.u.ids.u.initialize.delayTime.raw |= mask;
+    tagop->u.gen2.u.custom.u.ids.u.initialize.delayTime.Mode = (DelayMode)delayMode;
+  }
+
+  if (delayTime)
+  {
+    uint16_t maskDelayTime = 0xFFF << 4;
+    tagop->u.gen2.u.custom.u.ids.u.initialize.delayTime.raw &= (uint16_t)~maskDelayTime;
+    tagop->u.gen2.u.custom.u.ids.u.initialize.delayTime.raw |= (uint16_t)(delayTime << 4);
+    tagop->u.gen2.u.custom.u.ids.u.initialize.delayTime.Time = delayTime;
+  }
+  mask = 0x1;
+  if(timeEnable)
+  {
+    tagop->u.gen2.u.custom.u.ids.u.initialize.delayTime.raw |= mask;
+    tagop->u.gen2.u.custom.u.ids.u.initialize.delayTime.IrqTimerEnable = timeEnable;
+  }
+  else
+  {
+    tagop->u.gen2.u.custom.u.ids.u.initialize.delayTime.raw &= (uint16_t)~mask;
+    tagop->u.gen2.u.custom.u.ids.u.initialize.delayTime.IrqTimerEnable = timeEnable;
+  }
+
+  mask = 0x1FF;
+  if (numberOfWords)
+  {
+    tagop->u.gen2.u.custom.u.ids.u.initialize.applicationData.raw &= (uint16_t)~mask;
+    tagop->u.gen2.u.custom.u.ids.u.initialize.applicationData.raw |= (uint16_t)(numberOfWords << 7);
+    tagop->u.gen2.u.custom.u.ids.u.initialize.applicationData.NumberOfWords = numberOfWords;
+  }
+
+  mask = 0x7;
+  if (BrokenWordPointer)
+  {
+    tagop->u.gen2.u.custom.u.ids.u.initialize.applicationData.raw &= (uint16_t)~mask;
+    tagop->u.gen2.u.custom.u.ids.u.initialize.applicationData.raw |= (uint16_t)(BrokenWordPointer);
+    tagop->u.gen2.u.custom.u.ids.u.initialize.applicationData.BrokenWordPointer = BrokenWordPointer;
+  }
+
+  return TMR_SUCCESS;
+}
+
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A AcessFifo Status operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param password IDS password
+ * @param level IDS passwordlevel
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_AccessFifoStatus(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                                 PasswordLevel level, uint32_t password)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_ACCESSFIFOSTATUS;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoStatus.status.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoStatus.status.CommandCode = 0xAF;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoStatus.status.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoStatus.status.sl900A.level = level;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoStatus.status.operation = TMR_GEN2_IDS_SL900A_ACCESSFIFO_STATUS;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A AcessFifo Read operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param password IDS password
+ * @param level IDS passwordlevel
+ * @param readLength specify no of data to be read from fifo
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_AccessFifoRead(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                               PasswordLevel level, uint32_t password, uint8_t readLength)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_ACCESSFIFOREAD;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoRead.read.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoRead.read.CommandCode = 0xAF;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoRead.read.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoRead.read.sl900A.level = level;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoRead.read.operation = TMR_GEN2_IDS_SL900A_ACCESSFIFO_READ;
+  
+  if (readLength != (readLength & 0xF))
+  {
+    return TMR_ERROR_MSG_INVALID_PARAMETER_VALUE;
+  }
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoRead.length = readLength;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A AcessFifo Write operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param password IDS password
+ * @param level IDS passwordlevel
+ * @param payLoad specify  data to be written into fifo
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_AccessFifoWrite(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                               PasswordLevel level, uint32_t password, TMR_uint8List *payLoad)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_ACCESSFIFOWRITE;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoWrite.write.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoWrite.write.CommandCode = 0xAF;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoWrite.write.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoWrite.write.sl900A.level = level;
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoWrite.write.operation = TMR_GEN2_IDS_SL900A_ACCESSFIFO_WRITE;
+  
+  if (payLoad->len != (payLoad->len & 0xF))
+  {
+    return TMR_ERROR_MSG_INVALID_PARAMETER_VALUE;
+  }
+  tagop->u.gen2.u.custom.u.ids.u.accessFifoWrite.payLoad = payLoad;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A  StartLog operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param level IDS passwordlevel
+ * @param password IDS password
+ * @param timestamp pointer to TMR_TimeStructure (timestamp structure) 
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_StartLog(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                        PasswordLevel level, uint32_t password, TMR_TimeStructure *timestamp)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_STARTLOG;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.startLog.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.startLog.CommandCode = 0xA7;
+  tagop->u.gen2.u.custom.u.ids.u.startLog.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.startLog.sl900A.level = level;
+  if (NULL == timestamp)
+  {
+    /** in case user not providing the time stamp
+    * use current system time
+    */
+    return TMR_ERROR_TIMESTAMP_NULL;
+  }
+  
+  tagop->u.gen2.u.custom.u.ids.u.startLog.startTime = 0;
+  tagop->u.gen2.u.custom.u.ids.u.startLog.startTime |= (uint32_t)((timestamp->tm_year - 2010) << 26);
+  tagop->u.gen2.u.custom.u.ids.u.startLog.startTime |= (uint32_t)((timestamp->tm_mon) << 22);
+  tagop->u.gen2.u.custom.u.ids.u.startLog.startTime |= (uint32_t)(timestamp->tm_mday << 17);
+  tagop->u.gen2.u.custom.u.ids.u.startLog.startTime |= (uint32_t)(timestamp->tm_hour << 12);
+  tagop->u.gen2.u.custom.u.ids.u.startLog.startTime |= (uint32_t)(timestamp->tm_min << 6);
+  tagop->u.gen2.u.custom.u.ids.u.startLog.startTime |= (uint32_t)(timestamp->tm_sec);
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A GetBatteryLevel operation with the provided parameters.
+ * @param tagop Pointer to the tagop structure to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param level IDS passwordlevel
+ * @param password IDS password
+ * @param type IDS batterytype
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_GetBatteryLevel(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                               PasswordLevel level, uint32_t password, BatteryType type)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_GETBATTERYLEVEL;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.batteryLevel.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.batteryLevel.CommandCode = 0xAA;
+  tagop->u.gen2.u.custom.u.ids.u.batteryLevel.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.batteryLevel.sl900A.level = level;
+  tagop->u.gen2.u.custom.u.ids.u.batteryLevel.batteryType = type;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A Set Log Limits operation with
+ * @param tagop Pointer to the tagop struture to initialize.
+ * @param accessPassword Gen2 accessPassword
+ * @param level IDS apsswordlevel
+ * @param passowrd IDS password
+ * @param logLimits pointer to IDS LogLimits
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_SetLogLimit(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, PasswordLevel level,
+                                           uint32_t password, LogLimits *logLimits)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_SETLOGLIMITS;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.setLogLimit.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.setLogLimit.CommandCode = 0xA2;
+  tagop->u.gen2.u.custom.u.ids.u.setLogLimit.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.setLogLimit.sl900A.level = level;
+
+  /**
+   * LogLimit values are only 10 bit long,
+   */
+  if (0x03FF < logLimits->extremeLower)
+  {
+    return TMR_ERROR_MSG_INVALID_PARAMETER_VALUE; 
+  }
+
+  tagop->u.gen2.u.custom.u.ids.u.setLogLimit.limit.extremeLower = logLimits->extremeLower;
+
+  if (0x03FF < logLimits->lower)
+  {
+    return TMR_ERROR_MSG_INVALID_PARAMETER_VALUE;
+  }
+  tagop->u.gen2.u.custom.u.ids.u.setLogLimit.limit.lower = logLimits->lower;
+
+  if (0x03FF < logLimits->upper)
+  {
+    return TMR_ERROR_MSG_INVALID_PARAMETER_VALUE;
+  }
+  tagop->u.gen2.u.custom.u.ids.u.setLogLimit.limit.upper = logLimits->upper;
+
+  if (0x03FF < logLimits->extremeUpper)
+  {
+    return TMR_ERROR_MSG_INVALID_PARAMETER_VALUE;
+  }
+  tagop->u.gen2.u.custom.u.ids.u.setLogLimit.limit.extremeUpper = logLimits->extremeUpper;
+
+  return TMR_SUCCESS;
+
+}
+
+/**
+ * Initialize the Gen2 IDS SL900A SetShelfLifeBlock0 with
+ * @param block0 pointer to the TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock0,
+ * @param tmax SetShelfLife Tmax
+ * @param tmin SetShelfLife Tmin
+ * @param tstd SetshelfLIfe Tstd;
+ * @param ea   SetshelfLife Ea;
+ */ 
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_ShelfLifeBlock0(TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock0 *block0,
+                                               uint8_t tmax, uint8_t tmin, uint8_t tstd, uint8_t ea)
+{
+  uint64_t mask;
+  block0->raw = 0;
+
+  /* Copying the tmax to  block0 raw value */ 
+  {
+    block0->Tmax = tmax;
+    mask = TMR_makeBitMask(24, 8);
+    block0->raw &= ~mask;
+    block0->raw |= (uint32_t)((uint32_t)tmax << 24);
+  }
+
+  /* Copying the tmin to  block0 raw value */ 
+  {
+    block0->Tmin = tmin;
+    mask = TMR_makeBitMask(16, 8);
+    block0->raw &= ~mask;
+    block0->raw |= (uint32_t)((uint32_t)tmin << 16);
+  }
+
+  /* Copying the tstd to  block0 raw value */ 
+  {
+    block0->Tstd = tstd;
+    mask = TMR_makeBitMask(8, 8);
+    block0->raw &= ~mask;
+    block0->raw |= (uint32_t)((uint32_t)tstd << 8);
+  }
+
+  /* Copying the ea to  block0 raw value */ 
+  {
+    block0->Ea = ea;
+    mask = TMR_makeBitMask(0, 8);
+    block0->raw &= ~mask;
+    block0->raw |= (uint32_t)((uint32_t)ea << 0);
+  }
+
+  return TMR_SUCCESS;
+}
+
+
+/**
+ * Initialize the Gen2 IDS SL900A SetShelfLifeBlock1 with
+ * @param block1 pointer to the TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock1,
+ * @param slinit SetShelfLife SLinit
+ * @param tint SetShelfLife Tint
+ * @param sensorid SetshelfLIfe sensorID
+ * @param negative SetshelfLife enableNegative
+ * @param algorithm SetShelfLife algorithmEnable
+ */ 
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_ShelfLifeBlock1(TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock1 *block1,
+                                               uint16_t slinit, uint16_t tint, uint8_t sensorid,
+                                               bool negative, bool algorithm)
+{
+  uint64_t mask;
+  block1->raw = 0;
+
+  /* Copying the SLinit value to block1 raw value */
+  {
+    block1->SLinit = slinit;
+    mask = TMR_makeBitMask(16, 16);
+    block1->raw &= ~mask;
+    block1->raw |= (uint32_t)((uint32_t)slinit << 16);
+  }
+
+  /* Copying the tint value to block1 raw value */
+  {
+    block1->Tint = tint;
+    mask = TMR_makeBitMask(6, 10);
+    block1->raw &= ~mask;
+    block1->raw |= (uint32_t)((uint32_t)tint << 6);
+  }
+
+  /* Copying the sensorID to block1 raw value */
+  {
+    block1->sensorID = sensorid;
+    mask = TMR_makeBitMask(4, 2);
+    block1->raw &= ~mask;
+    block1->raw |= (uint32_t)((uint32_t)sensorid << 4);
+  }
+
+  /* Copying the enableNegative value to block1 raw value */
+  {
+    block1->enableNegative = negative;
+    mask = TMR_makeBitMask(3, 1);
+    block1->raw &= ~mask;
+    block1->raw |= (uint32_t)(negative << 3);
+  }
+
+  /* Copying the algorithemEnable value to block1 raw value */
+  {
+    block1->algorithmEnable = algorithm;
+    mask = TMR_makeBitMask(2, 1);
+    block1->raw &= ~mask;
+    block1->raw |= (uint32_t)(negative << 2);
+  }
+
+  /* Setting the RFU bytes to zero */
+  block1->rfu = 0;
+  mask = TMR_makeBitMask(0, 2);
+  block1->raw &= ~mask;
+  block1->raw |= (uint32_t)(0 << 0);
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize a TMR_TagOp as a Gen2 Ids SL900A Set Shelf Life operation with
+ * @param tagop pointer to the tagop struture to setShelfLife
+ * @param accessPassword Gen2 accessPassword
+ * @param level IDS passwordlevel
+ * @param password IDS password
+ * @param block0 pointer to the TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock0,
+ * @param block1 pointer to the TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock1,
+ */
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_SetShelfLife(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, PasswordLevel level,
+                                            uint32_t password,TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock0 *block0,
+                                            TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock1 *block1)
+{
+  tagop->type = TMR_TAGOP_GEN2_IDS_SL900A_SETSHELFLIFE;
+  tagop->u.gen2.u.custom.chipType = TMR_SR_GEN2_IDS_SL900A_SILICON;
+  tagop->u.gen2.u.custom.u.ids.u.setShelfLife.AccessPassword = accessPassword;
+  tagop->u.gen2.u.custom.u.ids.u.setShelfLife.CommandCode = 0xAB;
+  tagop->u.gen2.u.custom.u.ids.u.setShelfLife.Password = password;
+  tagop->u.gen2.u.custom.u.ids.u.setShelfLife.sl900A.level = level;
+  tagop->u.gen2.u.custom.u.ids.u.setShelfLife.shelfLifeBlock0 = block0;
+  tagop->u.gen2.u.custom.u.ids.u.setShelfLife.shelfLifeBlock1 = block1;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize TMR_UserConfigOp to set the default category.
+ * @param config pointer to the TMR_UserConfigOp structure to initialize
+ * @param op user configuration opeartion (save, restore or clear)
+ */
+TMR_Status
+TMR_init_UserConfigOp(TMR_SR_UserConfigOp *config, TMR_SR_UserConfigOperation op)
+{
+  config->category = TMR_SR_ALL;
+  config->op       = op;
+
+  return TMR_SUCCESS;
+}
+
+/**
+ *  Initialize TMR_NXP_ConfigWord to set the default value.
+ *  If the instance of the above structure is created as 'static',
+ *  then no need to call this constructor.
+ *  @param configWord Instance of TMR_NXP_ConfigWord
+ */
+TMR_Status 
+TMR_init_GEN2_NXP_G2I_ConfigWord(TMR_NXP_ConfigWord *configWord)
+{
+  configWord->data = 0x0000;
+  return TMR_SUCCESS;
+}
+
+/**
+ *  Initialize TMR_Monza4_ControlByte to set the default value to 0.
+ *  If the instance of the above structure is created as 'static' or
+ *  if it is already initialized to 0, then no need to call this constructor.
+ *  @param controlByte Instance of TMR_Monza4_ControlByte
+ */
+TMR_Status
+TMR_init_GEN2_Impinj_Monza4_ControlByte(TMR_Monza4_ControlByte *controlByte)
+{
+  controlByte->data = 0x00;
+  return TMR_SUCCESS;
+}
+
+/**
+ *  Initialize TMR_Monza4_Payload to set the default value to 0.
+ *  If the instance of the above structure is created as 'static' or
+ *  if it is already initialized to 0, then no need to call this constructor.
+ *  @param payload Instance of TMR_Monza4_Payload
+ */
+TMR_Status
+TMR_init_GEN2_Impinj_Monza4_Payload(TMR_Monza4_Payload *payload)
+{
+  payload->data = 0x0000;
+  return TMR_SUCCESS;
+}
+
+/**
+ * Helper function to update or modifying the sfe parameters
+ */
+TMR_Status
+TMR_update_GEN2_IDS_SL900A_SfeParameters(TMR_TagOp_GEN2_IDS_SL900A_SfeParameters *sfe)
+{
+  uint64_t mask;
+  /* Update the raw value as per the  field set by the user */
+  switch (sfe->type)
+  {
+    case TMR_GEN2_IDS_SL900A_SFE_RANG:
+      {
+        mask = TMR_makeBitMask(11, 5);
+        sfe->raw &= ~mask;
+        sfe->raw |= ((uint64_t)(((uint64_t)sfe->Rang) << 11));
+
+        break;
+      }
+    case TMR_GEN2_IDS_SL900A_SFE_SETI:
+      {
+        mask = TMR_makeBitMask(6, 5);
+        sfe->raw &= ~mask;
+        sfe->raw |= ((uint64_t)(((uint64_t)sfe->Seti) << 6));
+
+        break;
+      }
+    case TMR_GEN2_IDS_SL900A_SFE_EXT1:
+      {
+        mask = TMR_makeBitMask(4, 2);
+        sfe->raw &= ~mask;
+        sfe->raw |= ((uint64_t)(((uint64_t)sfe->Ext1) << 4));
+
+        break;
+      }
+    case TMR_GEN2_IDS_SL900A_SFE_EXT2:
+      {
+        mask = TMR_makeBitMask(3, 1);
+        sfe->raw &= ~mask;
+        sfe->raw |= ((uint64_t)(((uint64_t)sfe->Ext2) << 3));
+
+        break;
+      }
+    case TMR_GEN2_IDS_SL900A_SFE_AUTORANGEDISABLE:
+      {
+        mask = TMR_makeBitMask(2, 1);
+        sfe->raw &= ~mask;
+        sfe->raw |= ((uint64_t)(((uint64_t)sfe->AutorangeDisable) << 2));
+
+        break;
+      }
+    case TMR_GEN2_IDS_SL900A_SFE_VERIFYSENSORID:
+      {
+        mask = TMR_makeBitMask(0, 2);
+        sfe->raw &= ~mask;
+        sfe->raw |= ((uint64_t)(((uint64_t)sfe->VerifySensorID) << 0));
+
+        break;
+      }
+    default: 
+      break;
+  }
+  return TMR_SUCCESS;
+}
+
+/**
+ * Helper function to update or modifying the calibration Data
+ */
+TMR_Status
+TMR_update_GEN2_IDS_SL900A_CalibrationData(TMR_TagOp_GEN2_IDS_SL900A_CalibrationData *cal)
+{
+  uint64_t mask;
+  /* Update the raw value as per the  field set by the user */
+  switch (cal->type)
+  {
+    case TMR_GEN2_IDS_SL900A_CALIBRATION_COARSE1:
+      {
+        mask = TMR_makeBitMask(48, 3);
+        cal->raw &= ~mask;
+        cal->raw |= ((uint64_t)(((uint64_t)cal->Coarse1) << 48));
+        cal->raw = cal->raw;
+
+        break;
+      }
+    case TMR_GEN2_IDS_SL900A_CALIBRATION_COARSE2:
+      {
+        mask = TMR_makeBitMask(40, 3);
+        cal->raw &= ~mask;
+        cal->raw |= ((uint64_t)(((uint64_t)cal->Coarse2) << 40));
+        cal->raw = cal->raw;
+
+        break;
+      }
+    case TMR_GEN2_IDS_SL900A_CALIBRATION_GNDSWITCH:
+      {
+        mask = TMR_makeBitMask(39, 1);
+        cal->raw &= ~mask;
+        cal->raw |= ((uint64_t)(((uint64_t)cal->GndSwitch) << 39));
+        cal->raw = cal->raw;
+
+        break;
+      }
+    case TMR_GEN2_IDS_SL900A_CALIBRATION_SELP12:
+      {
+        mask = TMR_makeBitMask(37, 2);
+        cal->raw &= ~mask;
+        cal->raw |= ((uint64_t)(((uint64_t)cal->Selp12) << 37));
+        cal->raw = cal->raw;
+
+        break;
+      }
+    case TMR_GEN2_IDS_SL900A_CALIBRATION_DF:
+      {
+        mask = TMR_makeBitMask(24, 8);
+        cal->raw &= ~mask;
+        cal->raw |= ((uint64_t)(((uint64_t)cal->Df) << 24));
+        cal->raw = cal->raw;
+
+        break;
+      }
+    case TMR_GEN2_IDS_SL900A_CALIBRATION_SWEXTEN:
+      {
+        mask = TMR_makeBitMask(23, 1);
+        cal->raw &= ~mask;
+        cal->raw |= ((uint64_t)(((uint64_t)cal->SwExtEn) << 23));
+        cal->raw = cal->raw;
+
+        break;
+      }
+    case TMR_GEN2_IDS_SL900A_CALIBRATION_SELP22:
+      {
+        mask = TMR_makeBitMask(21, 2);
+        cal->raw &= ~mask;
+        cal->raw |= ((uint64_t)(((uint64_t)cal->Selp22) << 21));
+        cal->raw = cal->raw;
+
+        break;
+      }
+    case TMR_GEN2_IDS_SL900A_CALIBRATION_IRLEV:
+      {
+        mask = TMR_makeBitMask(19, 2);
+        cal->raw &= ~mask;
+        cal->raw |= ((uint64_t)(((uint64_t)cal->Irlev) << 19));
+        cal->raw = cal->raw;
+
+        break;
+      }
+    case TMR_GEN2_IDS_SL900A_CALIBRATION_EXCRES:
+      {
+        mask = TMR_makeBitMask(2, 1);
+        cal->raw &= ~mask;
+        cal->raw |= ((uint64_t)(((uint64_t)cal->ExcRes) << 2));
+        cal->raw = cal->raw;
+
+        break;
+      }
+    default: 
+      break;
+  }
+  return TMR_SUCCESS;
+}
+
+/**
+ * Helper function to set the calibration Data
+ */
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_CalibrationData(uint8_t byte[7], TMR_TagOp_GEN2_IDS_SL900A_CalibrationData *cal)
+{
+  if (NULL != byte)
+  {
+    /**
+     * ToU64 requires 8 bytes of input, but CalibrationData is only 7 bytes long
+     * Create a temporary array to provide the necessary padding.
+     */
+    uint8_t tmp[] = {0,0,0,0,0,0,0,0,};
+    memcpy(tmp+1, byte, 7);
+    cal->raw = (uint64_t)(0
+        | ((uint64_t)(tmp[ 0]) << 56)
+        | ((uint64_t)(tmp[ 1]) << 48)
+        | ((uint64_t)(tmp[ 2]) << 40)
+        | ((uint64_t)(tmp[3]) << 32)
+        | ((uint64_t)(tmp[4]) << 24)
+        | ((uint64_t)(tmp[5]) << 16)
+        | ((uint64_t)(tmp[ 6]) << 8)
+        | ((uint64_t)(tmp[7]) << 0));
+
+    cal->raw &= (uint64_t)0x00FFFFFFFFFFFFFFLL;
+  }
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Helper function to set the sfe parameters
+ */
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_SfeParameters(uint8_t byte[2], TMR_TagOp_GEN2_IDS_SL900A_SfeParameters *sfe)
+{
+  /* Create SFEParameters object from raw 2-byte reply */
+  int hi, lo;
+  hi = (uint16_t)(byte[0]) << 8;
+  lo = (uint16_t)(byte[1]);
+  sfe->raw = (hi | lo);
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize TMR_GEN2_SL900A_SensorReading to Get Sensor Value response.
+ * @param reply instance of TMR_uint8List
+ * @param sensor instance of TMR_TagOp_GEN2_IDS_SL900A_SensorReading,
+ * response for sl900A getSensorvalue command.
+ */
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_SensorReading(TMR_uint8List *reply, TMR_TagOp_GEN2_IDS_SL900A_SensorReading *sensor)
+{  
+
+  if (2 != reply->len)
+  {
+    /* Sensor Reading value must be exactly 2 bytes long */
+    return TMR_ERROR_MSG_INVALID_PARAMETER_VALUE;
+  }
+  sensor->reply = reply->list[0] << 8 | reply->list[1];
+  sensor->Raw = sensor->reply;
+  sensor->ADError = (((sensor->reply >> 15) & 0x1) != 0);
+  sensor->RangeLimit = (uint8_t) ((sensor->reply >> 10) & 0x1F);
+  sensor->Value = ((sensor->reply >> 0 ) & 0x3FF);
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize TMR_GEN2_SL900A_CalSfe to Get getcalibration response.
+ * @param reply instance of TMR_uint8List
+ * @param calSfe instance of TMR_TagOp_GEN2_IDS_SL900A_CalSfe,
+ * response for CalibrationData and SfeParameters.
+ */
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_CalSfe(TMR_uint8List *reply, TMR_TagOp_GEN2_IDS_SL900A_CalSfe *calSfe)
+{
+  uint64_t mask;
+  TMR_init_GEN2_IDS_SL900A_CalibrationData(reply->list, &calSfe->Cal);
+  TMR_init_GEN2_IDS_SL900A_SfeParameters(reply->list + 7, &calSfe->Sfe);
+
+  mask = TMR_makeBitMask(51, 5);
+  calSfe->Cal.Ad1 = (uint8_t)((calSfe->Cal.raw & mask) >> 51);
+
+  mask = TMR_makeBitMask(48, 3);
+  calSfe->Cal.Coarse1 = (uint8_t)((calSfe->Cal.raw & mask) >> 48);
+
+  mask = TMR_makeBitMask(43, 5);
+  calSfe->Cal.Ad2 = (uint8_t)((calSfe->Cal.raw & mask) >> 43);
+
+  mask = TMR_makeBitMask(40, 3);
+  calSfe->Cal.Coarse2 = (uint8_t)((calSfe->Cal.raw & mask) >> 40);
+
+  mask = TMR_makeBitMask(39, 1);
+  calSfe->Cal.GndSwitch = (uint8_t)((calSfe->Cal.raw & mask) >> 39);
+
+  mask = TMR_makeBitMask(37, 2);
+  calSfe->Cal.Selp12 = (uint8_t)((calSfe->Cal.raw & mask) >> 37);
+
+  mask = TMR_makeBitMask(32, 5);
+  calSfe->Cal.Adf = (uint8_t)((calSfe->Cal.raw & mask) >> 32);
+
+  mask = TMR_makeBitMask(24, 8);
+  calSfe->Cal.Df = (uint8_t)((calSfe->Cal.raw & mask) >> 24);
+
+  mask = TMR_makeBitMask(23, 1);
+  calSfe->Cal.SwExtEn = (uint8_t)((calSfe->Cal.raw & mask) >> 23);
+
+  mask = TMR_makeBitMask(21, 2);
+  calSfe->Cal.Selp22 = (uint8_t)((calSfe->Cal.raw & mask) >> 21);
+
+  mask = TMR_makeBitMask(19, 2);
+  calSfe->Cal.Irlev = (uint8_t)((calSfe->Cal.raw & mask) >> 19);
+
+  mask = TMR_makeBitMask(14, 5);
+  calSfe->Cal.RingCal = (uint8_t)((calSfe->Cal.raw & mask) >> 14);
+
+  mask = TMR_makeBitMask(7, 7);
+  calSfe->Cal.OffInt = (uint8_t)((calSfe->Cal.raw & mask) >> 7);
+
+  mask = TMR_makeBitMask(3, 4);
+  calSfe->Cal.Reftc = (uint8_t)((calSfe->Cal.raw & mask) >> 3);
+
+  mask = TMR_makeBitMask(2, 1);
+  calSfe->Cal.ExcRes = (uint8_t)((calSfe->Cal.raw & mask) >> 2);
+
+  mask = TMR_makeBitMask(0, 2);
+  calSfe->Cal.RFU = (uint8_t)((calSfe->Cal.raw & mask) >> 0);
+
+  mask = TMR_makeBitMask(11, 5);
+  calSfe->Sfe.Rang = (uint8_t)((calSfe->Sfe.raw & mask) >> 11);
+
+  mask = TMR_makeBitMask(6, 5);
+  calSfe->Sfe.Seti = (uint8_t)((calSfe->Sfe.raw & mask) >> 6);
+
+  mask = TMR_makeBitMask(4, 2);
+  calSfe->Sfe.Ext1 = (uint8_t)((calSfe->Sfe.raw & mask) >> 4);
+
+  mask = TMR_makeBitMask(3, 1);
+  calSfe->Sfe.Ext2 = (uint8_t)((calSfe->Sfe.raw & mask) >> 3);
+
+  mask = TMR_makeBitMask(2, 1);
+  calSfe->Sfe.AutorangeDisable = (uint8_t)((calSfe->Sfe.raw & mask) >> 2);
+
+  mask = TMR_makeBitMask(0, 2);
+  calSfe->Sfe.VerifySensorID = (uint8_t)((calSfe->Sfe.raw & mask) >> 0);
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize TMR_GEN2_SL900A_BatteryLevelReading to get the getBatteryLevel response.
+ * @param reply instance of TMR_uint8List
+ * @param battery instance of TMR_TagOp_GEN2_IDS_SL900A_BatteryLevelReading,
+ * the reply structure of getBatteryLevel
+ */ 
+
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_BatteryLevelReading(TMR_uint8List *reply, TMR_TagOp_GEN2_IDS_SL900A_BatteryLevelReading *battery)
+{  
+
+  if (2 != reply->len)
+  {
+    /* Sensor Reading value must be exactly 2 bytes long */
+    return TMR_ERROR_MSG_INVALID_PARAMETER_VALUE;
+  }
+  battery->reply = (uint16_t)(reply->list[0] << 8 | reply->list[1]);
+  battery->ADError = (bool)(((battery->reply >> 15) & 0x1) != 0);
+  battery->BatteryType = (uint8_t) ((battery->reply >> 14) & 0x1);
+  battery->Value = (uint16_t)((battery->reply >> 0 ) & 0x3FF);
+
+  return TMR_SUCCESS;
+}
+/**
+ * Initialize TMR_GEN2_SL900A_FifoStatus to Get status of fifo reply
+ * @param statusReply instance of TMR_uint8List
+ * @param status instance of TMR_TagOp_GEN2_IDS_SL900A_FifoStatus,
+ * the reply structure of sl900A fifistatus command. 
+ */
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_FifoStatus(TMR_uint8List *statusReply, TMR_TagOp_GEN2_IDS_SL900A_FifoStatus *status)
+{
+
+  uint8_t reply;
+  if (1 != statusReply->len)
+  {
+    /* Fifo Status value must be exactly 1 byte long */
+    return TMR_ERROR_MSG_INVALID_PARAMETER_VALUE;
+  }
+  status->raw = statusReply->list[0];
+  reply = statusReply->list[0];
+  status->fifoBusy = (0 != ((reply >> 7) & 1));
+  status->dataReady = (0 != ((reply >> 6) & 1));
+  status->noData = (0 != ((reply >> 5) & 1));
+  status->numValidBytes = (uint8_t)(reply & 0xF);
+
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize TMR_GEN2_SL900A_LogState to Get get log state Value response.
+ * @param reply instance of TMR_uint8List
+ * @param log instance of TMR_TagOp_GEN2_IDS_SL900A_LogState,
+ * sl900A logging parameters.
+ */
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_LogState(TMR_uint8List *reply, TMR_TagOp_GEN2_IDS_SL900A_LogState *log)
+{  
+
+  uint32_t offset = 0;
+  uint32_t raw;  
+  if ((9 != reply->len) && (20 != reply->len))
+  {
+    /* GetLogState replies must be 9 or 21 bytes in length */
+    return TMR_ERROR_MSG_INVALID_PARAMETER_VALUE;
+  }
+
+  if (9 == reply->len)
+  {
+    log->limitCount.extremeLower = reply->list[offset + 0];    
+    log->limitCount.lower = reply->list[offset + 1];
+    log->limitCount.upper = reply->list[offset + 2];
+    log->limitCount.extremeUpper = reply->list[offset + 3];
+
+    offset += 4;
+    raw = TMR_byteArrayToInt(reply->list, offset);
+    log->statStatus.MeasurementAddressPointer = (uint16_t)((raw >> 22) & 0x1FF);
+    log->statStatus.NumMemReplacements = (uint8_t) ((raw >> 16) & 0x3F);
+    log->statStatus.NumMeasurements = (uint16_t) ((raw >> 1) & 0x7FFF);
+    log->statStatus.Active = (bool)(0 != (raw & 0x1));
+    offset += 4;
+  }
+  if (20 == reply->len)
+  {
+    /* @todo Fully support shelf life arguments.  For now, just skip over them */
+    offset += 8;
+    offset += 4;
+  }
+  raw = TMR_byteArrayToInt(reply->list, offset);
+  log->statFlag.Active = (bool)(0 != ((raw >> 7) & 1));
+  log->statFlag.Full = (bool)(0 != ((raw >> 6) & 1));
+  log->statFlag.Overwritten = (bool)(0 != ((raw >> 5) & 1));
+  log->statFlag.ADError = (bool) (0 != ((raw >> 4) & 1));
+  log->statFlag.LowBattery = (bool) (0 != ((raw >> 3) & 1));
+  log->statFlag.ShelfLifeLow = (bool) (0 != ((raw >> 2) & 1));
+  log->statFlag.ShelfLifeHigh = (bool)(0 != ((raw >> 1) & 1));
+  log->statFlag.ShelfLifeExpired = (bool)(0 != ((raw >> 0) & 1));
+  
+  return TMR_SUCCESS;
+}
+
+/**
+ * Initialize TMR_TagOp_GEN2_IDS_SL900A_MeasurementSetupData to Get measurment setup data 
+ * Value response.
+ * @param reply instance of TMR_uint8List
+ * @param measurement instance of TMR_TagOp_GEN2_IDS_SL900A_MeasurementSetupData,
+ * response structure for sl900A getMeasurementSetupData command.
+ */
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_MeasurementSetupData(TMR_uint8List *reply, TMR_TagOp_GEN2_IDS_SL900A_MeasurementSetupData *measurement)
+{
+  if(16 != reply->len)
+  {
+    /* MeasurementSetupData value must be exactly 16 byte long */
+    return TMR_ERROR_MSG_INVALID_PARAMETER_VALUE;
+  }
+
+  memcpy(measurement->Raw, reply->list, reply->len);
+
+  //get the start time
+  {
+    uint32_t temp;
+    temp = TMR_byteArrayToInt(reply->list, 0);
+    measurement->startTime.tm_year = (int)(2010+((temp >> 26) & 0x3F));
+    measurement->startTime.tm_mon = (int)((temp >> 22) & 0xF);
+    measurement->startTime.tm_mday = (int)((temp >> 17) & 0x1F);
+    measurement->startTime.tm_hour = (int)((temp >> 12) & 0x1F);
+    measurement->startTime.tm_min = (int)((temp >> 6) & 0x3F);
+    measurement->startTime.tm_sec = (int)((temp >> 0) & 0x3F);
+  }
+  //get the log limits
+  {
+    int offset = 4;
+    uint64_t value = 0;
+    /* LogLimits value is of 40 bits
+     * extract that from the response
+     */
+    value = TMR_byteArrayToLong(reply->list, offset);
+    /* 
+     * Indivisual field in LogLimits is of 10 bits
+     * masking each of them to a 16 bit value for convinence
+     */
+    measurement->loglimit.extremeLower = (uint16_t) ((value >> 54) & 0x03FF);
+    measurement->loglimit.lower = (uint16_t) ((value >> 44) & 0x03FF);
+    measurement->loglimit.upper = (uint16_t) ((value >> 34) & 0x03FF);
+    measurement->loglimit.extremeUpper = (uint16_t) ((value >> 24) & 0x03FF);
+  }
+  //get log mode
+  {
+    uint8_t temp = (uint8_t)reply->list[9];
+    measurement->logModeData.Raw = temp;
+    measurement->logModeData.Form = (LoggingForm)((temp >> 5) & 7);
+    measurement->logModeData.Storage = (StorageRule)(((temp >> 4) & 1));
+    measurement->logModeData.Ext1Enable = (0 != ((temp >> 3) & 1));
+    measurement->logModeData.Ext2Enable = (0 != ((temp >> 2) & 1));
+    measurement->logModeData.TempEnable = (0 != ((temp >> 1) & 1));
+    measurement->logModeData.BattEnable = (0 != ((temp>> 0) & 1));
+  }
+  //log interval
+  {
+    uint16_t temp;
+    temp = TMR_byteArrayToShort(reply->list, 10);
+    temp = ((temp >> 1) & 0x0001);
+    measurement->logInterval = temp;
+  }
+  //delay time
+  {
+    uint16_t temp;
+    temp = TMR_byteArrayToShort(reply->list, 12);
+    measurement->delyTime.raw = temp;
+    measurement->delyTime.Mode = (0 == ((temp >> 1) & 0x1)) ? TMR_GEN2_IDS_SL900A_DELAYMODE_TIMER
+                                                           : TMR_GEN2_IDS_SL900A_DELAYMODE_EXTSWITCH;
+    measurement->delyTime.Time = (uint16_t)((temp >> 4) & 0xFFF);
+    measurement->delyTime.IrqTimerEnable = (0 != (temp & 0x1));
+  }
+  //application data
+  {
+    uint16_t temp;
+    temp = TMR_byteArrayToShort(reply->list, 14);
+    measurement->addData.raw = temp;
+    measurement->addData.NumberOfWords = (uint16_t)((temp >> 7) & 0x1FF);
+    measurement->addData.BrokenWordPointer = (uint8_t)(temp & 0x7);
+  }
+
+  return TMR_SUCCESS;
+}
+
+#endif /* TMR_ENABLE_GEN2_CUSTOM_TAGOPS  */
+void
+TMR_paramProbe(struct TMR_Reader *reader, TMR_Param key)
+{
+
+  /* buf is at least as large as the largest parameter, with all values 0
+   * (NULL pointers and 0 lengths).
+   */
+  uint32_t buf[] = {0, 0, 0, 0, 0, 0, 0, 0};
+  TMR_Status ret;
+
+  ret = TMR_paramGet(reader, key, &buf);
+  if (TMR_SUCCESS == ret)
+  {
+    if (TMR_READER_TYPE_SERIAL == reader->readerType)
+    {
+      BITSET(reader->u.serialReader.paramPresent, key);
+      BITSET(reader->u.serialReader.paramConfirmed, key);
+    }
+#ifdef TMR_ENABLE_LLRP_READER
+    if (TMR_READER_TYPE_LLRP == reader->readerType)
+    {
+      BITSET(reader->u.llrpReader.paramPresent, key);
+      BITSET(reader->u.llrpReader.paramConfirmed, key);
+    }
+#endif
+  }
+}
+
+
+/**
+ * Get a list of the parameters available
+ * @reader pointer of reader object
+ * @key pointer of TMR_Param
+ * @len pointer to uint32_t
+ */
+
+TMR_Status
+TMR_paramList(struct TMR_Reader *reader, TMR_Param *keys, uint32_t *len)
+{
+  int i, count, max;
+
+  max = *len;
+  count = 0;
+  for (i = TMR_PARAM_MIN; i <= TMR_PARAM_MAX ; i++)
+  {
+    if (TMR_READER_TYPE_SERIAL == reader->readerType)
+    {
+      if (0 == BITGET(reader->u.serialReader.paramConfirmed, i))
+      {
+        /* Fix me */
+        TMR_paramProbe(reader, (TMR_Param)i);
+      }
+
+      if (BITGET(reader->u.serialReader.paramPresent, i))
+      {
+        if (count < max)
+          keys[count] = (TMR_Param)i;
+        count++;
+      }
+    }
+#ifdef TMR_ENABLE_LLRP_READER
+    if (TMR_READER_TYPE_LLRP == reader->readerType)
+    {
+      if (0 == BITGET(reader->u.llrpReader.paramConfirmed, i))
+      {
+        TMR_paramProbe(reader, i);
+      }
+
+      if (BITGET(reader->u.llrpReader.paramPresent, i))
+      {
+        if (count < max)
+          keys[count] = i;
+        count++;
+      }
+    }
+#endif
+  }
+
+  *len = count;
+
+  return TMR_SUCCESS;
+}
+
+  TMR_Status
+TMR_receiveAutonomousReading(struct TMR_Reader *reader, TMR_TagReadData *trd, TMR_Reader_StatsValues *stats)
+{
+  TMR_Status ret;
+
+  ret = TMR_SUCCESS;
+
+  if (TMR_READER_TYPE_SERIAL != reader->readerType)
+  {
+    /* Currently supporting only serial reader */
+    return TMR_ERROR_UNSUPPORTED;
+  }
+
+#ifdef TMR_ENABLE_BACKGROUND_READS
+  {
+    /**
+     *      *     * create the thread
+     *           *         */
+    ret = pthread_create(&reader->autonomousBackgroundReader, NULL,
+        do_background_receiveAutonomousReading, reader);
+    if (0 != ret)
+    {
+      return TMR_ERROR_NO_THREADS;
+    }
+    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+    pthread_detach(reader->autonomousBackgroundReader);
+  }
+#else
+  {
+    /* This will add support for non thread platform */
+    ret =  TMR_SR_receiveAutonomousReading(reader, trd, stats);
+  }
+#endif
+
+  return ret;
+}
+
diff --git a/cbits/api/tm_reader.h b/cbits/api/tm_reader.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tm_reader.h
@@ -0,0 +1,1289 @@
+/* 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_ */
diff --git a/cbits/api/tm_reader_async.c b/cbits/api/tm_reader_async.c
new file mode 100644
--- /dev/null
+++ b/cbits/api/tm_reader_async.c
@@ -0,0 +1,1599 @@
+/**
+ *  @file tm_reader_async.c
+ *  @brief Mercury API - background reading implementation
+ *  @author Nathan Williams
+ *  @date 11/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.
+ */
+#include "tm_config.h"
+#include "tm_reader.h"
+#include "serial_reader_imp.h"
+#include <stdio.h>
+
+bool IsDutyCycleEnabled(TMR_Reader *reader);
+TMR_Status restart_reading(struct TMR_Reader *reader);
+#ifdef TMR_ENABLE_BACKGROUND_READS
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef WIN32
+#include <sys/time.h>
+#endif
+
+#ifdef TMR_ENABLE_LLRP_READER
+#include "llrp_reader_imp.h"
+#endif
+#include "osdep.h"
+#include "tmr_utils.h"
+
+static void *do_background_reads(void *arg);
+static void *parse_tag_reads(void *arg);
+static void process_async_response(TMR_Reader *reader);
+bool isBufferOverFlow = false;
+#endif /* TMR_ENABLE_BACKGROUND_READS */
+
+TMR_Status
+TMR_startReading(struct TMR_Reader *reader)
+{
+#ifdef SINGLE_THREAD_ASYNC_READ
+  TMR_Status ret;
+  uint32_t ontime;
+  
+  TMR_paramGet(reader, TMR_PARAM_READ_ASYNCONTIME, &ontime);
+  reader->continuousReading = true; 
+  if (((TMR_SR_MODEL_M6E == reader->u.serialReader.versionInfo.hardware[0])||
+	(TMR_SR_MODEL_M6E_I == reader->u.serialReader.versionInfo.hardware[0]) ||
+	(TMR_SR_MODEL_MICRO == reader->u.serialReader.versionInfo.hardware[0]) ||
+	(TMR_SR_MODEL_M6E_NANO == reader->u.serialReader.versionInfo.hardware[0])) &&
+	(reader->readParams.asyncOffTime == 0 || (reader->readParams.asyncOffTime != 0 && IsDutyCycleEnabled(reader)) ) &&
+	((TMR_READ_PLAN_TYPE_SIMPLE == reader->readParams.readPlan->type) ||
+	((TMR_READ_PLAN_TYPE_MULTI == reader->readParams.readPlan->type)  &&
+	(compareAntennas(&reader->readParams.readPlan->u.multi))))
+	)
+  {
+	if (reader->readParams.asyncOffTime == 0)
+	{
+		reader->dutyCycle = false;
+	}
+	else
+	{
+		reader->dutyCycle = true;
+	}
+  }
+  else
+  {
+	reader->dutyCycle = false;
+  }
+  ret = TMR_read(reader, ontime, NULL);
+  if(TMR_SUCCESS != ret)
+	return ret;
+	 
+#else
+#ifdef TMR_ENABLE_BACKGROUND_READS
+  int ret;
+  bool createParser = true;
+
+  if (TMR_READER_TYPE_SERIAL == reader->readerType)
+  {
+#ifdef TMR_ENABLE_SERIAL_READER
+    /**
+     * Currently we are not supporting stop N trigger for async read case.
+     * This is also true for pseudo continuous case as well. Pop up the error
+     * if user is trying to do so.
+     **/
+    if (TMR_READ_PLAN_TYPE_MULTI == reader->readParams.readPlan->type)
+    {
+      uint8_t loop = 0;
+      TMR_MultiReadPlan *multi;
+
+      multi = &reader->readParams.readPlan->u.multi;
+
+      for (loop = 0; loop < multi->planCount; loop++)
+      {
+        if (multi->plans[loop]->u.simple.stopOnCount.stopNTriggerStatus)
+        {
+          /* Not supporting stop N trigger */
+          return TMR_ERROR_UNSUPPORTED; 
+        }
+      }
+    }
+    else if (TMR_READ_PLAN_TYPE_SIMPLE == reader->readParams.readPlan->type)
+    {
+      if (reader->readParams.readPlan->u.simple.stopOnCount.stopNTriggerStatus)
+      {
+        /* Not supporting stop N trigger */
+        return TMR_ERROR_UNSUPPORTED;
+      }
+    }
+    else
+    {
+      /* do nothing */
+    }
+
+    /**
+	  * if model is M6e and it's varient
+	  * asyncOffTime == 0
+	  * only then use streaming
+	  */
+    if (
+        ((TMR_SR_MODEL_M6E == reader->u.serialReader.versionInfo.hardware[0])||
+         (TMR_SR_MODEL_M6E_I == reader->u.serialReader.versionInfo.hardware[0]) ||
+         (TMR_SR_MODEL_MICRO == reader->u.serialReader.versionInfo.hardware[0]) ||
+         (TMR_SR_MODEL_M6E_NANO == reader->u.serialReader.versionInfo.hardware[0])) &&
+        (reader->readParams.asyncOffTime == 0 || (reader->readParams.asyncOffTime != 0 && IsDutyCycleEnabled(reader)) ) &&
+        ((TMR_READ_PLAN_TYPE_SIMPLE == reader->readParams.readPlan->type) || 
+         ((TMR_READ_PLAN_TYPE_MULTI == reader->readParams.readPlan->type)  && 
+          (compareAntennas(&reader->readParams.readPlan->u.multi))))
+       )
+    {
+		if (reader->readParams.asyncOffTime == 0)
+		{
+			reader->dutyCycle = false;
+		}
+		else
+		{
+			reader->dutyCycle = true;
+		}
+    }
+    else
+    {
+      createParser = false;
+	  reader->dutyCycle = false;
+    }
+#else
+    return TMR_ERROR_UNSUPPORTED;
+#endif/* TMR_ENABLE_SERIAL_READER */    
+  }
+#ifdef TMR_ENABLE_LLRP_READER
+  if (TMR_READER_TYPE_LLRP == reader->readerType)
+  {
+    /**
+     * In case of LLRP reader and continuous reading, disable the
+     * LLRP background receiver.
+     **/
+    TMR_LLRP_setBackgroundReceiverState(reader, false);
+    /**
+     * Note the keepalive start time
+     * Keepalive monitoring happens only 
+     * for async reads.
+     **/
+    reader->u.llrpReader.ka_start = tmr_gettime();
+  }
+#endif
+
+  /**
+   * Initialize read_started semaphore
+   **/
+  pthread_mutex_lock(&reader->backgroundLock);
+  reader->readState = TMR_READ_STATE_STARTING;
+  pthread_cond_broadcast(&reader->readCond);
+  pthread_mutex_unlock(&reader->backgroundLock);
+
+  if (true == createParser)
+  {
+    /** Background parser thread initialization
+     *
+     * Only M6e supports Streaming, and in case of other readers
+     * we still use pseudo-async mechanism for continuous read.
+     * To achieve continuous reading, create a parser thread
+     */
+    pthread_mutex_lock(&reader->parserLock);
+    
+    if (false == reader->parserSetup)
+    {
+      ret = pthread_create(&reader->backgroundParser, NULL,
+                       parse_tag_reads, reader);
+      if (0 != ret)
+      {
+        pthread_mutex_unlock(&reader->parserLock);
+        return TMR_ERROR_NO_THREADS;
+      }
+      pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+      pthread_detach(reader->backgroundParser);
+    /** Initialize semaphores only for the first time
+     *  These semaphores are used only in case of streaming
+     */
+      reader->queue_depth = 0;
+      sem_init(&reader->queue_length, 0, 0);
+      sem_init(&reader->queue_slots, 0, TMR_MAX_QUEUE_SLOTS);
+      reader->parserSetup = true;
+    }
+
+    reader->parserEnabled = true;
+
+
+    /* Enable streaming */
+    reader->continuousReading = true;
+    reader->finishedReading = false;
+    pthread_cond_signal(&reader->parserCond);
+    pthread_mutex_unlock(&reader->parserLock);
+  }
+
+  /* Background reader thread initialization */
+  pthread_mutex_lock(&reader->backgroundLock);
+
+  if (false == reader->backgroundSetup)
+  {
+    ret = pthread_create(&reader->backgroundReader, NULL,
+                         do_background_reads, reader);
+    if (0 != ret)
+    {
+      pthread_mutex_unlock(&reader->backgroundLock);
+      return TMR_ERROR_NO_THREADS;
+    }
+    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+    reader->backgroundSetup = true;
+  }
+
+  reader->backgroundEnabled = true;
+  reader->searchStatus = true;
+
+#ifdef TMR_ENABLE_SERIAL_READER    
+  if (TMR_READER_TYPE_SERIAL == reader->readerType)
+  {
+    reader->u.serialReader.tagopFailureCount = 0;
+    reader->u.serialReader.tagopSuccessCount = 0;
+  }
+#endif/* TMR_ENABLE_SERIAL_READER */    
+  pthread_cond_signal(&reader->backgroundCond);
+  pthread_mutex_unlock(&reader->backgroundLock);
+
+  /* End of Background reader thread initialization */
+  /**
+   * Wait for the Background thread to send the read command.
+   * This will prevent of adding extra sleep in the application
+   * after TMR_startReading() call.
+   **/ 
+  pthread_mutex_lock(&reader->backgroundLock);
+  while (TMR_READ_STATE_STARTING == reader->readState)
+  {
+    pthread_cond_wait(&reader->readCond, &reader->backgroundLock);
+  }
+  pthread_mutex_unlock(&reader->backgroundLock);
+#endif /* TMR_ENABLE_BACKGROUND_READS */
+#endif
+
+  return TMR_SUCCESS;
+}
+
+#if defined(TMR_ENABLE_BACKGROUND_READS)|| defined(SINGLE_THREAD_ASYNC_READ)
+bool IsDutyCycleEnabled(struct TMR_Reader *reader)
+{
+	uint16_t i; 
+	uint8_t *readerVersion = reader->u.serialReader.versionInfo.fwVersion ;
+	uint8_t checkVersion[4];
+	switch (reader->u.serialReader.versionInfo.hardware[0])
+	{
+		case TMR_SR_MODEL_M6E:
+		case TMR_SR_MODEL_M6E_I:
+			checkVersion[0] = 0x01; checkVersion[1] = 0x21; checkVersion[2] = 0x01; checkVersion[3] = 0x07;
+			break;
+		case TMR_SR_MODEL_MICRO:
+			checkVersion[0] = 0x01; checkVersion[1] = 0x09; checkVersion[2] = 0x00; checkVersion[3] = 0x02;
+			break;
+		case TMR_SR_MODEL_M6E_NANO:
+			checkVersion[0] = 0x01; checkVersion[1] = 0x07; checkVersion[2] = 0x00; checkVersion[3] = 0x02;
+			break;
+		default:
+			checkVersion[0] = 0xFF; checkVersion[1] = 0xFF; checkVersion[2] = 0xFF; checkVersion[3] = 0xFF;
+	}
+	for (i = 0; i < 4; i++)
+	{
+		if (readerVersion[i] < checkVersion[i])
+			return false;
+		else if (readerVersion[i] > checkVersion[i])
+			return true;
+	}
+	return true;
+}
+
+#endif /* TMR_ENABLE_BACKGROUND_READS */
+
+void
+reset_continuous_reading(struct TMR_Reader *reader, bool dueToError)
+{
+  if (true == reader->continuousReading)
+  {
+#ifndef SINGLE_THREAD_ASYNC_READ
+#ifdef TMR_ENABLE_LLRP_READER
+    if (TMR_READER_TYPE_LLRP == reader->readerType)
+    {
+      /**
+       * In case of LLRP reader, re-enable the
+       * LLRP background receiver as continuous reading is finished
+       **/
+      TMR_LLRP_setBackgroundReceiverState(reader, true);
+    }
+#endif
+
+#ifdef TMR_ENABLE_SERIAL_READER      
+    if ((false == dueToError) && (TMR_READER_TYPE_SERIAL == reader->readerType))
+    {
+      /**
+       * Disable filtering on module
+       **/
+      TMR_Status ret;
+      bool value = reader->u.serialReader.enableReadFiltering;
+	  reader->hasContinuousReadStarted = false;
+      ret = TMR_SR_cmdSetReaderConfiguration(reader, TMR_SR_CONFIGURATION_ENABLE_READ_FILTER, &value);
+      if (TMR_SUCCESS != ret)
+      {
+#ifndef BARE_METAL
+        notify_exception_listeners(reader, ret);
+#endif
+      }
+    }
+#endif/* TMR_ENABLE_SERIAL_READER */      
+#endif /*SINGLE_THREAD_ASYNC_READ*/
+    /* disable streaming */
+    reader->continuousReading = false;
+  }
+}
+
+TMR_Status
+TMR_stopReading(struct TMR_Reader *reader)
+{
+  reader->hasContinuousReadStarted = false;
+#ifdef SINGLE_THREAD_ASYNC_READ
+  reader->cmdStopReading(reader);
+#else
+#ifdef TMR_ENABLE_BACKGROUND_READS
+
+  /* Check if background setup is active */
+  pthread_mutex_lock(&reader->backgroundLock);
+
+  if (false == reader->backgroundSetup)
+  {
+    pthread_mutex_unlock(&reader->backgroundLock);
+    return TMR_SUCCESS;
+  }
+
+  if (false == reader->searchStatus)
+  {
+    /**
+     * searchStatus is false, i.e., reading is already
+     * stopped. Returen success.
+     **/
+    pthread_mutex_unlock(&reader->backgroundLock);
+    return TMR_SUCCESS;
+  }
+  /**
+   * Else, read is in progress. Set
+   * searchStatus to false;
+   **/
+  reader->searchStatus = false;
+  pthread_mutex_unlock(&reader->backgroundLock);
+
+  /**
+   * Wait until the reading has started
+   **/
+  pthread_mutex_lock(&reader->backgroundLock);
+  while (TMR_READ_STATE_STARTING == reader->readState)
+  {
+    pthread_cond_wait(&reader->readCond, &reader->backgroundLock);
+    }
+  pthread_mutex_unlock(&reader->backgroundLock);
+
+  if ((true == reader->continuousReading) && (true == reader->trueAsyncflag))
+    {
+      /**
+     * In case of true continuous reading, we need to send
+     * stop reading message immediately.
+       **/
+    if(!isBufferOverFlow)
+    {
+      reader->cmdStopReading(reader);
+    }
+
+    /**
+     * Wait logic has been changed in case of continuous reading.
+     * Wait while the background reader is still reading.
+     **/
+    pthread_mutex_lock(&reader->backgroundLock);
+    while (TMR_READ_STATE_DONE != reader->readState)
+    {
+      pthread_cond_wait(&reader->readCond, &reader->backgroundLock);
+    }
+    pthread_mutex_unlock(&reader->backgroundLock);
+    /**
+     * By this time, reader->backgroundEnabled is
+     * already set to false. i.e., background reader thread
+     * is suspended.
+     **/
+  }
+
+  /**
+   * wait until background reader thread finishes.
+   * This is needed for pseudo-async reads and also
+   * worst case of continuous reading, when read isn't success
+   **/
+  pthread_mutex_lock(&reader->backgroundLock);
+  reader->backgroundEnabled = false;
+  while (true == reader->backgroundRunning)
+  {
+    pthread_cond_wait(&reader->backgroundCond, &reader->backgroundLock);
+  }
+  pthread_mutex_unlock(&reader->backgroundLock);
+
+  /**
+   * Reset continuous reading settings, so that
+   * the subsequent startReading() call doesn't have
+   * any surprises.
+   **/
+#else
+	reader->cmdStopReading(reader);
+#endif
+  reset_continuous_reading(reader, false);
+#endif
+  return TMR_SUCCESS;
+}
+
+void
+notify_read_listeners(TMR_Reader *reader, TMR_TagReadData *trd)
+{
+  TMR_ReadListenerBlock *rlb;
+
+  /* notify tag read to listener */
+  if (NULL != reader)
+  {
+#ifndef SINGLE_THREAD_ASYNC_READ
+    pthread_mutex_lock(&reader->listenerLock);
+#endif
+	rlb = reader->readListeners;
+    while (rlb)
+    {
+      rlb->listener(reader, trd, rlb->cookie);
+      rlb = rlb->next;
+    }
+#ifndef SINGLE_THREAD_ASYNC_READ
+    pthread_mutex_unlock(&reader->listenerLock);
+#endif
+  }
+}
+
+void
+notify_stats_listeners(TMR_Reader *reader, TMR_Reader_StatsValues *stats)
+{
+  TMR_StatsListenerBlock *slb;
+
+  /* notify stats to the listener */
+#ifndef SINGLE_THREAD_ASYNC_READ
+  pthread_mutex_lock(&reader->listenerLock);
+#endif
+  slb = reader->statsListeners;
+  while (slb)
+  {
+    slb->listener(reader, stats, slb->cookie);
+    slb = slb->next;
+  }
+#ifndef SINGLE_THREAD_ASYNC_READ
+  pthread_mutex_unlock(&reader->listenerLock);
+#endif
+}
+
+
+TMR_Status restart_reading(struct TMR_Reader *reader)
+{
+	TMR_Status ret = TMR_SUCCESS;
+
+	//Stop continuous reading
+	ret = TMR_stopReading(reader);
+	if(ret != TMR_SUCCESS)
+	{
+		return ret;
+	}
+
+	#ifdef SINGLE_THREAD_ASYNC_READ
+	//Receive all tags from the previous reading
+	{
+		TMR_TagReadData trd;
+		while(true)
+		{
+			ret = TMR_hasMoreTags(reader);
+			if (TMR_SUCCESS == ret)
+			{
+				TMR_getNextTag(reader, &trd);
+				notify_read_listeners(reader, &trd);
+			}
+			else if(ret == TMR_ERROR_END_OF_READING)
+			break;
+		}
+	}
+	#endif
+	//Restart reading
+	ret = TMR_startReading(reader);
+
+	return ret;
+}
+
+
+#ifdef TMR_ENABLE_BACKGROUND_READS
+/* NOTE: There is only one auth object for all the authreq listeners, so whichever listener touches it last wins.
+ * For now (2012 Jul 20) we only anticipate having a single authreq listener, but there may be future cases which 
+ * require multiples.  Revise this design if necessary. */
+void
+notify_authreq_listeners(TMR_Reader *reader, TMR_TagReadData *trd, TMR_TagAuthentication *auth)
+{
+  TMR_AuthReqListenerBlock *arlb;
+
+  /* notify tag read to listener */
+  pthread_mutex_lock(&reader->listenerLock);
+  arlb = reader->authReqListeners;
+  while (arlb)
+  {
+    arlb->listener(reader, trd, arlb->cookie, auth);
+    arlb = arlb->next;
+  }
+  pthread_mutex_unlock(&reader->listenerLock);
+}
+#endif /* TMR_ENABLE_BACKGROUND_READS */
+
+TMR_Status
+TMR_addReadExceptionListener(TMR_Reader *reader,
+                             TMR_ReadExceptionListenerBlock *b)
+{
+#ifndef SINGLE_THREAD_ASYNC_READ
+  if (0 != pthread_mutex_lock(&reader->listenerLock))
+    return TMR_ERROR_TRYAGAIN;
+#endif
+  b->next = reader->readExceptionListeners;
+  reader->readExceptionListeners = b;
+
+#ifndef SINGLE_THREAD_ASYNC_READ
+  pthread_mutex_unlock(&reader->listenerLock);
+#endif
+  return TMR_SUCCESS;
+}
+
+#ifdef TMR_ENABLE_BACKGROUND_READS
+TMR_Status
+TMR_removeReadExceptionListener(TMR_Reader *reader,
+                                TMR_ReadExceptionListenerBlock *b)
+{
+  TMR_ReadExceptionListenerBlock *block, **prev;
+
+  if (0 != pthread_mutex_lock(&reader->listenerLock))
+    return TMR_ERROR_TRYAGAIN;
+
+  prev = &reader->readExceptionListeners;
+  block = reader->readExceptionListeners;
+  while (NULL != block)
+  {
+    if (block == b)
+    {
+      *prev = block->next;
+      break;
+    }
+    prev = &block->next;
+    block = block->next;
+  }
+
+  pthread_mutex_unlock(&reader->listenerLock);
+
+  if (block == NULL)
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  return TMR_SUCCESS;
+}
+#endif
+
+void
+notify_exception_listeners(TMR_Reader *reader, TMR_Status status)
+{
+  TMR_ReadExceptionListenerBlock *relb;
+
+  if (NULL != reader)
+  {
+#ifndef SINGLE_THREAD_ASYNC_READ
+    pthread_mutex_lock(&reader->listenerLock);
+#endif
+    relb = reader->readExceptionListeners;
+    while (relb)
+    {
+      relb->listener(reader, status, relb->cookie);
+      relb = relb->next;
+    }
+#ifndef SINGLE_THREAD_ASYNC_READ
+    pthread_mutex_unlock(&reader->listenerLock);
+#endif
+  }
+}
+
+#ifdef TMR_ENABLE_BACKGROUND_READS
+TMR_Queue_tagReads *
+dequeue(TMR_Reader *reader)
+{
+  TMR_Queue_tagReads *tagRead = NULL;
+  pthread_mutex_lock(&reader->queue_lock);
+  if (NULL != reader->tagQueueHead)
+  {
+    /* Fetch the head always */
+    tagRead = reader->tagQueueHead;
+    reader->tagQueueHead = reader->tagQueueHead->next;
+  }
+  reader->queue_depth --;
+  pthread_mutex_unlock(&reader->queue_lock);
+  return(tagRead);
+}
+
+
+void enqueue(TMR_Reader *reader, TMR_Queue_tagReads *tagRead)
+{
+  pthread_mutex_lock(&reader->queue_lock);
+  if (NULL == reader->tagQueueHead)
+  {
+    /* first tag */
+    reader->tagQueueHead = tagRead;
+    reader->tagQueueHead->next = NULL;
+    reader->tagQueueTail = reader->tagQueueHead;
+  }
+  else
+  {
+    reader->tagQueueTail->next = tagRead;
+    reader->tagQueueTail = tagRead;
+    tagRead->next = NULL;
+  }
+  reader->queue_depth ++;
+  pthread_mutex_unlock(&reader->queue_lock);
+}
+
+static void *
+parse_tag_reads(void *arg)
+{
+  TMR_Reader *reader;
+  TMR_Queue_tagReads *tagRead;
+  reader = arg;  
+
+  while (1)
+  {
+    pthread_mutex_lock(&reader->parserLock);
+    reader->parserRunning = false;
+    pthread_cond_broadcast(&reader->parserCond);
+    while (false == reader->parserEnabled)
+    {
+      pthread_cond_wait(&reader->parserCond, &reader->parserLock);
+    }
+
+    reader->parserRunning = true;
+    pthread_mutex_unlock(&reader->parserLock);
+
+    /**
+     * Wait until queue_length is more than zero,
+     * i.e., Queue should have atleast one tagRead to process
+     */
+    sem_wait(&reader->queue_length);
+
+    if (NULL != reader->tagQueueHead)
+    {
+      /**
+       * At this point there is a tagEntry in the queue
+       * dequeue it and parse it.
+       */          
+      tagRead = dequeue(reader);
+      if (false == tagRead->isStatusResponse)
+      {
+        /* Tag Buffer stream response */
+
+#ifdef TMR_ENABLE_SERIAL_READER          
+        if (TMR_READER_TYPE_SERIAL == reader->readerType)
+        {
+          /**
+          * For serial readers, the tags results are already processed
+          * and placed in the queue. Just notify that to the listener.
+          */
+          notify_read_listeners(reader, &tagRead->trd);
+        }
+#endif/* TMR_ENABLE_SERIAL_READER */           
+#ifdef TMR_ENABLE_LLRP_READER
+        if (TMR_READER_TYPE_LLRP == reader->readerType)
+        {
+          /* Else it is LLRP message, parse it */
+          LLRP_tSRO_ACCESS_REPORT *pReport;
+          LLRP_tSTagReportData *pTagReportData;
+
+          pReport = (LLRP_tSRO_ACCESS_REPORT *)tagRead->tagEntry.lMsg;
+
+          for(pTagReportData = pReport->listTagReportData;
+              NULL != pTagReportData;
+              pTagReportData = (LLRP_tSTagReportData *)pTagReportData->hdr.pNextSubParameter)
+          {
+            TMR_TagReadData trd;
+
+            TMR_TRD_init(&trd);
+            TMR_LLRP_parseMetadataFromMessage(reader, &trd, pTagReportData);
+          
+            trd.reader = reader;
+            notify_read_listeners(reader, &trd);
+        }
+        }
+#endif
+        }
+      else
+      {
+       /* A status stream response */
+
+        if (TMR_READER_TYPE_SERIAL == reader->readerType)
+        {
+          TMR_Reader_StatsValues stats;
+          uint8_t offset, i,j;
+          uint16_t flags = 0;                 
+
+          TMR_STATS_init(&stats);
+          offset = tagRead->bufPointer;
+
+          if (NULL != reader->statusListeners && NULL== reader->statsListeners)
+          {
+            /* A status stream response */
+            TMR_StatusListenerBlock *slb;
+            uint8_t index = 0, j;
+            TMR_SR_StatusReport report[TMR_SR_STATUS_MAX];
+
+
+            /* Get status content flags */
+            flags = GETU16(tagRead->tagEntry.sMsg, offset);
+
+            if (0 != (flags & TMR_SR_STATUS_FREQUENCY))
+            {
+              report[index].type = TMR_SR_STATUS_FREQUENCY;
+              report[index].u.fsr.freq = (uint32_t)(GETU24(tagRead->tagEntry.sMsg, offset));
+              index ++;
+            }
+            if (0 != (flags & TMR_SR_STATUS_TEMPERATURE))
+            {
+              report[index].type = TMR_SR_STATUS_TEMPERATURE;
+              report[index].u.tsr.temp = GETU8(tagRead->tagEntry.sMsg, offset);
+              index ++;
+            }
+            if (0 != (flags & TMR_SR_STATUS_ANTENNA))
+            {
+              uint8_t tx, rx;
+              report[index].type = TMR_SR_STATUS_ANTENNA;
+              tx = GETU8(tagRead->tagEntry.sMsg, offset);
+              rx = GETU8(tagRead->tagEntry.sMsg, offset);
+
+              for (j = 0; j < reader->u.serialReader.txRxMap->len; j++)
+              {
+                if ((rx == reader->u.serialReader.txRxMap->list[j].rxPort) && (tx == reader->u.serialReader.txRxMap->list[j].txPort))
+                {
+                  report[index].u.asr.ant = reader->u.serialReader.txRxMap->list[j].antenna;
+                  break;
+                }
+              }
+              index ++;
+            }
+
+            report[index].type = TMR_SR_STATUS_NONE;
+            /* notify status response to listener */
+            pthread_mutex_lock(&reader->listenerLock);
+            slb = reader->statusListeners;
+            while (slb)
+            {
+              slb->listener(reader, report, slb->cookie);
+              slb = slb->next;
+            }
+            pthread_mutex_unlock(&reader->listenerLock);
+
+          }
+          else if (NULL != reader->statsListeners && NULL== reader->statusListeners)
+          {
+            /* Get status content flags */
+            if ((0x80) > reader->statsFlag)
+            {
+              offset += 1;
+            }
+            else
+            {
+              offset += 2;
+            }
+
+            /**
+             * preinitialize the rf ontime and the noise floor value to zero
+             * berfore getting the reader stats
+             */
+            for (i = 0; i < stats.perAntenna.max; i++)
+            {
+              stats.perAntenna.list[i].antenna = 0;
+              stats.perAntenna.list[i].rfOnTime = 0;
+              stats.perAntenna.list[i].noiseFloor = 0;
+            }
+
+            TMR_fillReaderStats(reader, &stats, flags, tagRead->tagEntry.sMsg, offset);
+
+            /**
+             * iterate through the per antenna values,
+             * If found  any 0-antenna rows, copy the
+             * later rows down to compact out the empty space.
+             */
+            for (i = 0; i < reader->u.serialReader.txRxMap->len; i++)
+            {
+              if (!stats.perAntenna.list[i].antenna)
+              {
+                for (j = i + 1; j < reader->u.serialReader.txRxMap->len; j++)
+                {
+                  if (stats.perAntenna.list[j].antenna)
+                  {
+                    stats.perAntenna.list[i].antenna = stats.perAntenna.list[j].antenna;
+                    stats.perAntenna.list[i].rfOnTime = stats.perAntenna.list[j].rfOnTime;
+                    stats.perAntenna.list[i].noiseFloor = stats.perAntenna.list[j].noiseFloor;
+                    stats.perAntenna.list[j].antenna = 0;
+                    stats.perAntenna.list[j].rfOnTime = 0;
+                    stats.perAntenna.list[j].noiseFloor = 0;
+
+                    stats.perAntenna.len++;
+                    break;
+                  }
+                }
+              }
+              else
+              {
+                /* Increment the length */
+                stats.perAntenna.len++;
+              }
+            }
+
+            /* store the requested flags for future use */
+            stats.valid = reader->statsFlag;
+
+            /* notify status response to listener */
+            notify_stats_listeners(reader, &stats);
+          }
+          else
+          {
+            /**
+             * Control comes here when, user added both the listeners,
+             * We should pop up error for that
+             **/
+            TMR_Status ret;
+            ret = TMR_ERROR_UNSUPPORTED;
+            notify_exception_listeners(reader, ret);
+          }
+        }
+#ifdef TMR_ENABLE_LLRP_READER
+        else
+        {
+          /**
+           * TODO: Handle RFSurveyReports in case of
+           * async read
+           **/
+        }
+#endif
+      }
+
+      /* Free the memory */
+      if (TMR_READER_TYPE_SERIAL == reader->readerType)
+      {
+      	free(tagRead->tagEntry.sMsg);
+      }
+#ifdef TMR_ENABLE_LLRP_READER
+      else
+      {
+      	TMR_LLRP_freeMessage(tagRead->tagEntry.lMsg);
+      }
+#endif
+      free(tagRead);
+
+      /* Now, increment the queue_slots as we have removed one entry */
+      sem_post(&reader->queue_slots);
+    }
+  }
+  return NULL;
+}
+
+
+static void
+process_async_response(TMR_Reader *reader)
+{
+  TMR_Queue_tagReads *tagRead;
+  uint16_t flags = 0;
+
+  /* Decrement Queue slots */
+  sem_wait(&reader->queue_slots);
+
+  tagRead = (TMR_Queue_tagReads *) malloc(sizeof(TMR_Queue_tagReads));
+  if (TMR_READER_TYPE_SERIAL == reader->readerType)
+  {
+    tagRead->tagEntry.sMsg = (uint8_t *) malloc(TMR_SR_MAX_PACKET_SIZE); /* size of bufResponse */
+    memcpy(tagRead->tagEntry.sMsg, reader->u.serialReader.bufResponse, TMR_SR_MAX_PACKET_SIZE);
+    tagRead->bufPointer = reader->u.serialReader.bufPointer;
+  }
+#ifdef TMR_ENABLE_LLRP_READER
+  else
+  {
+    tagRead->tagEntry.lMsg = reader->u.llrpReader.bufResponse[0];
+    reader->u.llrpReader.bufResponse[0] = NULL;
+  }
+#endif
+
+  tagRead->isStatusResponse = reader->isStatusResponse;
+  /**
+   * Process the tag results here. The stats responses will be extracted
+   * later by the parser thread.
+   */
+  if (TMR_READER_TYPE_SERIAL == reader->readerType)
+  {
+    if (false == tagRead->isStatusResponse)
+    {
+      TMR_TRD_init(&tagRead->trd);
+      flags = GETU16AT(tagRead->tagEntry.sMsg, 8);
+      TMR_SR_parseMetadataFromMessage(reader, &tagRead->trd, flags, &tagRead->bufPointer, tagRead->tagEntry.sMsg);
+      TMR_SR_postprocessReaderSpecificMetadata(&tagRead->trd, &reader->u.serialReader);
+      tagRead->trd.reader = reader;
+    }
+  }
+
+  /* Enqueue the tagRead into Queue */
+  enqueue(reader, tagRead);
+  /* Increment queue_length */
+  sem_post(&reader->queue_length);
+
+  if ((false == reader->isStatusResponse) && (TMR_READER_TYPE_SERIAL == reader->readerType))
+  {
+    reader->u.serialReader.tagsRemainingInBuffer--;
+  }
+}
+
+static void *
+do_background_reads(void *arg)
+{
+  TMR_Status ret;
+  TMR_Reader *reader;
+  uint32_t onTime, offTime;
+  int32_t sleepTime;
+  uint64_t end, now, difftime;
+
+  reader = arg;
+  reader->trueAsyncflag = false;
+
+  TMR_paramGet(reader, TMR_PARAM_READ_ASYNCOFFTIME, &offTime);
+
+  while (1)
+  {
+    /* Wait for reads to be enabled */
+    pthread_mutex_lock(&reader->backgroundLock);
+    reader->backgroundRunning = false;
+
+    pthread_cond_broadcast(&reader->backgroundCond);
+    while (false == reader->backgroundEnabled)
+    {
+      reader->trueAsyncflag = false;
+      pthread_cond_wait(&reader->backgroundCond, &reader->backgroundLock);
+      if (true == reader->backgroundThreadCancel)
+      {
+        /**
+         * thread is no more, required,
+         * hence, making it terminated
+         **/ 
+        goto EXIT;
+      }
+    }
+
+    TMR_paramGet(reader, TMR_PARAM_READ_ASYNCONTIME, &onTime);
+
+    if (!reader->trueAsyncflag)
+    {
+      ret = TMR_read(reader, onTime, NULL);
+      if (TMR_SUCCESS != ret)
+      {
+        if ((TMR_ERROR_TIMEOUT == ret) || (TMR_ERROR_CRC_ERROR == ret) ||
+              (TMR_ERROR_SYSTEM_UNKNOWN_ERROR == ret) || (TMR_ERROR_TM_ASSERT_FAILED == ret))
+        {
+          if (TMR_READER_TYPE_SERIAL == reader->readerType)
+          {
+            reader->u.serialReader.transport.flush(&reader->u.serialReader.transport);
+          }
+          reader->backgroundEnabled = false;
+        }
+
+        /**
+         * M5e and its variants hardware does not have a real PA protection.So, doing the read with out
+         * antenna may cause the damage to the reader.
+         *
+         * it's okay to let M6e and its variants continue to operate because it has a PA protection mechanism.
+         **/
+        if (((TMR_ERROR_HIGH_RETURN_LOSS == ret) || (TMR_ERROR_NO_ANTENNA == ret))
+            &&
+            ((TMR_SR_MODEL_M6E != reader->u.serialReader.versionInfo.hardware[0]) &&
+             (TMR_SR_MODEL_MICRO != reader->u.serialReader.versionInfo.hardware[0]) &&
+             (TMR_SR_MODEL_M6E_NANO != reader->u.serialReader.versionInfo.hardware[0]) &&
+             (TMR_SR_MODEL_M6E_I != reader->u.serialReader.versionInfo.hardware[0])))
+        {
+          reader->backgroundEnabled = false;
+          reader->readState = TMR_READ_STATE_DONE;
+          pthread_mutex_unlock(&reader->backgroundLock);
+          notify_exception_listeners(reader, ret);
+          break;
+        }
+
+        notify_exception_listeners(reader, ret);
+        if(false == reader->searchStatus)
+        {
+          /**
+           * There could be something wrong in initiating a search, continue the
+           * effort to initiate a search. But meanwhile if stopReading()
+           * is called, it will be blocked as the search itself is not started.
+           * sem_post on read_started will unblock it.
+           **/
+          reader->readState = TMR_READ_STATE_STARTED;
+          pthread_cond_broadcast(&reader->readCond);
+          reader->backgroundEnabled = false;
+        }
+        pthread_mutex_unlock(&reader->backgroundLock);
+        continue;
+      }
+      if(reader->continuousReading)
+      {
+        /**
+         * Set this flag, In case of true async reading
+         * we have to send the command only once.
+         */
+        reader->trueAsyncflag = true;
+      }
+
+      /**
+       * Set an indication that the reading is started
+       **/
+      reader->readState = TMR_READ_STATE_ACTIVE;
+      pthread_cond_broadcast(&reader->readCond);
+    }
+
+    reader->backgroundRunning = true;
+    pthread_mutex_unlock(&reader->backgroundLock);
+
+    if (true == reader->continuousReading)
+    {
+      /**  
+       * Streaming is enabled only in case of M6e, 
+       * read till the end of stream.
+       */
+      /* Make the time stamp zero for serial reader */
+      while (true)
+      {
+        if (TMR_READER_TYPE_SERIAL == reader->readerType)
+        {
+          if (false == reader->u.serialReader.isBasetimeUpdated)
+          {
+            /* Update the base time stamp */
+            TMR_SR_updateBaseTimeStamp(reader);
+            reader->u.serialReader.isBasetimeUpdated = true;
+          }
+        }
+        ret = TMR_hasMoreTags(reader);
+        if (TMR_SUCCESS == ret)
+        {
+          /* Got a valid message, before posting it to queue
+           * check whether we have slots free in the queue or
+           * not. Validate this only for Serial reader.
+           */
+          if (TMR_READER_TYPE_SERIAL == reader->readerType)
+          {
+            int slotsFree = 0;
+            int semret;
+            /* Get the semaphore value */
+            semret = sem_getvalue(&reader->queue_slots, &slotsFree);
+            if (0 == semret)
+            {
+              if (10 > slotsFree)
+              {
+                tmr_sleep(20);
+              }
+              if (0 >= slotsFree)
+              {
+                /* In a normal case we should not come here.
+                 * we are here means there is no place to
+                 * store the tags. May be the read listener
+                 * is not fast enough.
+                 * In this case stop the read and exit.
+                 */
+                if (true == reader->searchStatus)
+                {
+                  isBufferOverFlow = true;
+                  ret = TMR_ERROR_BUFFER_OVERFLOW;
+                  notify_exception_listeners(reader, ret);
+                  ret = verifySearchStatus(reader);
+                  /*isBufferOverFlow = false;
+                  pthread_mutex_lock(&reader->backgroundLock);
+                  reader->backgroundEnabled = false;
+                  reader->readState = TMR_READ_STATE_DONE;
+                  pthread_cond_broadcast(&reader->readCond);
+                  pthread_mutex_unlock(&reader->backgroundLock);
+                  reader->searchStatus = false;*/
+				  /* Waiting till all slots are free */
+				  while(slotsFree < TMR_MAX_QUEUE_SLOTS)
+				  {
+					  tmr_sleep(20);
+					  semret = sem_getvalue(&reader->queue_slots, &slotsFree);
+				  }
+				  reader->trueAsyncflag = false;
+                  break;
+                }
+              }
+            }
+          }
+
+          /* There is place to store the response. Post it */
+          process_async_response(reader);
+        }
+        else if (TMR_ERROR_CRC_ERROR == ret)
+        {
+          /* Currently, just drop the corrupted packet,
+           * inform the user about the error and move on.
+           *
+           * TODO: Fix the error by tracing the exact reason of failour
+           */
+          notify_exception_listeners(reader, ret);
+        }
+        else if (TMR_ERROR_TAG_ID_BUFFER_FULL == ret)
+        {
+          /* In case of buffer full error, notify the exception */
+          notify_exception_listeners(reader, ret);
+
+          /**
+           * If stop read is already called, no need to resumbit the seach again.
+           * Just spin in the curent loop and wait for the stop read command response.
+           **/ 
+          if (true == reader->searchStatus)
+          {
+            /**
+             * Stop read is not called. Resubmit the search immediately, without user interaction
+             * Resetting the trueAsyncFlag will send the continuous read command again.
+             */
+
+            ret = TMR_hasMoreTags(reader);
+            reader->trueAsyncflag = false;
+			reader->hasContinuousReadStarted = false;
+            break;
+          }
+        }
+        else
+        {
+          if ((TMR_ERROR_TIMEOUT == ret) || (TMR_ERROR_SYSTEM_UNKNOWN_ERROR == ret) || 
+            (TMR_ERROR_TM_ASSERT_FAILED == ret) || (TMR_ERROR_LLRP_READER_CONNECTION_LOST == ret))
+          {
+            notify_exception_listeners(reader, ret);
+            /** 
+             * In case of timeout error or CRC error, flush the transport buffer.
+             * this avoids receiving of junk response.
+             */
+            if (TMR_READER_TYPE_SERIAL == reader->readerType)
+            {
+              /* Handling this fix for serial reader now */
+		          reader->u.serialReader.transport.flush(&reader->u.serialReader.transport);
+            }
+
+            /**
+             * Check if reading is finished.
+             * If not, send stop command.
+             **/
+            if (!reader->finishedReading)
+            {
+              reader->cmdStopReading(reader);
+            }
+
+            pthread_mutex_lock(&reader->backgroundLock);
+            reader->backgroundEnabled = false;
+            reader->readState = TMR_READ_STATE_DONE;
+            pthread_cond_broadcast(&reader->readCond);
+            pthread_mutex_unlock(&reader->backgroundLock);
+
+
+            /**
+             * Forced stop 
+             * Reset continuous reading settings, so that
+             * the subsequent startReading() call doesn't have
+             * any surprises.
+             **/
+            reader->searchStatus = false;
+            reset_continuous_reading(reader, true);
+          }
+          else if (TMR_ERROR_END_OF_READING == ret)
+          {
+            while(0 < reader->queue_depth)
+            {
+              /**
+               * reader->queue_depth is greater than zero. i.e.,
+               * there are still some tags left in queue.
+               * Give some time for the parser to parse all of them.
+               * 5 ms sleep shouldn't cause much delay.
+               **/
+              tmr_sleep(5);
+            }
+
+            /**
+             * Since the reading is finished, disable this
+             * thread.
+             **/
+            pthread_mutex_lock(&reader->backgroundLock);
+            reader->backgroundEnabled = false;
+            reader->readState = TMR_READ_STATE_DONE;
+            pthread_cond_broadcast(&reader->readCond);
+            pthread_mutex_unlock(&reader->backgroundLock);
+            break;
+          }
+          else if ((TMR_ERROR_NO_TAGS_FOUND != ret) && (TMR_ERROR_NO_TAGS != ret) && (TMR_ERROR_TAG_ID_BUFFER_AUTH_REQUEST != ret) && (TMR_ERROR_TOO_BIG != ret))
+          {
+            /* Any exception other than 0x400 should be notified */
+            notify_exception_listeners(reader, ret);
+          }
+          break;
+        }
+      }
+    }
+    else
+    {
+      /** 
+       * On M5e and its variants, streaming is not supported
+       * So still, retain the pseudo-async mechanism
+       * Also, when asyncOffTime is non-zero the API should fallback to 
+       * pseudo async mode.
+       */
+
+      end = tmr_gettime();
+
+      while (TMR_SUCCESS == TMR_hasMoreTags(reader))
+      {
+        TMR_TagReadData trd;
+        TMR_ReadListenerBlock *rlb;
+
+        TMR_TRD_init(&trd);
+
+        ret = TMR_getNextTag(reader, &trd);
+        if (TMR_SUCCESS != ret)
+        {
+          pthread_mutex_lock(&reader->backgroundLock);
+          reader->backgroundEnabled = false;
+          pthread_mutex_unlock(&reader->backgroundLock);
+          notify_exception_listeners(reader, ret);
+          break;
+        }
+
+        pthread_mutex_lock(&reader->listenerLock);
+        rlb = reader->readListeners;
+        while (rlb)
+        { 
+          rlb->listener(reader, &trd, rlb->cookie);
+          rlb = rlb->next;
+        }
+        pthread_mutex_unlock(&reader->listenerLock);
+      }
+
+      /* Wait for the asyncOffTime duration to pass */
+      now = tmr_gettime();
+      difftime = now - end;
+
+      sleepTime = offTime - (uint32_t)difftime;
+      if(sleepTime > 0)
+      {
+        tmr_sleep(sleepTime);
+      }
+    }
+EXIT:
+    if (reader->backgroundThreadCancel)
+    {
+      /**
+       * oops.. time to exit
+       **/ 
+      pthread_exit(NULL);
+    }
+  }
+  return NULL;
+}
+#endif /* TMR_ENABLE_BACKGROUND_READS */
+
+TMR_Status
+TMR_addReadListener(TMR_Reader *reader, TMR_ReadListenerBlock *b)
+{
+#ifndef SINGLE_THREAD_ASYNC_READ
+  if (0 != pthread_mutex_lock(&reader->listenerLock))
+    return TMR_ERROR_TRYAGAIN;
+#endif
+  b->next = reader->readListeners;
+  reader->readListeners = b;
+#ifndef SINGLE_THREAD_ASYNC_READ
+  pthread_mutex_unlock(&reader->listenerLock);
+#endif
+  return TMR_SUCCESS;
+}
+#ifdef TMR_ENABLE_BACKGROUND_READS
+
+TMR_Status
+TMR_removeReadListener(TMR_Reader *reader, TMR_ReadListenerBlock *b)
+{
+  TMR_ReadListenerBlock *block, **prev;
+
+  if (0 != pthread_mutex_lock(&reader->listenerLock))
+    return TMR_ERROR_TRYAGAIN;
+
+  prev = &reader->readListeners;
+  block = reader->readListeners;
+  while (NULL != block)
+  {
+    if (block == b)
+    {
+      *prev = block->next;
+      break;
+    }
+    prev = &block->next;
+    block = block->next;
+  }
+
+  pthread_mutex_unlock(&reader->listenerLock);
+
+  if (block == NULL)
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_addAuthReqListener(TMR_Reader *reader, TMR_AuthReqListenerBlock *b)
+{
+
+  if (0 != pthread_mutex_lock(&reader->listenerLock))
+    return TMR_ERROR_TRYAGAIN;
+
+  b->next = reader->authReqListeners;
+  reader->authReqListeners = b;
+
+  pthread_mutex_unlock(&reader->listenerLock);
+
+  return TMR_SUCCESS;
+}
+
+
+TMR_Status
+TMR_removeAuthReqListener(TMR_Reader *reader, TMR_AuthReqListenerBlock *b)
+{
+  TMR_AuthReqListenerBlock *block, **prev;
+
+  if (0 != pthread_mutex_lock(&reader->listenerLock))
+    return TMR_ERROR_TRYAGAIN;
+
+  prev = &reader->authReqListeners;
+  block = reader->authReqListeners;
+  while (NULL != block)
+  {
+    if (block == b)
+    {
+      *prev = block->next;
+      break;
+    }
+    prev = &block->next;
+    block = block->next;
+  }
+
+  pthread_mutex_unlock(&reader->listenerLock);
+
+  if (block == NULL)
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_addStatusListener(TMR_Reader *reader, TMR_StatusListenerBlock *b)
+{
+
+  if (0 != pthread_mutex_lock(&reader->listenerLock))
+    return TMR_ERROR_TRYAGAIN;
+
+  b->next = reader->statusListeners;
+  reader->statusListeners = b;
+
+  /*reader->streamStats |= b->statusFlags & TMR_SR_STATUS_CONTENT_FLAGS_ALL;*/
+
+  pthread_mutex_unlock(&reader->listenerLock);
+
+  return TMR_SUCCESS;
+}
+#endif /* TMR_ENABLE_BACKGROUND_READS */
+
+TMR_Status
+TMR_addStatsListener(TMR_Reader *reader, TMR_StatsListenerBlock *b)
+{
+#ifndef SINGLE_THREAD_ASYNC_READ
+  if (0 != pthread_mutex_lock(&reader->listenerLock))
+    return TMR_ERROR_TRYAGAIN;
+#endif
+  b->next = reader->statsListeners;
+  reader->statsListeners = b;
+
+  /*reader->streamStats |= b->statusFlags & TMR_SR_STATUS_CONTENT_FLAGS_ALL; */
+#ifndef SINGLE_THREAD_ASYNC_READ
+  pthread_mutex_unlock(&reader->listenerLock);
+#endif
+  return TMR_SUCCESS;
+}
+#ifdef TMR_ENABLE_BACKGROUND_READS
+
+TMR_Status
+TMR_removeStatsListener(TMR_Reader *reader, TMR_StatsListenerBlock *b)
+{
+  TMR_StatsListenerBlock *block, **prev;
+
+  if (0 != pthread_mutex_lock(&reader->listenerLock))
+    return TMR_ERROR_TRYAGAIN;
+
+  prev = &reader->statsListeners;
+  block = reader->statsListeners;
+  while (NULL != block)
+  {
+    if (block == b)
+    {
+      *prev = block->next;
+      break;
+    }
+    prev = &block->next;
+    block = block->next;
+  }
+
+  /* Remove the status flags requested by this listener and reframe */
+  /*reader->streamStats = TMR_SR_STATUS_CONTENT_FLAG_NONE;
+  {
+    TMR_StatusListenerBlock *current;
+    current = reader->statusListeners;
+    while (NULL != current)
+    {
+      reader->streamStats |= current->statusFlags;
+      current = current->next;
+    }    
+  }*/
+  
+  pthread_mutex_unlock(&reader->listenerLock);
+
+  if (block == NULL)
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  return TMR_SUCCESS;
+}
+
+TMR_Status
+TMR_removeStatusListener(TMR_Reader *reader, TMR_StatusListenerBlock *b)
+{
+  TMR_StatusListenerBlock *block, **prev;
+
+  if (0 != pthread_mutex_lock(&reader->listenerLock))
+    return TMR_ERROR_TRYAGAIN;
+
+  prev = &reader->statusListeners;
+  block = reader->statusListeners;
+  while (NULL != block)
+  {
+    if (block == b)
+    {
+      *prev = block->next;
+      break;
+    }
+    prev = &block->next;
+    block = block->next;
+  }
+
+  /* Remove the status flags requested by this listener and reframe */
+  /*reader->streamStats = TMR_SR_STATUS_CONTENT_FLAG_NONE;
+    {
+    TMR_StatusListenerBlock *current;
+    current = reader->statusListeners;
+    while (NULL != current)
+    {
+    reader->streamStats |= current->statusFlags;
+    current = current->next;
+    }
+    }*/
+
+  pthread_mutex_unlock(&reader->listenerLock);
+
+  if (block == NULL)
+  {
+    return TMR_ERROR_INVALID;
+  }
+
+  return TMR_SUCCESS;
+}
+
+void cleanup_background_threads(TMR_Reader *reader)
+{
+  if (NULL != reader)
+  {
+    pthread_mutex_lock(&reader->backgroundLock);
+    pthread_mutex_lock(&reader->listenerLock);
+    reader->readExceptionListeners = NULL;
+    reader->statsListeners = NULL;
+    if (true == reader->backgroundSetup)
+    {
+      /**
+       * Signal for the thread exit by 
+       * removing all the pthread lock dependency
+       **/
+      reader->backgroundThreadCancel = true;
+      pthread_cond_broadcast(&reader->backgroundCond);
+    }
+    pthread_mutex_unlock(&reader->listenerLock);
+    pthread_mutex_unlock(&reader->backgroundLock);
+
+    if (true == reader->backgroundSetup)
+    {
+      /**
+       * Wait for the back ground thread to exit
+       **/ 
+      pthread_join(reader->backgroundReader, NULL);
+    }
+
+    pthread_mutex_lock(&reader->parserLock);
+    pthread_mutex_lock(&reader->listenerLock);
+    reader->readListeners = NULL;
+    if (true == reader->parserSetup)
+    {
+      pthread_cancel(reader->backgroundParser);
+    }
+    pthread_mutex_unlock(&reader->listenerLock);
+    pthread_mutex_unlock(&reader->parserLock);
+  }
+}
+
+void*
+do_background_receiveAutonomousReading(void * arg)
+{
+  TMR_Status ret;
+  TMR_TagReadData trd;
+  TMR_Reader *reader;
+  TMR_Reader_StatsValues stats;  
+
+  reader = arg;
+  TMR_TRD_init(&trd);
+
+  while (1)
+  {
+    ret = TMR_SR_receiveAutonomousReading(reader, &trd, &stats);
+    if (TMR_SUCCESS == ret)
+    {
+      if (false == reader->isStatusResponse)
+      {
+        /* Notify the read listener */
+        notify_read_listeners(reader, &trd);
+      }
+      else
+      {
+        notify_stats_listeners(reader, &stats);
+      }
+    }
+  }
+  return NULL;
+}
+#endif /* TMR_ENABLE_BACKGROUND_READS */
+
diff --git a/cbits/api/tmr_filter.h b/cbits/api/tmr_filter.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_filter.h
@@ -0,0 +1,102 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TMR_FILTER_H
+#define _TMR_FILTER_H
+/**
+ *  @file tmr_filter.h
+ *  @brief Mercury API - Tag Filter 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.
+ */
+
+#include "tmr_tag_data.h"
+#include "tmr_gen2.h"
+#include "tmr_iso180006b.h"
+
+/**
+ * @defgroup filter Tag filters
+ *
+ * Tag filters cause the reader to limit an inventory to a subset of
+ * tags (in a TMR_ReadPlan) or a tag operation to an individual tag
+ * (as a parameter to a tag operation function).
+ */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/** Type of a TMR_TagFilter structure */
+typedef enum TMR_FilterType
+{
+  /** Tag data filter - non-protocol-specific */
+  TMR_FILTER_TYPE_TAG_DATA          = 0,
+  /** Gen2 Select filter */
+  TMR_FILTER_TYPE_GEN2_SELECT       = 1, 
+  /** ISO180006B Select filter */
+  TMR_FILTER_TYPE_ISO180006B_SELECT = 2
+} TMR_FilterType;
+
+/**
+ * Structure representing a filter or subset of avaliable tags.
+ * @ingroup filter
+ */
+typedef struct TMR_TagFilter
+{
+  TMR_FilterType type;
+  union
+  {
+    /** A particular tag EPC */
+    TMR_TagData     tagData;
+    /** A Gen2 select operation */
+    TMR_GEN2_Select gen2Select;
+    /** An ISO180006B select operation */
+    TMR_ISO180006B_Select iso180006bSelect;
+  } u;
+} TMR_TagFilter;
+
+/**
+ * Test if a tag matches this filter. Only applies to selects based
+ * on the EPC.
+ * 
+ * @param filter The filter to test with.
+ * @param tag The tag to test.
+ * @return true if the tag matches the filter.
+ */
+bool TMR_TF_match(TMR_TagFilter *filter, TMR_TagData *tag);
+
+TMR_Status TMR_TF_init_tag(TMR_TagFilter *filter, TMR_TagData *tag);
+
+TMR_Status TMR_TF_init_gen2_select(TMR_TagFilter *filter, bool invert,
+                                   TMR_GEN2_Bank bank, uint32_t bitPointer,
+                                   uint16_t maskBitLength, uint8_t *mask);
+
+TMR_Status TMR_TF_init_ISO180006B_select(TMR_TagFilter *filter, bool invert,
+                                         TMR_ISO180006B_SelectOp op,
+                                         uint8_t address, uint8_t mask,
+                                         uint8_t wordData[8]);
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* _TMR_FILTER_H_ */
diff --git a/cbits/api/tmr_gen2.h b/cbits/api/tmr_gen2.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_gen2.h
@@ -0,0 +1,537 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TMR_GEN2_H
+#define _TMR_GEN2_H
+/** 
+ *  @file tmr_gen2.h  
+ *  @brief Mercury API - Gen2 tag information and interfaces
+ *  @author Brian Fiegel
+ *  @date 5/7/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.
+ */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/** Memory lock bits */
+typedef enum TMR_GEN2_LockBits
+{
+  /** User memory bank lock permalock bit */
+  TMR_GEN2_LOCK_BITS_USER_PERM    = (1 << 0),
+  /** User memory bank lock bit */
+  TMR_GEN2_LOCK_BITS_USER         = (1 << 1),
+  /** TID memory bank lock permalock bit */
+  TMR_GEN2_LOCK_BITS_TID_PERM     = (1 << 2),
+  /** TID memory bank lock bit */
+  TMR_GEN2_LOCK_BITS_TID          = (1 << 3),
+  /** EPC memory bank lock permalock bit */
+  TMR_GEN2_LOCK_BITS_EPC_PERM     = (1 << 4),
+  /** EPC memory bank lock bit */
+  TMR_GEN2_LOCK_BITS_EPC          = (1 << 5),
+  /** Access password lock permalock bit */
+  TMR_GEN2_LOCK_BITS_ACCESS_PERM  = (1 << 6),
+  /** Access password lock bit */
+  TMR_GEN2_LOCK_BITS_ACCESS       = (1 << 7),
+  /** Kill password lock permalock bit */
+  TMR_GEN2_LOCK_BITS_KILL_PERM    = (1 << 8),
+  /** Kill password lock bit */
+  TMR_GEN2_LOCK_BITS_KILL         = (1 << 9)
+} TMR_GEN2_LockBits;
+
+/**
+ * The arguments to a TMR_lockTag() method for Gen2 tags. 
+ */
+typedef struct TMR_GEN2_LockAction
+{
+  /** The gen2 lock mask bits */
+  uint16_t mask;
+  /** The gen2 lock action bits */
+  uint16_t action;
+}TMR_GEN2_LockAction;
+
+/**
+ * @ingroup tagauth
+ * A 32-bit password (access or kill) in the Gen2 protocol.
+ */
+typedef uint32_t TMR_GEN2_Password;
+
+/**
+ * @ingroup tagauth
+ * a 16 byte(128 bit) Gen2 Denatran IAV write credentials
+ */
+typedef struct TMR_GEN2_DENATRAN_IAV_WriteCredentials
+{
+  uint8_t value[16];
+  uint8_t tagId[8];
+  uint8_t credentialLength;
+  uint8_t tagIdLength;
+}TMR_GEN2_DENATRAN_IAV_WriteCredentials;
+
+/**
+ * @ingroup tagauth
+ * a 16 byte(128 bit) Gen2 Denatran IAV write sec credentials
+ */
+typedef struct TMR_GEN2_DENATRAN_IAV_WriteSecCredentials
+{
+  uint8_t value[16];
+  uint8_t data[6];
+  uint8_t credentialLength;
+  uint8_t dataLength;
+}TMR_GEN2_DENATRAN_IAV_WriteSecCredentials;
+
+/** Gen2 memory banks */
+typedef enum TMR_GEN2_Bank
+{
+  /** Reserved bank (kill and access passwords) */
+  TMR_GEN2_BANK_RESERVED  = 0x0,
+  /** EPC memory bank */
+  TMR_GEN2_BANK_EPC       = 0x1,
+  /** TID memory bank */
+  TMR_GEN2_BANK_TID       = 0x2,
+  /** User memory bank */
+  TMR_GEN2_BANK_USER      = 0x3,
+  /** Used to enable the read of additional membanks - reserved mem bank */
+  TMR_GEN2_BANK_RESERVED_ENABLED = 0x4,
+  /** Used to Filter Gen2 Tag with specified EPC length */
+  TMR_GEN2_EPC_LENGTH_FILTER = 0x6,
+  /** Gen2 Truncate Option */
+  TMR_GEN2_EPC_TRUNCATE = 0x7,
+  /** Used to enable the read of additional membanks - epc mem bank */
+  TMR_GEN2_BANK_EPC_ENABLED = 0x8,
+  /** Used to enable the read of additional membanks - tid mem bank */
+  TMR_GEN2_BANK_TID_ENABLED = 0x10,
+  /** Used to enable the read of additional membanks - user mem bank */
+  TMR_GEN2_BANK_USER_ENABLED = 0x20
+} TMR_GEN2_Bank;
+
+/**
+ * A single selection operation in the Gen2 protocol.
+ * @ingroup filter
+ */
+typedef struct TMR_GEN2_Select
+{
+  /** Whether to invert the selection (deselect tags that meet the comparison) */
+  bool invert;
+  /** The memory bank in which to compare the mask */
+  TMR_GEN2_Bank bank;
+  /** The location (in bits) at which to begin comparing the mask */
+  uint32_t bitPointer;
+  /** The length (in bits) of the mask */
+  uint16_t maskBitLength;
+  /** The mask value to compare with the specified region of tag memory, MSB first */ 
+  uint8_t *mask;
+} TMR_GEN2_Select;
+
+/** Gen2 session values */
+typedef enum TMR_GEN2_Session
+{
+  TMR_GEN2_SESSION_MIN= 0x00,
+  /** Session 0 */
+  TMR_GEN2_SESSION_S0 = 0x00,
+  /** Session 1 */
+  TMR_GEN2_SESSION_S1 = 0x01,
+  /** Session 2 */ 
+  TMR_GEN2_SESSION_S2 = 0x02,
+  /** Session 3 */ 
+  TMR_GEN2_SESSION_S3 = 0x03,
+  TMR_GEN2_SESSION_MAX     = TMR_GEN2_SESSION_S3,
+  TMR_GEN2_SESSION_INVALID = TMR_GEN2_SESSION_MAX + 1
+} TMR_GEN2_Session;
+
+/** Gen2 divide ratio values */
+typedef enum TMR_GEN2_DivideRatio
+{
+  /** DR of 8 */
+  TMR_GEN2_DIVIDE_RATIO_8    = 0,
+  /** DR of 64/3 */
+  TMR_GEN2_DIVIDE_RATIO_64_3 = 1
+} TMR_GEN2_DivideRatio;
+
+/** Gen2 TrExt bit */
+typedef enum TMR_GEN2_TrExt
+{
+  /** No pilot tone in tag response */
+  TMR_GEN2_TR_EXT_NO_PILOT_TONE = 0,
+  /** Pilot tone in tag response */
+  TMR_GEN2_TR_EXT_PILOT_TONE    = 1
+} TMR_GEN2_TrExt;
+
+/** Gen2 target search algorithms */
+typedef enum TMR_GEN2_Target
+{
+  TMR_GEN2_TARGET_MIN= 0,
+  /** Search target A */
+  TMR_GEN2_TARGET_A  = 0,
+  /** Search target B */
+  TMR_GEN2_TARGET_B  = 1,
+  /** Search target A until exhausted, then search target B */
+  TMR_GEN2_TARGET_AB = 2,
+  /** Search target B until exhausted, then search target A */
+  TMR_GEN2_TARGET_BA = 3,
+  TMR_GEN2_TARGET_MAX     = TMR_GEN2_TARGET_BA,
+  TMR_GEN2_TARGET_INVALID = TMR_GEN2_TARGET_MAX+1
+}TMR_GEN2_Target;
+
+/** Gen2 tag encoding modulation values */
+typedef enum TMR_GEN2_TagEncoding
+{
+  /** FM0 **/
+  TMR_GEN2_FM0 = 0,
+
+  TMR_GEN2_MILLER_MIN = 1,
+  /** M = 2 */
+  TMR_GEN2_MILLER_M_2 = 1,
+  /** M = 4 */
+  TMR_GEN2_MILLER_M_4 = 2,
+  /** M = 8 */
+  TMR_GEN2_MILLER_M_8 = 3,
+  TMR_GEN2_MILLER_MAX     = TMR_GEN2_MILLER_M_8,
+  TMR_GEN2_MILLER_INVALID = TMR_GEN2_MILLER_MAX+1
+}TMR_GEN2_TagEncoding;
+
+/** Gen2 link frequencies */
+typedef enum TMR_GEN2_LinkFrequency
+{
+  /** 250 kHz */
+  TMR_GEN2_LINKFREQUENCY_250KHZ  = 250,
+  /** 320 KHZ */
+  TMR_GEN2_LINKFREQUENCY_320KHZ  = 320,
+  /**640 kHz*/
+  TMR_GEN2_LINKFREQUENCY_640KHZ   = 640,
+  TMR_GEN2_LINKFREQUENCY_MAX     = 640,
+  TMR_GEN2_LINKFREQUENCY_INVALID = TMR_GEN2_LINKFREQUENCY_MAX + 1,
+} TMR_GEN2_LinkFrequency;
+
+/** Gen2 Protcol Extension parameters */
+typedef enum TMR_GEN2_ProtocolExtension
+{
+  TMR_GEN2_PROTOCOLEXTENSION_LICENSE_NONE			= 0,
+  TMR_GEN2_PROTOCOLEXTENSION_LICENSE_IAV_DENATRAN	= 1
+}TMR_GEN2_ProtocolExtension;
+
+/** Gen2 bap parameters */
+typedef struct TMR_GEN2_Bap
+{
+  /* Default to 3000 us */
+  int32_t powerUpDelayUs;
+  /* Default to 20000 us */
+  int32_t freqHopOfftimeUs;
+}TMR_GEN2_Bap;
+
+/** Gen2v2 untraceably hides part of EPC memory or not */
+typedef enum TMR_GEN2_UNTRACEABLE_Epc
+{
+	/* Tag exposes EPC memory */
+	EPC_SHOW = 0,
+	/*Tag untraceably hides EPC memory above that*/
+	EPC_HIDE = 1
+}TMR_GEN2_UNTRACEABLE_Epc;
+
+/** Gen2v2 untraceably hides part of TID memory or not */
+typedef enum TMR_GEN2_UNTRACEABLE_Tid
+{
+	/* Tag exposes TID memory. */
+	HIDE_NONE = 0,
+	/*Tag untraceably hides all of TID memory.*/
+	HIDE_ALL = 1,
+	/* Tags allocation class identifier is E0h then the 
+	Tag untraceably hides TID memory above 10h,inclusive;
+	if the Tags allocation class identifier is E2h then the
+	Tag untraceably hides TID memory above 20h, inclusive. */
+	HIDE_SOME = 2,
+	/* RFU */
+	TID_RFU = 3
+}TMR_GEN2_UNTRACEABLE_Tid;
+
+/** Gen2v2 untraceably hides part of UserMemory memory or not */
+typedef enum TMR_GEN2_UNTRACEABLE_UserMemory
+{
+	/* Tag exposes User memory */
+	SHOW = 0,
+	/*Tag untraceably hides User memory*/
+	HIDE = 1
+}TMR_GEN2_UNTRACEABLE_UserMemory;
+
+/** specifies Gen2v2 Tags operating range */
+typedef enum TMR_GEN2_UNTRACEABLE_Range
+{
+	/* Tag persistently enables normal operating range */
+	NORMAL = 0,
+	/*Tag persistently enables reduced operating range.*/
+	REDUCED = 1,
+	/* Tag temporarily toggles its operating range*/
+	TOGGLE_TEMPORARLY = 2,
+	/* RFU */
+	RFU = 3
+}TMR_GEN2_UNTRACEABLE_Range;
+
+/** Authentication KeyId */
+typedef enum TMR_NXP_KeyId
+{
+	/* key0*/
+	KEY0 = 0,
+	/*Key1*/
+	KEY1 = 1
+}TMR_NXP_KeyId;
+
+/** Memory profile for the addition of custom data */
+typedef enum TMR_NXP_Profile
+{
+	/* EPC memory bank */
+	EPC = 0,
+	/* TID memory bank */
+	TID = 1,
+	/* User memory bank */
+	USER = 2
+}TMR_NXP_Profile;
+
+/** Gen2 Tari values */
+typedef enum TMR_GEN2_Tari
+{
+  /** Tari of 25 microseconds */
+  TMR_GEN2_TARI_25US    = 0,
+  /** Tari of 12.5 microseconds */
+  TMR_GEN2_TARI_12_5US  = 1,
+  /** Tari of 6.25 microseconds */
+  TMR_GEN2_TARI_6_25US  = 2,
+  TMR_GEN2_TARI_MAX     = 2,
+  TMR_GEN2_TARI_INVALID = TMR_GEN2_TARI_MAX + 1,
+} TMR_GEN2_Tari;
+
+/** Gen2 WriteMode */
+typedef enum TMR_GEN2_WriteMode
+{
+  /** WORD ONLY */
+  TMR_GEN2_WORD_ONLY    = 0,
+  /** BLOCK ONLY */
+  TMR_GEN2_BLOCK_ONLY    = 1,
+  /** BLOCK FALLBACK */
+  TMR_GEN2_BLOCK_FALLBACK    = 2,
+
+} TMR_GEN2_WriteMode;
+
+/**
+ * Defines the values for different gen2 silicon types.
+ */
+typedef enum TMR_SR_GEN2_SiliconType
+{
+  TMR_SR_GEN2_SILICON_ANY             = 0x00,
+  TMR_SR_GEN2_ALIEN_HIGGS_SILICON     = 0x01,
+  TMR_SR_GEN2_NXP_G2X_SILICON         = 0x02,
+  TMR_SR_GEN2_ALIEN_HIGGS3_SILICON    = 0x05,
+  TMR_SR_GEN2_NXP_G2I_SILICON         = 0x07,
+  TMR_SR_GEN2_IMPINJ_MONZA4_SILICON   = 0x08,
+  TMR_SR_GEN2_IDS_SL900A_SILICON      = 0x0A,
+  TMR_SR_GEN2_DENATRAN_IAV_SILICON    = 0x0B,
+  TMR_SR_GEN2_NXP_AES_UCODE			  = 0x0C,
+}TMR_SR_GEN2_SiliconType;
+
+/**
+ * The argument to a ChangeConfig command for NXP G2iL tags
+ * User can set the configWord directly using the 16 bit 'data' field.
+ * Otherwise, provides an option to individually set each flag.
+ * Instance of TMR_NXP_ConfigWord must be initialized before using either
+ * by declaring it as 'static' or by using the constructor routine
+ * TMR_init_NXP_ConfigWord() method.
+ */
+typedef union TMR_NXP_ConfigWord
+{
+  uint16_t data;
+  /*
+   * Since the bit-fields are used, The bits in configWord are shown from
+   * Least significant bit to Most significant bit.
+   */
+  struct
+  {
+    /** Least significant bit */
+    /** PSF alarm flag (Permanently stored in tag memory)*/
+    unsigned psfAlarm:1;
+    /** Read protect TID bank (permanently stored in tag memory)*/
+    unsigned readProtectTID:1;
+    /** Read protect EPC bank (Permanently stored in tag memory)*/
+    unsigned readProtectEPC:1;
+     /** Read protect User memory bank (permanently stored in tag memory)*/
+    unsigned readProtectUser:1;
+    /** Read range reduction on/off (permanently stored in tag memory)*/
+    unsigned privacyMode:1;
+    /** Digital output (permanently stored in tag memory)*/
+    unsigned digitalOutput:1;
+    /** Maximum backscatter strength (permanently stored in tag memory)*/
+    unsigned maxBackscatterStrength:1;
+    /** Conditional Read Range Reduction open/short (permanently stored in tag memory)*/
+    unsigned conditionalReadRangeReduction_openShort:1;
+    /** Conditional Read Range Reduction on/off (permanently stored in tag memory)*/
+    unsigned conditionalReadRangeReduction_onOff:1;
+    /** Transparent mode data/raw (reset at power up)*/
+    unsigned dataMode:1;
+     /** Transparent mode on/off (reset at power up)*/
+    unsigned transparentMode:1;
+    /** Invert digital output (reset at power up)*/
+    unsigned invertDigitalOutput:1;
+    /** RFU 3*/
+    unsigned RFU3:1;
+    /** RFU 2*/
+    unsigned RFU2:1;
+    /** External supply flag digital input (read only)*/
+    unsigned externalSupply:1;
+    /** Tamper alarm flag (Read only)*/
+    unsigned tamperAlarm:1;    
+    /** Most significant bit */
+  }bits;
+}TMR_NXP_ConfigWord;
+
+/**
+ * TMR_Monza4_ControlByte is an argument to Monza4 QTReadWrite custom command
+ * User can set the control byte directly using the 8 bit 'data' field.
+ * Otherwise, provides an option to individually set each flag.
+ * Instance of TMR_Monza4_ControlByte must be initialized before using either
+ * by declaring it as 'static' (or initializing it to 0) or by using the constructor routine
+ * TMR_init_Monza4_ControlByte() method.
+ */
+typedef union TMR_Monza4_ControlByte
+{
+  /* 8-bit control byte */
+  uint8_t data;
+  /*
+   * Since bit-fields are used, The bits in control Byte are shown from
+   * Least significant bit to Most significant bit.
+   */
+  struct 
+  {
+    /**
+     * The following bits are Reserved for Future Use. And will be ignored.
+     * RFU_TM's are ThingMagic specific RFU bits, and RFU_Impinj bits are 
+     * as per the Monza4 specification.
+     */
+    unsigned RFU_TM0:1;
+    unsigned RFU_TM1:1;
+    unsigned RFU_TM2:1;
+    unsigned RFU_TM3:1;
+    unsigned RFU_Impinj4:1;
+    unsigned RFU_Impinj5:1;
+    /**
+     * If Read/Write=1, the Persistence field indicates whether the QT control is
+     * written to nonvolatile (NVM) or volatile memory.
+     * Persistence=0 means write to volatile memory. 
+     * Persistence=1 means write to NVM memory
+     */
+    unsigned persistence:1;
+    /**
+     * The Read/Write bit indicates whether the tag reads or writes QT control data.
+     * Read/Write=0 means read the QT control bits in cache.
+     * Read/Write=1 means write the QT control bits
+     */
+    unsigned readWrite:1;    
+  }bits;
+}TMR_Monza4_ControlByte;
+
+/**
+ * TMR_Monza4_Payload is an argument to Monza4 QTReadWrite custom command
+ * User can set the payload directly using the 16 bit 'data' field.
+ * Otherwise, provides an option to individually set each flag.
+ * Instance of TMR_Monza4_Payload must be initialized before using either
+ * by declaring it as 'static' (or initializing it to 0) or by using the constructor routine
+ * TMR_init_Monza4_Payload() method.
+ * This field controls the QT functionality. These bits are ignored when the
+ * Read/Write field equals 0 in control byte.
+ */
+typedef union TMR_Monza4_Payload
+{
+  /** 16-bit payload */
+  uint16_t data;
+  /*
+   * Since bit-fields are used, The bits in payload are shown from
+   * Least significant bit to Most significant bit.
+   */
+  struct
+  {
+    /**
+     * The following bits are Reserved for Future Use. And will be ignored.
+     * Tag will always return these bits as zero.
+     * All these RFU bits are as per the monza4 spec.
+     */
+    unsigned RFU0:1;
+    unsigned RFU1:1;
+    unsigned RFU2:1;
+    unsigned RFU3:1;
+    unsigned RFU4:1;
+    unsigned RFU5:1;
+    unsigned RFU6:1;
+    unsigned RFU7:1;
+    unsigned RFU8:1;
+    unsigned RFU9:1;
+    unsigned RFU10:1;
+    unsigned RFU11:1;
+    unsigned RFU12:1;
+    unsigned RFU13:1;
+    /**
+     *  Bit 14 
+     *  1: Tag uses Public Memory Map 
+     *  0: Tag uses Private Memory Map
+     */
+    unsigned QT_MEM:1;
+    /**
+     *  Bit 15 (MSB) is first transmitted bit of the payload field.
+     *  Bit # Name Description
+     *  1: Tag reduces range if in or about to be in OPEN or SECURED state
+     *  0: Tag does not reduce range
+     */
+    unsigned QT_SR:1;
+  }bits;
+}TMR_Monza4_Payload;
+
+typedef struct TMR_GEN2_HibikiSystemInformation
+{
+  uint16_t infoFlags;     /* Indicates whether the banks are present and Custom Commands are implemented*/ 
+  uint8_t reservedMemory; /* Indicates the size of this memory bank in words*/
+  uint8_t epcMemory;      /* Indicates the size of this memory bank in words*/
+  uint8_t tidMemory;      /* Indicates the size of this memory bank in words*/
+  uint8_t userMemory;     /* Indicates the size of this memory bank in words*/
+  uint8_t setAttenuate;   /**/
+  uint16_t bankLock;      /* Indicates Lock state for this type of lock*/
+  uint16_t blockReadLock; /* Indicates Lock state for this type of lock*/
+  uint16_t blockRwLock;   /* Indicates Lock state for this type of lock*/
+  uint16_t blockWriteLock;/* Indicates Lock state for this type of lock*/
+} TMR_GEN2_HibikiSystemInformation;
+
+/** Size allocated for storing PC data in TMR_GEN2_TagData */
+#define TMR_GEN2_MAX_PC_BYTE_COUNT (6)
+/**
+ * Gen2-specific per-tag data
+ */
+typedef struct TMR_GEN2_TagData
+{ 
+  /** Length of the tag PC */
+  uint8_t pcByteCount;
+  /** Tag PC */
+  uint8_t pc[TMR_GEN2_MAX_PC_BYTE_COUNT];
+} TMR_GEN2_TagData;
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_TMR_GEN2_H*/
diff --git a/cbits/api/tmr_gpio.h b/cbits/api/tmr_gpio.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_gpio.h
@@ -0,0 +1,55 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TMR_GPIO_H
+#define _TMR_GPIO_H
+/**
+ *  @file tmr_gpio.h
+ *  @brief Mercury API - GPIO Definitons
+ *  @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.
+ */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The identity and state of a single GPIO pin.
+ */
+typedef struct TMR_GpioPin
+{
+  /** The ID number of the pin. */
+  uint8_t id;
+  /** Whether the pin is in the high state. */
+  bool high;
+  /** The direction of the pin */
+  bool output;
+}TMR_GpioPin;
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* _TMR_GPIO_H_ */
diff --git a/cbits/api/tmr_ipx.h b/cbits/api/tmr_ipx.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_ipx.h
@@ -0,0 +1,41 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TMR_IPX_H
+#define _TMR_IPX_H
+/**
+ *  @file tmr_ipx.h  
+ *  @brief Mercury API - iPx tag information and interfaces
+ *  @author Nathan Williams
+ *  @date 1/21/2010
+ */
+
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_TMR_IPX_H*/
diff --git a/cbits/api/tmr_iso180006b.h b/cbits/api/tmr_iso180006b.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_iso180006b.h
@@ -0,0 +1,108 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TMR_ISO180006B_H
+#define _TMR_ISO180006B_H
+/**
+ *  @file tmr_iso180006b.h  
+ *  @brief Mercury API - ISO180006B tag information and interfaces
+ *  @author Brian Fiegel
+ *  @date 5/7/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.
+ */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/** ISO180006B Select operations */
+typedef enum TMR_ISO180006B_SelectOp
+{
+  /** Select if tag data matches op data */
+  TMR_ISO180006B_SELECT_OP_EQUALS       = 0,
+  /** Select if tag data does not match op data */
+  TMR_ISO180006B_SELECT_OP_NOT_EQUALS   = 1,
+  /** Select if tag data is less than op data */
+  TMR_ISO180006B_SELECT_OP_LESS_THAN    = 2,
+  /** Select if tag data is greater than op data */
+  TMR_ISO180006B_SELECT_OP_GREATER_THAN = 3
+} TMR_ISO180006B_SelectOp;
+
+/**
+ * A single selection operation in the ISO18000-6B protocol.
+ * @ingroup filter
+ */ 
+typedef struct TMR_ISO180006B_Select
+{
+  /** Whether to invert the selection (deselect tags that meet the comparison). */
+  bool invert;
+  /** The operation to use to compare the tag data to the provided data. */
+  TMR_ISO180006B_SelectOp op;
+  /** The address of the tag memory to compare to the provided data. */
+  uint8_t address;
+  /** Bitmask of which of the eight provided data bytes to compare to the tag memory. */
+  uint8_t mask;
+  /** The data to compare. Exactly eight bytes. */
+  uint8_t data[8];
+} TMR_ISO180006B_Select;
+
+/**
+ * The arguments to a TMR_lockTag() method for ISO18000-6B tags. 
+ * Represents the byte to be locked.
+ */
+typedef struct TMR_ISO180006B_LockAction
+{
+  /** The memory address of the byte to lock */
+  uint8_t address;
+} TMR_IS0180006B_LockAction;
+
+/** ISO180006B link frequencies */
+typedef enum TMR_ISO180006B_LinkFrequency
+{
+  /** 40 kHz */
+  TMR_ISO180006B_LINKFREQUENCY_40KHZ  = 40,
+  /** 160 kHz */
+  TMR_ISO180006B_LINKFREQUENCY_160KHZ = 160,
+} TMR_ISO180006B_LinkFrequency;
+
+/** ISO180006B modulation depth */
+typedef enum TMR_ISO180006B_ModulationDepth
+{
+  /** 99 percent modulation */
+  TMR_ISO180006B_Modulation99percent = 0x00,
+  /** 11 percent modulation */
+  TMR_ISO180006B_Modulation11percent = 0x01
+}TMR_ISO180006B_ModulationDepth;
+
+/** ISO180006B Delimiter */
+typedef enum TMR_ISO180006B_Delimiter
+{
+  /** delimiter 1*/
+  TMR_ISO180006B_Delimiter1 = 0x01,
+  /** delimiter 4 */
+  TMR_ISO180006B_Delimiter4 = 0x04
+}TMR_ISO180006B_Delimiter;
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_TMR_ISO180006B_H*/
diff --git a/cbits/api/tmr_llrp_reader.h b/cbits/api/tmr_llrp_reader.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_llrp_reader.h
@@ -0,0 +1,278 @@
+#ifndef _TMR_LLRP_READER_H
+#define _TMR_LLRP_READER_H
+/**
+ *  @file tmr_llrp_reader.h
+ *  @brief Mercury API - LLRP Reader interface
+ *  @author Somu
+ *  @date 05/23/2011
+ */
+
+/*
+ * Copyright (c) 2011 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.
+ */
+
+#include <pthread.h>
+#include <semaphore.h>
+#include "tmr_region.h"
+#include "tmr_tag_protocol.h"
+#include "tmr_serial_transport.h"
+#include "tmr_params.h"
+#include "ltkc.h"
+#include "tm_ltkc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ 
+#define TM_MANUFACTURER_ID  26554
+#define TMR_LLRP_SYNC_MAX_ROSPECS 256  
+#define TMR_LLRP_MAX_RFMODE_ENTRIES 7
+#define TMR_LLRP_READER_DEFAULT_PORT 5084
+
+/**
+ * This structure is returned from cmdGetRFControl
+ **/
+typedef struct TMR_LLRP_RFControl
+{
+  /* RFMode index */
+  llrp_u16_t index;
+
+  /* Tari */
+  TMR_GEN2_Tari tari;
+
+} TMR_LLRP_RFControl;
+
+/**
+ * Gen2 RF Mode Table structure.
+ * Currently we use only BLF and Encoding from 
+ * RF Mode table. 
+ **/
+typedef struct TMR_LLRP_C1G2RFModeTable
+{
+  /* Gen2 BLF */
+  TMR_GEN2_LinkFrequency blf;
+
+  /* Gen2 Tag encoding */
+  TMR_GEN2_TagEncoding m;
+
+  /* Min Tari Value*/
+  TMR_GEN2_Tari minTari;
+
+  /* Max Tari Value*/
+  TMR_GEN2_Tari maxTari;
+
+} TMR_LLRP_C1G2RFModeTable;
+
+/**
+ * This structure is returned from cmdGetReaderCapabilities.
+ **/
+typedef struct TMR_LLRP_ReaderCapabilities
+{
+  /** Country code */
+  llrp_u16_t countryCode;
+
+  /** Reader model */
+  uint32_t model;
+
+  /** Software version */
+  char softwareVersion[128];
+
+  /** Power level table */
+  TMR_uint16List powerTable;
+  uint16_t powerList[255];
+
+  /** Frequency table */
+  TMR_uint32List freqTable;
+  uint32_t freqList[64];
+
+  union
+  {
+    /** 
+     * Gen2 RF Mode tables
+     * FIXME: Max RFModes available for now is 5.
+     * and the index start from 1-5
+     **/
+    TMR_LLRP_C1G2RFModeTable gen2Modes[TMR_LLRP_MAX_RFMODE_ENTRIES];
+    /**
+     * Can have RF Mode table specific to 
+     * other protocols. 
+     **/
+  } u;
+
+} TMR_LLRP_ReaderCapabilities;
+
+/** 
+ * This struture used to
+ * moniter the protocol
+ * in read plan
+ **/
+typedef struct ROSpecProtocolTable
+{
+  /* rospecid */
+  uint8_t rospecID;
+  /*protocol */
+  TMR_TagProtocol rospecProtocol;
+}ROSpecProtocolTable;
+
+/**
+ * This is the structure used to
+ * store the unhandled async response
+ **/
+typedef struct TMR_LLRP_UnhandledAsyncResponse
+{
+  /** Buffer to hold the LLRP message */
+  LLRP_tSMessage *lMsg;
+}TMR_LLRP_UnhandledAsyncResponse;
+
+/**
+ * LLRP reader structure
+ */
+typedef struct TMR_LLRP_LlrpReader
+{
+  /* @privatesection */
+  LLRP_tSTypeRegistry *       pTypeRegistry;
+  LLRP_tSConnection *         pConn;
+  int                         portNum;
+  llrp_u32_t                  msgId;
+  llrp_u32_t                  roSpecId, accessSpecId;
+  llrp_u16_t                  opSpecId;
+
+  TMR_AntennaMapList *txRxMap;
+  uint32_t transportTimeout;
+  uint32_t commandTimeout;
+  TMR_Region  regionId;
+  TMR_GEN2_Password gen2AccessPassword;
+
+  /* Static storage for the default map */
+  TMR_AntennaMap staticTxRxMapData[TMR_SR_MAX_ANTENNA_PORTS];
+  TMR_AntennaMapList staticTxRxMap;
+
+  uint32_t portMask;
+  /* Bit mask of supported protocol list */
+  uint32_t supportedProtocols;
+
+  TMR_TagProtocol currentProtocol;
+
+  /* Buffer to store additional error message */
+  /* TODO: Change TMR_SR_MAX_PACKET_SIZE to appropriate value */
+  char errMsg[TMR_SR_MAX_PACKET_SIZE];
+
+  /* Large bitmask that stores whether each parameter's presence
+   * is known or not.
+   */
+  uint32_t paramConfirmed[TMR_PARAMWORDS];
+
+  /* Large bitmask that, if the corresponding bit in paramConfirmed is set,
+   * stores whether each parameter is present or not.
+   */
+  uint32_t paramPresent[TMR_PARAMWORDS];
+  
+  /* Number of tags reported by reader */
+  int tagsRemaining;
+
+  /* Array of LLRP_tSMessage pointers holding the tag read responses */
+  LLRP_tSMessage **bufResponse;
+
+  /* bufResponse read index */
+  uint8_t bufPointer;
+  uint8_t bufIndex;
+
+  /* Pointer to buffer holding the tag read data */
+  LLRP_tSTagReportData *pTagReportData;
+
+  int searchTimeoutMs;
+
+  /* Cache LLRP Reader Capabilities */
+  TMR_LLRP_ReaderCapabilities capabilities;
+
+  /**
+   * LLRP Asynchronous receiver to handle
+   * keep alive and events.
+   **/
+  pthread_t llrpReceiver;
+  bool receiverSetup, receiverRunning, receiverEnabled;
+  pthread_cond_t receiverCond;
+  int numOfROSpecEvents;
+  /** The above variables must be protected by this lock */
+  pthread_mutex_t receiverLock;
+
+  /**
+   * For monitoring keepalives:
+   * Used only in case of async reading
+   **/
+  uint64_t ka_start, ka_now;
+  bool get_report, reportReceived;
+  /**
+   * For monitoring protcol type
+   * in case of multiprotocol read
+   **/
+  ROSpecProtocolTable readPlanProtocol[TMR_SR_MAX_PACKET_SIZE];
+
+  /**
+   * For monitoring the unhandeled responses
+   * during the async read
+   **/
+  TMR_LLRP_UnhandledAsyncResponse unhandledAsyncResponse;
+  /** To check the status of async unhandled responses */
+  bool isResponsePending;
+  /** To cancel the receiver thread */
+  bool threadCancel;
+  /* To hold the No.of Keep alives missed count*/
+  uint8_t keepAliveAckMissCnt;
+}TMR_LLRP_LlrpReader;
+
+
+TMR_Status TMR_LLRP_connect(TMR_Reader *reader);
+TMR_Status TMR_LLRP_destroy(TMR_Reader *reader);
+TMR_Status TMR_LLRP_hasMoreTags(TMR_Reader *reader); 
+TMR_Status TMR_LLRP_getNextTag(TMR_Reader *reader, TMR_TagReadData *trd);
+TMR_Status TMR_LLRP_executeTagOp(TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *filter, TMR_uint8List *data);
+TMR_Status TMR_LLRP_gpiGet(struct TMR_Reader *reader,uint8_t *count, TMR_GpioPin state[]);
+TMR_Status TMR_LLRP_gpoSet(struct TMR_Reader *reader,uint8_t count, const TMR_GpioPin state[]);
+TMR_Status TMR_LLRP_readTagMemBytes(struct TMR_Reader *reader, const TMR_TagFilter *filter,
+                                    uint32_t bank, uint32_t addreass,
+                                    uint16_t count,uint8_t data[]);
+TMR_Status TMR_LLRP_readTagMemWords(struct TMR_Reader *reader, const TMR_TagFilter *filter,
+                                    uint32_t bank, uint32_t address,
+                                    uint16_t count, uint16_t *data);
+TMR_Status TMR_LLRP_writeTagMemBytes(struct TMR_Reader *reader, const TMR_TagFilter *filter,
+                                    uint32_t bank, uint32_t addreass,
+                                    uint16_t count,const uint8_t data[]);
+TMR_Status TMR_LLRP_writeTagMemWords(struct TMR_Reader *reader, const TMR_TagFilter *filter,
+                                    uint32_t bank, uint32_t address,
+                                    uint16_t count, const uint16_t *data);
+TMR_Status TMR_LLRP_firmwareLoad( TMR_Reader *reader, void *cookie, TMR_FirmwareDataProvider provider);
+TMR_Status TMR_LLRP_writeTag(TMR_Reader *reader, const TMR_TagFilter *filter, const TMR_TagData *data);
+TMR_Status TMR_LLRP_killTag(struct TMR_Reader *reader, const TMR_TagFilter *filter,
+                             const TMR_TagAuthentication *auth);
+TMR_Status TMR_LLRP_lockTag(struct TMR_Reader *reader,const TMR_TagFilter *filter, TMR_TagLockAction *action);
+TMR_Status TMR_LLRP_reboot(struct TMR_Reader *reader);
+/**
+ * Initialize LLRP reader.
+ */
+TMR_Status TMR_LLRP_LlrpReader_init(TMR_Reader *reader);
+
+TMR_Status TMR_LLRP_read(struct TMR_Reader *reader, uint32_t timeoutMs, int32_t *tagCount);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TMR_LLRP_READER_H */
diff --git a/cbits/api/tmr_param.c b/cbits/api/tmr_param.c
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_param.c
@@ -0,0 +1,152 @@
+/**
+ *  @file tmr_param.c
+ *  @brief Mercury API - parameter string implementation
+ *  @author Nathan Williams
+ *  @date 11/3/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.
+ */
+
+#include <string.h>
+
+#include "tm_reader.h"
+#include "tmr_utils.h"
+
+#ifdef TMR_ENABLE_PARAM_STRINGS
+
+static const char *paramNames[1 + TMR_PARAM_MAX] = {
+  "",  /* TMR_PARAM_NONE */
+  "/reader/baudRate",  /* TMR_PARAM_BAUDRATE */
+  "/reader/probeBaudRates",/* TMR_PARAM_PROBEBAUDRATES */
+  "/reader/commandTimeout",  /* TMR_PARAM_COMMANDTIMEOUT */
+  "/reader/transportTimeout",  /* TMR_PARAM_TRANSPORTTIMEOUT */
+  "/reader/powerMode",  /* TMR_PARAM_POWERMODE */
+  "/reader/userMode",  /* TMR_PARAM_USERMODE */
+  "/reader/antenna/checkPort",  /* TMR_PARAM_ANTENNA_CHECKPORT */
+  "/reader/antenna/portList",  /* TMR_PARAM_ANTENNA_PORTLIST */
+  "/reader/antenna/connectedPortList",  /* TMR_PARAM_ANTENNA_CONNECTEDPORTLIST */
+  "/reader/antenna/portSwitchGpos",  /* TMR_PARAM_ANTENNA_PORTSWITCHGPOS */
+  "/reader/antenna/settlingTimeList",  /* TMR_PARAM_ANTENNA_SETTLINGTIMELIST */
+  "/reader/antenna/returnLoss", /* TMR_PARAM_ANTENNA_RETURNLOSS */
+  "/reader/antenna/txRxMap",  /* TMR_PARAM_ANTENNA_TXRXMAP */
+  "/reader/gpio/inputList",  /* TMR_PARAM_GPIO_INPUTLIST */
+  "/reader/gpio/outputList",  /* TMR_PARAM_GPIO_OUTPUTLIST */
+  "/reader/gen2/accessPassword",  /* TMR_PARAM_GEN2_ACCESSPASSWORD */
+  "/reader/gen2/q",  /* TMR_PARAM_GEN2_Q */
+  "/reader/gen2/tagEncoding",  /* TMR_PARAM_GEN2_TAGENCODING*/
+  "/reader/gen2/session",  /* TMR_PARAM_GEN2_SESSION */
+  "/reader/gen2/target",  /* TMR_PARAM_GEN2_TARGET */
+  "/reader/gen2/BLF",  /* TMR_PARAM_GEN2_BLF */
+  "/reader/gen2/tari",  /* TMR_PARAM_GEN2_TARI */
+  "/reader/gen2/writeMode",/*TMR_PARAM_GEN2_WRITEMODE*/
+  "/reader/gen2/bap",  /* TMR_PARAM_GEN2_BAP */
+  "/reader/gen2/protocolExtension",  /* TMR_PARAM_GEN2_PROTOCOLEXTENSION */
+  "/reader/iso180006b/BLF",  /* TMR_PARAM_ISO18000_6B_LINKFREQUENCY */
+  "/reader/iso180006b/modulationDepth", /* TMR_PARAM_ISO18000_6B_MODULATION_DEPTH */
+  "/reader/iso180006b/delimiter", /* TMR_PARAM_ISO18000_6B_DELIMITER */
+  "/reader/read/asyncOffTime",  /* TMR_PARAM_READ_ASYNCOFFTIME */
+  "/reader/read/asyncOnTime",  /* TMR_PARAM_READ_ASYNCONTIME */
+  "/reader/read/plan",  /* TMR_PARAM_READ_PLAN */
+  "/reader/radio/enablePowerSave", /* TMR_PARAM_RADIO_ENABLEPOWERSAVE */
+  "/reader/radio/powerMax",  /* TMR_PARAM_RADIO_POWERMAX */
+  "/reader/radio/powerMin",  /* TMR_PARAM_RADIO_POWERMIN */
+  "/reader/radio/portReadPowerList",  /* TMR_PARAM_RADIO_PORTREADPOWERLIST */
+  "/reader/radio/portWritePowerList",  /* TMR_PARAM_RADIO_PORTWRITEPOWERLIST */
+  "/reader/radio/readPower",  /* TMR_PARAM_RADIO_READPOWER */
+  "/reader/radio/writePower",  /* TMR_PARAM_RADIO_WRITEPOWER */
+  "/reader/radio/temperature",  /* TMR_PARAM_RADIO_TEMPERATURE */
+  "/reader/tagReadData/recordHighestRssi",  /* TMR_PARAM_TAGREADDATA_RECORDHIGHESTRSSI */
+  "/reader/tagReadData/reportRssiInDbm",  /* TMR_PARAM_TAGREADDATA_REPORTRSSIINDBM */
+  "/reader/tagReadData/uniqueByAntenna",  /* TMR_PARAM_TAGREADDATA_UNIQUEBYANTENNA */
+  "/reader/tagReadData/uniqueByData",  /* TMR_PARAM_TAGREADDATA_UNIQUEBYDATA */
+  "/reader/tagop/antenna",  /* TMR_PARAM_TAGOP_ANTENNA */
+  "/reader/tagop/protocol",  /* TMR_PARAM_TAGOP_PROTOCOL */
+  "/reader/version/hardware",  /* TMR_PARAM_VERSION_HARDWARE */
+  "/reader/version/serial", /* TMR_PARAM_VERSION_SERIAL */
+  "/reader/version/model",  /* TMR_PARAM_VERSION_MODEL */
+  "/reader/version/software",  /* TMR_PARAM_VERSION_SOFTWARE */
+  "/reader/version/supportedProtocols",  /* TMR_PARAM_VERSION_SUPPORTEDPROTOCOLS */
+  "/reader/region/hopTable",  /* TMR_PARAM_REGION_HOPTABLE */
+  "/reader/region/hopTime",  /* TMR_PARAM_REGION_HOPTIME */
+  "/reader/region/id",  /* TMR_PARAM_REGION_ID */
+  "/reader/region/supportedRegions",  /* TMR_PARAM_REGION_SUPPORTEDREGIONS */
+  "/reader/region/lbt/enable",  /* TMR_PARAM_REGION_LBT_ENABLE */
+  "/reader/licenseKey",  /* TMR_PARAM_LICENSE_KEY */
+  "/reader/userConfig",  /* TMR_PARAM_USER_CONFIG */
+  "/reader/radio/enableSJC", /* TMR_PARAM_RADIO_ENABLESJC */
+  "/reader/extendedEpc", /* TMR_PARAM_EXTENDEDEPC */
+  "/reader/statistics", /* TMR_PARAM_READER_STATISTICS */
+  "/reader/stats", /* TMR_PARAM_READER_STATS */
+  "/reader/uri", /* TMR_PARAM_URI */
+  "/reader/version/productGroupID", /* TMR_PARAM_PRODUCT_GROUP_ID */
+  "/reader/version/productGroup", /* TMR_PARAM_PRODUCT_GROUP */
+  "/reader/version/productID", /* TMR_PARAM_PRODUCT_ID */
+  "/reader/tagReadData/tagopSuccesses",  /* TMR_PARAM_TAGREADATA_TAGOPSUCCESSCOUNT */
+  "/reader/tagReadData/tagopFailures", /* TMR_PARAM_TAGREADATA_TAGOPFAILURECOUNT */
+  "/reader/status/antennaEnable", /* TMR_PARAM_STATUS_ENABLE_ANTENNAREPORT */
+  "/reader/status/frequencyEnable", /* TMR_PARAM_STATUS_ENABLE_FREQUENCYREPORT */
+  "/reader/status/temperatureEnable", /* TMR_PARAM_STATUS_ENABLE_TEMPERATUREREPORT */
+  "/reader/tagReadData/enableReadFilter", /* TMR_PARAM_TAGREADDATA_ENABLEREADFILTER */
+  "/reader/tagReadData/readFilterTimeout", /* TMR_PARAM_TAGREADDATA_READFILTERTIMEOUT */
+  "/reader/tagReadData/uniqueByProtocol", /* TMR_PARAM_TAGREADDATA_UNIQUEBYPROTOCOL */
+  "/reader/description", /* TMR_PARAM_READER_DESCRIPTION */
+  "/reader/hostname", /* TMR_PARAM_READER_HOSTNAME */
+  "/reader/currentTime", /* TMR_PARAM_CURRENTTIME */
+	"/reader/gen2/writeReplyTimeout", /* TMR_PARAM_READER_WRITE_REPLY_TIMEOUT */
+	"/reader/gen2/writeEarlyExit", /* /reader/gen2/writeEarlyExit */
+  "/reader/stats/enable", /* /reader/stats/enable */
+  "/reader/trigger/read/Gpi", /* TMR_PARAM_TRIGGER_READ_GPI */
+  "/reader/metadataflags", /* TMR_PARAM_METADATAFLAG */
+  "/reader/licensedFeatures",  /* TMR_PARAM_LICENSED_FEATURES */
+  "/reader/selectedProtocols",  /* TMR_PARAM_SELECTED_PROTOCOLS */
+};
+
+
+TMR_Param
+TMR_paramID(const char *name)
+{
+  int i;
+
+  for (i = 1 ; i <= TMR_PARAM_MAX ; i++)
+  {
+    if (0 == strcasecmp(name, paramNames[i]))
+    {
+      return (TMR_Param)i;
+    }
+  }
+
+  return TMR_PARAM_NONE;
+}
+
+const char *
+TMR_paramName(TMR_Param key)
+{
+
+  if (key <= TMR_PARAM_MAX)
+  {
+    return paramNames[key];
+  }
+  return NULL;
+}
+
+#endif /* TMR_ENABLE_PARAM_STRINGS */
diff --git a/cbits/api/tmr_params.h b/cbits/api/tmr_params.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_params.h
@@ -0,0 +1,224 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TMR_PARAMS_H
+#define _TMR_PARAMS_H
+/** 
+ *  @file tmr_params.h
+ *  @brief Mercury API - Reader parameter interface
+ *  @author Nathan Williams
+ *  @date 10/20/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.
+ */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Parameter keys for TMR_paramSet() and TMR_paramGet().  Each
+ * parameter is listed with its associated string name and the
+ * parameter type. A pointer to that type is passed to TMR_paramGet()
+ * (for example, "TMR_String *" for /reader/version/model).
+ */
+typedef enum TMR_Param
+{
+  /** No such parameter - used as a return value from TMR_paramID().  */
+  TMR_PARAM_NONE,
+  TMR_PARAM_MIN,
+  /** "/reader/baudRate", uint32_t */
+  TMR_PARAM_BAUDRATE = TMR_PARAM_MIN,
+  /** "/reader/probeBaudRates", TMR_uint32List */
+  TMR_PARAM_PROBEBAUDRATES,
+  /** "/reader/commandTimeout", uint32_t */
+  TMR_PARAM_COMMANDTIMEOUT,
+  /** "/reader/transportTimeout", uint32_t */
+  TMR_PARAM_TRANSPORTTIMEOUT,
+  /** "/reader/powerMode", TMR_SR_PowerMode */
+  TMR_PARAM_POWERMODE,
+  /** "/reader/userMode", TMR_SR_UserMode */
+  TMR_PARAM_USERMODE,
+  /** "/reader/antenna/checkPort", bool  */
+  TMR_PARAM_ANTENNA_CHECKPORT,
+  /** "/reader/antenna/portList", TMR_uint8List  */
+  TMR_PARAM_ANTENNA_PORTLIST,
+  /** "/reader/antenna/connectedPortList", TMR_uint8List  */
+  TMR_PARAM_ANTENNA_CONNECTEDPORTLIST,
+  /** "/reader/antenna/portSwitchGpos", TMR_uint8List  */
+  TMR_PARAM_ANTENNA_PORTSWITCHGPOS,
+  /** "/reader/antenna/settlingTimeList", TMR_PortValueList  */
+  TMR_PARAM_ANTENNA_SETTLINGTIMELIST,
+  /** "/reader/antenna/returnLoss", TMR_PortValueList */
+  TMR_PARAM_ANTENNA_RETURNLOSS,
+  /** "/reader/antenna/txRxMap", TMR_AntennaMapList  */
+  TMR_PARAM_ANTENNA_TXRXMAP,
+  /** "/reader/gpio/inputList", TMR_uint8List */
+  TMR_PARAM_GPIO_INPUTLIST,
+  /** "/reader/gpio/outputList", TMR_uint8List */
+  TMR_PARAM_GPIO_OUTPUTLIST,
+  /** "/reader/gen2/accessPassword", TMR_GEN2_Password */
+  TMR_PARAM_GEN2_ACCESSPASSWORD,
+  /** "/reader/gen2/q", TMR_GEN2_Q */
+  TMR_PARAM_GEN2_Q,
+  /** "/reader/gen2/tagEncoding", TMR_GEN2_TagEncoding */
+  TMR_PARAM_GEN2_TAGENCODING,
+  /** "/reader/gen2/session", TMR_GEN2_Session */
+  TMR_PARAM_GEN2_SESSION,
+  /** "/reader/gen2/target", TMR_GEN2_Target */
+  TMR_PARAM_GEN2_TARGET,
+  /** "/reader/gen2/BLF", TMR_GEN2_LinkFrequency */
+  TMR_PARAM_GEN2_BLF,
+  /** "/reader/gen2/tari", TMR_GEN2_Tari */
+  TMR_PARAM_GEN2_TARI,
+  /**"/reader/gen2/writeMode", TMR_GEN2_WriteMode */
+  TMR_PARAM_GEN2_WRITEMODE,
+  /** "/reader/gen2/bap", TMR_GEN2_Bap */
+  TMR_PARAM_GEN2_BAP,
+  /** "/reader/gen2/protocolExtension", TMR_GEN2_ProtocolExtension */
+  TMR_PARAM_GEN2_PROTOCOLEXTENSION,
+  /** "/reader/iso180006b/BLF", TMR_ISO180006B_LinkFrequency */
+  TMR_PARAM_ISO180006B_BLF,
+  /** "/reader/iso180006b/modulationDepth", TMR_ISO180006B_ModulationDepth */
+  TMR_PARAM_ISO180006B_MODULATION_DEPTH,
+  /** "/reader/iso180006b/delimiter", TMR_PARAM_ISO18000_6B_DELIMITER */
+  TMR_PARAM_ISO180006B_DELIMITER,
+  /** "/reader/read/asyncOffTime", uint32_t */
+  TMR_PARAM_READ_ASYNCOFFTIME,
+  /** "/reader/read/asyncOnTime", uint32_t */
+  TMR_PARAM_READ_ASYNCONTIME,
+  /** "/reader/read/plan", TMR_ReadPlan */
+  TMR_PARAM_READ_PLAN,
+  /** "/reader/radio/enablePowerSave", bool **/
+  TMR_PARAM_RADIO_ENABLEPOWERSAVE,
+  /** "/reader/radio/powerMax", int16_t */
+  TMR_PARAM_RADIO_POWERMAX,
+  /** "/reader/radio/powerMin", int16_t */
+  TMR_PARAM_RADIO_POWERMIN,
+  /** "/reader/radio/portReadPowerList", TMR_PortValueList */
+  TMR_PARAM_RADIO_PORTREADPOWERLIST,
+  /** "/reader/radio/portWritePowerList", TMR_PortValueList */
+  TMR_PARAM_RADIO_PORTWRITEPOWERLIST,
+  /** "/reader/radio/readPower", int32_t */
+  TMR_PARAM_RADIO_READPOWER,
+  /** "/reader/radio/writePower", int32_t */
+  TMR_PARAM_RADIO_WRITEPOWER,
+  /** "/reader/radio/temperature", int8_t */
+  TMR_PARAM_RADIO_TEMPERATURE,
+  /** "/reader/tagReadData/recordHighestRssi", bool */
+  TMR_PARAM_TAGREADDATA_RECORDHIGHESTRSSI,
+  /** "/reader/tagReadData/reportRssiInDbm", bool */
+  TMR_PARAM_TAGREADDATA_REPORTRSSIINDBM,
+  /** "/reader/tagReadData/uniqueByAntenna", bool */
+  TMR_PARAM_TAGREADDATA_UNIQUEBYANTENNA,
+  /** "/reader/tagReadData/uniqueByData", bool */
+  TMR_PARAM_TAGREADDATA_UNIQUEBYDATA,
+  /** "/reader/tagop/antenna", uint8_t */
+  TMR_PARAM_TAGOP_ANTENNA,
+  /** "/reader/tagop/protocol", TMR_TagProtocol */
+  TMR_PARAM_TAGOP_PROTOCOL,
+  /** "/reader/version/hardware", TMR_String */
+  TMR_PARAM_VERSION_HARDWARE,
+  /** "/reader/version/serial", TMR_String */
+  TMR_PARAM_VERSION_SERIAL,
+  /** "/reader/version/model", TMR_String */
+  TMR_PARAM_VERSION_MODEL,
+  /** "/reader/version/software", TMR_String */
+  TMR_PARAM_VERSION_SOFTWARE,
+  /** "/reader/version/supportedProtocols", TMR_TagProtocolList */
+  TMR_PARAM_VERSION_SUPPORTEDPROTOCOLS,
+  /** "/reader/region/hopTable", TMR_uint32List */
+  TMR_PARAM_REGION_HOPTABLE,
+  /** "/reader/region/hopTime", uint32_t */
+  TMR_PARAM_REGION_HOPTIME,
+  /** "/reader/region/id", TMR_Region */
+  TMR_PARAM_REGION_ID,
+  /** "/reader/region/supportedRegions", TMR_RegionList */
+  TMR_PARAM_REGION_SUPPORTEDREGIONS,
+  /** "/reader/region/lbt/enable", bool */
+  TMR_PARAM_REGION_LBT_ENABLE,
+  /** "/reader/licenseKey", TMR_uint8List */
+  TMR_PARAM_LICENSE_KEY,
+  /** "/reader/userConfig", TMR_UserConfigOption */
+  TMR_PARAM_USER_CONFIG,
+  /** "/reader/radio/enableSJC", bool */
+  TMR_PARAM_RADIO_ENABLESJC,
+  /** "/reader/extendedEpc", bool */
+  TMR_PARAM_EXTENDEDEPC,
+  /** "/reader/statistics", TMR_SR_ReaderStatistics */
+  TMR_PARAM_READER_STATISTICS,
+  /** "/reader/stats", TMR_Reader_StatsValues */
+  TMR_PARAM_READER_STATS,
+  /** "/reader/uri", TMR_String */
+  TMR_PARAM_URI,
+  /** "/reader/version/productGroupID", uint16_t */
+  TMR_PARAM_PRODUCT_GROUP_ID,
+  /** "/reader/version/productGroup", TMR_String */
+  TMR_PARAM_PRODUCT_GROUP,
+  /** "/reader/version/productID", uint16_t */
+  TMR_PARAM_PRODUCT_ID,
+  /** "/reader/tagReadData/tagopSuccesses", uint16_t */
+  TMR_PARAM_TAGREADATA_TAGOPSUCCESSCOUNT,
+  /** "/reader/tagReadData/tagopFailures",  uint16_t */
+  TMR_PARAM_TAGREADATA_TAGOPFAILURECOUNT,
+  /** "/reader/status/antennaEnable", bool */
+  TMR_PARAM_STATUS_ENABLE_ANTENNAREPORT,
+  /** "/reader/status/frequencyEnable", bool */
+  TMR_PARAM_STATUS_ENABLE_FREQUENCYREPORT,
+  /** "/reader/status/temperatureEnable", bool */
+  TMR_PARAM_STATUS_ENABLE_TEMPERATUREREPORT,
+  /** "/reader/tagReadData/enableReadFilter", bool */
+  TMR_PARAM_TAGREADDATA_ENABLEREADFILTER,
+  /** "/reader/tagReadData/readFilterTimeout", int32_t */
+  TMR_PARAM_TAGREADDATA_READFILTERTIMEOUT,
+  /** "/reader/tagReadData/uniqueByProtocol", bool */
+  TMR_PARAM_TAGREADDATA_UNIQUEBYPROTOCOL,
+  /** "/reader/description", TMR_String */
+  TMR_PARAM_READER_DESCRIPTION,
+  /** "/reader/hostname", TMR_String */
+  TMR_PARAM_READER_HOSTNAME,
+  /** "/reader/currentTime", struct tm */
+  TMR_PARAM_CURRENTTIME,
+	/** "/reader/gen2/writeReplyTimeout", uint16_t */
+	TMR_PARAM_READER_WRITE_REPLY_TIMEOUT,
+	/** "/reader/gen2/writeEarlyExit", bool */
+	TMR_PARAM_READER_WRITE_EARLY_EXIT,
+  /** "/reader/stats/enable", TMR_StatsEnable */
+  TMR_PARAM_READER_STATS_ENABLE,
+  /** "/reader/trigger/read/Gpi", TMR_uint8List */
+  TMR_PARAM_TRIGGER_READ_GPI,
+  /** "/reader/metadataflags", TMR_TRD_MetadataFlag*/
+  TMR_PARAM_METADATAFLAG,
+  /** "/reader/licensedFeatures", TMR_uint8List */
+  TMR_PARAM_LICENSED_FEATURES,
+  TMR_PARAM_SELECTED_PROTOCOLS,
+  TMR_PARAM_END,
+  TMR_PARAM_MAX = TMR_PARAM_END-1,
+
+} TMR_Param;
+
+#define TMR_PARAMWORDS ((1 + TMR_PARAM_MAX +31) / 32)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TMR_PARAMS_H */
diff --git a/cbits/api/tmr_read_plan.h b/cbits/api/tmr_read_plan.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_read_plan.h
@@ -0,0 +1,211 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TMR_READ_PLAN_H
+#define _TMR_READ_PLAN_H
+/** 
+ *  @file tmr_read_plan.h
+ *  @brief Mercury API - Read Plan Definitions
+ *  @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.
+ */
+
+#include "tmr_tag_protocol.h"
+#include "tmr_filter.h"
+#include "tmr_tagop.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @defgroup readplan Read plans
+ *
+ * A read plan specifies the antennas, protocols, and filters to use
+ * for a search (read). Each ReadPlan structure has a numeric weight
+ * that controls what fraction of a search is used by that plan when
+ * combined in a MultiReadPlan (see below). Read plans are specified
+ * for the reader in the @c /reader/read/plan parameter.
+ *
+ * @{
+ */
+
+typedef struct TMR_ReadPlan TMR_ReadPlan;
+typedef struct TMR_SimpleReadPlan TMR_SimpleReadPlan;
+typedef struct TMR_MultiReadPlan TMR_MultiReadPlan;
+typedef struct TMR_StopOnTagCount TMR_StopOnTagCount;
+typedef struct TMR_TagObservationTrigger TMR_TagObservationTrigger;
+typedef struct TMR_StopTrigger TMR_StopTrigger;
+typedef struct TMR_GPITriggerRead TMR_GPITriggerRead;
+
+/**
+ * TODO: to be used later.
+ **/ 
+/*struct TMR_TagObservationTrigger
+{
+};
+
+struct TMR_StopTrigger
+{
+  TMR_TagObservationTrigger stopTrigger; 
+};*/
+
+/**
+ * A StopOnTagCount will be used in case of stop N trigger option.
+ * It contains a flag to specify that user is requesting for stop
+ * N trigger and a count to specify the number of tags user is 
+ * requesting to read.
+ **/
+struct TMR_StopOnTagCount
+{
+  /* option for stop N trigger */
+  bool stopNTriggerStatus;
+
+  /* Number of tags to be read */
+  uint32_t noOfTags;
+};
+
+/**
+ * This will be used for GPI trigger read option.
+ * It contains : 
+ * enableTriggerRead a flag to specify that user is requesting for trigger read.
+ * GPIList the list of GPI ports should be used to trigger the read.
+ **/
+struct TMR_GPITriggerRead
+{
+  /* option for trigger read */
+  bool enable;
+  /* RFU - The list of GPI ports */
+  TMR_uint8List gpiList;
+};
+
+/**
+ * A SimpleReadPlan contains a protocol, a list of antennas, and an
+ * optional filter. The list of antennas may be an empty list, in
+ * which case the reader will use all antennas in the antenna map (see
+ * @c /reader/antenna/txRxMap) where the reader has detected an
+ * antenna present. The filter describes any selection or filtering
+ * operation to perform in the RFID protocol during the search. The
+ * filter may be @c NULL, in which case no selection or filtering is
+ * performed. Invalid combinations of protocols and filters (a Gen2
+ * select on ISO180006B, for example) will produce an error at read
+ * time.
+ */
+struct TMR_SimpleReadPlan
+{
+  /** The list of antennas to read on */
+  TMR_uint8List antennas;
+  /** The protocol to use for reading */
+  TMR_TagProtocol protocol;
+  /** The filter to apply to reading, or NULL */
+  TMR_TagFilter *filter;
+  /** The tag operation to apply to each read tag, or NULL */
+  TMR_TagOp *tagop;
+  /** Option to use the FastSearch */
+  bool useFastSearch;
+  /** The stop N trigger */
+  TMR_StopOnTagCount stopOnCount;
+  /** The GPI trigger read */
+  TMR_GPITriggerRead triggerRead;
+};
+
+/**
+ * A MultiReadPlan contains a list of other ReadPlan objects. The
+ * relative weights of each of the included sub-plans are used
+ * determine what fraction of the total read time to allot to that
+ * sub-plan (for example, if the first plan has a weight of 20 and the
+ * second has a weight of 10, the first 2/3 of any read will use the
+ * first plan, and the remaining 1/3 will use the second
+ * plan). MultiReadPlan is useful for specifying searches over
+ * multiple protocols, for using different filters on different
+ * antennas, and other combinations.
+ */
+struct TMR_MultiReadPlan
+{
+  /** Array of pointers to the subsidiary read plans */
+  TMR_ReadPlan **plans;
+  uint32_t totalWeight; /** Internal value - initialize to 0 */
+  /** Number of elements in the array of read plans */
+  uint8_t planCount;
+};
+
+/** The type of a read plan */
+typedef enum TMR_ReadPlanType
+{
+  TMR_READ_PLAN_TYPE_INVALID,
+  /** Simple read plan - one protocol, a set of antennas, an optional
+   * tag filter, and an optional tag operation.
+   */
+  TMR_READ_PLAN_TYPE_SIMPLE,
+  /** Multi-read plan - a list of read plans (simple or multi). */
+  TMR_READ_PLAN_TYPE_MULTI
+} TMR_ReadPlanType;
+
+/**
+ * A ReadPlan structure specifies the antennas, protocols, and filters
+ * to use for a search (read).
+ */
+struct TMR_ReadPlan
+{
+  /** The type of the read plan and the type of the union that is populated */
+  TMR_ReadPlanType type;
+  /** The relative weight of this read plan */
+  uint32_t weight;
+  /** Option for Autonomous read */
+  bool enableAutonomousRead;
+  union
+  {
+    /** SimpleReadPlan contents */
+    TMR_SimpleReadPlan simple;
+    /** MultiReadPlan contents */
+    TMR_MultiReadPlan multi;
+  } u;
+};
+
+TMR_Status TMR_RP_init_simple(TMR_ReadPlan *plan, uint8_t antennaCount,
+                              uint8_t *antennaList, TMR_TagProtocol protocol,
+                              uint32_t weight);
+
+TMR_Status TMR_RP_init_multi(TMR_ReadPlan *plan, TMR_ReadPlan **plans,
+                             uint8_t planCount, uint32_t weight);
+
+TMR_Status TMR_GPITR_init_enable(TMR_GPITriggerRead *triggerRead, bool enable);
+
+TMR_Status TMR_RP_set_filter(TMR_ReadPlan *plan, TMR_TagFilter *filter);
+
+TMR_Status TMR_RP_set_tagop(TMR_ReadPlan *plan, TMR_TagOp *tagop);
+TMR_Status TMR_RP_set_enableTriggerRead(TMR_ReadPlan *plan, TMR_GPITriggerRead *triggerRead);
+
+TMR_Status TMR_RP_set_useFastSearch(TMR_ReadPlan *plan, bool useFastSearch);
+TMR_Status TMR_RP_set_stopTrigger(TMR_ReadPlan *plan, uint32_t count);
+TMR_Status TMR_RP_set_enableAutonomousRead(TMR_ReadPlan *plan, bool autonomousRead);
+/**
+ * @}
+ */
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* _TMR_READ_PLAN_H_ */
diff --git a/cbits/api/tmr_region.h b/cbits/api/tmr_region.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_region.h
@@ -0,0 +1,75 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TMR_REGION_H
+#define _TMR_REGION_H
+/**
+ *  @file tmr_region.h
+ *  @brief Mercury API - Region Definitions
+ *  @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.
+ */
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+  * RFID regulatory regions
+ */
+typedef enum TMR_Region
+{
+  /** Unspecified region */         TMR_REGION_NONE = 0,
+  /** North America */              TMR_REGION_NA   = 1,
+  /** European Union */             TMR_REGION_EU   = 2,
+  /** Korea */                      TMR_REGION_KR   = 3,
+  /** India */                      TMR_REGION_IN   = 4,
+  /** Japan */                      TMR_REGION_JP   = 5,
+  /** People's Republic of China */ TMR_REGION_PRC  = 6,
+  /** European Union 2 */           TMR_REGION_EU2  = 7,
+  /** European Union 3 */           TMR_REGION_EU3  = 8,
+  /** Korea 2*/                     TMR_REGION_KR2  = 9,
+  /** People's Republic of China(840MHZ)*/TMR_REGION_PRC2 = 10,
+  /** Australia */                  TMR_REGION_AU   = 11,
+  /** New Zealand !!EXPERIMENTAL!! */ TMR_REGION_NZ   = 12,
+  /** Reduced FCC region */         TMR_REGION_NA2 = 13,
+  /** 5MHZ FCC band */              TMR_REGION_NA3 = 14,
+  /** Israel  **/					TMR_REGION_IS= 15,
+  /** Open */                       TMR_REGION_OPEN = 0xFF
+} TMR_Region;
+
+/** A list of TMR_Region values */
+typedef struct TMR_RegionList
+{
+  /** Array of TMR_Region values */
+  TMR_Region *list;
+  /** Allocated size of the array */
+  uint8_t max;
+  /** Length of the list - may be larger than max, indicating truncated data */
+  uint8_t len;
+} TMR_RegionList;
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* _TMR_REGION_H_ */
diff --git a/cbits/api/tmr_serial_reader.h b/cbits/api/tmr_serial_reader.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_serial_reader.h
@@ -0,0 +1,473 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TMR_SERIAL_READER_H
+#define _TMR_SERIAL_READER_H
+/**
+ *  @file tmr_serial_reader.h
+ *  @brief Mercury API - Serial Reader interface
+ *  @author Nathan Williams
+ *  @date 10/20/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.
+ */
+
+#include "tmr_region.h"
+#include "tmr_tag_protocol.h"
+#include "tmr_serial_transport.h"
+
+#define TMR_SR_MAX_PACKET_SIZE 256
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Defines the values for the parameter @c /reader/powerMode and the
+ * return value and parameter to TMR_SR_cmdGetPowerMode and
+ * TMR_SR_cmdSetPowerMode.
+ */
+typedef enum TMR_SR_PowerMode
+{
+  TMR_SR_POWER_MODE_MIN     = 0,
+  TMR_SR_POWER_MODE_FULL    = 0,
+  TMR_SR_POWER_MODE_MINSAVE = 1,
+  TMR_SR_POWER_MODE_MEDSAVE = 2,
+  TMR_SR_POWER_MODE_MAXSAVE = 3,
+  TMR_SR_POWER_MODE_SLEEP   = 4,
+  TMR_SR_POWER_MODE_MAX     = TMR_SR_POWER_MODE_SLEEP,
+  TMR_SR_POWER_MODE_INVALID = TMR_SR_POWER_MODE_MAX + 1,
+} TMR_SR_PowerMode;
+
+/**
+Operation Options for cmdSetProtocolLicenseKey
+*/
+typedef enum TMR_SR_SetProtocolLicenseOption
+{
+/**  Set Valid License Key */
+TMR_SR_SET_LICENSE_KEY = 0x01,     
+/**  Erase License Key */
+TMR_SR_ERASE_LICENSE_KEY = 0x02, 
+}TMR_SR_SetProtocolLicenseOption;
+
+/** 
+Operation Options for cmdSetUserProfile 
+*/
+typedef enum TMR_SR_UserConfigOperation
+{          
+/**  Save operation */
+TMR_USERCONFIG_SAVE = 0x01,     
+/**  Restore operation */
+TMR_USERCONFIG_RESTORE = 0x02, 
+/**  Verify operation */
+TMR_USERCONFIG_VERIFY = 0x03,  
+/** Clear operation  */
+TMR_USERCONFIG_CLEAR = 0x04,
+/** Save read plan configuration */
+TMR_USERCONFIG_SAVE_WITH_READPLAN = 0x05,
+}TMR_SR_UserConfigOperation; 
+
+/**
+Congfiguration category for cmdSetUserProfile
+*/
+typedef enum TMR_SR_UserConfigCategory
+{
+  /** All Configuration */
+TMR_SR_ALL=0x01,   
+}TMR_SR_UserConfigCategory;
+
+/** 
+The configuration type for cmdSetUserProfile
+*/
+typedef enum TMR_SR_UserConfigType
+{
+/** Firmware default configurations */
+TMR_SR_FIRMWARE_DEFAULT=0x00,
+/** Custom configurations */
+TMR_SR_CUSTOM_CONFIGURATION=0x01,      
+}TMR_SR_UserConfigType;
+
+/**
+ * The user profile operation structure
+ */
+typedef struct TMR_SR_UserConfigOp
+{
+  /** @privatesection */
+
+  /** User config category */
+  TMR_SR_UserConfigCategory category;
+  /** User config operation */
+  TMR_SR_UserConfigOperation op;
+}TMR_SR_UserConfigOp;
+
+/**
+ * Defines the values for the parameter /reader/userMode and the
+ * return value and parameter to TMR_SR_cmdGetUserMode() and
+ * TMR_SR_cmdSetUserMode.
+ */
+typedef enum TMR_SR_UserMode
+{
+  TMR_SR_USER_MODE_MIN      = 0,
+  TMR_SR_USER_MODE_UNSPEC   = 0,
+  TMR_SR_USER_MODE_PRINTER  = 1,
+  TMR_SR_USER_MODE_CONVEYOR = 2,
+  TMR_SR_USER_MODE_PORTAL   = 3,
+  TMR_SR_USER_MODE_HANDHELD = 4,
+  TMR_SR_USER_MODE_MAX      = TMR_SR_USER_MODE_HANDHELD,
+  TMR_SR_USER_MODE_INVALID  = TMR_SR_USER_MODE_MAX + 1,
+}TMR_SR_UserMode;
+
+/**
+ * This represents the types of Q algorithms avaliable on the reader.
+ */
+typedef enum TMR_SR_GEN2_QType
+{
+  TMR_SR_GEN2_Q_MIN     = 0,
+  TMR_SR_GEN2_Q_DYNAMIC = 0,
+  TMR_SR_GEN2_Q_STATIC  = 1,
+  TMR_SR_GEN2_Q_MAX     = TMR_SR_GEN2_Q_STATIC,
+  TMR_SR_GEN2_Q_INVALID = TMR_SR_GEN2_Q_MAX + 1,
+} TMR_SR_GEN2_QType;
+
+/** Configuration of the static-Q algorithm. */
+typedef struct TMR_SR_GEN2_QStatic
+{
+  /** The initial Q value to use. */
+  uint8_t initialQ;
+} TMR_SR_GEN2_QStatic;
+
+/**
+ * This represents a Q algorithm on the reader.
+ */
+typedef struct TMR_SR_GEN2_Q
+{
+  /** The type of Q algorithm. */
+  TMR_SR_GEN2_QType type;
+  union
+  {
+    /** Configuration of the static-Q algorithm. */
+    TMR_SR_GEN2_QStatic staticQ;
+  }u;
+} TMR_SR_GEN2_Q;
+
+
+/** An antenna port with an associated int32_t value. */
+typedef struct TMR_PortValue
+{
+  /** The port number */
+  uint8_t port;
+  /** The value */
+  int32_t value;
+} TMR_PortValue;
+
+/** List of TMR_PortValue values */
+typedef struct TMR_PortValueList
+{
+  /** The array of values */
+  TMR_PortValue *list;
+  /** The number of entries there is space for in the array */
+  uint8_t max;
+  /** The number of entries in the list - may be larger than max, indicating truncated data. */
+  uint8_t len;
+} TMR_PortValueList;
+
+
+/**
+ * Mapping between an arbitrary "antenna" number and a TX/RX port
+ * pair. Not all TX/RX pairings are valid for a device.
+ */
+typedef struct TMR_AntennaMap
+{
+  /** The antenna number - an arbitrary value. */
+  uint8_t antenna;
+  /** The device antenna port to use for transmission. */
+  uint8_t txPort;
+  /** The device antenna port to use for reception. */
+  uint8_t rxPort;
+} TMR_AntennaMap;
+
+/** List of antenna mappings */
+typedef struct TMR_AntennaMapList
+{
+  /** The array of values */
+  TMR_AntennaMap *list;
+  /** The number of entries there is space for in the array */
+  uint8_t max;
+  /** The number of entries in the list - may be larger than max, indicating truncated data. */
+  uint8_t len;
+} TMR_AntennaMapList;
+
+/**
+ * The version structure returned from cmdVersion().
+ */
+typedef struct TMR_SR_VersionInfo
+{
+  /** Bootloader version, as four 8-bit numbers */
+  uint8_t bootloader[4];
+  /** Hardware version. Opaque format */
+  uint8_t hardware[4];
+  /** Date app firmware was built, as BCD YYYYMMDD */
+  uint8_t fwDate[4];
+  /** App firmware version, as four 8-bit numbers */
+  uint8_t fwVersion[4];
+  /** Bitmask of the protocols supported by the device (indexed by TMR_TagProtocol values minus one).  */
+  uint32_t protocols;
+} TMR_SR_VersionInfo;
+
+/**
+ * Current message TransportType
+ **/
+typedef enum TMR_TransportType
+{
+  /* Serial */
+  TMR_SR_MSG_SOURCE_SERIAL = 0x0000,
+  /* USB */
+  TMR_SR_MSG_SOURCE_USB = 0x0003,
+  /* Unknown */
+  TMR_SR_MSG_SOURCE_UNKNOWN = 0x0004,
+}TMR_TransportType;
+
+/**
+ * The serial reader structure.
+ */
+typedef struct TM_SR_SerialReader
+{
+  /** @privatesection */
+
+  /* Serial transport information */
+  TMR_SR_SerialTransport transport;
+  union
+  {
+#ifdef TMR_ENABLE_SERIAL_TRANSPORT_NATIVE
+    TMR_SR_SerialPortNativeContext nativeContext;
+#endif
+  } transportContext;
+
+  /* User-configurable values */
+  uint32_t baudRate;
+  TMR_AntennaMapList *txRxMap;
+  TMR_GEN2_Password gen2AccessPassword;
+  uint32_t transportTimeout;
+  uint32_t commandTimeout;
+  TMR_Region regionId;
+
+  /* Static storage for the default map */
+  TMR_AntennaMap staticTxRxMapData[TMR_SR_MAX_ANTENNA_PORTS];
+  TMR_AntennaMapList staticTxRxMap;
+
+  /* Mostly-fixed information about the connected reader */
+  TMR_SR_VersionInfo versionInfo;
+  uint32_t portMask;
+
+  /* Option to enable or disable the pre-amble */
+  bool supportsPreamble;
+
+  /* Cache extendedEPC setting */
+  bool extendedEPC;
+
+  /* Cached values */
+  TMR_SR_PowerMode powerMode;
+  TMR_TagProtocol currentProtocol;
+  int8_t gpioDirections;
+
+  /* Large bitmask that stores whether each parameter's presence
+   * is known or not.
+   */
+  uint32_t paramConfirmed[TMR_PARAMWORDS];
+  /* Large bitmask that, if the corresponding bit in paramConfirmed is set,
+   * stores whether each parameter is present or not.
+   */
+  uint32_t paramPresent[TMR_PARAMWORDS];
+
+  /* Temporary storage during a read and subsequent fetch of tags */
+  uint32_t readTimeLow, readTimeHigh;
+  uint32_t lastSentTagTimestampHigh, lastSentTagTimestampLow;
+  uint32_t searchTimeoutMs;
+  
+  /* Number of tags reported by module read command.
+   * In streaming mode, exact quantity is unknown, so use
+   * 0 if stream has ended, non-zero if end-of-stream has
+   * not yet been detected. */
+  int tagsRemaining;
+  /* Buffer tag records fetched from module but not yet passed to caller. */
+  uint8_t bufResponse[TMR_SR_MAX_PACKET_SIZE];
+  /* bufResponse read index */
+  uint8_t bufPointer;
+  /* Number of tag records in buffer but not yet passed to caller */
+  uint8_t tagsRemainingInBuffer;
+  /*TMR opCode*/
+  uint8_t opCode;
+  /*Gen2 Q Value from previous tagop */
+  TMR_SR_GEN2_Q oldQ;
+  /*Gen2 WriteMode*/
+  TMR_GEN2_WriteMode writeMode;
+  /* Buffer to store additional error message */
+  char errMsg[TMR_SR_MAX_PACKET_SIZE];
+  /* Product group id */
+  uint16_t productId;
+  /* Tag operation success count */
+  uint16_t tagopSuccessCount;
+  /* Tag operation failure count */
+  uint16_t tagopFailureCount;
+  /* Enable read filtering */
+  bool enableReadFiltering;
+  /* Read filter timeout */
+  int32_t readFilterTimeout;
+  /* Option to use the user specified transportTimeout */
+  bool usrTimeoutEnable;
+  /* Enable CRC calculation */
+  bool crcEnabled;
+  /* TransportType */
+  TMR_TransportType transportType;
+  /* Option for Gen2 all memory bank read */
+  bool gen2AllMemoryBankEnabled;
+  /* option for Gen2 Bap parameter */
+  bool isBapEnabled;
+  /* baud rates to be used for serial communication */
+  TMR_uint32List probeBaudRates;
+  /* storage for the probe baud rates */
+  uint32_t baudRates[TMR_MAX_PROBE_BAUDRATE_LENGTH];
+  /* Flag to be raised when Autonomous read is requested */
+  bool enableAutonomousRead;
+  /* The flag to be used in case of tag reading */
+  bool isBasetimeUpdated;
+} TMR_SR_SerialReader;
+
+/**
+ * This object is returned from TMR_SR_cmdGetReaderStatistics.
+ */
+typedef struct TMR_SR_ReaderStatistics
+{
+  /** The number of entries in the arrays. */
+  uint8_t numPorts;
+  /** per-port RF on time, in milliseconds. */
+  uint32_t rfOnTime[TMR_SR_MAX_ANTENNA_PORTS];
+  /** The per-port noise floor with transmitter off */
+  uint32_t noiseFloor[TMR_SR_MAX_ANTENNA_PORTS];
+  /** The per-port noise floor while transmitting. */
+  uint32_t noiseFloorTxOn[TMR_SR_MAX_ANTENNA_PORTS];
+}TMR_SR_ReaderStatistics;
+
+/**
+ *  Object of this contains antenna status report
+ */
+typedef struct TMR_SR_AntennaStatusReport
+{
+  /** Antenna */
+  uint8_t ant;
+}TMR_SR_AntennaStatusReport;
+
+/**
+ * Object of this contains frequency status report
+ */
+typedef struct TMR_SR_FrequencyStatusReport
+{
+  /** RF carrier frequency */
+  uint32_t freq;
+}TMR_SR_FrequencyStatusReport;
+
+/**
+ * Object of this contains temperature status report.
+ */
+typedef struct TMR_SR_TemperatureStatusReport
+{
+  /** Temperature */
+  int8_t temp;
+}TMR_SR_TemperatureStatusReport;
+
+/**
+ *  Status report content flags
+ */
+typedef enum TMR_SR_StatusType
+{
+  /* None */
+  TMR_SR_STATUS_NONE = 0x0000,
+  /* Frequency */
+  TMR_SR_STATUS_FREQUENCY = 0x0002,
+  /* Temperature */
+  TMR_SR_STATUS_TEMPERATURE = 0x0004,
+  /* Current Antenna Ports */
+  TMR_SR_STATUS_ANTENNA = 0x0008,
+  /* All */
+  TMR_SR_STATUS_ALL = 0x000E,
+  TMR_SR_STATUS_MAX = 4,
+}TMR_SR_StatusType;
+
+/**
+ * This object contains the information related to status reports
+ * sent by the module during continuous reading
+ */
+typedef struct TMR_SR_StatusReport
+{
+  TMR_SR_StatusType type;
+  union
+  {
+    /** Antenna status report */
+    TMR_SR_AntennaStatusReport asr;
+    /** Frequency status report */
+    TMR_SR_FrequencyStatusReport fsr;
+    /** Temperature status report */
+    TMR_SR_TemperatureStatusReport tsr;
+  } u;
+}TMR_SR_StatusReport;
+
+
+TMR_Status TMR_SR_connect(struct TMR_Reader *reader);
+TMR_Status TMR_SR_destroy(struct TMR_Reader *reader);
+TMR_Status TMR_SR_read(struct TMR_Reader *reader, uint32_t timeoutMs, int32_t *tagCount);
+TMR_Status TMR_SR_hasMoreTags(struct TMR_Reader *reader);
+TMR_Status TMR_SR_getNextTag(struct TMR_Reader *reader, TMR_TagReadData *read);
+TMR_Status TMR_SR_executeTagOp(struct TMR_Reader *reader, TMR_TagOp *tagop, TMR_TagFilter *filter, TMR_uint8List *data);
+TMR_Status TMR_SR_writeTag(struct TMR_Reader *reader, const TMR_TagFilter *filter, const TMR_TagData *data);
+TMR_Status TMR_SR_killTag(struct TMR_Reader *reader, const TMR_TagFilter *filter, const TMR_TagAuthentication *auth);
+TMR_Status TMR_SR_lockTag(struct TMR_Reader *reader, const TMR_TagFilter *filter, TMR_TagLockAction *action);
+TMR_Status TMR_SR_readTagMemBytes(struct TMR_Reader *reader, const TMR_TagFilter *filter,
+                              uint32_t bank, uint32_t address,
+                              uint16_t count, uint8_t data[]);
+TMR_Status TMR_SR_readTagMemWords(struct TMR_Reader *reader, const TMR_TagFilter *filter,
+                              uint32_t bank, uint32_t address,
+                              uint16_t count, uint16_t *data);
+TMR_Status TMR_SR_writeTagMemBytes(struct TMR_Reader *reader, const TMR_TagFilter *filter,
+                               uint32_t bank, uint32_t address,
+                               uint16_t count, const uint8_t data[]);
+TMR_Status TMR_SR_writeTagMemWords(struct TMR_Reader *reader, const TMR_TagFilter *filter,
+                               uint32_t bank, uint32_t address,
+                               uint16_t count, const uint16_t data[]);
+TMR_Status TMR_SR_gpoSet(struct TMR_Reader *reader, uint8_t count, const TMR_GpioPin state[]);
+TMR_Status TMR_SR_gpiGet(struct TMR_Reader *reader, uint8_t *count, TMR_GpioPin state[]);
+TMR_Status TMR_SR_firmwareLoad(TMR_Reader *reader, void *cookie,
+                               TMR_FirmwareDataProvider provider);
+TMR_Status TMR_SR_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 TMR_init_UserConfigOp(TMR_SR_UserConfigOp *config, TMR_SR_UserConfigOperation op);
+TMR_Status TMR_SR_reboot(struct TMR_Reader *reader);
+
+/**
+ * Initialize a serial reader. The reader->u.serialReader.transport
+ * structure must be initialized before calling this.
+ */
+TMR_Status TMR_SR_SerialReader_init(TMR_Reader *reader);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TMR_SERIAL_READER_H */
diff --git a/cbits/api/tmr_serial_transport.h b/cbits/api/tmr_serial_transport.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_serial_transport.h
@@ -0,0 +1,232 @@
+#ifndef _TMR_SERIAL_TRANSPORT_H
+#define _TMR_SERIAL_TRANSPORT_H
+/**
+ *  @file tmr_serial_transport.h
+ *  @brief Mercury API - Serial Transport Interface
+ *  @author Nathan Williams
+ *  @date 10/20/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.
+ */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifdef TMR_ENABLE_SERIAL_TRANSPORT_LLRP
+#include <sys/types.h>
+#include <sys/socket.h>
+#endif
+
+#if defined(WIN32) || defined(WINCE)
+#if !defined(_WINSOCK2API_) && !defined(_WINSOCKAPI_)
+#include <winsock2.h>
+#endif
+#endif
+
+#ifdef OSDEP_SERIAL_INCLUDE
+#include "osdep_serial_transport.h"
+#endif
+
+#ifndef PLATFORM_HANDLE
+# ifdef WIN32
+#  define PLATFORM_HANDLE HANDLE
+# else
+#if defined(ARDUINO) || defined(FREERTOS_USED)
+#   define PLATFORM_HANDLE void*
+# else
+#  define PLATFORM_HANDLE int
+# endif
+# endif
+#endif
+typedef struct TMR_SR_SerialTransport TMR_SR_SerialTransport;
+/**
+ * The TMR_SR_SerialTransport structure is the mechanism that the
+ * SerialReader layer uses to conduct low-level communications with
+ * the device. Users may create their own SerialTransport objects for
+ * systems with custom serial communication needs, and then use
+ * TMR_SR_SerialReader_init() to complete the construction of the
+ * reader object, as an alternative to using TMR_create().
+ *
+ * @see TMR_SR_SerialPortTransportInit and
+ * TMR_SR_LlrpEapiTransportInit for pre-existing
+ * TMR_SR_SerialTransport implementations.
+ */
+struct TMR_SR_SerialTransport
+{
+  /** Context value made avaliable to callback functions */
+  void *cookie;
+
+  /**
+   * This callback causes the communication interface to be opened but
+   * does not transmit any serial-layer data. This should perform
+   * actions such as opening a serial port device or establishing a
+   * network connection within a wrapper protocol.
+   *
+   * @param this The TMR_SR_SerialTransport structure.
+   */
+  TMR_Status (*open)(TMR_SR_SerialTransport *);
+
+  /**
+   * This callback transmits the provided bytes on the serial
+   * transport. If the operation takes longer than timeoutMs to
+   * complete, TMR_ERROR_TIMEOUT should be returned.
+   *
+   * @param this The TMR_SR_SerialTransport structure.
+   * @param length The number of bytes to send.
+   * @param message Pointer to the bytes to send.
+   * @param timeoutMs The duration for the operation to complete.
+   */
+  TMR_Status (*sendBytes)(TMR_SR_SerialTransport *, uint32_t length, 
+                          uint8_t* message, const uint32_t timeoutMs);
+
+  /**
+   * This callback recieves bytes message on the serial transport. The
+   * length parameter contains the size of the buffer pointed to by
+   * message. If the operation takes longer than timeoutMs to receive
+   * length bytes, TMR_ERROR_TIMEOUT should be returned.
+   *
+   * @param this The TMR_SR_SerialTransport structure.
+   * @param length The number of bytes to receive.
+   * @param[out] messageLength The number of bytes received.
+   * @param[out] message Pointer to the location to store received bytes.
+   * @param timeoutMs The duration for the operation to complete.
+   */
+  TMR_Status (*receiveBytes)(TMR_SR_SerialTransport *, uint32_t length,
+                             uint32_t *messageLength, uint8_t* message, const uint32_t timeoutMs);
+  /**
+   * This callback causes the underlying serial transport connected to
+   * the device to the provided baud rate.
+   *
+   * @param this The TMR_SR_SerialTransport structure.
+   * @param rate The baud rate to set.
+   */
+  TMR_Status (*setBaudRate)(TMR_SR_SerialTransport *, uint32_t rate);
+
+  /**
+   * This callback releases any resources allocated by the transport
+   * layer and informs the other end, if necessary, that the
+   * connection is ending.
+   *
+   * @param this The TMR_SR_SerialTransport structure.
+   */
+  TMR_Status (*shutdown)(TMR_SR_SerialTransport *);
+
+  /**
+   * This callback takes any actions necessary (possibly none) to
+   * remove unsent data from the output path.
+   *
+   * @param this The TMR_SR_SerialTransport structure.
+   */
+  TMR_Status (*flush)(TMR_SR_SerialTransport *);
+};
+
+#ifdef TMR_ENABLE_SERIAL_TRANSPORT_NATIVE
+/**
+ * The context structure used by the provided serial port transport interface.
+ */
+typedef struct TMR_SR_SerialPortNativeContext
+{
+  /** @privatesection */
+  /** The file handle for the serial device */
+  PLATFORM_HANDLE handle;
+  /** The filesystem name of the serial device */
+  char devicename[TMR_MAX_READER_NAME_LENGTH];
+} TMR_SR_SerialPortNativeContext;
+#endif
+
+#ifdef TMR_ENABLE_SERIAL_TRANSPORT_LLRP
+/**
+ * The context structure used by the provided
+ * serial-encapsulated-in-LLRP transport interface.
+ */
+typedef struct TMR_SR_LlrpEapiTransportContext
+{
+  /** @privatesection */
+  /** The network address of the remote device */
+  struct sockaddr_storage addr;
+  /** The length of the contents of addr */
+  socklen_t addrlen;
+  /** Whether or not to power-cycle the reader upon opening a connection */
+  bool powerCycleAtOpen;
+  /** The file handle for the network socket */
+  int socket;
+  /** The current LLRP message ID */
+  int sequenceId;
+  /** Temporary buffer for receiving and processing a LLRP packet */
+  uint8_t buf[270];
+  /** Pointers into the buffer */
+  uint16_t bufstart, buflen;
+} TMR_SR_LlrpEapiTransportContext;
+#endif
+
+#ifdef TMR_ENABLE_SERIAL_TRANSPORT_NATIVE
+/**
+ * Initialize a TMR_SR_SerialTransport structure with a given serial device.
+ *
+ * @param transport The TMR_SR_SerialTransport structure to initialize.
+ * @param context A TMR_SR_SerialPortNativeContext structure for the callbacks to use.
+ * @param device The path or name of the serial device (@c /dev/ttyS0, @c COM1)
+ */
+#if defined(WIN32) || defined(WINCE)
+__declspec(dllexport)
+#endif
+TMR_Status TMR_SR_SerialTransportNativeInit(TMR_SR_SerialTransport *transport,
+                                            TMR_SR_SerialPortNativeContext *context,
+                                            const char *device);
+#if defined(WIN32) || defined(WINCE)
+__declspec(dllexport)
+#endif
+TMR_Status TMR_SR_SerialTransportTcpNativeInit(TMR_SR_SerialTransport *transport,
+                                            TMR_SR_SerialPortNativeContext *context,
+                                            const char *device);
+#endif /* TMR_ENABLE_SERIAL_TRANSPORT_NATIVE */
+
+#ifdef TMR_ENABLE_SERIAL_TRANSPORT_LLRP
+/**
+ * Initialize a TMR_SR_SerialTransport structure with a LLRP+EAPI
+ * connection to the given host and port.
+ *
+ * @param transport The TMR_SR_SerialTransport structure to initialize.
+ * @param context A TMR_SR_LlrpEapiTransportContext structure for the callbacks to use.
+ * @param host The name or address of the network device implementing LLRP+EAPI.
+ * @param port The TCP port to use for the connection.
+ * @param powerCycleAtOpen Whether or not to power-cycle the reader upon opening a connection.
+ */
+TMR_Status TMR_SR_LlrpEapiTransportInit(TMR_SR_SerialTransport *transport,
+                                        TMR_SR_LlrpEapiTransportContext *context,
+                                        const char *host, int port,
+                                        bool powerCycleAtOpen);
+
+/**
+ * Power-cycle a device attached via LLRP transport
+ * @param transport The TMR_SR_SerialTransport connected to the device
+ */
+TMR_Status TMR_LlrpEapiPowerCycle(TMR_SR_SerialTransport *this);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TMR_SERIAL_TRANSPORT_H */
diff --git a/cbits/api/tmr_status.h b/cbits/api/tmr_status.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_status.h
@@ -0,0 +1,238 @@
+#ifndef _TMR_STATUS_H
+#define _TMR_STATUS_H
+
+/**
+ *  @file tmr_status.h
+ *  @brief Mercury API - status codes
+ *  @author Nathan Williams
+ *  @date 11/24/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.
+ */
+
+#include "tm_config.h"
+#ifdef WINCE
+#include <stdint_win32.h>
+#else
+#include <stdint.h>
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef uint32_t TMR_Status;
+
+#define TMR_STATUS_MAKE(type, value) (((type) << 24) | (value))
+#define TMR_STATUS_GET_TYPE(x)       (((x) >> 24) & 0xff)
+#define TMR_STATUS_GET_VALUE(x)      ((x) & 0xffffff)
+
+#define TMR_SUCCESS_TYPE    0L
+#define TMR_ERROR_TYPE_COMM 1L
+#define TMR_ERROR_TYPE_CODE 2L
+#define TMR_ERROR_TYPE_MISC 3L
+#define TMR_ERROR_TYPE_LLRP 4L
+
+#define TMR_SUCCESS TMR_STATUS_MAKE(TMR_SUCCESS_TYPE, 0)
+
+#define TMR_ERROR_CODE(x)     TMR_STATUS_MAKE(TMR_ERROR_TYPE_CODE, (x))
+#define TMR_ERROR_IS_CODE(x)  (TMR_ERROR_TYPE_CODE == TMR_STATUS_GET_TYPE(x))
+#define TMR_ERROR_GET_CODE(x) TMR_STATUS_GET_VALUE(x)
+/**Invalid number of arguments  */
+#define TMR_ERROR_MSG_WRONG_NUMBER_OF_DATA                TMR_ERROR_CODE(0x100)
+/**Command opcode not recognized.  */
+#define TMR_ERROR_INVALID_OPCODE                          TMR_ERROR_CODE(0x101)
+/**Command opcode recognized, but is not supported.  */
+#define TMR_ERROR_UNIMPLEMENTED_OPCODE                    TMR_ERROR_CODE(0x102)
+/**Requested power setting is above the allowed maximum.  */
+#define TMR_ERROR_MSG_POWER_TOO_HIGH                      TMR_ERROR_CODE(0x103)
+/**Requested frequency is outside the allowed range.  */
+#define TMR_ERROR_MSG_INVALID_FREQ_RECEIVED               TMR_ERROR_CODE(0x104)
+/**Parameter value is outside the allowed range.  */
+#define TMR_ERROR_MSG_INVALID_PARAMETER_VALUE             TMR_ERROR_CODE(0x105)
+/**Requested power setting is below the allowed minimum. */
+#define TMR_ERROR_MSG_POWER_TOO_LOW                       TMR_ERROR_CODE(0x106)
+/**Command not supported. */
+#define TMR_ERROR_UNIMPLEMENTED_FEATURE                   TMR_ERROR_CODE(0x109)
+/**Requested serial speed is not supported. */
+#define TMR_ERROR_INVALID_BAUD_RATE                       TMR_ERROR_CODE(0x10a)
+/**Region is not supported. */
+#define TMR_ERROR_INVALID_REGION                          TMR_ERROR_CODE(0x10b)
+/** License key code is invalid */
+#define TMR_ERROR_INVALID_LICENSE_KEY                     TMR_ERROR_CODE(0x10c)
+/**Firmware is corrupt: Checksum doesn't match content. */
+#define TMR_ERROR_BL_INVALID_IMAGE_CRC                    TMR_ERROR_CODE(0x200)
+/**Serial protocol status code for this exception. */
+#define TMR_ERROR_BL_INVALID_APP_END_ADDR                 TMR_ERROR_CODE(0x201)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_FLASH_BAD_ERASE_PASSWORD                TMR_ERROR_CODE(0x300)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_FLASH_BAD_WRITE_PASSWORD                TMR_ERROR_CODE(0x301)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_FLASH_UNDEFINED_SECTOR                  TMR_ERROR_CODE(0x302)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_FLASH_ILLEGAL_SECTOR                    TMR_ERROR_CODE(0x303)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_FLASH_WRITE_TO_NON_ERASED_AREA          TMR_ERROR_CODE(0x304)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_FLASH_WRITE_TO_ILLEGAL_SECTOR           TMR_ERROR_CODE(0x305)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_FLASH_VERIFY_FAILED                     TMR_ERROR_CODE(0x306)
+/**Reader was asked to find tags, but none were detected. */
+#define TMR_ERROR_NO_TAGS_FOUND                           TMR_ERROR_CODE(0x400)
+/**RFID protocol has not been configured. */
+#define TMR_ERROR_NO_PROTOCOL_DEFINED                     TMR_ERROR_CODE(0x401)
+/**Requested RFID protocol is not recognized. */
+#define TMR_ERROR_INVALID_PROTOCOL_SPECIFIED              TMR_ERROR_CODE(0x402)
+/**For write-then-lock commands, tag was successfully written, but lock failed.*/
+#define TMR_ERROR_WRITE_PASSED_LOCK_FAILED                TMR_ERROR_CODE(0x403)
+/**Tag data was requested, but could not be read. */
+#define TMR_ERROR_PROTOCOL_NO_DATA_READ                   TMR_ERROR_CODE(0x404)
+/**Reader not fully initialized and hasn't yet turned on its radio.  Have you set region?*/
+#define TMR_ERROR_AFE_NOT_ON                              TMR_ERROR_CODE(0x405)
+/**Write to tag failed. */
+#define TMR_ERROR_PROTOCOL_WRITE_FAILED                   TMR_ERROR_CODE(0x406)
+/**Command is not supported in the current RFID protocol. */
+#define TMR_ERROR_NOT_IMPLEMENTED_FOR_THIS_PROTOCOL       TMR_ERROR_CODE(0x407)
+/**Data does not conform to protocol standards. */
+#define TMR_ERROR_PROTOCOL_INVALID_WRITE_DATA             TMR_ERROR_CODE(0x408)
+/**Requested data address is outside the valid range. */
+#define TMR_ERROR_PROTOCOL_INVALID_ADDRESS                TMR_ERROR_CODE(0x409)
+/**Unknown error during RFID operation. */
+#define TMR_ERROR_GENERAL_TAG_ERROR                       TMR_ERROR_CODE(0x40a)
+/**Read Tag Data was asked for more data than it supports. */
+#define TMR_ERROR_DATA_TOO_LARGE                          TMR_ERROR_CODE(0x40b)
+/**Incorrect password was provided to Kill Tag. */
+#define TMR_ERROR_PROTOCOL_INVALID_KILL_PASSWORD          TMR_ERROR_CODE(0x40c)
+/**Kill failed for unknown reason. */
+#define TMR_ERROR_PROTOCOL_KILL_FAILED                    TMR_ERROR_CODE(0x40e)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_PROTOCOL_BIT_DECODING_FAILED            TMR_ERROR_CODE(0x40f)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_PROTOCOL_INVALID_EPC                    TMR_ERROR_CODE(0x410)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_PROTOCOL_INVALID_NUM_DATA               TMR_ERROR_CODE(0x411)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_GEN2_PROTOCOL_OTHER_ERROR               TMR_ERROR_CODE(0x420)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_GEN2_PROTOCOL_MEMORY_OVERRUN_BAD_PC     TMR_ERROR_CODE(0x423)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_GEN2_PROTOCOL_MEMORY_LOCKED             TMR_ERROR_CODE(0x424)
+/**Authentication failed with specified key. */
+#define TMR_ERROR_GEN2_PROTOCOL_V2_AUTHEN_FAILED				TMR_ERROR_CODE(0x425)
+/** Untrace operation failed. */
+#define TMR_ERROR_GEN2_PROTOCOL_V2_UNTRACE_FAILED				TMR_ERROR_CODE(0x426)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_GEN2_PROTOCOL_INSUFFICIENT_POWER        TMR_ERROR_CODE(0x42b)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_GEN2_PROTOCOL_NON_SPECIFIC_ERROR        TMR_ERROR_CODE(0x42f)
+/**Internal reader error.  Contact support. */ 
+#define TMR_ERROR_GEN2_PROTOCOL_UNKNOWN_ERROR             TMR_ERROR_CODE(0x430)
+/**A command was received to set a frequency outside the specified range. */
+#define TMR_ERROR_AHAL_INVALID_FREQ                       TMR_ERROR_CODE(0x500)
+/**With LBT enabled an attempt was made to set the frequency to an occupied channel. */
+#define TMR_ERROR_AHAL_CHANNEL_OCCUPIED                   TMR_ERROR_CODE(0x501)
+/**Checking antenna status while CW is on is not allowed. */
+#define TMR_ERROR_AHAL_TRANSMITTER_ON                     TMR_ERROR_CODE(0x502)
+/** Antenna not detected during pre-transmit safety test. */
+#define TMR_ERROR_ANTENNA_NOT_CONNECTED                   TMR_ERROR_CODE(0x503)
+/**Reader temperature outside safe range. */
+#define TMR_ERROR_TEMPERATURE_EXCEED_LIMITS               TMR_ERROR_CODE(0x504)
+/** Excess power detected at transmitter port, usually due to antenna tuning mismatch. */
+#define TMR_ERROR_HIGH_RETURN_LOSS                        TMR_ERROR_CODE(0x505)
+#define TMR_ERROR_INVALID_ANTENNA_CONFIG                  TMR_ERROR_CODE(0x507)
+/**Asked for more tags than were available in the buffer. */
+#define TMR_ERROR_TAG_ID_BUFFER_NOT_ENOUGH_TAGS_AVAILABLE TMR_ERROR_CODE(0x600)
+/**Too many tags are in buffer.  Remove some with Get Tag ID Buffer or Clear Tag ID Buffer. */
+#define TMR_ERROR_TAG_ID_BUFFER_FULL                      TMR_ERROR_CODE(0x601)
+/**Internal error -- reader is trying to insert a duplicate tag record.  Contact support. */
+#define TMR_ERROR_TAG_ID_BUFFER_REPEATED_TAG_ID           TMR_ERROR_CODE(0x602)
+/**Asked for tags than a single transaction can handle. */
+#define TMR_ERROR_TAG_ID_BUFFER_NUM_TAG_TOO_LARGE         TMR_ERROR_CODE(0x603)
+/**Blocked response to get additional data from host. */
+#define TMR_ERROR_TAG_ID_BUFFER_AUTH_REQUEST              TMR_ERROR_CODE(0x604)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_SYSTEM_UNKNOWN_ERROR                    TMR_ERROR_CODE(0x7f00)
+/**Internal reader error.  Contact support. */
+#define TMR_ERROR_TM_ASSERT_FAILED                        TMR_ERROR_CODE(0x7f01)
+
+#define TMR_ERROR_COMM(x)           TMR_STATUS_MAKE(TMR_ERROR_TYPE_COMM, (x))
+#define TMR_ERROR_IS_COMM(x)        (TMR_ERROR_TYPE_COMM == TMR_STATUS_GET_TYPE(x))
+#define TMR_ERROR_COMM_ERRNO(x)     TMR_ERROR_COMM(0x8000 | (x))
+#define TMR_ERROR_COMM_IS_ERRNO(x)  (0x8000 == (TMR_STATUS_GET_VALUE(x) & 0x8000))
+#define TMR_ERROR_COMM_GET_ERRNO(x) (TMR_STATUS_GET_VALUE(x) & 0x7fff)
+#define TMR_ERROR_TIMEOUT           TMR_ERROR_COMM(1)
+#define TMR_ERROR_NO_HOST           TMR_ERROR_COMM(2)
+#define TMR_ERROR_LLRP              TMR_ERROR_COMM(3)
+#define TMR_ERROR_PARSE             TMR_ERROR_COMM(4)
+#define TMR_ERROR_DEVICE_RESET      TMR_ERROR_COMM(5)
+#define TMR_ERROR_CRC_ERROR         TMR_ERROR_COMM(6)
+
+#define TMR_ERROR_MISC(x)  TMR_STATUS_MAKE(TMR_ERROR_TYPE_MISC, (x))
+#define TMR_ERROR_INVALID          TMR_ERROR_MISC(1)
+#define TMR_ERROR_UNIMPLEMENTED    TMR_ERROR_MISC(2)
+#define TMR_ERROR_UNSUPPORTED      TMR_ERROR_MISC(3)
+#define TMR_ERROR_NO_ANTENNA       TMR_ERROR_MISC(4)
+#define TMR_ERROR_READONLY         TMR_ERROR_MISC(5)
+#define TMR_ERROR_TOO_BIG          TMR_ERROR_MISC(6)
+#define TMR_ERROR_NO_THREADS       TMR_ERROR_MISC(7)
+#define TMR_ERROR_NO_TAGS          TMR_ERROR_MISC(8)
+#define TMR_ERROR_NOT_FOUND        TMR_ERROR_MISC(9)
+#define TMR_ERROR_FIRMWARE_FORMAT  TMR_ERROR_MISC(10)
+#define TMR_ERROR_TRYAGAIN         TMR_ERROR_MISC(11)
+#define TMR_ERROR_OUT_OF_MEMORY    TMR_ERROR_MISC(12)
+#define TMR_ERROR_INVALID_WRITE_MODE  TMR_ERROR_MISC(13)
+#define TMR_ERROR_ILLEGAL_VALUE	   TMR_ERROR_MISC(14)
+#define TMR_ERROR_END_OF_READING	 TMR_ERROR_MISC(15)
+#define TMR_ERROR_UNSUPPORTED_READER_TYPE  TMR_ERROR_MISC(16)
+#define TMR_ERROR_BUFFER_OVERFLOW  TMR_ERROR_MISC(17)
+#define TMR_ERROR_LOADSAVE_CONFIG  TMR_ERROR_MISC(18)
+#define TMR_ERROR_AUTOREAD_ENABLED TMR_ERROR_MISC(19)
+#define TMR_ERROR_FIRMWARE_UPDATE_ON_AUTOREAD  TMR_ERROR_MISC(20)
+#define TMR_ERROR_TIMESTAMP_NULL  TMR_ERROR_MISC(21)
+
+/* LLRP related errors */
+#define TMR_ERROR_LLRP_SPECIFIC(x)            TMR_STATUS_MAKE(TMR_ERROR_TYPE_LLRP, (x))
+#define TMR_ERROR_IS_LLRP_SPECIFIC(x)         (TMR_ERROR_TYPE_LLRP == TMR_STATUS_GET_TYPE(x))
+#define TMR_ERROR_LLRP_GETTYPEREGISTRY        TMR_ERROR_LLRP_SPECIFIC(1)
+#define TMR_ERROR_LLRP_CONNECTIONFAILED       TMR_ERROR_LLRP_SPECIFIC(2)
+#define TMR_ERROR_LLRP_SENDIO_ERROR           TMR_ERROR_LLRP_SPECIFIC(3)
+#define TMR_ERROR_LLRP_RECEIVEIO_ERROR        TMR_ERROR_LLRP_SPECIFIC(4)
+#define TMR_ERROR_LLRP_RECEIVE_TIMEOUT        TMR_ERROR_LLRP_SPECIFIC(5)
+#define TMR_ERROR_LLRP_MSG_PARSE_ERROR        TMR_ERROR_LLRP_SPECIFIC(6)
+#define TMR_ERROR_LLRP_ALREADY_CONNECTED      TMR_ERROR_LLRP_SPECIFIC(7)
+#define TMR_ERROR_LLRP_INVALID_RFMODE         TMR_ERROR_LLRP_SPECIFIC(8)
+#define TMR_ERROR_LLRP_UNDEFINED_VALUE        TMR_ERROR_LLRP_SPECIFIC(9)
+#define TMR_ERROR_LLRP_READER_ERROR           TMR_ERROR_LLRP_SPECIFIC(10)
+#define TMR_ERROR_LLRP_READER_CONNECTION_LOST TMR_ERROR_LLRP_SPECIFIC(11)
+#define TMR_ERROR_LLRP_CLIENT_CONNECTION_EXISTS     TMR_ERROR_LLRP_SPECIFIC(12)
+
+#ifdef TMR_ENABLE_ERROR_STRINGS
+const char *TMR_strerror(TMR_Status status);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TMR_STATUS_H */
diff --git a/cbits/api/tmr_strerror.c b/cbits/api/tmr_strerror.c
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_strerror.c
@@ -0,0 +1,296 @@
+/**
+ *  @file tmr_strerror.c
+ *  @brief Mercury API - status code to string conversion
+ *  @author Nathan Williams
+ *  @date 10/23/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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "tm_reader.h"
+
+#if defined(TMR_ENABLE_ERROR_STRINGS)
+
+const char *
+TMR_strerror(TMR_Status status)
+{
+  return TMR_strerr(NULL, status);
+}
+
+const char *
+TMR_strerr(TMR_Reader *reader, TMR_Status status)
+{
+
+  if (TMR_ERROR_IS_COMM(status) && TMR_ERROR_COMM_IS_ERRNO(status))
+  {
+#ifdef TMR_USE_STRERROR
+    return strerror(TMR_ERROR_COMM_GET_ERRNO(status));
+#else
+    return "Error";
+#endif    
+  }
+
+#ifdef TMR_ENABLE_LLRP_READER
+  if (TMR_ERROR_IS_LLRP_SPECIFIC(status))
+  {
+    switch (status)
+    {
+      case TMR_ERROR_LLRP_MSG_PARSE_ERROR:
+        return "Error parsing LLRP message";
+      case TMR_ERROR_LLRP_ALREADY_CONNECTED:
+        return "Already connected to reader";
+      case TMR_ERROR_LLRP_INVALID_RFMODE:
+        return "Specified RF Mode operation is not supported";
+      case TMR_ERROR_LLRP_UNDEFINED_VALUE:
+        return "Undefined Value";
+      case TMR_ERROR_LLRP_READER_ERROR:
+        return "LLRP reader unknown error";
+      case TMR_ERROR_LLRP_READER_CONNECTION_LOST:
+        return "LLRP reader connection lost";
+      case TMR_ERROR_LLRP_GETTYPEREGISTRY:
+        return "LLRP Reader GetTypeRegistry Failed";
+      case TMR_ERROR_LLRP_CONNECTIONFAILED:
+        return "LLRP Reader Connection attempt is failed";
+      case TMR_ERROR_LLRP_CLIENT_CONNECTION_EXISTS:
+        return "LLRP Reader Connection attempt is failed, A Client initiated connection already exists";
+      case TMR_ERROR_LLRP_SENDIO_ERROR:
+        return "LLRP Reader Send Messages failed";
+      case TMR_ERROR_LLRP_RECEIVEIO_ERROR:
+        return "LLRP Reader Receive Messages failed";
+      case TMR_ERROR_LLRP_RECEIVE_TIMEOUT:
+        return "LLRP Reader Receive Messages Timeout";
+      default:
+        {
+          if (NULL == reader)
+            return "Unknown error: Reader reference lost";
+          else
+        return reader->u.llrpReader.errMsg;
+    }
+  }
+  }
+#endif
+
+  switch (status)
+  {
+  case TMR_ERROR_MSG_WRONG_NUMBER_OF_DATA:
+    return "Message command length is incorrect";
+  case TMR_ERROR_INVALID_OPCODE:
+    return "Invalid command opcode";
+  case TMR_ERROR_UNIMPLEMENTED_OPCODE:
+    return "Unimplemented opcode";
+  case TMR_ERROR_MSG_POWER_TOO_HIGH:
+    return "Command attempted to set power above maximum";
+  case TMR_ERROR_MSG_INVALID_FREQ_RECEIVED:
+    return "Command attempted to set an unsupported frequency";
+  case TMR_ERROR_MSG_INVALID_PARAMETER_VALUE:
+    return "Parameter to command is invalid";
+  case TMR_ERROR_MSG_POWER_TOO_LOW:
+    return "Command attempted to set power below minimum";
+  case TMR_ERROR_UNIMPLEMENTED_FEATURE:
+    return "Unimplemented feature";
+  case TMR_ERROR_INVALID_BAUD_RATE:
+    return "Invalid baud rate";
+  case TMR_ERROR_INVALID_REGION:
+    return "Invalid region";
+  case TMR_ERROR_INVALID_LICENSE_KEY:
+    return "The license key code received is invalid";
+  case TMR_ERROR_BL_INVALID_IMAGE_CRC:
+    return "Application image failed CRC check";
+  case TMR_ERROR_BL_INVALID_APP_END_ADDR:
+    return "Application image failed data check";
+  case TMR_ERROR_FLASH_BAD_ERASE_PASSWORD:
+    return "Incorrect password to erase flash sector";
+  case TMR_ERROR_FLASH_BAD_WRITE_PASSWORD:
+    return "Incorrect password to write to flash sector";
+  case TMR_ERROR_FLASH_UNDEFINED_SECTOR:
+    return "Internal error in flash";
+  case TMR_ERROR_FLASH_ILLEGAL_SECTOR:
+    return "Incorrect password to erase or write to flash sector";
+  case TMR_ERROR_FLASH_WRITE_TO_NON_ERASED_AREA:
+    return "Area of flash to write to is not erased";
+  case TMR_ERROR_FLASH_WRITE_TO_ILLEGAL_SECTOR:
+    return "Flash write attempted to cross sector boundary";
+  case TMR_ERROR_FLASH_VERIFY_FAILED:
+    return "Flash verify failed";
+  case TMR_ERROR_NO_TAGS_FOUND:
+    return "No tags found";
+  case TMR_ERROR_NO_PROTOCOL_DEFINED:
+    return "Protocol not set";
+  case TMR_ERROR_INVALID_PROTOCOL_SPECIFIED:
+    return "Specified protocol not supported";
+  case TMR_ERROR_WRITE_PASSED_LOCK_FAILED:
+    return "Lock failed after write operation";
+  case TMR_ERROR_PROTOCOL_NO_DATA_READ:
+    return "No data could be read from a tag";
+  case TMR_ERROR_AFE_NOT_ON:
+    return "AFE not on - reader not sufficiently configured";
+  case TMR_ERROR_PROTOCOL_WRITE_FAILED:
+    return "Tag write operation failed";
+  case TMR_ERROR_NOT_IMPLEMENTED_FOR_THIS_PROTOCOL:
+    return "Operation not supported for this protocol";
+  case TMR_ERROR_PROTOCOL_INVALID_WRITE_DATA:
+    return "Tag ID supplied in write operation is incorrect";
+  case TMR_ERROR_PROTOCOL_INVALID_ADDRESS:
+    return "Invalid address in tag address space";
+  case TMR_ERROR_GENERAL_TAG_ERROR:
+    return "General tag error";
+  case TMR_ERROR_DATA_TOO_LARGE:
+    return "Size specified in read tag data command is too large";
+  case TMR_ERROR_PROTOCOL_INVALID_KILL_PASSWORD:
+    return "Kill password is not correct";
+  case TMR_ERROR_PROTOCOL_KILL_FAILED:
+    return "Kill failed";
+  case TMR_ERROR_PROTOCOL_BIT_DECODING_FAILED:
+    return "Bit decoding failed";
+  case TMR_ERROR_PROTOCOL_INVALID_EPC:
+    return "Invalid EPC provided";
+  case TMR_ERROR_PROTOCOL_INVALID_NUM_DATA:
+    return "Invalid amount of data provided";
+  case TMR_ERROR_GEN2_PROTOCOL_OTHER_ERROR:
+    return "Other Gen2 error";
+  case TMR_ERROR_GEN2_PROTOCOL_MEMORY_OVERRUN_BAD_PC:
+    return "Gen2 memory overrun - bad PC";
+  case TMR_ERROR_GEN2_PROTOCOL_MEMORY_LOCKED:
+    return "Gen2 memory locked";
+  case TMR_ERROR_GEN2_PROTOCOL_INSUFFICIENT_POWER:
+    return "Gen2 tag has insufficent power for operation";
+  case TMR_ERROR_GEN2_PROTOCOL_NON_SPECIFIC_ERROR:
+    return "Gen2 nonspecific error";
+  case TMR_ERROR_GEN2_PROTOCOL_UNKNOWN_ERROR:
+    return "Gen2 unknown error";
+	case TMR_ERROR_GEN2_PROTOCOL_V2_AUTHEN_FAILED:
+		return "Authentication failed with specified key.";
+	case TMR_ERROR_GEN2_PROTOCOL_V2_UNTRACE_FAILED:
+		return "Untrace operation failed.";
+  case TMR_ERROR_AHAL_INVALID_FREQ:
+    return "Invalid frequency";
+  case TMR_ERROR_AHAL_CHANNEL_OCCUPIED:
+    return "Channel occupied";
+  case TMR_ERROR_AHAL_TRANSMITTER_ON:
+    return "Transmitter already on";
+  case TMR_ERROR_ANTENNA_NOT_CONNECTED:
+    return "Antenna not connected";
+  case TMR_ERROR_TEMPERATURE_EXCEED_LIMITS:
+    return "Reader temperature too high";
+  case TMR_ERROR_HIGH_RETURN_LOSS:
+    return "High return loss detected, RF ended to avoid damage";
+  case TMR_ERROR_INVALID_ANTENNA_CONFIG:
+    return "Invalid antenna configuration";
+  case TMR_ERROR_TAG_ID_BUFFER_NOT_ENOUGH_TAGS_AVAILABLE:
+    return "Not enough tag IDs in buffer";
+  case TMR_ERROR_TAG_ID_BUFFER_FULL:
+    return "Tag ID buffer full";
+  case TMR_ERROR_TAG_ID_BUFFER_REPEATED_TAG_ID:
+    return "Tag ID buffer repeated tag ID";
+  case TMR_ERROR_TAG_ID_BUFFER_NUM_TAG_TOO_LARGE:
+    return "Number of tags too large";
+  case TMR_ERROR_SYSTEM_UNKNOWN_ERROR:
+    return "Unknown system error";
+  case TMR_ERROR_TM_ASSERT_FAILED:
+	{
+	  if (NULL == reader)
+	  {
+    return "Assertion failed";
+	  }
+	  else
+	  {
+	    return reader->u.serialReader.errMsg;
+	  }
+	}
+  case TMR_ERROR_BUFFER_OVERFLOW:
+  return "Buffer overflow";
+  case TMR_ERROR_TIMEOUT:
+    return "Timeout";
+  case TMR_ERROR_NO_HOST:
+    return "No matching host found";
+  case TMR_ERROR_LLRP:
+    return "LLRP error";
+  case TMR_ERROR_PARSE:
+    return "Error parsing device response";
+  case TMR_ERROR_DEVICE_RESET:
+    return "Device was reset externally";
+  case TMR_ERROR_CRC_ERROR:
+    return "CRC Error";
+  case TMR_ERROR_INVALID:
+    return "Invalid argument";
+  case TMR_ERROR_UNIMPLEMENTED:
+    return "Unimplemented operation";
+  case TMR_ERROR_NO_ANTENNA:
+    return "No antenna or invalid antenna";
+  case TMR_ERROR_READONLY:
+    return "Value is read-only";
+  case TMR_ERROR_TOO_BIG:
+    return "Value too big";
+  case TMR_ERROR_NO_THREADS:
+    return "Thread initialization failed";
+  case TMR_ERROR_NO_TAGS:
+    return "No tags to be retrieved";
+  case TMR_ERROR_NOT_FOUND:
+    return "Key not found";
+  case TMR_ERROR_FIRMWARE_FORMAT:
+    return "Size or format of firmware image is incorrect";
+  case TMR_ERROR_TRYAGAIN:
+    return "Temporary error, try again";
+  case TMR_ERROR_OUT_OF_MEMORY:
+    return "Out of memory";
+  case TMR_ERROR_UNSUPPORTED:
+    return "Unsupported operation";
+  case TMR_ERROR_INVALID_WRITE_MODE:
+	return "Invalid write mode";
+  case TMR_ERROR_ILLEGAL_VALUE:
+    return "Illegal value";
+  case TMR_ERROR_UNSUPPORTED_READER_TYPE:
+    return "Unsupported reader type";
+  case TMR_ERROR_AUTOREAD_ENABLED:
+    return "Autonomous mode is enabled on reader. Please disable it";
+  case TMR_ERROR_FIRMWARE_UPDATE_ON_AUTOREAD:
+    return "Firmware update is successful. Autonomous mode is already enabled on reader";
+  case TMR_ERROR_TIMESTAMP_NULL:
+    return "Timestamp cannot be null";
+
+  default:
+    {
+      if (NULL == reader)
+        return "Unknown error: Reader reference lost";
+      else
+      {
+#ifdef TMR_ENABLE_LLRP_READER
+        if (TMR_READER_TYPE_LLRP == reader->readerType)
+        {
+          return reader->u.llrpReader.errMsg;
+        }
+        else
+#endif
+        {
+          return reader->u.serialReader.errMsg;
+        }
+      }
+    }
+  }
+}
+
+#endif /* defined(TMR_ENABLE_ERROR_STRINGS) */
diff --git a/cbits/api/tmr_tag_auth.h b/cbits/api/tmr_tag_auth.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_tag_auth.h
@@ -0,0 +1,79 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TMR_TAG_AUTH_H
+#define _TMR_TAG_AUTH_H
+/**
+ *  @file tmr_tag_auth.h
+ *  @brief Mercury API - Tag Authentication 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.
+ */
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include "tmr_gen2.h"
+
+/* 
+ * RFID Authentication structures
+ */
+typedef enum TMR_AuthType
+{
+  TMR_AUTH_TYPE_GEN2_PASSWORD = 0,
+  TMR_AUTH_TYPE_GEN2_DENATRAN_IAV_WRITE_CREDENTIALS = 1,
+  TMR_AUTH_TYPE_GEN2_DENATRAN_IAV_WRITE_SEC_CREDENTIALS = 2,
+} TMR_AuthType;
+
+/**
+ * Authentication data for RFID tag protocols.
+ */
+typedef struct TMR_TagAuthentication
+{
+  /**
+   * The type of authentication data.
+   * Indicates which member of the union is valid.
+   */
+  TMR_AuthType type;
+  union
+  {
+    /** Gen2 authentication data */
+    TMR_GEN2_Password gen2Password;
+    /** Gen2 Denatran IAV write credential */
+    TMR_GEN2_DENATRAN_IAV_WriteCredentials writeCreds;
+    TMR_GEN2_DENATRAN_IAV_WriteSecCredentials writeSecCreds;
+  } u;
+} TMR_TagAuthentication;
+
+TMR_Status TMR_TA_init_gen2(TMR_TagAuthentication *auth,
+                            TMR_GEN2_Password password);
+
+TMR_Status TMR_TA_init_gen2_Denatran_IAV_writeCredentials(TMR_TagAuthentication *auth, uint8_t idLength, uint8_t* tafId, uint8_t len,
+                                                          uint8_t  *data);
+TMR_Status TMR_TA_init_gen2_Denatran_IAV_writeSecCredentials(TMR_TagAuthentication *auth, uint8_t dataLength, uint8_t* data, uint8_t len,
+                                                          uint8_t  *credentials);
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* _TMR_TAG_AUTH_H_ */
diff --git a/cbits/api/tmr_tag_data.h b/cbits/api/tmr_tag_data.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_tag_data.h
@@ -0,0 +1,186 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TMR_TAG_DATA_H
+#define _TMR_TAG_DATA_H
+/**
+ *  @file tmr_tag_data.h  
+ *  @brief Mercury API - Tag and tag read data structures
+ *  @author Brian Fiegel
+ *  @date 5/7/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.
+ */
+
+#include "tmr_tag_protocol.h"
+#include "tmr_gen2.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define TMR_MAX_EPC_BYTE_COUNT (62)
+
+/**
+ * A structure to represent RFID tags.
+ * @ingroup filter
+ */
+typedef struct TMR_TagData
+{
+  /** Tag EPC */
+  uint8_t epc[TMR_MAX_EPC_BYTE_COUNT];
+  /** Protocol of the tag */
+  TMR_TagProtocol protocol;
+  /** Length of the tag's EPC in bytes */
+  uint8_t epcByteCount;
+  /** Tag CRC */
+  uint16_t crc;
+  /** Protocol-specific tag information */
+  union
+  {
+    /** Gen2-specific tag information */
+    TMR_GEN2_TagData gen2;
+  }u;
+} TMR_TagData;
+  
+/**
+ * Convert a hexadecimal string into an array of bytes. The string may
+ * optionally include a "0x" prefix, which will be ignored. 
+ *
+ * @param hex The hexadecimal string to convert.
+ * @param[out] bytes The array to store the converted bytes.
+ * @param size The length of the byte array to store into.
+ * @param[out] convertLen The number of bytes written to the array, or @c NULL.
+ * 
+ * @test If hex string is empty, *bytes should not be altered.
+ * @test *convertLen is set to the correct value.
+ * @test Function works when convertLen is @c NULL.
+ * @test Specific values: @c "00", @c "0000", @c "ffff", @c "0xffff", @c "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899aabb".
+ */
+TMR_Status TMR_hexToBytes(const char *hex, uint8_t *bytes, uint32_t size, 
+                          uint32_t *convertLen);
+
+/**
+ * Convert an array of bytes, such as a tag EPC, into a hexadecimal string.
+ *
+ * @param bytes The byte array to convert.
+ * @param size The length of the byte array to convert.
+ * @param[out] hex The converted hexadecimal string, null-terminated.
+ *
+ * @test If size is 0, *hex should point to an empty string.
+ */
+void TMR_bytesToHex(const uint8_t *bytes, uint32_t size, char *hex);
+
+/**
+ * Defines the constants that may be combined to form the metadata
+ * bitmask argument to the TMR_SR_cmdReadTagSingle,
+ * TMR_SR_cmdReadTagData, and TMR_SR_cmdGetTagBuffer methods.
+ */
+typedef enum TMR_TRD_MetadataFlag
+{
+  TMR_TRD_METADATA_FLAG_NONE      = 0x0000,
+  TMR_TRD_METADATA_FLAG_READCOUNT = 0x0001,
+  TMR_TRD_METADATA_FLAG_RSSI      = 0x0002,
+  TMR_TRD_METADATA_FLAG_ANTENNAID = 0x0004,
+  TMR_TRD_METADATA_FLAG_FREQUENCY = 0x0008,
+  TMR_TRD_METADATA_FLAG_TIMESTAMP = 0x0010,
+  TMR_TRD_METADATA_FLAG_PHASE     = 0x0020,
+  TMR_TRD_METADATA_FLAG_PROTOCOL  = 0x0040,
+  TMR_TRD_METADATA_FLAG_DATA      = 0x0080,
+  TMR_TRD_METADATA_FLAG_GPIO_STATUS = 0x0100,
+  TMR_TRD_METADATA_FLAG_ALL       =                         
+                                       (TMR_TRD_METADATA_FLAG_READCOUNT |
+                                        TMR_TRD_METADATA_FLAG_RSSI      |
+                                        TMR_TRD_METADATA_FLAG_ANTENNAID |
+                                        TMR_TRD_METADATA_FLAG_FREQUENCY |
+                                        TMR_TRD_METADATA_FLAG_TIMESTAMP |
+                                        TMR_TRD_METADATA_FLAG_PHASE |
+                                        TMR_TRD_METADATA_FLAG_PROTOCOL  |
+                                        TMR_TRD_METADATA_FLAG_DATA |
+                                        TMR_TRD_METADATA_FLAG_GPIO_STATUS)
+} TMR_TRD_MetadataFlag;
+
+/**
+ * A class to represent a read of an RFID tag. Provides access to the
+ TMR_TRD_METADATA_FLAG_FREQUENCY tag structure and the metadata of the read event, such as the time
+ * of the read, the antenna that read the tag, and the number of times
+ * the tag was seen by the air protocol.
+ */
+typedef struct TMR_TagReadData
+{
+  /** The tag that was read */
+  TMR_TagData tag;
+  /** The set of metadata items below that are valid */
+  uint16_t metadataFlags;
+  /** Tag response phase */
+  uint16_t phase;
+  /** Antenna where the tag was read */
+  uint8_t antenna;
+  /** State of GPIO pins at the moment of the tag read */ 
+  TMR_GpioPin gpio[16];
+   /** the actual number of available gpio pins on module*/
+  uint8_t gpioCount;
+  /** Number of times the tag was read */
+  uint32_t readCount;
+  /** Strength of the signal received from the tag */
+  int32_t rssi;
+  /** RF carrier frequency the tag was read with */
+  uint32_t frequency;
+  /** Absolute time of the read (32 least-significant bits), in milliseconds since 1/1/1970 UTC */
+  uint32_t timestampLow;
+  /** Absolute time of the read (32 most-significant bits), in milliseconds since 1/1/1970 UTC */
+  uint32_t timestampHigh;
+  /** Data read from the tag */
+  TMR_uint8List data;
+  /** Read EPC bank data bytes */
+  TMR_uint8List epcMemData;
+  /** Read TID bank data bytes */
+  TMR_uint8List tidMemData;
+  /** Read USER bank data bytes */
+  TMR_uint8List userMemData;
+  /** Read RESERVED bank data bytes */
+  TMR_uint8List reservedMemData;
+  /** [PRIVATE] Relative time of the read within the read interval, in microseconds (for internal use only,
+   * this value is used to calculate timestampLow and timestampHigh)
+   **/
+  bool isAsyncRead;
+  uint32_t dspMicros;
+#if TMR_MAX_EMBEDDED_DATA_LENGTH
+  /** Preallocated storage for data */
+  uint8_t _dataList[TMR_MAX_EMBEDDED_DATA_LENGTH];
+  uint8_t _epcMemDataList[TMR_MAX_EMBEDDED_DATA_LENGTH];
+  uint8_t _tidMemDataList[TMR_MAX_EMBEDDED_DATA_LENGTH];
+  uint8_t _userMemDataList[TMR_MAX_EMBEDDED_DATA_LENGTH];
+  uint8_t _reservedMemDataList[TMR_MAX_EMBEDDED_DATA_LENGTH];
+#endif 
+  /** Reader instance, to keep track of tag reads */
+  TMR_Reader *reader;
+} TMR_TagReadData;
+
+TMR_Status TMR_TRD_init(TMR_TagReadData *trd);
+TMR_Status TMR_TRD_init_data(TMR_TagReadData *trd, uint16_t size, uint8_t *buf);
+TMR_Status TMR_TRD_MEMBANK_init_data(TMR_uint8List *data, uint16_t size, uint8_t *buf);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __TAG_DATA_H */
diff --git a/cbits/api/tmr_tag_lock_action.h b/cbits/api/tmr_tag_lock_action.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_tag_lock_action.h
@@ -0,0 +1,77 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TMR_TAG_LOCK_ACTION_H
+#define _TMR_TAG_LOCK_ACTION_H
+/**
+ *  @file tmr_tag_lock_action.h
+ *  @brief Mercury API - Tag Lock Action 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.
+ */
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include "tmr_gen2.h"
+#include "tmr_iso180006b.h"
+
+/**
+ * Types of RFID Tag Locking Structures
+ */
+typedef enum TMR_TagLockActionType
+{
+  TMR_LOCK_ACTION_TYPE_GEN2_LOCK_ACTION       = 0,
+  TMR_LOCK_ACTION_TYPE_ISO180006B_LOCK_ACTION = 1
+} TMR_TagLockActionType;
+
+/**
+ * Tag locking structure
+ */
+typedef struct TMR_TagLockAction
+{
+  /** 
+   * Type of the included locking structure. 
+   * Indicates which member of the union is valid.
+   */
+  TMR_TagLockActionType type;
+  union
+  {
+    /** Gen2 locking data */
+    TMR_GEN2_LockAction gen2LockAction;
+    /** ISO180006B locking data */
+    TMR_IS0180006B_LockAction iso180006bLockAction;
+  } u;
+}TMR_TagLockAction;
+
+TMR_Status TMR_TLA_init_gen2(TMR_TagLockAction *lockAction, uint16_t mask,
+                             uint16_t action);
+
+TMR_Status TMR_TLA_init_ISO180006B(TMR_TagLockAction *lockAction,
+                                   uint8_t address);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* _TMR_TAG_LOCK_ACTION_H_ */
diff --git a/cbits/api/tmr_tag_protocol.h b/cbits/api/tmr_tag_protocol.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_tag_protocol.h
@@ -0,0 +1,70 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TMR_TAG_PROTOCOL_H
+#define _TMR_TAG_PROTOCOL_H
+/**
+ *  @file tmr_tag_protocol.h
+ *  @brief Mercury API - Tag Protocols
+ *  @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.
+ */
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include "tmr_gen2.h"
+#include "tmr_iso180006b.h"
+#include "tmr_ipx.h"
+
+/**
+ * RFID Tag Protocols
+ */
+typedef enum TMR_TagProtocol 
+{
+  TMR_TAG_PROTOCOL_NONE              = 0x00,
+  TMR_TAG_PROTOCOL_ISO180006B        = 0x03,
+  TMR_TAG_PROTOCOL_GEN2              = 0x05,
+  TMR_TAG_PROTOCOL_ISO180006B_UCODE  = 0x06, 
+  TMR_TAG_PROTOCOL_IPX64             = 0x07,
+  TMR_TAG_PROTOCOL_IPX256            = 0x08,
+	TMR_TAG_PROTOCOL_ATA               = 0x1D,
+} TMR_TagProtocol;
+
+/** A list of TMR_Protocol values */
+typedef struct TMR_TagProtocolList
+{
+  /** The array of values */
+  TMR_TagProtocol *list;
+  /** The number of entries there is space for in the array */
+  uint8_t max;
+  /** The number of entries in the list - may be larger than max, indicating truncated data. */
+  uint8_t len;
+} TMR_TagProtocolList;
+
+#ifdef  __cplusplus
+}
+#endif
+
+
+#endif /* _TMR_TAG_PROTOCOL_H_ */
diff --git a/cbits/api/tmr_tagop.h b/cbits/api/tmr_tagop.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_tagop.h
@@ -0,0 +1,1734 @@
+#ifndef _TMR_TAGOP_H
+#define _TMR_TAGOP_H
+/** 
+ *  @file tmr_tagop.h
+ *  @brief Mercury API - Tag Operations Interface
+ *  @author Nathan Williams
+ *  @date 1/8/2010
+ */
+
+/*
+ * 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.
+ */
+#include "tmr_tag_auth.h"
+#include "osdep.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/** The type of a tag operation structure */
+typedef enum TMR_TagOpType
+{
+  /** Gen2 EPC write */
+  TMR_TAGOP_GEN2_WRITETAG,
+  /** Gen2 memory read */
+  TMR_TAGOP_GEN2_READDATA,
+  /** Gen2 memory write */
+  TMR_TAGOP_GEN2_WRITEDATA,
+  /** Gen2 memory lock/unlock */
+  TMR_TAGOP_GEN2_LOCK,
+  /** Gen2 tag kill */
+  TMR_TAGOP_GEN2_KILL,
+  /** Gen2 tag block write */
+  TMR_TAGOP_GEN2_BLOCKWRITE,
+  /** Gen2 tag block permalock */
+  TMR_TAGOP_GEN2_BLOCKPERMALOCK,
+  /** Gen2 tag block erase */
+  TMR_TAGOP_GEN2_BLOCKERASE,
+  /** Higgs2 Partial Load Image */
+  TMR_TAGOP_GEN2_ALIEN_HIGGS2_PARTIALLOADIMAGE,
+  /** Higgs2 Full Load Image */
+  TMR_TAGOP_GEN2_ALIEN_HIGGS2_FULLLOADIMAGE,
+  /** Higgs3 Fast Load Image */
+  TMR_TAGOP_GEN2_ALIEN_HIGGS3_FASTLOADIMAGE,
+  /** Higgs3 Load Image */
+  TMR_TAGOP_GEN2_ALIEN_HIGGS3_LOADIMAGE,
+  /** Higgs3 Block Read Lock */
+  TMR_TAGOP_GEN2_ALIEN_HIGGS3_BLOCKREADLOCK,
+
+  /** NXP set read protect */
+  TMR_TAGOP_GEN2_NXP_SETREADPROTECT,
+  /** NXP reset read protect */
+  TMR_TAGOP_GEN2_NXP_RESETREADPROTECT,
+  /** NXP Change EAS */
+  TMR_TAGOP_GEN2_NXP_CHANGEEAS,
+  /** NXP EAS Alarm */
+  TMR_TAGOP_GEN2_NXP_EASALARM,
+  /** NXP Calibrate */
+  TMR_TAGOP_GEN2_NXP_CALIBRATE,
+  /** NXP ChangeConfig */
+  TMR_TAGOP_GEN2_NXP_CHANGECONFIG,
+
+/** NXP AES Gen2v2 untraceable operations */
+  TMR_TAGOP_GEN2_NXP_UNTRACEABLE,
+  /** NXP AES Gen2v2 Authenticate operations */
+  TMR_TAGOP_GEN2_NXP_AUTHENTICATE,
+  /** NXP AES Gen2v2 ReadBuffer operations */
+  TMR_TAGOP_GEN2_NXP_READBUFFER,
+
+
+  /** Monza4 QT Read/Write*/
+  TMR_TAGOP_GEN2_IMPINJ_MONZA4_QTREADWRITE,
+
+  /** ISO180006B memory read */
+  TMR_TAGOP_ISO180006B_READDATA,
+  /** ISO180006B memory write */
+  TMR_TAGOP_ISO180006B_WRITEDATA,
+  /** ISO180006B memory lock/unlock */
+  TMR_TAGOP_ISO180006B_LOCK,
+  /** ISO180006B tag kill */
+  /** Gen2 Secure read */
+  TMR_TAGOP_GEN2_SECURE_READDATA,
+
+  /** Gen2 IAVDenatran ActivateSecureMode - PA Protocol */
+  TMR_TAGOP_GEN2_DENATRAN_IAV_ACTIVATESECUREMODE,
+  /** Gen2 IAVDenatran Authenticate OBU - PA Protocol */
+  TMR_TAGOP_GEN2_DENATRAN_IAV_AUTHENTICATEOBU,
+  /** Gen2 IAVDenatran GEN2_ACTIVATE_SINIAV_MODE - G0 Protocol */
+  TMR_TAGOP_GEN2_ACTIVATE_SINIAV_MODE,
+  /** Gen2 IAVDenatran GEN2_OBU_AUTH_ID - G0 Protocol */
+  TMR_TAGOP_GEN2_OBU_AUTH_ID,
+  /** Gen2 IAVDenatran GEN2_AUTHENTICATE_OBU_FULL_PASS1 - G0 Protocol */
+  TMR_TAGOP_GEN2_AUTHENTICATE_OBU_FULL_PASS1,
+  /** Gen2 IAVDenatran GEN2_AUTHENTICATE_OBU_FULL_PASS2 - G0 Protocol */
+  TMR_TAGOP_GEN2_AUTHENTICATE_OBU_FULL_PASS2,
+  /** Gen2 IAVDenatran GEN2_OBU_READ_FROM_MEM_MAP - G0 Protocol */
+  TMR_TAGOP_GEN2_OBU_READ_FROM_MEM_MAP,
+  /** Gen2 IAVDenatran GEN2_OBU_WRITE_TO_MEM_MAP - G0 Protocol */
+  TMR_TAGOP_GEN2_OBU_WRITE_TO_MEM_MAP,
+  /** Gen2 IAVDenatran GET_TOKEN_ID - G0 Protocol */
+  TMR_TAGOP_GEN2_DENATRAN_IAV_GET_TOKEN_ID,
+  /** Gen2 IAVDenatran AUTHENTICATE_OBU_FULL_PASS */
+  TMR_TAGOP_GEN2_DENATRAN_IAV_AUTHENTICATE_OBU_FULL_PASS,
+  /** Gen2 IAVDenatran Read Sec - IP63 protocol */
+  TMR_TAGOP_GEN2_DENATRAN_IAV_READ_SEC,
+  /** Gen2 IAVDenatran Write Sec - IP63 protocol */
+  TMR_TAGOP_GEN2_DENATRAN_IAV_WRITE_SEC,
+  /** Gen2 IAVDenatran GEN2_G0_PA_OBU_AUTHENTICATE_ID - ( PA + G0 ) Protocol */
+  TMR_TAGOP_GEN2_DENATRAN_IAV_G0_PA_OBU_AUTHENTICATE_ID,
+  
+  /** Gen2 Ids get sensor type */
+  TMR_TAGOP_GEN2_IDS_SL900A_GETSENSOR,
+  /** Gen2 Ids get log state */
+  TMR_TAGOP_GEN2_IDS_SL900A_GETLOGSTATE,
+  /** Gen2 Ids set log mode */
+  TMR_TAGOP_GEN2_IDS_SL900A_SETLOGMODE,
+  /** Gen2 Ids end log */
+  TMR_TAGOP_GEN2_IDS_SL900A_ENDLOG,
+  /** Gen2 Ids Initialize */
+  TMR_TAGOP_GEN2_IDS_SL900A_INITIALIZE,
+  /** Gen2 Ids Fifo Status */
+  TMR_TAGOP_GEN2_IDS_SL900A_ACCESSFIFOSTATUS,
+  /** Gen2 Ids Fifo Read */
+  TMR_TAGOP_GEN2_IDS_SL900A_ACCESSFIFOREAD,
+  /** Gen2 Ids Fifo write */
+  TMR_TAGOP_GEN2_IDS_SL900A_ACCESSFIFOWRITE,
+  /** Gen2 Ids Starrt Log */
+  TMR_TAGOP_GEN2_IDS_SL900A_STARTLOG,
+  /** Gen2 Ids GetCalibrationData */
+  TMR_TAGOP_GEN2_IDS_SL900A_GETCALIBRATIONDATA,
+  /** Gen2 Ids SetCalibration */
+  TMR_TAGOP_GEN2_IDS_SL900A_SETCALIBRATIONDATA,
+  /** Gen2 Ids SetSfeParameters */
+  TMR_TAGOP_GEN2_IDS_SL900A_SETSFEPARAMETERS,
+  /** Gen2 Ids GetMeasurmentSetup */
+  TMR_TAGOP_GEN2_IDS_SL900A_GETMEASUREMENTSETUP,
+  /** Gen2 Ids GetBattery Level */
+  TMR_TAGOP_GEN2_IDS_SL900A_GETBATTERYLEVEL,
+  /** Gen2 Ids SetLogLimits */
+  TMR_TAGOP_GEN2_IDS_SL900A_SETLOGLIMITS,
+  /** Gen2 Ids SetShelfLife */
+  TMR_TAGOP_GEN2_IDS_SL900A_SETSHELFLIFE,
+  /** Set IDS Password */
+  TMR_TAGOP_GEN2_IDS_SL900A_SETPASSWORD,
+
+
+  /** List of tag operations */
+  TMR_TAGOP_LIST
+} TMR_TagOpType;
+
+/** The type of Gen2 Secure operation  */
+typedef enum SecureTagType
+{
+  GEN2_EMBEDDED_SECURE_DEFAULT = 0x00,
+  /* Alien Higgs 3 secure access */
+  GEN2_EMBEDDED_SECURE_HIGGS3_ACCESS   = (1 << 1),
+  /* Monza 4 secure access */
+  GEN2_EMBEDDED_SECURE_MONZA4_ACCESS   = (1 << 2)
+}SecureTagType;
+ 
+/* The type of Gen2 IAVDenatranCmdEnum */
+typedef enum IAVDenatranSecureTagOpType
+{
+  /* Activate Secure Mode - PA Protocol */
+  GEN2_ACTIVATE_SECURE_MODE  = 0x00,
+  /* Authenticate OBU - PA Protocol */
+  GEN2_AUTHENTICATE_OBU  = 0x01,
+  /* Activate Siniav Mode OBU - G0 Protocol */
+  GEN2_ACTIVATE_SINIAV_MODE = 0x02,
+  /* Authenticate OBU ID - G0 Protocol */
+  GEN2_OBU_AUTH_ID = 0x03,
+  /* Authenticate OBU FullPass1 - G0 Protocol */
+  GEN2_AUTHENTICATE_OBU_FULL_PASS1 = 0x04,
+  /* Authenticate OBU FullPass2 - G0 Protocol */
+  GEN2_AUTHENTICATE_OBU_FULL_PASS2 = 0x05,
+  /* Read From Mem - G0 Protocol */
+  GEN2_OBU_READ_FROM_MEM_MAP = 0x06,
+  /* Write to Mem - G0 Protocol */
+  GEN2_OBU_WRITE_TO_MEM_MAP = 0x07,
+  /* Authenticate OBU FullPass2 - G0 Protocol */
+  GEN2_AUTHENTICATE_OBU_FULL_PASS = 0x08,
+  /* Get token ID - Go Protocol */
+  GEN2_GET_TOKEN_ID = 0x09,
+  /* Read Sec - IP63 Protocol */
+  GEN2_READ_SEC = 0x0A,
+  /* Write Sec - IP63 Protocol */
+  GEN2_WRITE_SEC = 0x0B,
+  /* Pa G0 - (PA + G0) Protocol */
+  GEN2_PA_G0_AUTHENTICATE = 0x0C,
+}IAVDenatranSecureTagOpType;
+
+/* The type of Gen2 secure password  */
+typedef enum SecurePasswordType
+{
+  /* Gen2 password type */
+  TMR_SECURE_GEN2_PASSWORD = 0x01,
+  /* Look up table password */
+  TMR_SECURE_GEN2_LOOKUP_TABLE_PASSWORD = 0x02
+}SecurePasswordType;
+
+/* The fild type of calibration data that user can modify */
+typedef enum CalibrationParameter
+{
+  /* AD1 lower voltage reference - coarse */
+  TMR_GEN2_IDS_SL900A_CALIBRATION_COARSE1,
+  /* AD2 lower voltage reference - coarse */
+  TMR_GEN2_IDS_SL900A_CALIBRATION_COARSE2,
+  /* Switches the lower AD voltage reference to ground */
+  TMR_GEN2_IDS_SL900A_CALIBRATION_GNDSWITCH,
+  /* POR voltage level for 1.5V system */
+  TMR_GEN2_IDS_SL900A_CALIBRATION_SELP12,
+  /* RTC oscillator calibration */
+  TMR_GEN2_IDS_SL900A_CALIBRATION_DF,
+  /* Controlled battery supply for external sensor - the battery voltage is connected to the EXC pin */
+  TMR_GEN2_IDS_SL900A_CALIBRATION_SWEXTEN,
+  /* POR voltage level for 3V system */
+  TMR_GEN2_IDS_SL900A_CALIBRATION_SELP22,
+  /* Voltage level interrupt level for external sensor -- ratiometric */
+  TMR_GEN2_IDS_SL900A_CALIBRATION_IRLEV,
+  /* Excitate for resistive sensors without DC */
+  TMR_GEN2_IDS_SL900A_CALIBRATION_EXCRES,
+}CalibrationParameter;
+
+/* The field type of sfe parameters that user can modify */
+typedef enum SfeParameter
+{
+  /* External sensor 2 range */
+  TMR_GEN2_IDS_SL900A_SFE_RANG,
+  /* External sensor 1 range */
+  TMR_GEN2_IDS_SL900A_SFE_SETI,
+  /* External sensor 1 type */
+  TMR_GEN2_IDS_SL900A_SFE_EXT1,
+  /* External sensor 2 type */
+  TMR_GEN2_IDS_SL900A_SFE_EXT2,
+  /* Use preset range */
+  TMR_GEN2_IDS_SL900A_SFE_AUTORANGEDISABLE,
+  /* Sensor used in limit check */
+  TMR_GEN2_IDS_SL900A_SFE_VERIFYSENSORID,
+}SfeParameter;
+
+typedef struct TMR_TagOp_GEN2_NXP_Tam1Authentication
+{
+	uint8_t Authentication;
+	uint8_t CSI;
+	uint8_t keyID;
+	uint8_t KeyLength;
+	uint8_t IchallengeLength;
+	TMR_uint8List  Key;
+	TMR_uint8List Ichallenge;
+} TMR_TagOp_GEN2_NXP_Tam1Authentication;
+
+typedef struct TMR_TagOp_GEN2_NXP_Tam2Authentication
+{
+	TMR_TagOp_GEN2_NXP_Tam1Authentication tam1Auth;
+	uint16_t Offset;
+	uint8_t ProtMode;
+	uint8_t BlockCount;
+	TMR_NXP_Profile profile;
+} TMR_TagOp_GEN2_NXP_Tam2Authentication;
+
+typedef enum TMR_GEN2_UNTRACEABLE_AuthType
+{
+	/* Tag exposes EPC memory */
+	UNTRACEABLE_WITH_AUTHENTICATION = 0,
+	/*Tag untraceably hides EPC memory above that*/
+	UNTRACEABLE_WITH_ACCESS = 1
+
+}TMR_GEN2_UNTRACEABLE_AuthType;
+typedef struct TMR_TagOp_GEN2_NXP_UNTRACEABLE_Authentication
+{   
+	TMR_GEN2_UNTRACEABLE_AuthType authType;
+	TMR_TagOp_GEN2_NXP_Tam1Authentication tam1Auth;
+	TMR_GEN2_Password accessPassword;
+
+}TMR_TagOp_GEN2_NXP_UNTRACEABLE_Authentication;
+
+typedef struct TMR_TagOp_GEN2_NXP_Untraceable
+{
+	TMR_TagOp_GEN2_NXP_UNTRACEABLE_Authentication auth; 
+	TMR_GEN2_UNTRACEABLE_Epc epc;
+	int32_t epcLength;
+	TMR_GEN2_UNTRACEABLE_Tid tid;
+	TMR_GEN2_UNTRACEABLE_UserMemory userMemory;
+	TMR_GEN2_UNTRACEABLE_Range range;
+	uint8_t subCommand;
+
+} TMR_TagOp_GEN2_NXP_Untraceable;
+
+typedef enum TMR_GEN2_AUTHENTICATE_Type
+{
+	TAM1_AUTHENTICATION,
+	TAM2_AUTHENTICATION
+}TMR_GEN2_AUTHENTICATE_Type;
+
+typedef struct TMR_TagOp_GEN2_NXP_Authenticate
+{
+	TMR_GEN2_AUTHENTICATE_Type type;
+	TMR_TagOp_GEN2_NXP_Tam1Authentication tam1Auth;
+	TMR_TagOp_GEN2_NXP_Tam2Authentication tam2Auth;
+	uint8_t subCommand;
+}TMR_TagOp_GEN2_NXP_Authenticate;
+
+typedef struct TMR_TagOp_GEN2_NXP_Readbuffer
+{
+	uint16_t wordPointer;
+	uint16_t bitCount;
+	TMR_TagOp_GEN2_NXP_Authenticate authenticate;
+
+}TMR_TagOp_GEN2_NXP_Readbuffer;
+
+/** Parameters of a Gen2 EPC write operation */
+typedef struct TMR_TagOp_GEN2_WriteTag
+{
+  /** Tag EPC */
+  TMR_TagData* epcptr;
+} TMR_TagOp_GEN2_WriteTag;
+
+/** Parameters of a Gen2 memory read operation */
+typedef struct TMR_TagOp_GEN2_ReadData
+{
+  /** Gen2 memory bank to read from */
+  TMR_GEN2_Bank bank;
+  /** Word address to start reading at */
+  uint32_t wordAddress;
+  /** Number of words to read */
+  uint8_t len;
+} TMR_TagOp_GEN2_ReadData;
+
+/** Parameters of Gen2 Secure operation */
+
+/* Parameters of SecurePassWordLookup Table */
+typedef struct SecurePasswordLookup
+{
+  /* used in case Gen2 passWord */
+  TMR_TagAuthentication gen2PassWord;
+
+  /* used in case of password look table */
+  /* Number of bits used to address the AP list (MSB byte - byte 4) */
+  uint8_t secureAddressLength;
+  /* EPC word offset (Next MSB byte - byte 3) */
+  uint8_t secureAddressOffset;
+  /*  User flash offset, starting from 0x0000 (LSB 2 bytes) */
+   uint16_t secureFlashOffset;
+} SecurePasswordLookup;
+
+typedef struct TMR_TagOp_GEN2_SecureReadData
+{
+  /** Gen2 read operation */
+  TMR_TagOp_GEN2_ReadData readData;
+
+  /** type of Gen2 Secure operation*/
+  /* Options to select Alien Higgs 3 secure access and Monza 4 secure access */
+  SecureTagType type;
+  /* option to select Gen2 password or look up table password */
+  SecurePasswordType passwordType;
+  /* Options to specify the password */
+  SecurePasswordLookup password;
+ } TMR_TagOp_GEN2_SecureReadData;
+
+/** Parameters of a Gen2 memory write operation */
+typedef struct TMR_TagOp_GEN2_WriteData
+{
+  /** Gen2 memory bank to write to */
+  TMR_GEN2_Bank bank;
+  /** Word address to start writing at */
+  uint32_t wordAddress;
+  /** Data to write */
+  TMR_uint16List data;
+} TMR_TagOp_GEN2_WriteData;
+
+/** Parameters of a Gen2 memory lock/unlock operation */
+typedef struct TMR_TagOp_GEN2_Lock
+{ 
+  /** Bitmask indicating which lock bits to change */
+  uint16_t mask;
+  /** New values of each bit specified in the mask */
+  uint16_t action;
+  /** Access Password to use to lock the tag*/
+  TMR_GEN2_Password accessPassword;
+} TMR_TagOp_GEN2_Lock;
+
+/** Parameters of a Gen2 tag kill operation */
+typedef struct TMR_TagOp_GEN2_Kill
+{
+  /** Kill password to use to kill the tag */
+  TMR_GEN2_Password password;
+} TMR_TagOp_GEN2_Kill;
+
+/** Parameters of a Gen2 tag Block Write operation */
+typedef struct TMR_TagOp_GEN2_BlockWrite
+{
+  /** Gen2 memory bank to write to */
+  TMR_GEN2_Bank bank; 
+  /** The word address to start writing to */
+  uint32_t wordPtr; 
+  /** The data to write */
+  TMR_uint16List data; 
+}TMR_TagOp_GEN2_BlockWrite;
+
+/** Parameters of a Gen2 tag Block PermaLock operation */
+typedef struct TMR_TagOp_GEN2_BlockPermaLock
+{
+  /** Read lock status or write it? */
+  uint8_t readLock; 
+  /** Gen2 memory bank to lock */
+  TMR_GEN2_Bank bank; 
+  /** The starting word address to lock */
+  uint32_t blockPtr;
+  /** Mask: Which blocks to lock? */
+  TMR_uint16List mask;
+}TMR_TagOp_GEN2_BlockPermaLock;
+
+/** Parameters of a Gen2 tag Block Erase operation */
+typedef struct TMR_TagOp_GEN2_BlockErase
+{
+  /** Gen2 memory bank to erase */
+  TMR_GEN2_Bank bank;
+  /** The starting word address for block erase */
+  uint32_t wordPtr;
+  /** Number of words to erase */
+  uint8_t wordCount;
+} TMR_TagOp_GEN2_BlockErase;
+
+/** Parameters of a Gen2 memory lock/unlock operation */
+typedef struct TMR_TagOp_ISO180006B_Lock
+{ 
+  /** The memory address of the byte to lock */
+  uint8_t address;
+} TMR_TagOp_ISO180006B_Lock;
+
+/** Parameters of an ISO180006B memory read operation */
+typedef struct TMR_TagOp_ISO180006B_ReadData
+{
+  /** Byte address to start reading at */
+  uint8_t byteAddress;
+  /** Number of bytes to read */
+  uint8_t len;
+} TMR_TagOp_ISO180006B_ReadData;
+
+/** Parameters of an ISO180006B memory write operation */
+typedef struct TMR_TagOp_ISO180006B_WriteData
+{
+  /** Byte address to start writing at */
+  uint8_t byteAddress;
+  /** Data to write */
+  TMR_uint8List data;
+} TMR_TagOp_ISO180006B_WriteData;
+
+/**
+ *  Tagops for Gen2 custom commands
+ **/
+
+/** Parameters for Alien Higgs2, Partial Load Image command*/
+typedef struct TMR_TagOp_GEN2_Alien_Higgs2_PartialLoadImage
+{
+  /** Kill password to write to the tag */
+  TMR_GEN2_Password killPassword;
+  /** Access password to write to the tag */
+  TMR_GEN2_Password accessPassword;
+  /** Tag EPC to write to the tag*/
+  TMR_TagData* epcptr;
+} TMR_TagOp_GEN2_Alien_Higgs2_PartialLoadImage;
+
+/** Parameters for Alien Higgs2, Full Load Image command*/
+typedef struct TMR_TagOp_GEN2_Alien_Higgs2_FullLoadImage
+{
+  /** Kill password to write to the tag */
+  TMR_GEN2_Password killPassword;
+  /** Access password to write to the tag */
+  TMR_GEN2_Password accessPassword;
+  /** Lock Bits */
+  uint16_t lockBits;
+  /** PC word */
+  uint16_t pcWord;
+  /** Tag EPC to write to the tag*/
+  TMR_TagData* epcptr;
+} TMR_TagOp_GEN2_Alien_Higgs2_FullLoadImage;
+
+/** Parameters for Alien Higgs3, Fast Load Image command*/
+typedef struct TMR_TagOp_GEN2_Alien_Higgs3_FastLoadImage
+{
+  /** Access password used to write to the tag */
+  TMR_GEN2_Password currentAccessPassword;
+  /** Kill password to write to the tag */
+  TMR_GEN2_Password killPassword;
+  /** Access password to write to the tag */
+  TMR_GEN2_Password accessPassword;
+  /** PC word */
+  uint16_t pcWord;
+  /** Tag EPC to write to the tag*/
+  TMR_TagData* epcptr;
+} TMR_TagOp_GEN2_Alien_Higgs3_FastLoadImage;
+
+
+/** Parameters for Alien Higgs3, Load Image command*/
+typedef struct TMR_TagOp_GEN2_Alien_Higgs3_LoadImage
+{
+  /** Access password used to write to the tag */
+  TMR_GEN2_Password currentAccessPassword;
+  /** Kill password to write to the tag */
+  TMR_GEN2_Password killPassword;
+  /** Access password to write to the tag */
+  TMR_GEN2_Password accessPassword;
+  /** PC word */
+  uint16_t pcWord;
+  /** Tag EPC and user data to write to the tag (76 bytes)*/
+  TMR_uint8List *epcAndUserData;
+} TMR_TagOp_GEN2_Alien_Higgs3_LoadImage;
+
+/** Parameters for Alien Higgs3, Block Read Lock command*/
+typedef struct TMR_TagOp_GEN2_Alien_Higgs3_BlockReadLock
+{
+  /** Access password to use to write to the tag, in case if the tag is already locked */
+  TMR_GEN2_Password accessPassword;
+  /** A bitmask of bits to lock */
+  uint8_t lockBits;
+} TMR_TagOp_GEN2_Alien_Higgs3_BlockReadLock;
+
+/** Parameters for NXP, Set Read Protect command */
+typedef struct TMR_TagOp_GEN2_NXP_SetReadProtect
+{
+  /** Access password to use to write to the tag */
+  TMR_GEN2_Password accessPassword;
+}TMR_TagOp_GEN2_NXP_SetReadProtect;
+
+/** Parameters for NXP, Reset Read Protect Command*/
+typedef struct TMR_TagOp_GEN2_NXP_ResetReadProtect
+{
+  /** Access password to use to write to the tag */
+  TMR_GEN2_Password accessPassword;
+} TMR_TagOp_GEN2_NXP_ResetReadProtect;
+
+/** Parameters for NXP, Change EAS Command*/
+typedef struct TMR_TagOp_GEN2_NXP_ChangeEAS
+{
+  /** Access password to use to write to the tag */
+  TMR_GEN2_Password accessPassword;
+  /** Reset or set EAS bit */
+  bool reset;
+} TMR_TagOp_GEN2_NXP_ChangeEAS;
+
+/** Parameters for NXP, EAS alarm command */
+typedef struct TMR_TagOp_GEN2_NXP_EASAlarm
+{
+  /** Gen2 divide ratio to use */
+  TMR_GEN2_DivideRatio dr;
+  /** Gen2 M parameter to use */
+  TMR_GEN2_TagEncoding m;
+  /** Gen2 TrExt value to use */
+  TMR_GEN2_TrExt trExt;  
+} TMR_TagOp_GEN2_NXP_EASAlarm;
+
+/** Parameters for NXP, Calibration command */
+typedef struct TMR_TagOp_GEN2_NXP_Calibrate
+{
+  /** Access password to use to write to the tag */
+  TMR_GEN2_Password accessPassword;
+} TMR_TagOp_GEN2_NXP_Calibrate;
+
+/** Parameters for NXP, Change Config command */
+typedef struct TMR_TagOp_GEN2_NXP_ChangeConfig
+{
+  /** Access password to use to write to the tag */
+  TMR_GEN2_Password accessPassword;
+  /** ConfigWord to write to the tag*/
+  TMR_NXP_ConfigWord configWord;
+}TMR_TagOp_GEN2_NXP_ChangeConfig;
+
+/** Parameters for NXP, Change Config command */
+typedef struct TMR_TagOp_GEN2_Impinj_Monza4_QTReadWrite
+{
+  /** Access password to use to write to the tag */
+  TMR_GEN2_Password accessPassword;
+  /** Control Byte to write to the tag*/
+  TMR_Monza4_ControlByte controlByte;
+  /** Payload */
+  TMR_Monza4_Payload payload;    
+}TMR_TagOp_GEN2_Impinj_Monza4_QTReadWrite;
+ 
+/** Parameters for IAV, ActivateSecureMode command */
+typedef struct TMR_TagOp_GEN2_Denatran_IAV_Activate_Secure_Mode
+{
+  /* Enum for IAV tagoperation */
+  IAVDenatranSecureTagOpType mode;
+  /* RFU field */
+  uint8_t payload;
+}TMR_TagOp_GEN2_Denatran_IAV_Activate_Secure_Mode;
+
+/** Parameters for IAV, AuthenticateOBU command */
+typedef struct TMR_TagOp_GEN2_Denatran_IAV_Authenticate_OBU
+{
+  /* Enum for IAV tagoperation */
+  IAVDenatranSecureTagOpType mode;
+  /* RFU field */
+  uint8_t payload;
+}TMR_TagOp_GEN2_Denatran_IAV_Authenticate_OBU;
+
+/** Parameters for IAV, Activate_Siniav_Mode command - G0 Protocol */
+typedef struct TMR_TagOp_GEN2_Denatran_IAV_Activate_Siniav_Mode
+{
+  /* Enum for IAV tagoperation */
+  IAVDenatranSecureTagOpType mode;
+  /* RFU field */
+  uint8_t payload;
+  /* token desc */
+  bool isTokenDesc;
+  /* 64 bits of token data */
+  uint8_t token[8];
+}TMR_TagOp_GEN2_Denatran_IAV_Activate_Siniav_Mode;
+
+/** Parameters for IAV, OBU_Auth_ID command - G0 Protocol */
+typedef struct TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_ID
+{
+  /* Enum for IAV tagoperation */
+  IAVDenatranSecureTagOpType mode;
+  /* RFU field */
+  uint8_t payload;
+}TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_ID;
+
+/** Parameters for IAV, OBU_Auth_Full_Pass1 command - G0 Protocol */
+typedef struct TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass1
+{
+  /* Enum for IAV tagoperation */
+  IAVDenatranSecureTagOpType mode;
+  /* RFU field */
+  uint8_t payload;
+}TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass1;
+
+/** Parameters for IAV,  OBU_Auth_Full_Pass2 command - G0 Protocol */
+typedef struct TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass2
+{
+  /* Enum for IAV tagoperation */
+  IAVDenatranSecureTagOpType mode;
+  /* RFU field */
+  uint8_t payload;
+}TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass2;
+
+/** Parameters for IAV,  OBU_ReadFromMemMap command - G0 Protocol */
+typedef struct TMR_TagOp_GEN2_Denatran_IAV_OBU_ReadFromMemMap
+{
+  /* Enum for IAV tagoperation */
+  IAVDenatranSecureTagOpType mode;
+  /* RFU field */
+  uint8_t payload;
+  /* address to be read from USER bank */
+  uint16_t readPtr;
+}TMR_TagOp_GEN2_Denatran_IAV_OBU_ReadFromMemMap;
+
+/** Parameters for IAV, read sec  command - IP63 Protocol */
+typedef struct TMR_TagOp_GEN2_Denatran_IAV_Read_Sec
+{
+  /* Enum for IAV tagoperation */
+  IAVDenatranSecureTagOpType mode;
+  /* RFU field */
+  uint8_t payload;
+  /* address to be read from USER bank */
+  uint16_t readPtr;
+}TMR_TagOp_GEN2_Denatran_IAV_Read_Sec;
+
+/** Parameters for IAV,  OBU_WriteToMemMap command - G0 Protocol */
+typedef struct TMR_TagOp_GEN2_Denatran_IAV_OBU_WriteToMemMap
+{
+  /* Enum for IAV tagoperation */
+  IAVDenatranSecureTagOpType mode;
+  /* RFU field */
+  uint8_t payload;
+  /* Pointer to the USER data */
+  uint16_t writePtr;
+  /* data to be written */
+  uint16_t wordData;
+  /* Tag ID */
+  uint8_t* tagIdentification;
+  /* Credentials written word */
+  uint8_t* dataBuf;  
+}TMR_TagOp_GEN2_Denatran_IAV_OBU_WriteToMemMap;
+
+/** Parameters for IAV,  write sec command - IP63 Protocol */
+typedef struct TMR_TagOp_GEN2_Denatran_IAV_Write_Sec
+{
+  /* Enum for IAV tagoperation */
+  IAVDenatranSecureTagOpType mode;
+  /* RFU field */
+  uint8_t payload;
+  /* data words */
+  uint8_t* dataWords;
+  /* Credentials written word */
+  uint8_t* dataBuf;
+}TMR_TagOp_GEN2_Denatran_IAV_Write_Sec;
+
+/** Parameters for IAV, Get Token ID command */
+typedef struct TMR_TagOp_GEN2_Denatran_IAV_Get_Token_Id
+{
+  /* Enum for IAV tagoperation */
+  IAVDenatranSecureTagOpType mode;
+}TMR_TagOp_GEN2_Denatran_IAV_Get_Token_Id;
+
+/** Parameters for IAV, Authenticate OBU Full Pass */
+typedef struct TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass
+{
+  /* Enum for IAV tagoperation */
+  IAVDenatranSecureTagOpType mode;
+  /* RFU field */
+  uint8_t payload;
+}TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass;
+
+/** Parameters for IAV, G0_PA_OBU_Auth_ID */
+typedef struct TMR_TagOp_GEN2_Denatran_IAV_G0_PA_OBU_Auth_ID
+{
+  /* Enum for IAV tagoperation */
+  IAVDenatranSecureTagOpType mode;
+  /* RFU field */
+  uint8_t payload;
+}TMR_TagOp_GEN2_Denatran_IAV_G0_PA_OBU_Auth_ID;
+
+/* Forward declaration for the benefit of TMR_TagOp_List */
+typedef struct TMR_TagOp TMR_TagOp;
+
+/** List of tag operations */
+typedef struct TMR_TagOp_List
+{
+  /** Array of pointers to tag operations*/
+  TMR_TagOp **list;
+  /** Number of tag operations in list */
+  uint16_t len;
+} TMR_TagOp_List;
+
+/** Sub-class for Gen2 Alien Higgs2 custom tag extensions */
+typedef struct TMR_TagOp_GEN2_Alien_Higgs2
+{
+  union
+  {
+    TMR_TagOp_GEN2_Alien_Higgs2_PartialLoadImage partialLoadImage;
+    TMR_TagOp_GEN2_Alien_Higgs2_FullLoadImage fullLoadImage;
+  } u;
+}TMR_TagOp_GEN2_Alien_Higgs2;
+
+/** Sub-class for Gen2 Alien Higgs3 custom tag extensions */
+typedef struct TMR_TagOp_GEN2_Alien_Higgs3
+{
+  union
+  {
+    TMR_TagOp_GEN2_Alien_Higgs3_FastLoadImage fastLoadImage;
+    TMR_TagOp_GEN2_Alien_Higgs3_LoadImage loadImage;
+    TMR_TagOp_GEN2_Alien_Higgs3_BlockReadLock blockReadLock;
+  } u;
+}TMR_TagOp_GEN2_Alien_Higgs3;
+
+/** Sub-class for Gen2 Alien custom tag extensions */
+typedef struct TMR_TagOp_GEN2_Alien
+{
+  union
+  {
+    TMR_TagOp_GEN2_Alien_Higgs2 higgs2;
+    TMR_TagOp_GEN2_Alien_Higgs3 higgs3;
+  } u;
+}TMR_TagOp_GEN2_Alien;
+
+/** Sub-class for Gen2 NXP custom tag extensions */
+typedef struct TMR_TagOp_GEN2_NXP
+{
+  union
+  {
+    TMR_TagOp_GEN2_NXP_SetReadProtect setReadProtect;
+    TMR_TagOp_GEN2_NXP_ResetReadProtect resetReadProtect;
+    TMR_TagOp_GEN2_NXP_ChangeEAS changeEAS;
+    TMR_TagOp_GEN2_NXP_EASAlarm EASAlarm;
+    TMR_TagOp_GEN2_NXP_Calibrate calibrate;
+    TMR_TagOp_GEN2_NXP_ChangeConfig changeConfig;
+	TMR_TagOp_GEN2_NXP_Untraceable untraceable;
+	TMR_TagOp_GEN2_NXP_Authenticate authenticate;
+	TMR_TagOp_GEN2_NXP_Readbuffer readBuffer;
+  }u;
+}TMR_TagOp_GEN2_NXP;
+
+/** Sub-class for Gen2 Impinj Monza4 custom tag extensions */
+typedef struct TMR_TagOp_GEN2_Impinj_Monza4
+{
+  union
+  {
+    TMR_TagOp_GEN2_Impinj_Monza4_QTReadWrite qtReadWrite;
+  } u;
+}TMR_TagOp_GEN2_Impinj_Monza4;
+
+/** Sub-class for Gen2 Impinj custom tag extensions */
+typedef struct TMR_TagOp_GEN2_Impinj
+{
+  union
+  {
+    TMR_TagOp_GEN2_Impinj_Monza4 monza4;
+  } u;
+}TMR_TagOp_GEN2_Impinj;
+
+/** Sub-class for Gen2 IavDenatran custom tag extensions */
+typedef struct TMR_TagOp_GEN2_Denatran
+{
+  union
+  {
+    TMR_TagOp_GEN2_Denatran_IAV_Activate_Secure_Mode secureMode;
+    TMR_TagOp_GEN2_Denatran_IAV_Authenticate_OBU authenticateOBU;
+    TMR_TagOp_GEN2_Denatran_IAV_Activate_Siniav_Mode activateSiniavMode;
+    TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_ID obuAuthId;
+    TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass1 obuAuthFullPass1;
+    TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass2 obuAuthFullPass2;
+    TMR_TagOp_GEN2_Denatran_IAV_OBU_ReadFromMemMap obuReadFromMemMap;
+    TMR_TagOp_GEN2_Denatran_IAV_OBU_WriteToMemMap obuWriteToMemMap;
+    TMR_TagOp_GEN2_Denatran_IAV_Get_Token_Id getTokenId;
+    TMR_TagOp_GEN2_Denatran_IAV_Read_Sec readSec;
+    TMR_TagOp_GEN2_Denatran_IAV_Write_Sec writeSec;
+    TMR_TagOp_GEN2_Denatran_IAV_OBU_Auth_Full_Pass obuAuthFullPass;
+    TMR_TagOp_GEN2_Denatran_IAV_G0_PA_OBU_Auth_ID g0paobuauthid;
+  } u;
+}TMR_TagOp_GEN2_Denatran;
+
+/** Sensor type for IDS Sl900A chip */
+typedef enum Sensor
+{
+  /* SL900A sensor type values */
+  TMR_GEN2_IDS_SL900A_SENSOR_TEMP  = 0x00,
+  TMR_GEN2_IDS_SL900A_SENSOR_EXT1  = 0x01,
+  TMR_GEN2_IDS_SL900A_SENSOR_EXT2  = 0x02,
+  TMR_GEN2_IDS_SL900A_SENSOR_BATTV = 0x03,
+}Sensor;
+
+/** SL900A password access level values */
+typedef enum PasswordLevel
+{
+  /* No access to any protected area */
+  TMR_GEN2_IDS_SL900A_PASSWORD_NOT_ALLOWED = 0x00,
+  /* System area access */
+  TMR_GEN2_IDS_SL900A_PASSWORD_SYSTEM = 0x01,
+  /* Application area access */
+  TMR_GEN2_IDS_SL900A_PASSWORD_APPLICATION = 0x02,
+  /* Measurement area access */
+  TMR_GEN2_IDS_SL900A_PASSWORD_MEASUREMENT = 0x03,
+}PasswordLevel;
+
+/** SL900A Data log format selection */
+typedef enum LoggingForm
+{
+  /* Dense Logging */
+  TMR_GEN2_IDS_SL900A_LOGGINGFORM_DENSE = 0x00,
+  /* Log values outside specified limits */
+  TMR_GEN2_IDS_SL900A_LOGGINGFORM_OUTOFLIMITS = 0x01,
+  /* Log values at limit crossing points */
+  TMR_GEN2_IDS_SL900A_LOGGINGFORM_LIMITSCROSSING = 0x03,
+  /* Trigger log on EXT1 input */
+  TMR_GEN2_IDS_SL900A_LOGGINGFORM_IRQ1 = 0x05,
+  /* Trigger log on EXT2 input */
+  TMR_GEN2_IDS_SL900A_LOGGINGFORM_IRQ2 = 0x06,
+  /* Trigger log on EXT1 and EXT2 input */
+  TMR_GEN2_IDS_SL900A_LOGGINGFORM_IRQ1IRQ2 = 0x07,
+}LoggingForm;
+
+/** SL900A Data log memory-full behavior */
+typedef enum DelayMode
+{
+  /* Start logging after delay time */
+  TMR_GEN2_IDS_SL900A_DELAYMODE_TIMER = 0x00,
+  /* Start logging on external input */
+  TMR_GEN2_IDS_SL900A_DELAYMODE_EXTSWITCH = 0x01,
+}DelayMode;
+
+/** SL900A Logging memory-full behavior */
+typedef enum StorageRule
+{
+  /* Stop logging when memory fills */
+  TMR_GEN2_IDS_SL900A_STORAGERULE_NORMAL = 0x00,
+  /*  Roll around (circular buffer) when memory fills */
+  TMR_GEN2_IDS_SL900A_STORAGERULE_ROLLING = 0x01,
+}StorageRule;
+
+/** Sub-Class for BatterType, re-check or default */
+typedef enum BatteryType
+{
+  /* Default */
+  TMR_GEN2_IDS_SL900A_BATTERYTYPE_CHECK = 0x00,
+  /* Application requested for the re-check of battery type */
+  TMR_GEN2_IDS_SL900A_BATTERYTYPE_RECHECK = 0x01,
+}BatteryType;
+
+/** Sub-Class for Raw 9 or 21-bit Get Log State reply */
+typedef struct LimitCounter
+{
+  /* Number of times selected sensor has gone beyond extreme lower limit */
+  uint8_t extremeLower;
+  /* Number of times selected sensor has gone beyond lower limit */
+  uint8_t lower;
+  /* Number of times selected sensor has gone beyond upper limit */
+  uint8_t upper;
+  /* Number of times selected sensor has gone beyond extreme upper limit */
+  uint8_t extremeUpper;
+}LimitCounter;
+
+/** Sub-Class for  specifying 40 bit LogLimits Value */
+typedef struct LogLimits
+{
+  /* Specifying the extreme lower limit */
+  uint16_t extremeLower;
+  /* Specifying the lower limit */
+  uint16_t lower;
+  /* Specifying the upper limit */
+  uint16_t upper;
+  /* Specifying the extreme upper limit */
+  uint16_t extremeUpper;
+}LogLimits;
+
+/** Sub-class for SystemStatus reply object */
+typedef struct SystemStatus
+{
+  /* Measurement Address Pointer */
+  uint16_t MeasurementAddressPointer;
+  /* Number of memory replacements */
+  uint8_t NumMemReplacements;
+  /* Number of measurements */
+  uint16_t NumMeasurements;
+  /* Active */
+  bool Active;
+}SystemStatus;
+
+/** Sub-Class for Log Status Flags */
+typedef struct StatusFlags
+{
+  /* Logging active */
+  bool Active;
+  /* Measurement area full */
+  bool Full;
+  /* Measurement overwritten */
+  bool Overwritten;
+  /* A/D error occurred */
+  bool ADError;
+  /* Low battery */
+  bool LowBattery;
+  /* Shelf life low error */
+  bool ShelfLifeLow;
+  /* Shelf life high error */
+  bool ShelfLifeHigh;
+  /* ShelfLifeExpired */
+  bool ShelfLifeExpired;
+}StatusFlags;
+/** Sub-class for get log state value reply */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_LogState
+{
+  /* Number of excursions beyond set limits */
+  LimitCounter limitCount;
+  /* Logging system status */
+  SystemStatus statStatus;
+  /* Logging status flags */
+  StatusFlags  statFlag;
+}TMR_TagOp_GEN2_IDS_SL900A_LogState;
+
+/** Sub-Class for Get Sensor Value reply */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_SensorReading
+{
+  /* Raw 16-bit response from GetSensorValue command */
+  uint16_t reply;
+  /* Raw sensor reply */
+  uint16_t Raw;
+  /* Did A/D conversion error occur? */
+  bool ADError;
+  /* 5-bit Range/Limit value */
+  uint8_t RangeLimit;
+  /* 10-bit Sensor value */
+  uint16_t Value;
+}TMR_TagOp_GEN2_IDS_SL900A_SensorReading;
+
+/** Sub-Class for Get Battery Level Reply */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_BatteryLevelReading
+{
+  /* Raw 16-bit response from GetBatteryLevel command */
+  uint16_t reply;
+  /* Did A/D conversion error occur? */
+  bool ADError;
+  /* 1-bit Battery Type */
+  uint8_t BatteryType;
+  /* 10-bit Battery Level value */
+  uint16_t Value;
+}TMR_TagOp_GEN2_IDS_SL900A_BatteryLevelReading;
+
+/** Sub-class for  SL900A  Log Mode Data */
+typedef struct LogModeData
+{
+  /* Raw 8-bit response from Measurement Setup Data command */
+  uint8_t Raw;
+  /* Logging Format */
+  LoggingForm Form;
+  /* Log Memory-Full Behavior */
+  StorageRule Storage;
+  /* Enable log for EXT1 external sensor */
+  bool Ext1Enable;
+  /* Enable log for EXT2 external sensor */
+  bool Ext2Enable;
+  /* Enable log for temperature sensor */
+  bool TempEnable;
+  /* Enable log for battery sensor */
+  bool BattEnable;
+}LogModeData;
+
+/** Sub-class for Calibration Data */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_CalibrationData
+{
+  /* Raw 56-bit Calibration data value */
+  uint64_t raw;
+  /* AD1 lower voltage reference - fine - DO NOT MODIFY */
+  uint8_t Ad1;
+  /* AD1 lower voltage reference - coarse */
+  uint8_t Coarse1;
+  /* AD2 lower voltage reference - fine - DO NOT MODIFY */
+  uint8_t Ad2;
+  /* AD2 lower voltage reference - coarse */
+  uint8_t Coarse2;
+  /* Switches the lower AD voltage reference to ground */
+  bool GndSwitch;
+  /* POR voltage level for 1.5V system */
+  uint8_t Selp12;
+  /* Main reference voltage calibration -- DO NOT MODIFY */
+  uint8_t Adf;
+  /* RTC oscillator calibration */
+  uint8_t Df;
+  /* Controlled battery supply for external sensor - the battery voltage is connected to the EXC pin */
+  bool SwExtEn;
+  /* POR voltage level for 3V system */
+  uint8_t Selp22;
+  /* Voltage level interrupt level for external sensor -- ratiometric */
+  uint8_t Irlev;
+  /* Main system clock oscillator calibration -- DO NOT MODIFY */
+  uint8_t RingCal;
+  /* Temperature conversion offset calibration -- DO NOT MODIFY */
+  uint8_t  OffInt;
+  /* Bandgap voltage temperature coefficient calibration -- DO NOT MODIFY */
+  uint8_t Reftc;
+  /* Excitate for resistive sensors without DC */
+  bool ExcRes;
+  /*  Reserved for Future Use */
+  uint8_t RFU;
+  /* Specifyes the field user can modify */
+  CalibrationParameter type;
+}TMR_TagOp_GEN2_IDS_SL900A_CalibrationData;
+
+/** Sub-class to specify Sensor Front End Parameters */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_SfeParameters
+{
+  /*  Raw 16-bit SFE parameters value */
+  uint16_t raw;
+  /* External sensor 2 range */
+  uint8_t Rang;
+  /* External sensor 1 range */
+  uint8_t Seti;
+  /** 
+   * External sensor 1 type
+   * 00 -- linear resistive sensor
+   * 01 -- high impedance input (voltage follower), bridge
+   * 10 -- capacitive sensor with DC
+   * 11 -- capacitive or resistive sensor without DC
+   */
+  uint8_t Ext1;
+  /**
+   * External sensor 2 type
+   * 00 -- linear conductive sensor
+   * 01 -- high impedance input (voltage follower), bridge
+   */
+  uint8_t Ext2;
+  /* Use preset range */
+  bool AutorangeDisable;
+  /**
+   * Sensor used in limit check
+   * 00 - first selected sensor
+   * 01 -- second selected sensor
+   * 10 -- third selected sensor
+   * 11 -- fourth selected sensor
+   */
+  uint8_t VerifySensorID;
+  /* specifies the type of field user want to modufy */
+  SfeParameter type;
+}TMR_TagOp_GEN2_IDS_SL900A_SfeParameters;
+
+/** Sub-Class to Combination Calibration Data / SFE Parameters object */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_CalSfe
+{
+  /* Calibration Data */
+  TMR_TagOp_GEN2_IDS_SL900A_CalibrationData Cal;
+  /* Sensor Front End Parameters */
+  TMR_TagOp_GEN2_IDS_SL900A_SfeParameters Sfe;
+}TMR_TagOp_GEN2_IDS_SL900A_CalSfe;
+
+/**Sub-Class to spcify fifo source */
+typedef enum FifoSource
+{
+  /* Data from SPI */
+  TMR_GEN2_IDS_SL900A_FIFOSOURCE_SPI = 0x00,
+  /* Data from RFID */
+  TMR_GEN2_IDS_SL900A_FIFOSOURCE_RFID = 0x01,
+}FifoSource;
+/** Sub-Class for Get status fifo reply */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_FifoStatus
+{
+  /* Raw 8-bit response from AccessFifo Status command */
+  uint8_t raw;
+  /* FIFO Busy bit */
+  bool fifoBusy;
+  /* Data Ready bit */
+  bool dataReady;
+  /* No Data bit */
+  bool noData;
+  /* Data Source bit (SPI, RFID) */
+  FifoSource source;
+  /* Number of valid bytes in FIFO register */
+  uint8_t numValidBytes;
+}TMR_TagOp_GEN2_IDS_SL900A_FifoStatus;
+
+/** Sub-Class for specifying SL900A application data */
+typedef struct ApplicationData
+{
+  /* Raw 16-bit protocol value */
+  uint16_t raw;
+  /* Number of user bank memory words to reserve for non-logging purposes */
+  uint16_t NumberOfWords;
+  /* Broken word pointer */
+  uint8_t BrokenWordPointer;
+}ApplicationData;
+
+/** Sub-Class for Gen2 Ids Sl900A coustom tag extension */
+typedef struct TMR_TagOP_GEN2_IDS_SL900A
+{
+  /* SL900A sensor type values */
+  Sensor sensortype;
+  /* SL900A password access level values */
+  PasswordLevel level;
+  /* Data log format selection */
+  LoggingForm dataLog;
+  /* Data log memory-full behavior */
+  DelayMode mode;
+  /* Logging memory-full behavior */
+  StorageRule rule;
+}TMR_TagOP_GEN2_IDS_SL900A;
+
+/** Sub- class for Ids Sl900A sensor */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_GetSensorValue
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+}TMR_TagOp_GEN2_IDS_SL900A_GetSensorValue;
+
+/** Sub-class for IDs SL900A get log state */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_GetLogState
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+}TMR_TagOp_GEN2_IDS_SL900A_GetLogState;
+
+/** Sub-Class for IDS SL900A set log mode */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_SetLogMode
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+  /*Enable log for EXT1 external sensor */
+  bool Ext1Enable;
+  /* Enable log for EXT2 external sensor */
+  bool Ext2Enable;
+  /* Enable log for temperature sensor */
+  bool TempEnable;
+  /* Enable log for battery sensor */
+  bool BattEnable;
+  /* Time (seconds) between log readings */
+  uint16_t LogInterval;
+}TMR_TagOp_GEN2_IDS_SL900A_SetLogMode;
+
+/** Sub-Class for Gen2 end log command*/
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_EndLog
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+}TMR_TagOp_GEN2_IDS_SL900A_EndLog;
+
+/** Sub-Class for DelayTime */
+typedef struct Delay
+{
+  /* Raw 16-bit protocol value */
+  uint16_t raw;
+  /* Logging start mode */
+  DelayMode Mode;
+  /* Logging timer delay value (units of 512 seconds) */
+  uint16_t Time;
+  /* Trigger log on both timer and external interrupts */
+  bool IrqTimerEnable;
+}Delay;
+
+/** Sub-Classs for ShelfLife Block 0 */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock0
+{
+  /* raw value of block0 */
+  uint32_t raw;
+  /* Tmax */
+  uint8_t Tmax;
+  /* Tmin */
+  uint8_t Tmin;
+  /* Tstd */
+  uint8_t Tstd;
+  /* Ea */
+  uint8_t Ea;
+}TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock0;
+
+/** Sub-Class for ShelfLife Block 1 */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock1
+{
+  /* raw value for block 1 */
+  uint32_t raw;
+  /* SLinit */
+  uint16_t SLinit;
+  /* Tint */
+  uint16_t Tint;
+  /* SensorID */
+  uint8_t sensorID;
+  /* Enable negative shelf life */
+  bool enableNegative;
+  /* Shelf life algorithem enable */
+  bool algorithmEnable;
+  /* RFU bytes */
+  uint8_t rfu;
+}TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock1;
+
+/** Sub-class for GetMeasurmentSetUp command */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_MeasurementSetupData
+{
+  /* Raw 16 byte response from Measurement Setup Data command */
+  uint8_t Raw[16];
+  /* LogLimits Data */
+  LogLimits loglimit;
+  /* Log Mode Data */
+  LogModeData logModeData;
+  /* Delay Data */
+  Delay delyTime;
+  /* Application Data */
+  ApplicationData addData;
+  /* Time (seconds) between log readings */
+  uint16_t logInterval;
+  /* Start Time */
+  TMR_TimeStructure startTime;
+}TMR_TagOp_GEN2_IDS_SL900A_MeasurementSetupData;
+
+/** Sub-Class for GEN2 initialize command */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_Initialize
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Logging memory configuration */
+  ApplicationData applicationData;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+  /* Delay time */
+  Delay delayTime;
+}TMR_TagOp_GEN2_IDS_SL900A_Initialize;
+
+/** Sub-Class for specifying AccessFifo operation */
+typedef enum AccessFifoOperation
+{
+  /* Read from FIFO */
+  TMR_GEN2_IDS_SL900A_ACCESSFIFO_READ = 0x80,
+  /* Write to FIFO */
+  TMR_GEN2_IDS_SL900A_ACCESSFIFO_WRITE = 0xA0,
+  /* Get FIFO status */
+  TMR_GEN2_IDS_SL900A_ACCESSFIFO_STATUS = 0xC0,
+}AccessFifoOperation;
+
+/** Sub-Class for Gen2 Ids AccessFifo command */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_AccessFifo
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+  /* specify the operation do be done on fifo */
+  AccessFifoOperation operation;
+}TMR_TagOp_GEN2_IDS_SL900A_AccessFifo;
+
+/** Sub-Class for Gen2 Ids accessFifo write command */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_AccessFifoWrite
+{
+  TMR_TagOp_GEN2_IDS_SL900A_AccessFifo write;
+  /* Bytes to write to FIFO */
+  TMR_uint8List *payLoad;
+}TMR_TagOp_GEN2_IDS_SL900A_AccessFifoWrite;
+
+/** Sub-Class for Gen2 Ids accessFifo read command */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_AccessFifoRead
+{
+  TMR_TagOp_GEN2_IDS_SL900A_AccessFifo read;
+  /* Number of bytes to read from FIFO */
+  uint8_t length;
+}TMR_TagOp_GEN2_IDS_SL900A_AccessFifoRead;
+
+/** Sub-Class for Gen2 Ids accessFifo status command */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_AccessFifoStatus
+{
+  TMR_TagOp_GEN2_IDS_SL900A_AccessFifo status;
+}TMR_TagOp_GEN2_IDS_SL900A_AccessFifoStatus;
+
+/** Sub-Class for Gen2 StartLog command */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_StartLog
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+  /* Time to initialize log timestamp counter with */
+  uint32_t startTime;  
+}TMR_TagOp_GEN2_IDS_SL900A_StartLog;
+
+/** Sub-Class for Gen2 IDS GetCalibrationData command */
+typedef struct  TMR_TagOp_GEN2_IDS_SL900A_GetCalibrationData
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+}TMR_TagOp_GEN2_IDS_SL900A_GetCalibrationData;
+
+/** Sub-Class for Gen2 IDS SetCalibrationData command */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_SetCalibrationData
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+  /* Calibration parameters */
+  TMR_TagOp_GEN2_IDS_SL900A_CalibrationData cal; 
+}TMR_TagOp_GEN2_IDS_SL900A_SetCalibrationData;
+
+/** Sub-class for Gen2 Ids SetSfeParameters command */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_SetSfeParameters
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+  /* Sfe Parameters */
+  TMR_TagOp_GEN2_IDS_SL900A_SfeParameters *sfe;
+}TMR_TagOp_GEN2_IDS_SL900A_SetSfeParameters;
+
+/** Sub-class for Gen2 Ids GetMeasurementSetup command */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_GetMeasurementSetup
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+}TMR_TagOp_GEN2_IDS_SL900A_GetMeasurementSetup;
+
+/** Sub-class for Gen2 Ids GetBatteryLevel command */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_GetBatteryLevel
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+  /* enum BatterType, re-check or default */
+  BatteryType batteryType;
+}TMR_TagOp_GEN2_IDS_SL900A_GetBatteryLevel;
+
+/** Sub-Class for Gen2 Ids SetLogLimits Command */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_SetLogLimits
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+  /* Specify the Log Limits */
+  LogLimits limit;
+}TMR_TagOp_GEN2_IDS_SL900A_SetLogLimits;
+
+/** Sub-Class for Gen2 Ids SetShelfLife Command */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_SetShelfLife
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+  /* Specify the ShelfLifeBlock0 */
+  TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock0 *shelfLifeBlock0;
+  /* Specify the ShelfLifeBlock1 */
+  TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock1 *shelfLifeBlock1;
+}TMR_TagOp_GEN2_IDS_SL900A_SetShelfLife;
+
+/** Sub-Class for Gen2 Ids SetPassword Command */
+typedef struct TMR_TagOp_GEN2_IDS_SL900A_SetPassword
+{
+  TMR_TagOP_GEN2_IDS_SL900A sl900A;
+  /* Custom Command Code */
+  uint8_t CommandCode;
+  /* Gen2 access password */
+  uint32_t AccessPassword;
+  /* IDS SL900A Password */
+  uint32_t Password;
+  /* New Passwordlevel */
+  PasswordLevel NewPasswordLevel;
+  /* New password */
+  uint32_t NewPassword;
+}TMR_TagOp_GEN2_IDS_SL900A_SetPassword;
+
+/** Sub-class for Gen2 Ids parameters */
+typedef struct TMR_TagOP_GEN2_IDS
+{
+  union
+  {
+    TMR_TagOp_GEN2_IDS_SL900A_GetSensorValue sensor;
+    TMR_TagOp_GEN2_IDS_SL900A_GetLogState  getLog;
+    TMR_TagOp_GEN2_IDS_SL900A_SetLogMode   setLogMode;
+    TMR_TagOp_GEN2_IDS_SL900A_EndLog endLog;
+    TMR_TagOp_GEN2_IDS_SL900A_Initialize initialize;
+    TMR_TagOp_GEN2_IDS_SL900A_AccessFifoRead accessFifoRead;
+    TMR_TagOp_GEN2_IDS_SL900A_AccessFifoWrite accessFifoWrite;
+    TMR_TagOp_GEN2_IDS_SL900A_AccessFifoStatus accessFifoStatus;
+    TMR_TagOp_GEN2_IDS_SL900A_StartLog startLog;
+    TMR_TagOp_GEN2_IDS_SL900A_GetCalibrationData calibrationData;
+    TMR_TagOp_GEN2_IDS_SL900A_SetCalibrationData setCalibration;
+    TMR_TagOp_GEN2_IDS_SL900A_SetSfeParameters setSfeParameters;
+    TMR_TagOp_GEN2_IDS_SL900A_GetMeasurementSetup measurementSetup;
+    TMR_TagOp_GEN2_IDS_SL900A_GetBatteryLevel batteryLevel;
+    TMR_TagOp_GEN2_IDS_SL900A_SetLogLimits setLogLimit;
+    TMR_TagOp_GEN2_IDS_SL900A_SetShelfLife setShelfLife;
+    TMR_TagOp_GEN2_IDS_SL900A_SetPassword setPassword;
+    
+  }u;
+}TMR_TagOP_GEN2_IDS;
+/** Sub-class for Gen2 custom tagops */
+typedef struct TMR_TagOp_GEN2_Custom
+{
+  TMR_SR_GEN2_SiliconType chipType;
+  union
+  {
+    TMR_TagOp_GEN2_Alien alien;
+    TMR_TagOp_GEN2_NXP nxp;
+    TMR_TagOp_GEN2_Impinj impinj;
+    TMR_TagOP_GEN2_IDS ids;
+    TMR_TagOp_GEN2_Denatran IavDenatran;
+  } u;
+}TMR_TagOp_GEN2_Custom;
+
+/** Sub-class for ISO180006B tagops */
+typedef struct TMR_TagOp_ISO180006B
+{
+  union
+  {
+    TMR_TagOp_ISO180006B_Lock lock;
+    TMR_TagOp_ISO180006B_WriteData writeData;
+    TMR_TagOp_ISO180006B_ReadData readData;
+  } u;
+}TMR_TagOp_ISO180006B;
+
+/** Sub-class for Gen2 standard tagops */
+typedef struct TMR_TagOp_GEN2
+{
+  union
+  {
+    TMR_TagOp_GEN2_WriteTag writeTag;
+    TMR_TagOp_GEN2_WriteData writeData;
+    TMR_TagOp_GEN2_ReadData readData;
+    TMR_TagOp_GEN2_SecureReadData secureReadData;
+    TMR_TagOp_GEN2_Lock lock;
+    TMR_TagOp_GEN2_Kill kill;
+    TMR_TagOp_GEN2_BlockWrite blockWrite;
+    TMR_TagOp_GEN2_BlockPermaLock blockPermaLock;
+    TMR_TagOp_GEN2_BlockErase blockErase;
+    TMR_TagOp_GEN2_Custom custom;
+  } u;
+}TMR_TagOp_GEN2;
+
+/** Tag operation data structure */
+struct TMR_TagOp
+{
+  TMR_TagOpType type;
+  union
+  {
+    TMR_TagOp_GEN2 gen2;
+    TMR_TagOp_ISO180006B iso180006b;
+    TMR_TagOp_List list;
+  } u;
+};
+
+TMR_Status TMR_TagOp_init_GEN2_WriteTag(TMR_TagOp *tagop, TMR_TagData* epc);
+TMR_Status TMR_TagOp_init_GEN2_ReadData(TMR_TagOp *tagop, TMR_GEN2_Bank bank,
+                                        uint32_t wordAddress, uint8_t len);
+TMR_Status TMR_TagOp_init_GEN2_SecureReadData(TMR_TagOp *tagop, TMR_GEN2_Bank bank, uint32_t wordAddress,
+                                               uint8_t len, uint8_t type, uint8_t passwordType);
+TMR_Status TMR_TagOp_init_GEN2_SecurePassWord(TMR_TagOp *tagop, uint8_t passwordType, uint32_t gen2PassWord,
+                                              uint8_t addressLength, uint8_t addressOffset, uint16_t flashOffset);
+TMR_Status TMR_TagOp_init_GEN2_WriteData(TMR_TagOp *tagop, TMR_GEN2_Bank bank,
+                                         uint32_t wordAddress,
+                                         TMR_uint16List *data);
+TMR_Status TMR_TagOp_init_GEN2_Lock(TMR_TagOp *tagop, uint16_t mask,
+                                    uint16_t action,  TMR_GEN2_Password accessPassword);
+TMR_Status TMR_TagOp_init_GEN2_Kill(TMR_TagOp *tagop,
+                                    TMR_GEN2_Password killPassword);
+TMR_Status TMR_TagOp_init_GEN2_BlockWrite(TMR_TagOp *tagop, TMR_GEN2_Bank bank, uint32_t wordPtr, TMR_uint16List *data);
+TMR_Status TMR_TagOp_init_GEN2_BlockPermaLock(TMR_TagOp *tagop, uint8_t readLock, TMR_GEN2_Bank bank, uint32_t blockPtr, TMR_uint16List* mask);
+TMR_Status TMR_TagOp_init_GEN2_BlockErase(TMR_TagOp *tagop, TMR_GEN2_Bank bank, uint32_t wordPtr, uint8_t wordCount);
+
+TMR_Status TMR_TagOp_init_ISO180006B_ReadData(TMR_TagOp *tagop, uint8_t byteAddress, uint8_t len);
+TMR_Status TMR_TagOp_init_ISO180006B_WriteData(TMR_TagOp *tagop, uint8_t byteAddress, TMR_uint8List *data);
+TMR_Status TMR_TagOp_init_ISO180006B_Lock(TMR_TagOp *tagop, uint8_t address);
+TMR_Status TMR_TagOp_init_GEN2_Alien_Higgs2_PartialLoadImage(TMR_TagOp *tagop, TMR_GEN2_Password killPassword,
+                                                  TMR_GEN2_Password accessPassword, TMR_TagData *epc);
+TMR_Status TMR_TagOp_init_GEN2_Alien_Higgs2_FullLoadImage(TMR_TagOp *tagop, TMR_GEN2_Password killPassword,
+                                    TMR_GEN2_Password accessPassword, uint16_t lockBits, 
+                                    uint16_t pcWord, TMR_TagData *epc);
+TMR_Status TMR_TagOp_init_GEN2_Alien_Higgs3_FastLoadImage(TMR_TagOp *tagop, TMR_GEN2_Password currentAccessPassword,
+                                    TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword, 
+                                    uint16_t pcWord, TMR_TagData *epc);
+TMR_Status TMR_TagOp_init_GEN2_Alien_Higgs3_LoadImage(TMR_TagOp *tagop, TMR_GEN2_Password currentAccessPassword,
+                                    TMR_GEN2_Password accessPassword, TMR_GEN2_Password killPassword, 
+                                    uint16_t pcWord, TMR_uint8List *epcAndUserData);
+TMR_Status TMR_TagOp_init_GEN2_Alien_Higgs3_BlockReadLock(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, uint8_t lockBits);
+
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2I_SetReadProtect(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword);
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2X_SetReadProtect(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword);
+
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2I_ResetReadProtect(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword);
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2X_ResetReadProtect(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword);
+
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2I_ChangeEAS(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, bool resetEAS);
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2X_ChangeEAS(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, bool resetEAS);
+
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2I_EASAlarm(TMR_TagOp *tagop, TMR_GEN2_DivideRatio dr, TMR_GEN2_TagEncoding m, TMR_GEN2_TrExt trExt);
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2X_EASAlarm(TMR_TagOp *tagop, TMR_GEN2_DivideRatio dr, TMR_GEN2_TagEncoding m, TMR_GEN2_TrExt trExt);
+
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2I_Calibrate(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword);
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2X_Calibrate(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword);
+
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2I_ChangeConfig(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, TMR_NXP_ConfigWord configWord);
+TMR_Status TMR_TagOp_init_GEN2_NXP_G2X_ChangeConfig(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, TMR_NXP_ConfigWord configWord);
+TMR_Status TMR_TagOp_init_GEN2_NXP_AES_Untraceable(TMR_TagOp *tagop,TMR_GEN2_UNTRACEABLE_Epc epc, int epclen , TMR_GEN2_UNTRACEABLE_Tid tid,
+				    TMR_GEN2_UNTRACEABLE_UserMemory user, TMR_GEN2_UNTRACEABLE_Range range, TMR_TagOp_GEN2_NXP_Untraceable *auth);
+TMR_Status TMR_TagOp_init_GEN2_NXP_AES_Authenticate(TMR_TagOp *tagop, TMR_TagOp_GEN2_NXP_Authenticate *authenticate);
+TMR_Status TMR_TagOp_init_GEN2_NXP_AES_ReadBuffer(TMR_TagOp *tagop, uint16_t wordPointer, uint16_t bitCount, TMR_TagOp_GEN2_NXP_Readbuffer *readbuffer);
+TMR_Status TMR_TagOp_init_GEN2_NXP_AES_Tam1authentication(TMR_TagOp_GEN2_NXP_Tam1Authentication *auth, TMR_NXP_KeyId keyid, TMR_uint8List *key, 
+					TMR_uint8List *ichallenge ,bool sendRawData );
+TMR_Status TMR_TagOp_init_GEN2_NXP_AES_Tam2authentication(TMR_TagOp_GEN2_NXP_Tam2Authentication *auth, TMR_NXP_KeyId keyid, TMR_uint8List *key, 
+					TMR_uint8List *ichallenge, TMR_NXP_Profile profile, uint16_t Offset,uint8_t blockCount,bool sendRawData);
+
+TMR_Status TMR_TagOp_init_GEN2_Impinj_Monza4_QTReadWrite(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                             TMR_Monza4_ControlByte controlByte, TMR_Monza4_Payload payload);
+
+TMR_Status TMR_TagOp_init_GEN2_Denatran_IAV_Activate_Secure_Mode(TMR_TagOp *tagop, uint8_t rfuByte);
+TMR_Status TMR_TagOp_init_GEN2_Denatran_IAV_Authenticate_OBU(TMR_TagOp *tagop, uint8_t rfuByte);
+TMR_Status TMR_TagOp_init_GEN2_Denatran_IAV_Activate_Siniav_Mode(TMR_TagOp *tagop, uint8_t rfuByte, TMR_uint8List *data);
+TMR_Status TMR_TagOp_init_GEN2_Denatran_IAV_OBU_Auth_ID(TMR_TagOp *tagop, uint8_t rfuByte);
+TMR_Status TMR_TagOp_init_GEN2_Denatran_IAV_OBU_Auth_Full_Pass1(TMR_TagOp *tagop, uint8_t rfuByte);
+TMR_Status TMR_TagOp_init_GEN2_Denatran_IAV_OBU_Auth_Full_Pass2(TMR_TagOp *tagop, uint8_t rfuByte);
+TMR_Status TMR_TagOp_init_GEN2_Denatran_IAV_OBU_ReadFromMemMap(TMR_TagOp *tagop, uint8_t rfuByte, uint16_t wordAddress);
+TMR_Status TMR_TagOp_init_GEN2_Denatran_IAV_OBU_WriteToMemMap(TMR_TagOp *tagop, uint8_t rfuByte, uint16_t wordAddress, uint16_t word, uint8_t* tagID, uint8_t* data);
+TMR_Status TMR_TagOp_init_GEN2_Denatran_IAV_GetTokenId(TMR_TagOp *tagop);
+TMR_Status TMR_TagOp_init_GEN2_Denatran_IAV_OBU_Auth_Full_Pass(TMR_TagOp *tagop, uint8_t payload);
+TMR_Status TMR_TagOp_init_GEN2_Denatran_IAV_ReadSec(TMR_TagOp *tagop, uint8_t payload, uint16_t wordAddress);
+TMR_Status TMR_TagOp_init_GEN2_Denatran_IAV_WriteSec(TMR_TagOp *tagop, uint8_t payload, uint8_t* data, uint8_t* credentials);
+TMR_Status TMR_TagOp_init_GEN2_Denatran_IAV_G0_PA_OBU_Auth(TMR_TagOp *tagop, uint8_t rfuByte);
+
+TMR_Status 
+TMR_init_GEN2_NXP_G2I_ConfigWord(TMR_NXP_ConfigWord *configWord);
+
+TMR_Status
+TMR_init_GEN2_Impinj_Monza4_ControlByte(TMR_Monza4_ControlByte *controlByte);
+
+TMR_Status
+TMR_init_GEN2_Impinj_Monza4_Payload(TMR_Monza4_Payload *payload);
+
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_GetSensorValue(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                              PasswordLevel level, uint32_t password, Sensor type);
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_GetCalibrationData(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                                  PasswordLevel leveli, uint32_t password);
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_SetLogLimit(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, 
+                                           PasswordLevel level, uint32_t password, LogLimits *logLimits);
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_SetCalibrationData(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, PasswordLevel level, 
+                                                  uint32_t password, TMR_TagOp_GEN2_IDS_SL900A_CalibrationData *data);
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_SetSfeParameters(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, PasswordLevel level, 
+                                                uint32_t password, TMR_TagOp_GEN2_IDS_SL900A_SfeParameters *data);
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_SensorReading(TMR_uint8List *reply, TMR_TagOp_GEN2_IDS_SL900A_SensorReading *sensor);
+
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_BatteryLevelReading(TMR_uint8List *reply, TMR_TagOp_GEN2_IDS_SL900A_BatteryLevelReading *battery);
+
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_MeasurementSetupData(TMR_uint8List *reply, TMR_TagOp_GEN2_IDS_SL900A_MeasurementSetupData *measurment);
+
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_CalSfe(TMR_uint8List *reply, TMR_TagOp_GEN2_IDS_SL900A_CalSfe *calSfe);
+
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_CalibrationData(uint8_t byte[7], TMR_TagOp_GEN2_IDS_SL900A_CalibrationData *cal);
+
+TMR_Status
+TMR_update_GEN2_IDS_SL900A_CalibrationData(TMR_TagOp_GEN2_IDS_SL900A_CalibrationData *cal);
+
+TMR_Status
+TMR_update_GEN2_IDS_SL900A_SfeParameters(TMR_TagOp_GEN2_IDS_SL900A_SfeParameters *sfe);
+
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_SfeParameters(uint8_t byte[2], TMR_TagOp_GEN2_IDS_SL900A_SfeParameters *sfe);
+
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_GetLogState(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                           PasswordLevel level, uint32_t password);
+
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_SetLogMode(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, PasswordLevel level,
+                                          uint32_t password, LoggingForm form, StorageRule rule, bool Ext1Enable,
+                                          bool Ext2Enable, bool TempEnable, bool BattEnable, uint16_t LogInterval);
+
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_LogState(TMR_uint8List *reply, TMR_TagOp_GEN2_IDS_SL900A_LogState *log);
+
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_Initialize(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, PasswordLevel level,
+                                          uint32_t password, uint8_t delayMode, uint16_t delayTime, bool timeEnable,
+                                          uint16_t numberOfWords, uint8_t BrokenWordPointer);
+
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_EndLog(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                      PasswordLevel level, uint32_t password);
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_AccessFifoStatus(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                                PasswordLevel level ,uint32_t password);
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_AccessFifoRead(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, PasswordLevel level,
+                                              uint32_t password,  uint8_t readLength);
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_AccessFifoWrite(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                               PasswordLevel level, uint32_t password, TMR_uint8List *payLoad);
+TMR_Status
+TMR_init_GEN2_IDS_SL900A_FifoStatus(TMR_uint8List *reply, TMR_TagOp_GEN2_IDS_SL900A_FifoStatus *status);
+
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_StartLog(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                        PasswordLevel level, uint32_t password, TMR_TimeStructure *timestamp);
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_GetMeasurementSetup(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                                   PasswordLevel level, uint32_t password);
+
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_SetPassword(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, PasswordLevel level,
+                                           uint32_t password, PasswordLevel newPasswordLevel, uint32_t newPassword);
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_GetBatteryLevel(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword,
+                                               PasswordLevel level, uint32_t password, BatteryType type);
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_ShelfLifeBlock0(TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock0 *block0,
+                                               uint8_t tmax, uint8_t Tmin, uint8_t tstd, uint8_t Ea);
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_ShelfLifeBlock1(TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock1 *block1,
+                                               uint16_t slinit, uint16_t tint, uint8_t sensorid,
+                                               bool negative, bool algorithm);
+TMR_Status
+TMR_TagOp_init_GEN2_IDS_SL900A_SetShelfLife(TMR_TagOp *tagop, TMR_GEN2_Password accessPassword, PasswordLevel level,
+                                            uint32_t password, TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock0 *block0,
+                                            TMR_TagOp_GEN2_IDS_SL900A_ShelfLifeBlock1 *block1);
+TMR_Status
+TMR_GEN2_init_BapParams(TMR_GEN2_Bap *bapVal, int32_t powerUpDelayUs, int32_t freqHopOfftimeUs);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TMR_TAGOP_H */
diff --git a/cbits/api/tmr_types.h b/cbits/api/tmr_types.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_types.h
@@ -0,0 +1,121 @@
+/* ex: set tabstop=2 shiftwidth=2 expandtab cindent: */
+#ifndef _TMR_TYPES_H
+#define _TMR_TYPES_H
+/**
+ *  @file tmr_types.h
+ *  @brief Mercury API - General data type definitions
+ *  @author Nathan Williams
+ *  @date 10/20/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.
+ */
+
+#ifdef WINCE
+#include <stdint_win32.h>
+#else
+#include <stdint.h>
+#endif
+#include <stdbool.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/** Internal string representation with known storage size */
+typedef struct TMR_String
+{
+  /** The null-terminated string value */
+  char *value;
+  /** The allocated number of bytes pointed to */
+  uint16_t max;
+} TMR_String;
+
+/** List of uint8_t values */
+typedef struct TMR_uint8List
+{
+  /** The array of values */
+  uint8_t *list;
+  /** The number of entries there is space for in the array */
+  uint16_t max;
+  /** The number of entries in the list - may be larger than max, indicating truncated data. */
+  uint16_t len;
+} TMR_uint8List;
+
+/** List of uint16_t values */
+typedef struct TMR_uint16List
+{
+  /** The array of values */
+  uint16_t *list;
+  /** The number of entries there is space for in the array */
+  uint16_t max;
+  /** The number of entries in the list - may be larger than max, indicating truncated data. */
+  uint16_t len;
+} TMR_uint16List;
+
+/** List of uint32_t values */
+typedef struct TMR_uint32List
+{
+  /** The array of values */
+  uint32_t *list;
+  /** The number of entries there is space for in the array */
+  uint16_t max;
+  /** The number of entries in the list - may be larger than max, indicating truncated data. */
+  uint16_t len;
+} TMR_uint32List;
+
+/** List of int8_t values */
+typedef struct TMR_int8List
+{
+  /** The array of values */
+  int8_t *list;
+  /** The number of entries there is space for the array */
+  int8_t max;
+  /** The number of entries in the list - may be larger than max, indicating truncated data. */
+  int8_t len;
+}TMR_int8List;
+
+/**
+ * Function callback used to obtain firmware data during a firmware
+ * load operation.  TMR_firmwareLoad will call this repeatedly to
+ * obtain data to send to the reader. A buffer of a specified size
+ * will be passed in; the callback is free to place less than that
+ * amount of data in the buffer, provided that size is modified
+ * accordingly. When the end of the firmware image has been reached,
+ * the callback should return false.  
+
+ * @see TMR_memoryProvider and TMR_fileProvider for pre-existing
+ * callbacks to load firmware from system memory or from a file.
+ * 
+ * @param cookie Arbitrary data passed to the callback.
+ * @param[in] size Pointer to amount of space in the buffer.
+ * @param[out] Points to number of bytes stored in the buffer.
+ * @param[out] data Buffer of bytes of firmware image.
+ * @return true if there is more data to load
+ */
+typedef bool (*TMR_FirmwareDataProvider)(void *cookie, uint16_t *size, uint8_t *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TMR_TYPES_H */
diff --git a/cbits/api/tmr_utils.c b/cbits/api/tmr_utils.c
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_utils.c
@@ -0,0 +1,233 @@
+/**
+ *  @file tmr_utils.c
+ *  @brief Mercury API - utility functions
+ *  @author Nathan Williams
+ *  @date 12/10/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.
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "osdep.h"
+#include "tmr_types.h"
+#include "tmr_utils.h"
+
+#ifndef TMR_USE_HOST_C_LIBRARY
+
+void *
+tm_memcpy(void *dest, const void *src, size_t n)
+{
+  const uint8_t *u8src;
+  uint8_t *u8dest;
+
+  u8dest = dest;
+  u8src = src;
+
+  while (0 != n)
+  {
+    *u8dest = *u8src;
+    u8dest++;
+    u8src++;
+    n--;
+  }
+
+  return dest;
+}
+
+char *
+tm_strcpy(char *dest, const char *src)
+{
+  char *ptr, val;
+
+  ptr = dest;
+
+  do
+  {
+    val = *src;
+    *ptr = val;
+    ptr++;
+    src++;
+  } 
+  while ('\0' != val);
+
+  return dest;
+}
+
+char *
+tm_strchr(const char *s, int c)
+{
+  const char *ptr;
+
+  for (ptr = s; *ptr != '\0'; ptr++)
+  {
+    if (*ptr == c)
+    {
+      return (char *)ptr;
+    }
+  }
+
+  return NULL;
+}
+
+#endif /* TMR_USE_HOST_C_LIBRARY */
+
+int
+tm_strcasecmp(const char *s1, const char *s2)
+{
+  char v1, v2;
+  int diff;
+
+  do
+  {
+    v1 = *s1;
+    if (v1 >= 'a' && v1 <= 'z')
+      v1 -= 'a' - 'A';
+    v2 = *s2;
+    if (v2 >= 'a' && v2 <= 'z')
+      v2 -= 'a' - 'A';
+    s1++;
+    s2++;
+  }
+  while (v1 == v2 && '\0' != v1 && '\0' != v2);
+
+  diff = v1 - v2;
+  if (diff < 0)
+    return -1;
+  else if (diff > 0)
+    return 1;
+  else
+    return 0;
+}
+
+/* Get a high/low timestamp pair, being careful not to get one value
+ * before a wraparound and the other one after, which would lead to
+ * 50-day time jumps forward or backwards.  (high<<32)|low is in milliseconds.
+ */
+void
+tm_gettime_consistent(uint32_t *high, uint32_t *low)
+{
+  uint32_t tmpHigh;
+
+  *high   = tmr_gettime_high();
+  *low    = tmr_gettime_low();
+  tmpHigh = tmr_gettime_high();
+
+  if (tmpHigh != *high)
+  {
+    *high = tmpHigh;
+    *low = tmr_gettime_low();
+  }
+}
+
+/* Find the time difference from start to end, allowing for end having
+ * wrapped around UINT32_MAX and back to zero.
+ */
+uint32_t
+tm_time_subtract(uint32_t end, uint32_t start)
+{
+  if (end >= start)
+    return end - start;
+  else
+    return (UINT32_MAX - start) + end;
+}
+
+/** Minimum number of bytes required to hold a given number of bits.
+ *
+ * @param bitCount  number of bits to hold
+ * @return  Minimum length of bytes that can contain that many bits
+ */
+int tm_u8s_per_bits(int bitCount) 
+{
+	return ((0<bitCount) ?((((bitCount)-1)>>3)+1) :0);
+}
+
+void
+TMR_stringCopy(TMR_String *dest, const char *src, int len)
+{
+  if (dest->max - 1 < len)
+  {
+    len = dest->max - 1;
+  }
+  if (dest->max > 0)
+  {
+    memcpy(dest->value, src, len);
+    dest->value[len] = '\0';
+  }
+}
+
+uint64_t
+TMR_makeBitMask(int offset, int length)
+{
+  uint64_t mask;
+
+  mask = 0;
+  mask = ~mask;
+  mask <<= length;
+  mask = ~mask;
+
+  mask <<= offset;
+
+  return mask;
+}
+
+uint32_t
+TMR_byteArrayToInt(uint8_t data[], int offset)
+{
+  uint32_t value = 0;
+  int count;
+
+  for( count = 0; count < 4; count++)
+  {
+    value <<= 8;
+    value ^= (data[count + offset] & 0x000000FF);
+  }
+  return value;
+}
+
+uint16_t
+TMR_byteArrayToShort(uint8_t data[], int offset)
+{
+  uint16_t value = 0;
+  int hi, lo;
+  hi = (uint16_t) (data[offset++]) << 8;
+  lo = (uint16_t) (data[offset++]);
+  value = (uint16_t)(hi | lo);
+
+  return value;
+}
+
+uint64_t
+TMR_byteArrayToLong(uint8_t data[], int offset)
+{
+  uint64_t value = 0;
+  int i;
+  for (i = 0; i < 8; i++)
+  {
+    value <<= 8;
+    value ^= (uint64_t) (data[i + offset] & 0xff);
+  }
+  return value;
+}
+
diff --git a/cbits/api/tmr_utils.h b/cbits/api/tmr_utils.h
new file mode 100644
--- /dev/null
+++ b/cbits/api/tmr_utils.h
@@ -0,0 +1,156 @@
+#ifndef _TMR_UTILS_H
+#define _TMR_UTILS_H
+
+/**
+ *  @file tmr_utils.h
+ *  @brief Mercury API - generic utilities
+ *  @author Nathan Williams
+ *  @date 12/1/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.
+ */
+
+#ifdef WINCE
+#include <stdint_win32.h>
+#else
+#include <stdint.h>
+#endif
+#include <stddef.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Macros for working with values embedded in uint8_t arrays (msg) */
+/* Absolute-value get */
+#define GETU8AT(msg, i) ( \
+  ((msg)[(i)])          )
+
+#define GETU16AT(msg, i) ( \
+  ((uint16_t)((msg)[(i)  ]) <<  8)   | \
+  ((msg)[(i)+1] <<  0)   )
+
+#define GETS16AT(msg, i) ( \
+    ((int16_t)((msg)[(i)  ]) <<  8)   | \
+    ((int16_t)((msg)[(i)+1]) <<  0)   )
+
+#define GETU24AT(msg, i) ( \
+  ((uint32_t)((msg)[(i)  ]) <<  16)  | \
+  ((uint32_t)((msg)[(i)+1]) <<   8)  | \
+  ((msg)[(i)+2] <<   0)  )
+
+#define GETU32AT(msg, i) ( \
+  ((uint32_t)((msg)[(i)  ]) <<  24)  | \
+  ((uint32_t)((msg)[(i)+1]) <<  16)  | \
+  ((uint32_t)((msg)[(i)+2]) <<   8)  | \
+  ((msg)[(i)+3] <<   0)  )
+
+/* Get and update index to next position */
+#define GETU8(msg, i)   ((msg)[(i)++])
+#define GETU16(msg, i)  (i+=2, GETU16AT((msg), i-2))
+#define GETU24(msg, i)  (i+=3, GETU24AT((msg), i-3))
+#define GETU32(msg, i)  (i+=4, GETU32AT((msg), i-4))
+
+/* Set and update index to next position */
+#define SETU8(msg, i, u8val) do {      \
+  (msg)[(i)++] = (u8val)      & 0xff;  \
+} while (0)
+
+#define SETU16(msg, i, u16val) do {    \
+  uint16_t _tmp = (u16val);            \
+  (msg)[(i)++] =(uint8_t) (_tmp >>  8) & 0xff;  \
+  (msg)[(i)++] =(uint8_t)(_tmp >>  0) & 0xff;  \
+} while (0)
+
+#define SETS16(msg, i, s16val) do {    \
+  int16_t _tmp = (s16val);            \
+  (msg)[(i)++] =(int8_t) (_tmp >>  8) & 0xff;  \
+  (msg)[(i)++] =(int8_t)(_tmp >>  0) & 0xff;  \
+} while (0)
+
+#define SETU32(msg, i, u32val) do {    \
+  uint32_t _tmp = (u32val);            \
+  (msg)[(i)++] = (uint8_t)(_tmp >> 24) & 0xff;  \
+  (msg)[(i)++] = (uint8_t)(_tmp >> 16) & 0xff;  \
+  (msg)[(i)++] = (uint8_t)(_tmp >>  8) & 0xff;  \
+  (msg)[(i)++] = (uint8_t)(_tmp >>  0) & 0xff;  \
+} while (0)
+
+#define SETS32(msg, i, s32val) do {    \
+  int32_t _tmp = (s32val);            \
+  (msg)[(i)++] = (int8_t)(_tmp >> 24) & 0xff;  \
+  (msg)[(i)++] = (int8_t)(_tmp >> 16) & 0xff;  \
+  (msg)[(i)++] = (int8_t)(_tmp >>  8) & 0xff;  \
+  (msg)[(i)++] = (int8_t)(_tmp >>  0) & 0xff;  \
+} while (0)
+
+/* Append a value to our list structures, which have both
+ * a allocated-space value (max) and a length-of-underlying-list
+ * value (len). Len can exceed max, which indicates to the caller
+ * that there was not enough space in the passed-in list structure
+ * to store the entire list.
+ */
+#define LISTAPPEND(l, value) do {         \
+  (l)->len++;                             \
+  if ((l)->len <= (l)->max)               \
+    (l)->list[(l)->len - 1] = (value);    \
+} while (0)
+
+
+/* Macros for working with large bitmasks made up of arrays of uint32_t */
+#define BITGET(array, number) (((array)[(number)/32] >> ((number)&31)) & 1)
+#define BITSET(array, number) ((array)[(number)/32] |= ((uint32_t)1 << ((number)&31)))
+#define BITCLR(array, number) ((array)[(number)/32] &= ~((uint32_t)1 << ((number)&31)))
+
+#define numberof(x) (sizeof((x))/sizeof((x)[0]))
+
+#ifndef TMR_USE_HOST_C_LIBRARY
+void *tm_memcpy(void *dest, const void *src, size_t n);
+char *tm_strcpy(char *dest, const char *src);
+char *tm_strchr(const char *s, int c);
+
+#undef memcpy
+#undef strcpy
+#undef strchr
+
+#define memcpy tm_memcpy
+#define strcpy tm_strcpy
+#define strchr tm_strchr
+#endif
+
+int tm_strcasecmp(const char *s1, const char *s2);
+#define strcasecmp tm_strcasecmp
+
+void tm_gettime_consistent(uint32_t *high, uint32_t *low);
+uint32_t tm_time_subtract(uint32_t end, uint32_t start);
+int tm_u8s_per_bits(int bitCount);
+void TMR_stringCopy(TMR_String *dest, const char *src, int len);
+uint64_t TMR_makeBitMask(int offset, int lenght);
+uint32_t TMR_byteArrayToInt(uint8_t data[], int offset);
+uint16_t TMR_byteArrayToShort(uint8_t data[], int offset);
+uint64_t TMR_byteArrayToLong(uint8_t data[], int offset);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TMR_UTILS_H */
diff --git a/cbits/glue/glue.c b/cbits/glue/glue.c
new file mode 100644
--- /dev/null
+++ b/cbits/glue/glue.c
@@ -0,0 +1,340 @@
+#define _GNU_SOURCE
+
+#include <locale.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#ifndef _WIN32
+#include <xlocale.h>
+#endif
+#include <HsFFI.h>
+
+#include "glue.h"
+#include "serial_reader_imp.h"
+
+static TMR_Status free_transport_listener (TMR_Reader *reader,
+                                           TransportListenerEtc *listener,
+                                           TransportListenerEtc **prev)
+{
+    TMR_Status stat;
+
+    stat = TMR_removeTransportListener (reader, &listener->block);
+    free (listener->key);
+    hs_free_fun_ptr (listener->funPtr);
+    *prev = listener->next;
+    free (listener);
+
+    return stat;
+}
+
+static void free_all_transport_listeners (ReaderEtc *reader)
+{
+    while (reader->transportListeners) {
+        free_transport_listener (&reader->reader,
+                                 reader->transportListeners,
+                                 &reader->transportListeners);
+    }
+}
+
+/* These wrapper functions have at least two purposes:
+ * 1) Check whether the reader has been destroyed
+ * 2) Many of the reader methods are actually macros, so wrapping
+ *    them in a real function makes it possible to call them
+ *    from Haskell.
+ *
+ * Some of the wrapper functions also perform additional actions to
+ * make calling from Haskell easier.
+ */
+
+TMR_Status c_TMR_create (ReaderEtc *reader, const char *deviceUri)
+{
+    reader->transportListeners = NULL;
+    reader->readPlan = NULL;
+    reader->destroyed = false;
+    strcpy (reader->uri, deviceUri);
+    return TMR_create (&reader->reader, deviceUri);
+}
+
+TMR_Status c_TMR_connect (ReaderEtc *reader)
+{
+    if (reader->destroyed)
+        return ERROR_ALREADY_DESTROYED;
+    else
+        return TMR_connect (&reader->reader);
+}
+
+TMR_Status c_TMR_destroy (ReaderEtc *reader)
+{
+    if (reader->destroyed) {
+        return ERROR_ALREADY_DESTROYED;
+    } else {
+        TMR_Status status;
+
+        free_all_transport_listeners (reader);
+        status = TMR_destroy (&reader->reader);
+        free (reader->readPlan);
+        reader->destroyed = true;
+        return status;
+    }
+}
+
+TMR_Status c_TMR_read (ReaderEtc *reader, uint32_t timeoutMs, int32_t *tagCount)
+{
+    if (reader->destroyed)
+        return ERROR_ALREADY_DESTROYED;
+    else
+        return TMR_read (&reader->reader, timeoutMs, tagCount);
+}
+
+TMR_Status c_TMR_hasMoreTags (ReaderEtc *reader)
+{
+    if (reader->destroyed)
+        return ERROR_ALREADY_DESTROYED;
+    else
+        return TMR_hasMoreTags (&reader->reader);
+}
+
+TMR_Status c_TMR_getNextTag (ReaderEtc *reader, TMR_TagReadData *tagData)
+{
+    if (reader->destroyed)
+        return ERROR_ALREADY_DESTROYED;
+    else
+        return TMR_getNextTag (&reader->reader, tagData);
+}
+
+TMR_Status c_TMR_executeTagOp (ReaderEtc *reader,
+                               TMR_TagOp *tagop,
+                               TMR_TagFilter *filter,
+                               TMR_uint8List *data)
+{
+    if (reader->destroyed)
+        return ERROR_ALREADY_DESTROYED;
+    else
+        return TMR_executeTagOp (&reader->reader, tagop, filter, data);
+}
+
+TMR_Status c_TMR_gpoSet (ReaderEtc *reader,
+                         uint8_t count,
+                         const TMR_GpioPin state[])
+{
+    if (reader->destroyed)
+        return ERROR_ALREADY_DESTROYED;
+    else
+        return TMR_gpoSet (&reader->reader, count, state);
+}
+
+TMR_Status c_TMR_gpiGet (ReaderEtc *reader,
+                         uint8_t *count,
+                         TMR_GpioPin state[])
+{
+    if (reader->destroyed)
+        return ERROR_ALREADY_DESTROYED;
+    else
+        return TMR_gpiGet (&reader->reader, count, state);
+}
+
+TMR_Status c_TMR_firmwareLoad (ReaderEtc *reader,
+                               uint8_t *firmwareStart,
+                               uint32_t firmwareSize)
+{
+    if (reader->destroyed)
+        return ERROR_ALREADY_DESTROYED;
+    else {
+        TMR_memoryCookie cookie;
+        cookie.firmwareStart = firmwareStart;
+        cookie.firmwareSize = firmwareSize;
+        return TMR_firmwareLoad (&reader->reader, &cookie, TMR_memoryProvider);
+    }
+}
+
+TMR_Status c_TMR_paramSet(ReaderEtc *reader,
+                          TMR_Param key,
+                          const void *value)
+{
+    if (reader->destroyed)
+        return ERROR_ALREADY_DESTROYED;
+    else {
+        TMR_Status status;
+
+        status = TMR_paramSet (&reader->reader, key, value);
+        if (key == TMR_PARAM_READ_PLAN) {
+            if (status == TMR_SUCCESS) {
+                /* TMR_paramSet appears to only do a shallow copy of the
+                 * read plan, meaning that the internal pointers need to
+                 * stay pointing at valid memory.  We handle this by
+                 * keeping ownership of the ReadPlanEtc, which includes
+                 * space for the lists to point at.
+                 *
+                 * When the read plan is set, we need to free the old
+                 * ReadPlanEtc, and keep a pointer to the new one.
+                 */
+                free (reader->readPlan);
+                reader->readPlan = (ReadPlanEtc *) value;
+            }
+        }
+
+        return status;
+    }
+}
+
+TMR_Status c_TMR_paramGet(ReaderEtc *reader, TMR_Param key, void *value)
+{
+    if (reader->destroyed)
+        return ERROR_ALREADY_DESTROYED;
+    else {
+        /* TMR_PARAM_READ_PLAN appears to be write-only, so fulfill the
+         * read from our cached copy. */
+        if (key == TMR_PARAM_READ_PLAN) {
+            TMR_ReadPlan *rp;
+
+            rp = (TMR_ReadPlan *) value;
+            if (reader->readPlan) {
+                /* Shallow copy the ReadPlan, although the pointers will
+                 * still point at parts of the cached ReadPlanEtc. */
+                *rp = reader->readPlan->plan;
+            } else {
+                /* No cached read plan, which means it's initialized to
+                 * the default. */
+                c_default_read_plan (rp);
+            }
+
+            return TMR_SUCCESS;
+        } else {
+            return TMR_paramGet (&reader->reader, key, value);
+        }
+    }
+}
+
+TMR_Status c_TMR_reboot (ReaderEtc *reader)
+{
+    if (reader->destroyed)
+        return ERROR_ALREADY_DESTROYED;
+    else
+        return TMR_reboot (&reader->reader);
+}
+
+void c_default_read_plan (TMR_ReadPlan *rp)
+{
+    /* This should match the call to TMR_RP_init_simple() in
+     * TMR_reader_init_internal() in tm_reader.c. */
+    TMR_RP_init_simple (rp, 0, NULL, TMR_TAG_PROTOCOL_GEN2, 1);
+}
+
+TMR_Status c_TMR_paramList (ReaderEtc *reader, TMR_Param *keys, uint32_t *len)
+{
+    if (reader->destroyed)
+        return ERROR_ALREADY_DESTROYED;
+    else
+        return TMR_paramList (&reader->reader, keys, len);
+}
+
+/* takes ownership of func and unique */
+TMR_Status c_TMR_addTransportListener (ReaderEtc *reader,
+                                       TMR_TransportListener func,
+                                       char *unique)
+{
+    TransportListenerEtc *listener;
+
+    if (reader->destroyed)
+        return ERROR_ALREADY_DESTROYED;
+
+    listener = (TransportListenerEtc *) malloc (sizeof (TransportListenerEtc));
+    if (! listener)
+        return TMR_ERROR_OUT_OF_MEMORY;
+
+    listener->block.listener = func;
+    listener->block.cookie = NULL;
+    listener->key = unique;
+    listener->funPtr = (HsFunPtr) func;
+    listener->next = reader->transportListeners;
+    reader->transportListeners = listener;
+
+    return TMR_addTransportListener (&reader->reader, &listener->block);
+}
+
+TMR_Status c_TMR_removeTransportListener (ReaderEtc *reader,
+                                          const char *unique)
+{
+    TransportListenerEtc *listener, **prev;
+
+    if (reader->destroyed)
+        return ERROR_ALREADY_DESTROYED;
+
+    prev = &reader->transportListeners;
+    for (listener = reader->transportListeners;
+         listener != NULL;
+         prev = &listener->next, listener = listener->next) {
+        if (0 == strcmp (unique, listener->key))
+            return free_transport_listener (&reader->reader, listener, prev);
+    }
+
+    return TMR_ERROR_INVALID;
+}
+
+const char *c_TMR_strerr (ReaderEtc *reader, TMR_Status status)
+{
+    TMR_Reader *tmr;
+
+    if (reader && !reader->destroyed)
+        tmr = &reader->reader;
+    else
+        tmr = NULL;
+
+    switch (status) {
+    case ERROR_ALREADY_DESTROYED:
+        return "Attempt to use reader after it was destroyed";
+    default:
+        return TMR_strerr (tmr, status);
+    }
+}
+
+void *c_new_c_locale (void)
+{
+    /* We need to call tzset once before calling localtime_r, and this seems
+     * like a good place to do it. */
+    tzset();
+#ifdef _WIN32
+    /* Unused on Windows, so value doesn't matter, but can't be NULL. */
+    return (void*) 1;
+#else
+    /* Allocate a new locale.  We only do this once, so it's okay
+     * that it leaks. */
+    return (void *) newlocale(LC_ALL_MASK, "C", (locale_t) 0);
+#endif
+}
+
+int c_format_time (char *buf,
+                   size_t len,
+                   const char *fmt,
+                   time_t seconds,
+                   bool local,
+                   void *locale)
+{
+    time_t t;
+    struct tm stm, *stmp;
+
+    t = seconds;
+#ifdef _WIN32
+    if (local)
+        stmp = localtime (&t);
+    else
+        stmp = gmtime (&t);
+#else
+    if (local)
+        stmp = localtime_r (&t, &stm);
+    else
+        stmp = gmtime_r (&t, &stm);
+#endif
+
+    if (! stmp)
+        return -1;
+#ifdef _WIN32
+    if (0 == strftime (buf, len, fmt, stmp))
+        return -1;
+#else
+    if (0 == strftime_l (buf, len, fmt, stmp, (locale_t) locale))
+        return -1;
+#endif
+    return 0;
+}
diff --git a/cbits/glue/glue.h b/cbits/glue/glue.h
new file mode 100644
--- /dev/null
+++ b/cbits/glue/glue.h
@@ -0,0 +1,141 @@
+#ifndef GLUE_H
+#define GLUE_H
+
+#include <stdbool.h>
+#include <time.h>
+#include <HsFFI.h>
+
+#include "tm_reader.h"
+
+/** An error which originates from the Haskell binding, not the underlying C library. */
+#define ERROR_TYPE_BINDING 127L
+
+#define ERROR_BINDING(x)                TMR_STATUS_MAKE(ERROR_TYPE_BINDING, (x))
+
+/** Attempt to use reader after it was destroyed. */
+#define ERROR_ALREADY_DESTROYED         ERROR_BINDING(1)
+
+typedef struct TransportListenerEtc TransportListenerEtc;
+typedef struct ReaderEtc ReaderEtc;
+typedef struct List16 List16;
+typedef struct List8 List8;
+typedef struct ReadPlanEtc ReadPlanEtc;
+typedef struct TagOpEtc TagOpEtc;
+typedef struct TagFilterEtc TagFilterEtc;
+
+struct ReaderEtc {
+    TMR_Reader reader;
+    TransportListenerEtc *transportListeners;
+    ReadPlanEtc *readPlan;
+    bool destroyed;
+    char uri[1]; // must be last
+};
+
+struct TransportListenerEtc {
+    TMR_TransportListenerBlock block;
+    char *key;
+    HsFunPtr funPtr;
+    struct TransportListenerEtc *next;
+};
+
+/* Has the same storage layout as the various TMR_*List structs
+ * which use a 16-bit length, such as:
+ * TMR_uint8List
+ * TMR_uint16List
+ * TMR_uint32List
+ * TMR_StatsPerAntennaValuesList
+ * Can also be used for TMR_String, if you ignore len.
+ */
+struct List16 {
+    /** The array of values */
+    void *list;
+    /** The number of entries there is space for in the array */
+    uint16_t max;
+    /** The number of entries in the list - may be larger than max, indicating truncated data. */
+    uint16_t len;
+};
+
+/* Has the same storage layout as the various TMR_*List structs
+ * which use an 8-bit length, such as:
+ * TMR_int8List
+ * TMR_RegionList
+ * TMR_TagProtocolList
+ */
+struct List8 {
+    /** The array of values */
+    void *list;
+    /** The number of entries there is space for in the array */
+    uint8_t max;
+    /** The number of entries in the list - may be larger than max, indicating truncated data. */
+    uint8_t len;
+};
+
+#define GLUE_MAX_MASK TMR_MAX_EMBEDDED_DATA_LENGTH
+
+struct TagFilterEtc {
+    TMR_TagFilter filter;
+    uint8_t mask[GLUE_MAX_MASK];
+};
+
+#define GLUE_MAX_DATA16 TMR_MAX_EMBEDDED_DATA_LENGTH
+
+struct TagOpEtc {
+    TMR_TagOp tagop;
+    union {
+        TMR_TagData epc;
+        uint16_t data16[GLUE_MAX_DATA16];
+    } u;
+};
+
+#define GLUE_MAX_ANTENNAS TMR_SR_MAX_ANTENNA_PORTS
+#define GLUE_MAX_GPIPORTS 16
+
+struct ReadPlanEtc {
+    TMR_ReadPlan plan;
+    uint8_t antennas[GLUE_MAX_ANTENNAS];
+    uint8_t gpiPorts[GLUE_MAX_GPIPORTS];
+    TagFilterEtc filter;
+    TagOpEtc tagop;
+};
+
+TMR_Status c_TMR_create (ReaderEtc *reader, const char *deviceUri);
+TMR_Status c_TMR_connect (ReaderEtc *reader);
+TMR_Status c_TMR_destroy (ReaderEtc *reader);
+TMR_Status c_TMR_read (ReaderEtc *reader, uint32_t timeoutMs, int32_t *tagCount);
+TMR_Status c_TMR_hasMoreTags (ReaderEtc *reader);
+TMR_Status c_TMR_getNextTag (ReaderEtc *reader, TMR_TagReadData *tagData);
+TMR_Status c_TMR_executeTagOp (ReaderEtc *reader,
+                               TMR_TagOp *tagop,
+                               TMR_TagFilter *filter,
+                               TMR_uint8List *data);
+TMR_Status c_TMR_gpoSet (ReaderEtc *reader,
+                         uint8_t count,
+                         const TMR_GpioPin state[]);
+TMR_Status c_TMR_gpiGet (ReaderEtc *reader,
+                         uint8_t *count,
+                         TMR_GpioPin state[]);
+TMR_Status c_TMR_firmwareLoad (ReaderEtc *reader,
+                               uint8_t *firmwareStart,
+                               uint32_t firmwareSize);
+TMR_Status c_TMR_paramSet (ReaderEtc *reader,
+                           TMR_Param key,
+                           const void *value);
+TMR_Status c_TMR_paramGet (ReaderEtc *reader, TMR_Param key, void *value);
+TMR_Status c_TMR_reboot (ReaderEtc *reader);
+void c_default_read_plan (TMR_ReadPlan *rp);
+TMR_Status c_TMR_paramList (ReaderEtc *reader, TMR_Param *keys, uint32_t *len);
+TMR_Status c_TMR_addTransportListener (ReaderEtc *reader,
+                                       TMR_TransportListener func,
+                                       char *unique);
+TMR_Status c_TMR_removeTransportListener (ReaderEtc *reader,
+                                          const char *unique);
+const char *c_TMR_strerr (ReaderEtc *reader, TMR_Status status);
+void *c_new_c_locale (void);
+int c_format_time (char *buf,
+                   size_t len,
+                   const char *fmt,
+                   time_t seconds,
+                   bool local,
+                   void *locale);
+
+#endif  /* GLUE_H */
diff --git a/examples/ExampleUtil.hs b/examples/ExampleUtil.hs
new file mode 100644
--- /dev/null
+++ b/examples/ExampleUtil.hs
@@ -0,0 +1,122 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module ExampleUtil
+  ( createAndConnect
+  , createConnectAndParams
+  , optUri
+  , optRegion
+  , optPower
+  , optListen
+  ) where
+
+import Control.Exception ( throw, try )
+import Control.Monad ( when, void, forM_ )
+import Data.Int ( Int32 )
+import Data.Monoid ( (<>) )
+import qualified Data.Text as T ( replicate, pack, length )
+import qualified Data.Text.IO as T ( putStrLn )
+import Options.Applicative
+    ( Parser,
+      value,
+      switch,
+      strOption,
+      short,
+      option,
+      metavar,
+      long,
+      help,
+      auto )
+import qualified System.Hardware.MercuryApi as TMR
+import qualified System.Hardware.MercuryApi.Params as TMR
+import System.Exit ( exitFailure )
+import System.Info ( os )
+import System.IO ( stdout )
+
+printRegionsAndFail :: TMR.Reader -> IO a
+printRegionsAndFail rdr = do
+  rgns <- TMR.paramGetRegionSupportedRegions rdr
+  T.putStrLn "Region must be one of:"
+  forM_ rgns $ \rgn -> do
+    let dr = TMR.displayRegion rgn
+        nSpaces = 6 - T.length dr
+        spaces = T.replicate nSpaces " "
+    T.putStrLn $ "  " <> dr <> spaces <> TMR.displayRegionDescription rgn
+  exitFailure
+
+parseRegionOrFail :: TMR.Reader -> String -> IO TMR.Region
+parseRegionOrFail rdr s =
+  case TMR.parseRegion (T.pack s) of
+    Nothing -> printRegionsAndFail rdr
+    Just rgn -> return rgn
+
+printPowerAndFail :: TMR.Reader -> IO a
+printPowerAndFail rdr = do
+  lo <- TMR.paramGetRadioPowerMin rdr
+  hi <- TMR.paramGetRadioPowerMax rdr
+  putStrLn $ "Power must be between " ++ show lo ++ " and " ++ show hi
+  exitFailure
+
+handleParamError :: TMR.Reader -> Either TMR.MercuryException () -> IO ()
+handleParamError _ (Right _) = return ()
+handleParamError rdr (Left err) = hpe (TMR.meStatus err)
+  where hpe TMR.ERROR_INVALID_REGION = printRegionsAndFail rdr
+        hpe TMR.ERROR_MSG_POWER_TOO_HIGH = printPowerAndFail rdr
+        hpe TMR.ERROR_MSG_POWER_TOO_LOW = printPowerAndFail rdr
+        hpe _ = throw err
+
+createAndConnect :: String -> Bool -> IO TMR.Reader
+createAndConnect uri listen = do
+  rdr <- TMR.create $ T.pack uri
+  when (listen) $ do
+    listener <- TMR.opcodeListener stdout
+    void $ TMR.addTransportListener rdr listener
+  TMR.paramSetTransportTimeout rdr 10000
+  TMR.connect rdr
+  return rdr
+
+createConnectAndParams :: String -> Bool -> String -> Int32 -> IO TMR.Reader
+createConnectAndParams uri listen region power = do
+  rdr <- createAndConnect uri listen
+  rgn <- parseRegionOrFail rdr region
+  eth <- try $ TMR.paramSetBasics rdr rgn power TMR.sparkFunAntennas
+  handleParamError rdr eth
+  TMR.paramSetTagReadDataRecordHighestRssi rdr True
+  return rdr
+
+defUri :: String
+defUri = case os of
+           "darwin" -> "tmr:///dev/cu.SLAB_USBtoUART"
+           "mingw32" -> "tmr:///COM4"
+           _ -> "tmr:///dev/ttyUSB0"
+
+defRegion :: String
+defRegion = "na2"
+
+defPower :: Int32
+defPower = 2300
+
+optUri :: Parser String
+optUri = strOption (long "uri" <>
+                    short 'u' <>
+                    metavar "URI" <>
+                    help ("Reader to connect to (default " ++ defUri ++ ")") <>
+                    value defUri)
+
+optRegion :: Parser String
+optRegion = strOption (long "region" <>
+                       short 'r' <>
+                       metavar "REGION" <>
+                       help ("Regulatory region (default " ++ defRegion ++ ")") <>
+                       value defRegion)
+
+optPower :: Parser Int32
+optPower = option auto (long "power" <>
+                        short 'p' <>
+                        metavar "CENTI-DBM" <>
+                        help ("Power level (0-2700, default " ++ show defPower ++ ")") <>
+                        value defPower)
+
+optListen :: Parser Bool
+optListen = switch (long "transport-listener" <>
+                    short 't' <>
+                    help "Print bytes sent on serial port")
diff --git a/examples/LICENSE-FOR-EXAMPLES b/examples/LICENSE-FOR-EXAMPLES
new file mode 100644
--- /dev/null
+++ b/examples/LICENSE-FOR-EXAMPLES
@@ -0,0 +1,121 @@
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+    HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+  i. the right to reproduce, adapt, distribute, perform, display,
+     communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+     likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+     subject to the limitations in paragraph 4(a), below;
+  v. rights protecting the extraction, dissemination, use and reuse of data
+     in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+     European Parliament and of the Council of 11 March 1996 on the legal
+     protection of databases, and under any national implementation
+     thereof, including any amended or successor version of such
+     directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+     world based on applicable law or treaty, and any national
+     implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+    surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+    warranties of any kind concerning the Work, express, implied,
+    statutory or otherwise, including without limitation warranties of
+    title, merchantability, fitness for a particular purpose, non
+    infringement, or the absence of latent or other defects, accuracy, or
+    the present or absence of errors, whether or not discoverable, all to
+    the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+    that may apply to the Work or any use thereof, including without
+    limitation any person's Copyright and Related Rights in the Work.
+    Further, Affirmer disclaims responsibility for obtaining any necessary
+    consents, permissions or other rights required for any use of the
+    Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+    party to this document and has no duty or obligation with respect to
+    this CC0 or use of the Work.
diff --git a/examples/tmr-firmware.hs b/examples/tmr-firmware.hs
new file mode 100644
--- /dev/null
+++ b/examples/tmr-firmware.hs
@@ -0,0 +1,65 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Control.Monad ( when )
+import Data.Monoid ( (<>) )
+import qualified Data.Text.IO as T ( putStrLn )
+import Options.Applicative
+    ( Applicative((<*>)),
+      Parser,
+      helper,
+      execParser,
+      str,
+      progDesc,
+      metavar,
+      info,
+      header,
+      fullDesc,
+      argument,
+      (<$>),
+      optional )
+import qualified System.Hardware.MercuryApi as TMR
+import System.Exit ( exitSuccess )
+
+import ExampleUtil
+
+data Opts = Opts
+  { oUri :: String
+  , oListen :: Bool
+  , oFilename :: Maybe String
+  }
+
+opts :: Parser Opts
+opts = Opts
+  <$> optUri
+  <*> optListen
+  <*> optional (argument str (metavar "FILENAME"))
+
+opts' = info (helper <*> opts)
+  ( fullDesc <>
+    progDesc ("If run without firmware file, just print current " ++
+              "firmware version.  " ++
+              "Firmware file can be downloaded from: " ++
+              "http://www.thingmagic.com/index.php/download-nano-firmware") <>
+    header "tmr-firmware - write a new firmware image to reader" )
+
+printFwVers :: TMR.Reader -> IO ()
+printFwVers rdr =
+  TMR.paramGet rdr TMR.PARAM_VERSION_SOFTWARE >>= T.putStrLn
+
+main = do
+  o <- execParser opts'
+  rdr <- createAndConnect (oUri o) (oListen o)
+
+  putStr "Current firmware version: "
+  printFwVers rdr
+
+  when (oFilename o == Nothing) exitSuccess
+  let (Just fwFile) = oFilename o
+
+  putStrLn $ "Loading firmware image from " ++ fwFile
+  TMR.firmwareLoadFile rdr fwFile
+
+  putStr "New firmware version: "
+  printFwVers rdr
+
+  TMR.destroy rdr
diff --git a/examples/tmr-gpio.hs b/examples/tmr-gpio.hs
new file mode 100644
--- /dev/null
+++ b/examples/tmr-gpio.hs
@@ -0,0 +1,81 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Control.Concurrent ( threadDelay )
+import Control.Exception ( finally )
+import Control.Monad ( when )
+import Data.Monoid ( (<>) )
+import qualified Data.Text.IO as T ( putStrLn )
+import Options.Applicative
+    ( Alternative(many),
+      Applicative((<*>)),
+      Parser,
+      helper,
+      execParser,
+      metavar,
+      info,
+      header,
+      fullDesc,
+      auto,
+      argument,
+      (<$>) )
+import qualified System.Hardware.MercuryApi as TMR
+import qualified System.Hardware.MercuryApi.Params as TMR
+
+import ExampleUtil
+
+data Opts = Opts
+  { oUri :: String
+  , oListen :: Bool
+  , oGpos :: [TMR.PinNumber]
+  }
+
+opts :: Parser Opts
+opts = Opts
+  <$> optUri
+  <*> optListen
+  <*> many (argument auto (metavar "OUTPUTS..."))
+
+opts' = info (helper <*> opts)
+  ( fullDesc <>
+    header "tmr-gpio - print GPIs and control GPOs" )
+
+delayMillis :: Int
+delayMillis = 100
+
+mkPin :: TMR.PinNumber -> TMR.PinNumber -> TMR.GpioPin
+mkPin highPin pin =
+  TMR.GpioPin
+  { TMR.gpId = pin
+  , TMR.gpHigh = highPin == pin
+  , TMR.gpOutput = True
+  }
+
+gpioLoop :: TMR.Reader -> [TMR.PinNumber] -> Integer -> [TMR.GpioPin] -> IO ()
+gpioLoop rdr outPins millis oldPins = do
+  pins <- TMR.gpiGet rdr
+  when (pins /= oldPins) $ mapM_ T.putStrLn $ TMR.displayGpio pins
+  when (not $ null outPins) $ do
+    let oLen = length outPins
+        pinNo = outPins !! fromIntegral ((millis `div` 1000) `mod` fromIntegral oLen)
+        gpoPins = map (mkPin pinNo) outPins
+    TMR.gpoSet rdr gpoPins
+  threadDelay $ delayMillis * 1000
+  gpioLoop rdr outPins (millis + fromIntegral delayMillis) pins
+
+main = do
+  o <- execParser opts'
+  rdr <- createAndConnect (oUri o) (oListen o)
+
+  -- set all the pins to input
+  TMR.paramSetGpioInputList rdr [1..4]
+
+  -- then set some to output
+  let outPins = oGpos o
+  TMR.paramSetGpioOutputList rdr outPins
+  putStrLn $ "cycling among output pins " ++ show outPins
+
+  -- now see which inputs are left
+  inPins <- TMR.paramGetGpioInputList rdr
+  putStrLn $ "listening on input pins " ++ show inPins
+
+  gpioLoop rdr outPins 0 [] `finally` TMR.destroy rdr
diff --git a/examples/tmr-lock.hs b/examples/tmr-lock.hs
new file mode 100644
--- /dev/null
+++ b/examples/tmr-lock.hs
@@ -0,0 +1,96 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Control.Exception ( throw, try )
+import Control.Monad ( when, void )
+import Data.Int ( Int32 )
+import Data.List ( maximumBy )
+import Data.Monoid ( (<>) )
+import Data.Ord ( comparing )
+import qualified Data.Text.IO as T ( putStrLn )
+import Options.Applicative
+    ( Applicative((<*>)),
+      Parser,
+      helper,
+      execParser,
+      info,
+      header,
+      fullDesc,
+      (<$>) )
+import qualified System.Hardware.MercuryApi as TMR
+
+import ExampleUtil
+
+data Opts = Opts
+  { oUri :: String
+  , oRegion :: String
+  , oPower :: Int32
+  , oListen :: Bool
+  }
+
+opts :: Parser Opts
+opts = Opts
+  <$> optUri
+  <*> optRegion
+  <*> optPower
+  <*> optListen
+
+opts' = info (helper <*> opts)
+  ( fullDesc <>
+    header "tmr-lock - test that locking works" )
+
+password :: TMR.GEN2_Password
+password = 12345
+
+main = do
+  o <- execParser opts'
+
+  rdr <- createConnectAndParams (oUri o) (oListen o) (oRegion o) (oPower o)
+
+  tags <- TMR.read rdr 1000
+  putStrLn $ "read " ++ show (length tags) ++ " tags"
+  when (not $ null tags) $ do
+    let trd = maximumBy (comparing TMR.trRssi) tags
+        td = TMR.trTag trd
+        epc = TMR.tdEpc td
+        hex = TMR.bytesToHex epc
+
+    T.putStrLn $ "writing password to <" <> hex <> ">"
+    let epcFilt = TMR.TagFilterEPC td
+        opWrite = TMR.TagOp_GEN2_WriteData
+                  { TMR.opBank = TMR.GEN2_BANK_RESERVED
+                  , TMR.opWordAddress = TMR.accessPasswordAddress
+                  , TMR.opData = TMR.passwordToWords password
+                  }
+    TMR.executeTagOp rdr opWrite (Just epcFilt)
+
+    T.putStrLn $ "locking <" <> hex <> ">"
+    let opLock = TMR.TagOp_GEN2_Lock
+                 { TMR.opMask   = [TMR.GEN2_LOCK_BITS_USER]
+                 , TMR.opAction = [TMR.GEN2_LOCK_BITS_USER]
+                 , TMR.opAccessPassword = password
+                 }
+    TMR.executeTagOp rdr opLock (Just epcFilt)
+
+    T.putStrLn $ "attempting to write user data to <" <> hex <> ">"
+    let opWrite2 = TMR.TagOp_GEN2_WriteData
+                  { TMR.opBank = TMR.GEN2_BANK_USER
+                  , TMR.opWordAddress = 0
+                  , TMR.opData = TMR.packBytesIntoWords "This should fail"
+                  }
+    eth <- try $ TMR.executeTagOp rdr opWrite2 (Just epcFilt)
+    case eth of
+      Right _ ->
+        T.putStrLn "Write succeeded, but it shouldn't have."
+      Left err ->
+        when (TMR.meStatus err /= TMR.ERROR_PROTOCOL_WRITE_FAILED &&
+              TMR.meStatus err /= TMR.ERROR_PROTOCOL_BIT_DECODING_FAILED) $ throw err
+
+    T.putStrLn $ "unlocking <" <> hex <> ">"
+    let opUnlock = TMR.TagOp_GEN2_Lock
+                   { TMR.opMask   = [TMR.GEN2_LOCK_BITS_USER]
+                   , TMR.opAction = []
+                   , TMR.opAccessPassword = password
+                   }
+    void $ TMR.executeTagOp rdr opUnlock (Just epcFilt)
+
+  TMR.destroy rdr
diff --git a/examples/tmr-params.hs b/examples/tmr-params.hs
new file mode 100644
--- /dev/null
+++ b/examples/tmr-params.hs
@@ -0,0 +1,79 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Control.Exception ( try )
+import Control.Monad ( forM_ )
+import Data.List ( sortBy )
+import Data.Monoid ( (<>) )
+import qualified Data.Text as T ( dropWhileEnd )
+import qualified Data.Text.IO as T ( putStrLn, putStr )
+import Options.Applicative
+    ( Applicative((<*>)),
+      Parser,
+      helper,
+      execParser,
+      info,
+      header,
+      fullDesc,
+      (<$>) )
+import System.Console.ANSI
+    ( SGR(Reset, SetColor),
+      Color(Blue, Green, Red),
+      ColorIntensity(Dull, Vivid),
+      ConsoleLayer(Foreground),
+      setSGR )
+import qualified System.Hardware.MercuryApi as TMR
+import qualified System.Hardware.MercuryApi.Params as TMR
+
+import ExampleUtil
+
+data Opts = Opts
+  { oUri :: String
+  , oListen :: Bool
+  }
+
+opts :: Parser Opts
+opts = Opts
+  <$> optUri
+  <*> optListen
+
+opts' = info (helper <*> opts)
+  ( fullDesc <>
+    header "tmr-params - print parameters" )
+
+compareParams :: TMR.Param -> TMR.Param -> Ordering
+compareParams p1 p2 =
+  let n1 = TMR.paramName p1
+      n2 = TMR.paramName p2
+      b1 = T.dropWhileEnd (/= '/') n1
+      b2 = T.dropWhileEnd (/= '/') n2
+  in case b1 `compare` b2 of
+       EQ -> n1 `compare` n2
+       x -> x
+
+main = do
+  o <- execParser opts'
+  T.putStrLn $ "API version: " <> TMR.apiVersion
+  rdr <- createAndConnect (oUri o) (oListen o)
+
+  params <- TMR.paramList rdr
+  forM_ (sortBy compareParams params) $ \param -> do
+    setSGR [SetColor Foreground Vivid Blue]
+    putStr $ show param
+    setSGR [Reset]
+    T.putStrLn $ " - " <> TMR.paramName param
+    let typ = TMR.displayParamType $ TMR.paramType param
+    eth <- try $ TMR.paramGetString rdr param
+    case eth of
+      Left err -> do
+        setSGR [SetColor Foreground Vivid Red]
+        putStrLn $ "  " ++ show (TMR.meStatus err)
+        setSGR [Reset]
+      Right txt -> do
+        setSGR [SetColor Foreground Dull Green]
+        T.putStr $ "  " <> txt
+        setSGR [Reset]
+        T.putStr $ " :: " <> typ
+        case TMR.paramUnits param of
+          Nothing -> T.putStrLn ""
+          Just units -> T.putStrLn $ " (" <> units <> ")"
+  TMR.destroy rdr
diff --git a/examples/tmr-read.hs b/examples/tmr-read.hs
new file mode 100644
--- /dev/null
+++ b/examples/tmr-read.hs
@@ -0,0 +1,99 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Control.Monad ( when, forM_ )
+import qualified Data.ByteString as B ( takeWhile, null )
+import Data.Int ( Int32 )
+import Data.List ( sortBy )
+import Data.Monoid ( (<>) )
+import Data.Ord ( comparing )
+import qualified Data.Text as T ( Text, takeWhile, pack, null )
+import qualified Data.Text.IO as T ( putStrLn )
+import Options.Applicative
+    ( Applicative((<*>)),
+      Parser,
+      helper,
+      execParser,
+      switch,
+      short,
+      long,
+      info,
+      help,
+      header,
+      fullDesc,
+      (<$>) )
+import System.Console.ANSI
+    ( SGR(Reset, SetColor, SetConsoleIntensity),
+      Color(Blue),
+      ColorIntensity(Vivid),
+      ConsoleIntensity(BoldIntensity),
+      ConsoleLayer(Foreground),
+      setSGR )
+import qualified System.Hardware.MercuryApi as TMR
+import Text.Printf ( printf )
+
+import ExampleUtil
+
+data Opts = Opts
+  { oUri :: String
+  , oRegion :: String
+  , oPower :: Int32
+  , oListen :: Bool
+  , oLong :: Bool
+  }
+
+opts :: Parser Opts
+opts = Opts
+  <$> optUri
+  <*> optRegion
+  <*> optPower
+  <*> optListen
+  <*> switch (long "long" <>
+              short 'l' <>
+              help "Print lots of information per tag")
+
+opts' = info (helper <*> opts)
+  ( fullDesc <>
+    header "tmr-read - read tags" )
+
+readUser =
+  TMR.TagOp_GEN2_ReadData
+  { TMR.opBank = TMR.GEN2_BANK_USER
+  , TMR.opExtraBanks = []
+  , TMR.opWordAddress = 0
+  , TMR.opLen = 32
+  }
+
+putWithBold :: T.Text -> IO ()
+putWithBold txt = do
+  let bold = T.null $ T.takeWhile (== ' ') txt
+  when bold $ setSGR [SetConsoleIntensity BoldIntensity]
+  T.putStrLn txt
+  when bold $ setSGR [Reset]
+
+displayTag :: TMR.TagReadData -> T.Text
+displayTag trd = strength <> " <" <> epc <> ">" <> user
+  where
+    strength = T.pack $ printf "%3d" (TMR.trRssi trd)
+    epc = TMR.bytesToHex $ TMR.tdEpc $ TMR.trTag trd
+    dat = TMR.trData trd
+    user =
+      if B.null dat
+      then "" -- this means it failed to read the user data
+      else T.pack $ ' ' : show (B.takeWhile (/= 0) dat)
+
+main = do
+  o <- execParser opts'
+
+  rdr <- createConnectAndParams (oUri o) (oListen o) (oRegion o) (oPower o)
+  TMR.paramSetReadPlanTagop rdr (Just readUser)
+
+  tags <- TMR.read rdr 1000
+  let tags' = reverse $ sortBy (comparing TMR.trRssi) tags
+  setSGR [SetColor Foreground Vivid Blue]
+  putStrLn $ "read " ++ show (length tags') ++ " tags"
+  setSGR [Reset]
+  if oLong o
+    then mapM_ putWithBold (concatMap TMR.displayTagReadData tags')
+    else forM_ tags' (T.putStrLn . displayTag)
+
+  TMR.destroy rdr
diff --git a/examples/tmr-write.hs b/examples/tmr-write.hs
new file mode 100644
--- /dev/null
+++ b/examples/tmr-write.hs
@@ -0,0 +1,100 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Control.Monad ( when )
+import qualified Data.ByteString as B ( snoc, pack )
+import Data.Int ( Int32 )
+import Data.List ( maximumBy )
+import Data.Monoid ( (<>) )
+import Data.Ord ( comparing )
+import qualified Data.Text as T ( Text, pack )
+import qualified Data.Text.Encoding as T ( encodeUtf8 )
+import qualified Data.Text.IO as T ( putStrLn )
+import Options.Applicative
+    ( Applicative((<*>)),
+      Parser,
+      helper,
+      execParser,
+      switch,
+      str,
+      short,
+      metavar,
+      long,
+      info,
+      help,
+      header,
+      fullDesc,
+      argument,
+      (<$>) )
+import System.Console.ANSI
+    ( SGR(Reset, SetColor),
+      Color(Green, Red),
+      ColorIntensity(Vivid),
+      ConsoleLayer(Foreground),
+      setSGR )
+import qualified System.Hardware.MercuryApi as TMR
+
+import ExampleUtil
+
+data Opts = Opts
+  { oUri :: String
+  , oRegion :: String
+  , oPower :: Int32
+  , oListen :: Bool
+  , oRewrite :: Bool
+  , oString :: String
+  }
+
+opts :: Parser Opts
+opts = Opts
+  <$> optUri
+  <*> optRegion
+  <*> optPower
+  <*> optListen
+  <*> switch (long "rewrite" <>
+              short 'R' <>
+              help "Write to a tag even if written before")
+  <*> argument str (metavar "STRING")
+
+opts' = info (helper <*> opts)
+  ( fullDesc <>
+    header "tmr-write - write a string to user data of tag" )
+
+emptyUserDataFilter :: TMR.TagFilter
+emptyUserDataFilter = TMR.mkFilterGen2 TMR.GEN2_BANK_USER 0 $ B.pack [0, 0]
+
+printColor :: Color -> T.Text -> IO ()
+printColor c txt = do
+  setSGR [SetColor Foreground Vivid c]
+  T.putStrLn txt
+  setSGR [Reset]
+
+main = do
+  o <- execParser opts'
+
+  rdr <- createConnectAndParams (oUri o) (oListen o) (oRegion o) (oPower o)
+  when (not $ oRewrite o) $
+    TMR.paramSetReadPlanFilter rdr (Just emptyUserDataFilter)
+
+  tags <- TMR.read rdr 1000
+  putStrLn $ "read " ++ show (length tags) ++ " tags"
+  if null tags
+    then do
+    printColor Red "No tag found"
+    else do
+    let trd = maximumBy (comparing TMR.trRssi) tags
+        td = TMR.trTag trd
+        epc = TMR.tdEpc td
+        hex = TMR.bytesToHex epc
+    T.putStrLn $ "writing <" <> hex <> ">"
+    let epcFilt = TMR.TagFilterEPC td
+        txt = T.pack (oString o)
+        words = TMR.packBytesIntoWords $ T.encodeUtf8 txt `B.snoc` 0
+        opWrite = TMR.TagOp_GEN2_WriteData
+                  { TMR.opBank = TMR.GEN2_BANK_USER
+                  , TMR.opWordAddress = 0
+                  , TMR.opData = words
+                  }
+    TMR.executeTagOp rdr opWrite (Just epcFilt)
+    printColor Green "Success!"
+
+  TMR.destroy rdr
diff --git a/mercury-api.cabal b/mercury-api.cabal
new file mode 100644
--- /dev/null
+++ b/mercury-api.cabal
@@ -0,0 +1,270 @@
+-- Initial mercury-api.cabal generated by cabal init.  For further
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+-- The name of the package.
+name:                mercury-api
+
+-- The package version.  See the Haskell package versioning policy (PVP)
+-- for standards guiding when and how versions should be incremented.
+-- https://wiki.haskell.org/Package_versioning_policy
+-- PVP summary:      +-+------- breaking API changes
+--                   | | +----- non-breaking API additions
+--                   | | | +--- code changes with no API change
+version:             0.1.0.0
+
+-- A short (one-line) description of the package.
+synopsis:            Haskell binding to Mercury API for ThingMagic RFID readers
+
+-- A longer description of the package.
+description:
+    This package is a Haskell binding to the \"Mercury API\" C API for
+    ThingMagic RFID readers.  It is especially geared toward the
+    <https://www.sparkfun.com/products/14066 SparkFun Simultaneous RFID Reader>,
+    which uses ThingMagic's M6e Nano module, but it should work with other
+    ThingMagic readers.  (Though currently, only support for serial readers
+    is compiled in.)  Most of the function and type names are the same as
+    their counterparts in the C API, with the @TMR_@ prefix dropped.  For more
+    in-depth, language-independent documentation of Mercury API, see
+    <http://www.thingmagic.com/images/Downloads/Docs/MercuryAPI_ProgrammerGuide_for_v1.27.3.pdf Mercury API Programmers Guide>.
+
+-- The license under which the package is released.
+license:             MIT
+
+-- The file containing the license text.
+license-file:        LICENSE
+
+-- The package author(s).
+author:              Patrick Pelletier
+
+-- An email address to which users can send suggestions, bug reports, and
+-- patches.
+maintainer:          code@funwithsoftware.org
+
+homepage:            https://github.com/ppelleti/hs-mercury-api
+
+bug-reports:         https://github.com/ppelleti/hs-mercury-api/issues
+
+-- A copyright notice.
+copyright:           © Patrick Pelletier, 2017
+
+category:            Hardware
+
+build-type:          Simple
+
+-- Extra files to be distributed with the package, such as examples or a
+-- README.
+extra-source-files:  ChangeLog.md
+                   , README.md
+                   , UPGRADING.md
+                   , examples/LICENSE-FOR-EXAMPLES
+                   , tests/*.result
+                   , tests/*.transport
+                   , cbits/api/*.h
+                   , cbits/api/patches/README.md
+                   , cbits/api/patches/*.patch
+                   , cbits/glue/glue.h
+
+-- Constraint on the version of Cabal needed to build this package.
+cabal-version:       >=1.10
+
+tested-with:
+  GHC==7.6.3,
+  GHC==7.8.4,
+  GHC==7.10.3,
+  GHC==8.0.2
+
+source-repository head
+  Type:     git
+  Location: https://github.com/ppelleti/hs-mercury-api.git
+
+
+library
+  -- Modules exported by the library.
+  exposed-modules:     System.Hardware.MercuryApi
+                     , System.Hardware.MercuryApi.Params
+                     , System.Hardware.MercuryApi.Testing
+
+  -- Modules included in this library but not exported.
+  other-modules:       System.Hardware.MercuryApi.Enums
+                     , System.Hardware.MercuryApi.Records
+                     , System.Hardware.MercuryApi.ParamValue
+
+  -- LANGUAGE extensions used by modules in this package.
+  -- other-extensions:
+
+  -- Apparently these are supposed to be listed in dependency order,
+  -- although the Cabal documentation doesn't breathe a word about it:
+  -- https://ghc.haskell.org/trac/ghc/ticket/13786#comment:3
+  --
+  -- Furthermore, it appears that Cabal always puts conditional sources
+  -- after unconditional sources, so in order to get the sources in the
+  -- right order, they need to all be conditional, i. e. we have to list
+  -- the sources twice, once for Windows and once for POSIX.
+  if os(windows)
+    c-sources:         cbits/api/serial_transport_win32.c
+                     , cbits/api/osdep_win32.c
+                     , cbits/api/tmr_strerror.c
+                     , cbits/api/tmr_utils.c
+                     , cbits/api/tmr_param.c
+                     , cbits/api/hex_bytes.c
+                     , cbits/api/serial_reader_l3.c
+                     , cbits/api/serial_reader.c
+                     , cbits/api/tm_reader_async.c
+                     , cbits/api/tm_reader.c
+                     , cbits/glue/glue.c
+  else
+    c-sources:         cbits/api/serial_transport_posix.c
+                     , cbits/api/osdep_posix.c
+                     , cbits/api/tmr_strerror.c
+                     , cbits/api/tmr_utils.c
+                     , cbits/api/tmr_param.c
+                     , cbits/api/hex_bytes.c
+                     , cbits/api/serial_reader_l3.c
+                     , cbits/api/serial_reader.c
+                     , cbits/api/tm_reader_async.c
+                     , cbits/api/tm_reader.c
+                     , cbits/glue/glue.c
+
+  include-dirs:        cbits/api
+                     , cbits/glue
+
+  cc-options:          -DTMR_ENABLE_SERIAL_READER_ONLY=1
+                       -DTMR_USE_HOST_C_LIBRARY=1
+
+  -- Other library packages from which modules are imported.
+  build-depends:       base >= 4.6 && < 5
+                     , ansi-terminal >= 0.6.2.3 && < 0.7
+                     , bytestring >= 0.10.4 && < 0.11
+                     , clock >= 0.7.2 && < 0.8
+                     , hashable >= 1.2.4 && < 1.3
+                     , text >= 1.2 && < 1.3
+                     , unordered-containers >= 0.2.7.1 && < 0.3
+
+  -- Directories containing source files.
+  hs-source-dirs:      src
+
+  -- Extra tools (e.g. alex, hsc2hs, ...) needed to build the source.
+  build-tools:         hsc2hs
+
+  -- Base language which the package is written in.
+  default-language:    Haskell2010
+
+
+executable tmr-params
+  main-is:             tmr-params.hs
+  other-modules:       ExampleUtil
+  build-depends:       base >= 4.6 && < 5
+                     , ansi-terminal >= 0.6.2.3 && < 0.7
+                     , bytestring >= 0.10.4 && < 0.11
+                     , mercury-api
+                     , optparse-applicative >= 0.13 && < 0.14
+                     , text >= 1.2 && < 1.3
+  hs-source-dirs:      examples
+  default-language:    Haskell2010
+  ghc-options:         -threaded
+
+
+executable tmr-firmware
+  main-is:             tmr-firmware.hs
+  other-modules:       ExampleUtil
+  build-depends:       base >= 4.6 && < 5
+                     , bytestring >= 0.10.4 && < 0.11
+                     , mercury-api
+                     , optparse-applicative >= 0.13 && < 0.14
+                     , text >= 1.2 && < 1.3
+  hs-source-dirs:      examples
+  default-language:    Haskell2010
+  ghc-options:         -threaded
+
+
+executable tmr-read
+  main-is:             tmr-read.hs
+  other-modules:       ExampleUtil
+  build-depends:       base >= 4.6 && < 5
+                     , ansi-terminal >= 0.6.2.3 && < 0.7
+                     , bytestring >= 0.10.4 && < 0.11
+                     , mercury-api
+                     , optparse-applicative >= 0.13 && < 0.14
+                     , text >= 1.2 && < 1.3
+  hs-source-dirs:      examples
+  default-language:    Haskell2010
+  ghc-options:         -threaded
+
+
+executable tmr-write
+  main-is:             tmr-write.hs
+  other-modules:       ExampleUtil
+  build-depends:       base >= 4.6 && < 5
+                     , ansi-terminal >= 0.6.2.3 && < 0.7
+                     , bytestring >= 0.10.4 && < 0.11
+                     , mercury-api
+                     , optparse-applicative >= 0.13 && < 0.14
+                     , text >= 1.2 && < 1.3
+  hs-source-dirs:      examples
+  default-language:    Haskell2010
+  ghc-options:         -threaded
+
+
+executable tmr-lock
+  main-is:             tmr-lock.hs
+  other-modules:       ExampleUtil
+  build-depends:       base >= 4.6 && < 5
+                     , bytestring >= 0.10.4 && < 0.11
+                     , mercury-api
+                     , optparse-applicative >= 0.13 && < 0.14
+                     , text >= 1.2 && < 1.3
+  hs-source-dirs:      examples
+  default-language:    Haskell2010
+  ghc-options:         -threaded
+
+
+executable tmr-gpio
+  main-is:             tmr-gpio.hs
+  other-modules:       ExampleUtil
+  build-depends:       base >= 4.6 && < 5
+                     , bytestring >= 0.10.4 && < 0.11
+                     , mercury-api
+                     , optparse-applicative >= 0.13 && < 0.14
+                     , text >= 1.2 && < 1.3
+  hs-source-dirs:      examples
+  default-language:    Haskell2010
+  ghc-options:         -threaded
+
+
+test-suite replay
+  type:                exitcode-stdio-1.0
+  main-is:             replay.hs
+  build-depends:       base >= 4.6 && < 5
+                     , bytestring >= 0.10.4 && < 0.11
+                     , directory >= 1.2.2 && < 1.4
+                     , mercury-api
+                     , optparse-applicative >= 0.13 && < 0.14
+                     , text >= 1.2 && < 1.3
+  hs-source-dirs:      tests
+  default-language:    Haskell2010
+  ghc-options:         -threaded
+
+
+test-suite unit
+  type:                exitcode-stdio-1.0
+  main-is:             unit.hs
+  build-depends:       base >= 4.6 && < 5
+                     , bytestring >= 0.10.4 && < 0.11
+                     , HUnit >= 1.5 && < 1.7
+                     , mercury-api
+                     , text >= 1.2 && < 1.3
+  hs-source-dirs:      tests
+  default-language:    Haskell2010
+  ghc-options:         -threaded
+
+
+test-suite param-test
+  type:                exitcode-stdio-1.0
+  main-is:             param-test.hs
+  build-depends:       base >= 4.6 && < 5
+                     , HUnit >= 1.5 && < 1.7
+                     , mercury-api
+                     , text >= 1.2 && < 1.3
+  hs-source-dirs:      tests
+  default-language:    Haskell2010
+  ghc-options:         -threaded
diff --git a/src/System/Hardware/MercuryApi.hs b/src/System/Hardware/MercuryApi.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Hardware/MercuryApi.hs
@@ -0,0 +1,1048 @@
+{-# LANGUAGE ForeignFunctionInterface, DeriveDataTypeable, OverloadedStrings, BangPatterns #-}
+{-|
+Module      : System.Hardware.MercuryApi
+Description : Control ThingMagic RFID readers
+Copyright   : © Patrick Pelletier, 2017
+License     : MIT
+Maintainer  : code@funwithsoftware.org
+Portability : POSIX, Windows
+
+This module is a Haskell binding to the \"Mercury API\" C API for
+ThingMagic RFID readers.  It is especially geared toward the
+<https://www.sparkfun.com/products/14066 SparkFun Simultaneous RFID Reader>,
+which uses ThingMagic's M6e Nano module, but it should work with other
+ThingMagic readers.  (Though currently, only support for serial readers
+is compiled in.)  Most of the function and type names are the same as
+their counterparts in the C API, with the @TMR_@ prefix dropped.  For more
+in-depth, language-independent documentation of Mercury API, see
+<http://www.thingmagic.com/images/Downloads/Docs/MercuryAPI_ProgrammerGuide_for_v1.27.3.pdf Mercury API Programmers Guide>.
+
+This module is intended to be imported @qualified@, e. g.
+
+> import qualified System.Hardware.MercuryApi as TMR
+-}
+
+module System.Hardware.MercuryApi
+  ( -- * Reader
+    create
+  , connect
+  , read
+  , executeTagOp
+  , reboot
+  , destroy
+  , withReader
+    -- ** Parameters
+    -- | Although 'paramGet' and 'paramSet' are very flexible, they only
+    -- check that the parameter type is correct at runtime.  You may
+    -- prefer to use the functions in "System.Hardware.MercuryApi.Params",
+    -- which ensure the correct type at compile time.
+  , paramList
+  , paramGet
+  , paramSet
+  , paramSetBasics
+  , paramSetReadPlanFilter
+  , paramSetReadPlanTagop
+    -- ** Listeners
+    -- | Transport listeners can be used to monitor the raw serial data
+    -- going to and from the reader, for debugging purposes.  A listener
+    -- that prints the data to a 'Handle' is available from 'hexListener'
+    -- or 'opcodeListener'.
+  , addTransportListener
+  , removeTransportListener
+    -- ** GPIO
+    -- | The M6e Nano has 4 GPIO pins that can be controlled by software,
+    -- numbered 1-4.  On the
+    -- <https://www.sparkfun.com/products/14066 SparkFun Simultaneous RFID Reader>,
+    -- GPIO 1 is available on the GPIO1 pin, and GPIOs 2, 3, and 4 are available
+    -- on the LV2, LV3, and LV4 pins.  The GPIO1 pin is 5V, but
+    -- <https://learn.sparkfun.com/tutorials/simultaneous-rfid-tag-reader-hookup-guide/hardware-overview the LV pins are 3.3V only>.
+    -- To configure GPIOs as inputs or outputs, use 'PARAM_GPIO_INPUTLIST'
+    -- and 'PARAM_GPIO_OUTPUTLIST'.
+  , gpiGet
+  , gpoSet
+    -- ** Firmware
+    -- | Firmware for the M6e Nano can be obtained
+    -- <http://www.thingmagic.com/index.php/download-nano-firmware here>.
+  , firmwareLoad
+  , firmwareLoadFile
+    -- * Utility functions
+    -- ** Listeners
+  , hexListener
+  , opcodeListener
+    -- ** Data helpers
+  , packBytesIntoWords
+  , passwordToWords
+  , mkFilterGen2
+    -- ** Parameters
+  , paramName
+  , paramID
+  , paramType
+  , paramUnits
+    -- ** Hex conversion
+  , bytesToHex
+  , bytesToHexWithSpaces
+  , hexToBytes
+    -- ** Display
+    -- | Some functions to format data in a more human-friendly
+    -- format than 'show'.
+  , displayTimestamp
+  , displayLocalTimestamp
+  , displayData
+  , displayGpio
+  , displayTagData
+  , displayTagReadData
+  , displayParamType
+  , displayRegion
+  , displayRegionDescription
+  , parseRegion
+    -- * Constants
+  , apiVersion
+  , sparkFunAntennas
+  , defaultReadPlan
+  , killPasswordAddress
+  , accessPasswordAddress
+    -- * Types
+    -- ** Opaque types
+  , Reader
+  , ParamValue
+  , TransportListenerId
+    -- ** Typedefs
+  , TransportListener
+  , PinNumber
+  , AntennaPort
+  , GEN2_Password
+  , MillisecondsSinceEpoch
+    -- ** Records
+  , MercuryException (..)
+  , ReadPlan (..)
+  , TagOp (..)
+  , TagFilter (..)
+  , FilterOn (..)
+  , TagReadData (..)
+  , GpioPin (..)
+  , TagData (..)
+  , GEN2_TagData (..)
+  , ReadWrite (..)
+    -- ** Enums
+  , StatusType (..)
+  , Status (..)
+  , Param (..)
+  , ParamType (..)
+  , Region (..)
+  , TagProtocol (..)
+  , MetadataFlag (..)
+  , GEN2_Bank (..)
+  , GEN2_LockBits (..)
+  , GEN2_WriteMode (..)
+  , PowerMode (..)
+  , TransportDirection (..)
+  ) where
+
+import Prelude hiding (read)
+
+import Control.Applicative ( (<$>) )
+-- IOException is needed here so that Haddock can link to it
+import Control.Exception ( Exception, IOException, throwIO, try, bracket )
+import Control.Monad ( when )
+import qualified Data.ByteString as B
+import qualified Data.HashMap.Strict as H
+import Data.IORef ( IORef, newIORef, atomicModifyIORef' )
+import Data.List ( intercalate )
+import Data.Monoid ( (<>) )
+import qualified Data.Text as T
+import qualified Data.Text.IO as T ( hPutStrLn )
+import Data.Typeable ( Typeable )
+import Data.Word ( Word8, Word16, Word32 )
+import Foreign
+    ( Int32,
+      Ptr,
+      FunPtr,
+      ForeignPtr,
+      nullPtr,
+      withForeignPtr,
+      Storable(peek, poke),
+      Bits((.&.), (.|.), bit, shiftL, shiftR, testBit),
+      castPtr,
+      mallocForeignPtrBytes,
+      addForeignPtrFinalizer,
+      with,
+      toBool,
+      withArrayLen,
+      peekArray,
+      allocaArray,
+      allocaBytes,
+      alloca )
+import Foreign.C
+    ( CStringLen,
+      CString,
+      CInt(..),
+      CTime(..),
+      CSize(..),
+      Errno(..),
+      withCAString,
+      newCAString,
+      throwErrnoIfNull,
+      errnoToIOError )
+import Text.Printf ( printf )
+import System.Clock
+    ( TimeSpec(nsec, sec), Clock(Monotonic), getTime )
+import System.Console.ANSI
+    ( SGR(Reset, SetColor),
+      ConsoleLayer(Foreground),
+      ColorIntensity(Vivid),
+      Color(Cyan, Magenta),
+      hSupportsANSI,
+      hSetSGR )
+import System.IO ( Handle, hFlush )
+import qualified System.IO.Unsafe as U ( unsafePerformIO )
+import Text.Read (readMaybe)
+
+import System.Hardware.MercuryApi.Enums
+import System.Hardware.MercuryApi.Records
+import System.Hardware.MercuryApi.ParamValue
+
+-- | An opaque type which represents a connection to an RFID reader.
+-- Note that @Reader@ is not threadsafe, so if you want to use a
+-- @Reader@ from more than one thread, you will need to implement
+-- your own locking.
+newtype Reader = Reader (ForeignPtr ReaderEtc)
+
+type RawStatus = Word32
+type RawType = Word32
+
+type RawTransportListener =
+  CBool -> Word32 -> Ptr Word8 -> Word32 -> Ptr () -> IO ()
+
+-- | The direction of data travel.  Passed to 'TransportListener'.
+data TransportDirection = Rx -- ^ Receive
+                        | Tx -- ^ Transmit
+                        deriving (Eq, Ord, Show, Read, Bounded, Enum)
+
+-- | A function which can be installed via 'addTransportListener'
+-- to be called every time Mercury API sends or receives data on
+-- the serial port.
+type TransportListener = TransportDirection -- ^ Direction of data transmission
+                       -> B.ByteString  -- ^ Binary data sent or received
+                       -> Word32        -- ^ Timeout
+                       -> IO ()
+
+-- | An opaque type which can be passed to 'removeTransportListener'
+-- to remove a transport listener.
+newtype TransportListenerId = TransportListenerId Integer deriving (Eq)
+
+newtype Locale = Locale ()
+
+-- Many of these need to be safe because they could call back
+-- into Haskell via the transport listener.  (Or via the custom
+-- transport we use for testing.)
+
+foreign import ccall safe "glue.h c_TMR_create"
+    c_TMR_create :: Ptr ReaderEtc
+                 -> CString
+                 -> IO RawStatus
+
+foreign import ccall safe "glue.h c_TMR_connect"
+    c_TMR_connect :: Ptr ReaderEtc
+                  -> IO RawStatus
+
+foreign import ccall safe "glue.h c_TMR_destroy"
+    c_TMR_destroy :: Ptr ReaderEtc
+                  -> IO RawStatus
+
+foreign import ccall unsafe "glue.h &c_TMR_destroy"
+    p_TMR_destroy :: FunPtr (Ptr ReaderEtc -> IO ())
+
+foreign import ccall safe "glue.h c_TMR_read"
+    c_TMR_read :: Ptr ReaderEtc
+               -> Word32
+               -> Ptr Word32
+               -> IO RawStatus
+
+foreign import ccall safe "glue.h c_TMR_hasMoreTags"
+    c_TMR_hasMoreTags :: Ptr ReaderEtc
+                      -> IO RawStatus
+
+foreign import ccall safe "glue.h c_TMR_getNextTag"
+    c_TMR_getNextTag :: Ptr ReaderEtc
+                     -> Ptr TagReadData
+                     -> IO RawStatus
+
+foreign import ccall unsafe "tmr_tag_data.h TMR_TRD_init"
+    c_TMR_TRD_init :: Ptr TagReadData
+                   -> IO RawStatus
+
+foreign import ccall safe "glue.h c_TMR_executeTagOp"
+    c_TMR_executeTagOp :: Ptr ReaderEtc
+                       -> Ptr TagOp
+                       -> Ptr TagFilter
+                       -> Ptr List16
+                       -> IO RawStatus
+
+foreign import ccall safe "glue.h c_TMR_gpoSet"
+    c_TMR_gpoSet :: Ptr ReaderEtc
+                 -> Word8
+                 -> Ptr GpioPin
+                 -> IO RawStatus
+
+foreign import ccall safe "glue.h c_TMR_gpiGet"
+    c_TMR_gpiGet :: Ptr ReaderEtc
+                 -> Ptr Word8
+                 -> Ptr GpioPin
+                 -> IO RawStatus
+
+foreign import ccall safe "glue.h c_TMR_firmwareLoad"
+    c_TMR_firmwareLoad :: Ptr ReaderEtc
+                       -> Ptr Word8
+                       -> Word32
+                       -> IO RawStatus
+
+foreign import ccall safe "glue.h c_TMR_paramSet"
+    c_TMR_paramSet :: Ptr ReaderEtc
+                   -> RawParam
+                   -> Ptr ()
+                   -> IO RawStatus
+
+foreign import ccall safe "glue.h c_TMR_paramGet"
+    c_TMR_paramGet :: Ptr ReaderEtc
+                   -> RawParam
+                   -> Ptr ()
+                   -> IO RawStatus
+
+foreign import ccall safe "glue.h c_TMR_reboot"
+    c_TMR_reboot :: Ptr ReaderEtc
+                 -> IO RawStatus
+
+foreign import ccall unsafe "glue.h c_default_read_plan"
+    c_default_read_plan :: Ptr ReadPlan
+                        -> IO ()
+
+foreign import ccall safe "glue.h c_TMR_paramList"
+    c_TMR_paramList :: Ptr ReaderEtc
+                    -> Ptr RawParam
+                    -> Ptr Word32
+                    -> IO RawStatus
+
+foreign import ccall "wrapper"
+    wrapTransportListener :: RawTransportListener
+                          -> IO (FunPtr RawTransportListener)
+
+-- takes ownership of the FunPtr and the CString
+foreign import ccall unsafe "glue.h c_TMR_addTransportListener"
+    c_TMR_addTransportListener :: Ptr ReaderEtc
+                               -> FunPtr RawTransportListener
+                               -> CString
+                               -> IO RawStatus
+
+foreign import ccall unsafe "glue.h c_TMR_removeTransportListener"
+    c_TMR_removeTransportListener :: Ptr ReaderEtc
+                                  -> CString
+                                  -> IO RawStatus
+
+foreign import ccall unsafe "glue.h c_TMR_strerr"
+    c_TMR_strerr :: Ptr ReaderEtc
+                 -> RawStatus
+                 -> IO CString
+
+-- This is a pure function, because it returns a string literal
+foreign import ccall unsafe "tm_reader.h TMR_paramName"
+    c_TMR_paramName :: RawParam
+                    -> CString
+
+foreign import ccall unsafe "tmr_tag_data.h TMR_hexToBytes"
+    c_TMR_hexToBytes :: CString
+                     -> Ptr Word8
+                     -> Word32
+                     -> Ptr Word32
+                     -> IO RawStatus
+
+foreign import ccall unsafe "tmr_tag_data.h TMR_bytesToHex"
+    c_TMR_bytesToHex :: Ptr Word8
+                     -> Word32
+                     -> CString
+                     -> IO ()
+
+foreign import ccall unsafe "glue.h c_new_c_locale"
+    c_new_c_locale :: IO (Ptr Locale)
+
+foreign import ccall unsafe "glue.h c_format_time"
+    c_format_time :: CString
+                  -> CSize
+                  -> CString
+                  -> CTime
+                  -> CBool
+                  -> Ptr Locale
+                  -> IO CInt
+
+-- | Represents any error that can occur in a MercuryApi call,
+-- except for those which can be represented by 'IOException'.
+data MercuryException =
+  MercuryException
+  { meStatusType :: StatusType -- ^ general category of error
+  , meStatus     :: Status     -- ^ the specific error
+  , meMessage    :: T.Text     -- ^ the error message
+  , meLocation   :: T.Text     -- ^ function where the error occurred
+  , meParam      :: T.Text     -- ^ more information, such as the parameter
+                               -- in 'paramGet' or 'paramSet'
+  , meUri        :: T.Text     -- ^ URI of the reader
+  }
+  deriving (Eq, Ord, Show, Read, Typeable)
+
+instance Exception MercuryException
+
+statusGetType :: RawStatus -> RawType
+statusGetType stat = stat `shiftR` 24
+
+errnoBit :: Int
+errnoBit = 15
+
+statusIsErrno :: StatusType -> RawStatus -> Bool
+statusIsErrno ERROR_TYPE_COMM rstat = rstat `testBit` errnoBit
+statusIsErrno _ _ = False
+
+statusGetErrno :: RawStatus -> Errno
+statusGetErrno rstat = Errno $ fromIntegral $ rstat .&. (bit errnoBit - 1)
+
+checkStatus' :: Ptr ReaderEtc
+             -> RawStatus
+             -> T.Text
+             -> T.Text
+             -> IO T.Text
+             -> IO ()
+checkStatus' rdr rstat loc param getUri = do
+  let t = toStatusType $ statusGetType rstat
+      stat = toStatus rstat
+  case t of
+    SUCCESS_TYPE -> return ()
+    _ -> do
+      uri <- getUri
+      if statusIsErrno t rstat
+        then do
+        let errno = statusGetErrno rstat
+            ioe = errnoToIOError (T.unpack loc) errno Nothing
+                  (Just $ T.unpack uri)
+        throwIO ioe
+        else do
+        cstr <- c_TMR_strerr rdr rstat
+        msg <- textFromCString cstr
+        let exc = MercuryException
+                  { meStatusType = t
+                  , meStatus = stat
+                  , meMessage = msg
+                  , meLocation = loc
+                  , meParam = param
+                  , meUri = uri
+                  }
+        throwIO exc
+
+checkStatus :: Ptr ReaderEtc -> RawStatus -> T.Text -> T.Text -> IO ()
+checkStatus rdr rstat loc param =
+  checkStatus' rdr rstat loc param (textFromCString $ uriPtr rdr)
+
+uniqueCounter :: IORef Integer
+{-# NOINLINE uniqueCounter #-}
+uniqueCounter = U.unsafePerformIO $ newIORef 0
+
+newUnique :: IO Integer
+newUnique = atomicModifyIORef' uniqueCounter f
+  where f x = (x + 1, x)
+
+castToCStringLen :: Integral a => a -> Ptr Word8 -> CStringLen
+castToCStringLen len ptr = (castPtr ptr, fromIntegral len)
+
+paramPairs :: [(Param, T.Text)]
+paramPairs = map f [minBound..maxBound]
+  where
+    f p = (p, U.unsafePerformIO $ textFromCString $ c_TMR_paramName $ fromParam p)
+
+paramMap :: H.HashMap Param T.Text
+paramMap = H.fromList paramPairs
+
+paramMapReverse :: H.HashMap T.Text Param
+paramMapReverse = H.fromList $ map swap paramPairs
+  where swap (x, y) = (y, x)
+
+-- | Return the string name (e. g. \"\/reader\/read\/plan\")
+-- corresponding to a 'Param'.
+paramName :: Param -> T.Text
+paramName p = paramMap H.! p -- all possible keys are in the map, so can't fail
+
+-- | Return the 'Param' corresponding to a string name
+-- (e. g. \"\/reader\/read\/plan\").  Returns 'PARAM_NONE' if no such
+-- parameter exists.
+paramID :: T.Text -> Param
+paramID name = H.lookupDefault PARAM_NONE name paramMapReverse
+
+-- | Create a new 'Reader' with the specified URI.  The reader is
+-- not contacted at this point.  On Mac OS X, be sure to use the
+-- serial device that starts with @cu.@, not the one that starts with
+-- @tty.@.
+create :: T.Text -- ^ a reader URI, such as @tmr:\/\/\/dev\/ttyUSB0@ on Linux,
+                 -- @tmr:\/\/\/dev\/cu.SLAB_USBtoUART@ on Mac OS X, or
+                 -- @tmr:\/\/\/COM4@ on Windows.
+       -> IO Reader
+create deviceUri = do
+  B.useAsCStringLen (textToBS deviceUri) $ \(cs, len) -> do
+    fp <- mallocForeignPtrBytes (sizeofReaderEtc + len)
+    withForeignPtr fp $ \p -> do
+      status <- c_TMR_create p cs
+      checkStatus' p status "create" "" (return deviceUri)
+    addForeignPtrFinalizer p_TMR_destroy fp
+    return $ Reader fp
+
+withReaderEtc :: Reader
+              -> T.Text
+              -> T.Text
+              -> (Ptr ReaderEtc -> IO RawStatus)
+              -> IO ()
+withReaderEtc (Reader fp) location param func = do
+  withForeignPtr fp $ \p -> do
+    status <- func p
+    checkStatus p status location param
+
+-- | Establishes the connection to the reader at the URI specified in
+-- the '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.
+connect :: Reader -> IO ()
+connect rdr = withReaderEtc rdr "connect" "" c_TMR_connect
+
+-- | Closes the connection to the reader and releases any resources
+-- that have been consumed by the reader structure.  Any further
+-- operations performed on the reader will fail with
+-- 'ERROR_ALREADY_DESTROYED'.  On finalization of the 'Reader',
+-- 'destroy' will be called automatically if it has not already been called.
+destroy :: Reader -> IO ()
+destroy rdr = withReaderEtc rdr "destroy" "" c_TMR_destroy
+
+-- | Create a new 'Reader' with the specified URI, pass it to the given
+-- computation, and destroy it when the computation exits.
+withReader :: T.Text -- ^ a reader URI, such as @tmr:\/\/\/dev\/ttyUSB0@ on
+                     -- Linux, @tmr:\/\/\/dev\/cu.SLAB_USBtoUART@ on Mac OS X,
+                     -- or @tmr:\/\/\/COM4@ on Windows.
+           -> (Reader -> IO a) -- ^ computation to run with Reader
+           -> IO a
+withReader uri = bracket (create uri) destroy
+
+hasMoreTags :: Ptr CBool -> Ptr ReaderEtc -> IO RawStatus
+hasMoreTags boolPtr rdrPtr = do
+  status <- c_TMR_hasMoreTags rdrPtr
+  let (moreTags, status') = case toStatus status of
+                              ERROR_NO_TAGS -> (cFalse, 0)
+                              _ -> (cTrue, status)
+  poke boolPtr moreTags
+  return status'
+
+tShow :: Show a => a -> T.Text
+tShow = T.pack . show
+
+readLoop :: Reader
+         -> Word32
+         -> Ptr TagReadData
+         -> Ptr CBool
+         -> Int
+         -> [TagReadData]
+         -> IO [TagReadData]
+readLoop rdr tagCount trdPtr boolPtr !tagNum !trds = do
+  let tagNum' = tagNum + 1
+      progress = "(" <> tShow tagNum' <> " of " <> tShow tagCount <> ")"
+  withReaderEtc rdr "read"
+    ("hasMoreTags " <> progress)
+    (hasMoreTags boolPtr)
+  moreTags <- toBool' <$> peek boolPtr
+  if moreTags
+    then do
+    c_TMR_TRD_init trdPtr -- ignore return value because it is always success
+    withReaderEtc rdr "read" ("getNextTag " <> progress)
+      $ \p -> c_TMR_getNextTag p trdPtr
+    trd <- peek trdPtr
+    readLoop rdr tagCount trdPtr boolPtr tagNum' (trd : trds)
+    else do
+    return $ reverse trds
+
+-- | Search for tags for a fixed duration.  Follows the 'ReadPlan'
+-- stored in 'PARAM_READ_PLAN'.
+read :: Reader -- ^ The reader being operated on
+     -> Word32 -- ^ The number of milliseconds to search for tags
+     -> IO [TagReadData]
+read rdr timeoutMs = do
+  alloca $ \tagCountPtr -> do
+    withReaderEtc rdr "read" "" $ \p -> c_TMR_read p timeoutMs tagCountPtr
+    tagCount <- peek tagCountPtr
+    alloca $ \trdPtr -> alloca $
+                        \boolPtr -> readLoop rdr tagCount trdPtr boolPtr 0 []
+
+-- | Directly executes a 'TagOp' command.
+-- Operates on the first tag found, with applicable tag filtering.
+-- 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 the
+-- 'PARAM_TAGOP_ANTENNA' parameter.
+-- 'PARAM_TAGOP_PROTOCOL' specifies the protocol to be used.
+-- Some TagOps return data, while others will just return an
+-- empty 'B.ByteString'.
+executeTagOp :: Reader -> TagOp -> Maybe TagFilter -> IO B.ByteString
+executeTagOp rdr tagOp tagFilter = alloca $ \pOp -> alloca $ \pFilt -> do
+  eth1 <- try $ poke pOp tagOp
+  case eth1 of
+    Left err -> throwPE rdr err "executeTagOp" "tagop"
+    Right _ -> return ()
+  pFilt' <- case tagFilter of
+              Nothing -> return nullPtr
+              Just tf -> do
+                eth2 <- try $ poke pFilt tf
+                case eth2 of
+                  Left err -> throwPE rdr err "executeTagOp" "filter"
+                  Right _ -> return pFilt
+  results <- getList16 $ \pList -> do
+    withReaderEtc rdr "executeTagOp" (tagOpName tagOp) $ \pRdr -> do
+      c_TMR_executeTagOp pRdr pOp pFilt' (castPtr pList)
+  return $ B.pack results
+
+-- | Set the state of some GPO pins.
+gpoSet :: Reader -> [GpioPin] -> IO ()
+gpoSet rdr gpios = do
+  withArrayLen gpios $ \len gpioPtr -> do
+    eth <- try $ castLen "[GpioPin]" len
+    case eth of
+      Left err -> throwPE rdr err "gpoSet" ""
+      Right len' -> do
+        withReaderEtc rdr "gpoSet" "" $ \pRdr -> do
+          c_TMR_gpoSet pRdr len' gpioPtr
+
+-- | Get the state of all GPI pins.
+gpiGet :: Reader -> IO [GpioPin]
+gpiGet rdr = do
+  let maxLen = maxBound
+  with maxLen $ \lenPtr -> do
+    allocaArray (fromIntegral maxLen) $ \gpioPtr -> do
+      withReaderEtc rdr "gpiGet" "" $ \pRdr -> do
+        c_TMR_gpiGet pRdr lenPtr gpioPtr
+      len <- peek lenPtr
+      peekArray (fromIntegral len) gpioPtr
+
+-- | Attempts to install firmware on the reader, then restart and reinitialize.
+firmwareLoad :: Reader       -- ^ The reader being operated on
+             -> B.ByteString -- ^ The binary firmware image to install
+             -> IO ()
+firmwareLoad = firmwareLoad' ""
+
+firmwareLoad' :: T.Text -> Reader -> B.ByteString -> IO ()
+firmwareLoad' filename rdr firmware = do
+  B.useAsCStringLen firmware $ \(fwPtr, fwLen) -> do
+    withReaderEtc rdr "firmwareLoad" filename $
+      \p -> c_TMR_firmwareLoad p (castPtr fwPtr) (fromIntegral fwLen)
+
+-- | Like 'firmwareLoad', but loads firmware from a file.
+-- (e. g. @NanoFW-1.7.1.2.sim@)
+firmwareLoadFile :: Reader   -- ^ The reader being operated on
+                 -> FilePath -- ^ Name of file containing firmware image
+                 -> IO ()
+firmwareLoadFile rdr filename = do
+  firmware <- B.readFile filename
+  firmwareLoad' (T.pack filename) rdr firmware
+
+throwPE :: Reader -> ParamException -> T.Text -> T.Text -> IO a
+throwPE (Reader fp) (ParamException statusType status msg) loc param = do
+  uri <- withForeignPtr fp (textFromCString . uriPtr)
+  throwIO $ MercuryException
+    { meStatusType = statusType
+    , meStatus = status
+    , meMessage = msg
+    , meLocation = loc
+    , meParam = param
+    , meUri = uri
+    }
+
+unimplementedParam :: ParamException
+unimplementedParam =
+  ParamException ERROR_TYPE_BINDING ERROR_UNIMPLEMENTED_PARAM
+  "The given parameter is not yet implemented in the Haskell binding."
+
+invalidParam :: ParamType -> ParamType -> ParamException
+invalidParam expected actual =
+  ParamException ERROR_TYPE_BINDING ERROR_INVALID_PARAM_TYPE
+  ( "Expected " <> displayParamType expected <>
+    " but got " <> displayParamType actual )
+
+-- | Sets the value of a reader parameter.  Throws 'MercuryException'
+-- with a 'meStatus' of 'ERROR_INVALID_PARAM_TYPE' if the parameter value
+-- is not of the correct type (sadly, this is only checked at runtime) or
+-- 'ERROR_UNIMPLEMENTED_PARAM' if the parameter has not yet been implemented
+-- in the Haskell binding.  Can also propagate errors from the C API, such
+-- as 'ERROR_UNSUPPORTED' or 'ERROR_READONLY'.
+paramSet :: ParamValue a => Reader -> Param -> a -> IO ()
+paramSet rdr param value = do
+  let pt = paramType param
+      pt' = pType value
+      rp = fromParam param
+      pName = T.pack $ show param
+  when (pt == ParamTypeUnimplemented) $
+    throwPE rdr unimplementedParam "paramSet" pName
+  when (pt /= pt') $
+    throwPE rdr (invalidParam pt pt') "paramSet" pName
+  eth <- try $ pSet value $ \pp -> withReaderEtc rdr "paramSet" pName $
+                                   \p -> c_TMR_paramSet p rp pp
+  case eth of
+    Left err -> throwPE rdr err "paramSet" pName
+    Right _ -> return ()
+
+withReturnType :: (a -> IO a) -> IO a
+withReturnType f = f undefined
+
+-- | Gets the value of a reader parameter.  Throws 'MercuryException'
+-- with a 'meStatus' of 'ERROR_INVALID_PARAM_TYPE' if the parameter value
+-- is not of the correct type (sadly, this is only checked at runtime) or
+-- 'ERROR_UNIMPLEMENTED_PARAM' if the parameter has not yet been implemented
+-- in the Haskell binding.  Can also propagate errors from the C API, such
+-- as 'ERROR_UNSUPPORTED'.
+paramGet :: ParamValue a => Reader -> Param -> IO a
+paramGet rdr param = withReturnType $ \returnType -> do
+  let pt = paramType param
+      pt' = pType returnType
+      rp = fromParam param
+      pName = T.pack $ show param
+  when (pt == ParamTypeUnimplemented) $
+    throwPE rdr unimplementedParam "paramGet" pName
+  when (pt /= pt') $
+    throwPE rdr (invalidParam pt pt') "paramGet" pName
+  pGet $ \pp -> withReaderEtc rdr "paramGet" pName $
+                \p -> c_TMR_paramGet p rp pp
+
+-- | Convenience function to set some of the most essential parameters.
+-- The specified 'Region' is written into 'PARAM_REGION_ID'.
+-- The specified power level is written into 'PARAM_RADIO_READPOWER'
+-- and 'PARAM_RADIO_WRITEPOWER'.  The specified antenna list is
+-- written into the 'rpAntennas' field of 'PARAM_READ_PLAN', and the first
+-- antenna in the list is written into 'PARAM_TAGOP_ANTENNA'.  For the
+-- <https://www.sparkfun.com/products/14066 SparkFun Simultaneous RFID Reader>,
+-- the antenna list should be 'sparkFunAntennas', and if powering the reader
+-- off USB, the power level should be 500
+-- (<https://learn.sparkfun.com/tutorials/simultaneous-rfid-tag-reader-hookup-guide/power-supply-considerations 5 dBm>).
+-- (Higher power levels can be used with a separate power supply.)
+paramSetBasics :: Reader   -- ^ The reader being operated on
+               -> Region   -- ^ The region
+               -> Int32    -- ^ Power in centi-dBm
+               -> [AntennaPort] -- ^ Antenna list
+               -> IO ()
+paramSetBasics rdr rgn pwr ant = do
+  paramSet rdr PARAM_REGION_ID rgn
+  paramSet rdr PARAM_RADIO_READPOWER pwr
+  paramSet rdr PARAM_RADIO_WRITEPOWER pwr
+  plan <- paramGet rdr PARAM_READ_PLAN
+  paramSet rdr PARAM_READ_PLAN plan { rpAntennas = ant }
+  when (not $ null ant) $ paramSet rdr PARAM_TAGOP_ANTENNA (head ant)
+
+-- | Sets the 'rpFilter' field of the 'PARAM_READ_PLAN' parameter,
+-- while leaving the rest of the read plan unchanged.
+paramSetReadPlanFilter :: Reader -> Maybe TagFilter -> IO ()
+paramSetReadPlanFilter rdr filt = do
+  plan <- paramGet rdr PARAM_READ_PLAN
+  paramSet rdr PARAM_READ_PLAN plan { rpFilter = filt }
+
+-- | Sets the 'rpTagop' field of the 'PARAM_READ_PLAN' parameter,
+-- while leaving the rest of the read plan unchanged.
+paramSetReadPlanTagop :: Reader -> Maybe TagOp -> IO ()
+paramSetReadPlanTagop rdr op = do
+  plan <- paramGet rdr PARAM_READ_PLAN
+  paramSet rdr PARAM_READ_PLAN plan { rpTagop = op }
+
+-- | The read plan that the reader starts out with by default.
+-- This has reasonable settings for most things, except for the
+-- antennas, which need to be set.  (e. g. set 'rpAntennas' to
+-- 'sparkFunAntennas')
+defaultReadPlan :: ReadPlan
+defaultReadPlan = U.unsafePerformIO $ do
+  alloca $ \p -> do
+    c_default_read_plan p
+    peek p
+
+-- | The constant @[1]@, which is the correct value for 'rpAntennas'
+-- when using the
+-- <http://sparkfun.com/products/14066 SparkFun Simultaneous RFID Reader>.
+sparkFunAntennas :: [AntennaPort]
+sparkFunAntennas = [1]
+
+-- | Reboot the reader
+reboot :: Reader -> IO ()
+reboot rdr = withReaderEtc rdr "reboot" "" c_TMR_reboot
+
+-- | Get a list of parameters supported by the reader.
+paramList :: Reader -> IO [Param]
+paramList rdr = do
+  let maxParams = paramMax + 1
+  alloca $ \nParams -> do
+    poke nParams (fromIntegral maxParams)
+    allocaArray (fromIntegral maxParams) $ \params -> do
+      withReaderEtc rdr "paramList" "" $ \p -> c_TMR_paramList p params nParams
+      actual <- peek nParams
+      result <- peekArray (min (fromIntegral actual) (fromIntegral maxParams)) params
+      return $ map toParam result
+
+txToDirection :: Bool -> TransportDirection
+txToDirection True = Tx
+txToDirection False = Rx
+
+callTransportListener :: TransportListener -> RawTransportListener
+callTransportListener listener tx dataLen dataPtr timeout _ = do
+  bs <- B.packCStringLen (castToCStringLen dataLen dataPtr)
+  listener (txToDirection $ toBool tx) bs timeout
+
+-- | Add a listener to the list of functions that will be called for
+-- each message sent to or recieved from the reader.
+addTransportListener :: Reader                 -- ^ The reader to operate on.
+                     -> TransportListener      -- ^ The listener to call.
+                     -> IO TransportListenerId -- ^ A unique identifier which
+                                               -- can be used to remove the
+                                               -- listener later.
+addTransportListener rdr listener = do
+  unique <- newUnique
+  funPtr <- wrapTransportListener (callTransportListener listener)
+  cs <- newCAString (show unique)
+  withReaderEtc rdr "addTransportListener" "" $
+    \p -> c_TMR_addTransportListener p funPtr cs
+  return (TransportListenerId unique)
+
+-- | Remove a listener from the list of functions that will be called
+-- for each message sent to or recieved from the reader.
+removeTransportListener :: Reader              -- ^ The reader to operate on.
+                        -> TransportListenerId -- ^ The return value of a call
+                                               -- to 'addTransportListener'.
+                        -> IO ()
+removeTransportListener rdr (TransportListenerId unique) = do
+  withCAString (show unique) $ \cs -> do
+    withReaderEtc rdr "removeTransportListener" "" $
+      \p -> c_TMR_removeTransportListener p cs
+
+-- | Given a 'Handle', returns a 'TransportListener' which prints
+-- transport data to that handle in hex.  If the handle is a terminal,
+-- prints transmitted data in magenta and received data in cyan.
+hexListener :: Handle -> IO TransportListener
+hexListener h = do
+  useColor <- hSupportsANSI h
+  return (listenerImpl h useColor False)
+
+-- | Identical to 'hexListener', but also prints the opcode of each packet,
+-- and a timestamp.  (The timestamp is relative to an arbitrary point in
+-- time, so is only useful for computing differences between timestamps.)
+opcodeListener :: Handle -> IO TransportListener
+opcodeListener h = do
+  useColor <- hSupportsANSI h
+  return (listenerImpl h useColor True)
+
+listenerImpl :: Handle -> Bool -> Bool -> TransportListener
+listenerImpl h useColor printOpcode dir dat _ = do
+  setColors useColor [SetColor Foreground Vivid (color dir)]
+  opc <- if printOpcode
+         then opcodeAndTime dat
+         else return []
+  mapM_ (T.hPutStrLn h) $ lstn opc (prefix dir)
+  setColors useColor [Reset]
+  flushColor useColor
+  where
+    setColors False _ = return ()
+    setColors True sgr = hSetSGR h sgr
+    flushColor False = return ()
+    flushColor True = hFlush h
+    prefix Tx = "Sending: "
+    prefix Rx = "Received:"
+    color Tx = Magenta
+    color Rx = Cyan
+    lstn opc pfx =
+      zipWith T.append (pfx : repeat "         ") (opc ++ displayData dat)
+
+extractOpcode :: B.ByteString -> T.Text
+extractOpcode bs
+  | B.length bs < 3 = "too short"
+  | otherwise = opcodeName (bs `B.index` 2)
+
+opcodeAndTime :: B.ByteString -> IO [T.Text]
+opcodeAndTime bs = do
+  now <- getTime Monotonic
+  let opcode = extractOpcode bs
+      tm = printf "%d.%09d" (sec now) (nsec now)
+  return [pad 30 opcode <> T.pack tm]
+
+-- | Convert a hexadecimal string (without spaces) into a
+-- 'B.ByteString'.  The hex string may optionally include a "0x"
+-- prefix, which will be ignored.  If the input cannot be parsed as a
+-- hex string, returns 'Nothing'.
+hexToBytes :: T.Text -> Maybe B.ByteString
+hexToBytes hex = U.unsafePerformIO $ do
+  let hexBs = textToBS hex
+      hexLen = B.length hexBs
+      bufLen = 1 + (hexLen `div` 2)
+  alloca $ \pLen -> allocaBytes bufLen $ \buf -> B.useAsCString hexBs $ \cs -> do
+    status <- c_TMR_hexToBytes cs buf (fromIntegral bufLen) pLen
+    outLen <- peek pLen
+    if (status == 0)
+      then Just <$> B.packCStringLen (castPtr buf, fromIntegral outLen)
+      else return Nothing
+
+-- | Convert a 'B.ByteString', such as a tag EPC, into a hexadecimal string.
+bytesToHex :: B.ByteString -> T.Text
+bytesToHex bytes = U.unsafePerformIO $ do
+  let bytesLen = B.length bytes
+      bufLen = 1 + bytesLen * 2
+  allocaBytes bufLen $ \buf -> B.useAsCString bytes $ \cs -> do
+    c_TMR_bytesToHex (castPtr cs) (fromIntegral bytesLen) buf
+    textFromBS <$> B.packCString buf
+
+-- | Like 'bytesToHex', but with a space between each byte.
+bytesToHexWithSpaces :: B.ByteString -> T.Text
+bytesToHexWithSpaces = T.pack . intercalate " " . map (printf "%02x") . B.unpack
+
+pad :: Int -> T.Text -> T.Text
+pad x t = t <> T.replicate (x - T.length t) " "
+
+-- | Format a 'B.ByteString' as 16 bytes per line, with both hex and ascii
+-- on the line.
+displayData :: B.ByteString -> [T.Text]
+displayData bytes
+  | B.null bytes = []
+  | otherwise =
+    let (bs1, bs2) = B.splitAt 16 bytes
+        (bs1a, bs1b) = B.splitAt 8 bs1
+        dotify x = if x < 0x20 || x >= 0x7f then 0x2e else x
+        hex = map (pad 25 . bytesToHexWithSpaces) [bs1a, bs1b]
+        ascii = B.map dotify bs1
+        txt = T.concat $ hex ++ ["|", textFromBS ascii, "|"]
+    in txt : displayData bs2
+
+displayByteString :: B.ByteString -> T.Text
+displayByteString bs =
+  "<" <> bytesToHex bs <> "> (" <> T.pack (show $ B.length bs) <> " bytes)"
+
+-- | Convert a 'TagData' to a human-readable list of lines.
+displayTagData :: TagData -> [T.Text]
+displayTagData td =
+  concat
+  [ [ "TagData"
+    , "  epc         = " <> displayByteString (tdEpc td)
+    , "  protocol    = " <> tShow (tdProtocol td)
+    , "  crc         = " <> T.pack (printf "0x%04x" $ tdCrc td)
+    ]
+  , case tdGen2 td of
+      Nothing -> []
+      Just gen2 -> ["  gen2.pc     = " <> displayByteString (g2Pc gen2)]
+  ]
+
+indent :: [T.Text] -> [T.Text]
+indent = map ("  " <>)
+
+cLocale :: Ptr Locale
+{-# NOINLINE cLocale #-}
+cLocale = U.unsafePerformIO $ throwErrnoIfNull "newlocale" c_new_c_locale
+
+formatTimestamp :: MillisecondsSinceEpoch -> CBool -> String -> IO T.Text
+formatTimestamp t local z = do
+  let (seconds, millis) = t `divMod` 1000
+      fmt = "%Y-%m-%dT%H:%M:%S" ++ printf ".%03d" millis ++ z
+      bufSize = 80
+  withCAString fmt $ \cFmt -> allocaBytes bufSize $ \buf -> do
+    ret <- c_format_time buf (fromIntegral bufSize) cFmt
+           (CTime $ fromIntegral seconds) local cLocale
+    if ret < 0
+      then return $ T.pack $ printf "%d.%03d" seconds millis
+      else textFromCString buf
+
+-- | Convert a timestamp into
+-- <https://en.wikipedia.org/wiki/ISO_8601 ISO 8601> format in UTC.
+displayTimestamp :: MillisecondsSinceEpoch -- ^ milliseconds since 1\/1\/1970 UTC
+                 -> T.Text
+displayTimestamp t = U.unsafePerformIO $ formatTimestamp t cFalse "Z"
+
+-- | Convert a timestamp into <https://en.wikipedia.org/wiki/ISO_8601 ISO 8601>
+-- format in the local timezone.
+displayLocalTimestamp :: MillisecondsSinceEpoch -- ^ milliseconds since 1\/1\/1970 UTC
+                      -> IO T.Text
+displayLocalTimestamp t = formatTimestamp t cTrue "%z"
+
+-- | Convert a list of 'GpioPin' to a human-readable list of lines.
+displayGpio :: [GpioPin] -> [T.Text]
+displayGpio gpios = "Gpio" : map dispGpio gpios
+  where
+    dispGpio gpio = "  pin " <> tShow (gpId gpio) <>
+                    (if (gpHigh gpio) then " high" else " low ") <>
+                    (if (gpOutput gpio) then " output" else "  input")
+
+-- | Convert a 'TagReadData' to a human-readable list of lines.
+displayTagReadData :: TagReadData -> [T.Text]
+displayTagReadData trd =
+  concat
+  [ [ "TagReadData" ]
+  , indent (displayTagData $ trTag trd)
+  , [ "  metadataFlags = " <> T.intercalate "|" (map fl $ trMetadataFlags trd)
+    , "  phase         = " <> tShow (trPhase trd)
+    , "  antenna       = " <> tShow (trAntenna trd)
+    ]
+  , indent (displayGpio $ trGpio trd)
+  , [ "  readCount     = " <> tShow (trReadCount trd)
+    , "  rssi          = " <> tShow (trRssi trd)
+    , "  frequency     = " <> tShow (trFrequency trd)
+    , "  timestamp     = " <> displayTimestamp (trTimestamp trd)
+    ]
+  , dat "data" (trData trd)
+  , dat "epcMemData" (trEpcMemData trd)
+  , dat "tidMemData" (trTidMemData trd)
+  , dat "userMemData" (trUserMemData trd)
+  , dat "reservedMemData" (trReservedMemData trd)
+  ]
+  where
+    nDrop = T.length "METADATA_FLAG_"
+    fl = T.drop nDrop . tShow
+    dat name bs =
+      if B.null bs
+      then []
+      else indent ((name <> ": " <> T.pack (show $ B.length bs) <> " bytes")
+                   : indent (displayData bs))
+
+regionPrefix :: T.Text
+regionPrefix = "REGION_"
+
+-- | Like 'show' for 'Region', but in lower case and without the
+-- @REGION_@ prefix.
+displayRegion :: Region -> T.Text
+displayRegion = T.toLower . T.pack . drop (T.length regionPrefix) . show
+
+-- | Like 'readMaybe' for 'Region', but case-insenstive and without the
+-- @REGION_@ prefix.
+parseRegion :: T.Text -> Maybe Region
+parseRegion = readMaybe . T.unpack . T.toUpper . T.append regionPrefix
+
+-- | Convert a 'B.ByteString' into a list of 'Word16', in big-endian
+-- order.  Padded with 0 if the number of bytes is odd.
+packBytesIntoWords :: B.ByteString -> [Word16]
+packBytesIntoWords bs = pbw (B.unpack bs)
+  where pbw [] = []
+        pbw [x] = [pk x 0]
+        pbw (x1:x2:xs) = pk x1 x2 : pbw xs
+        pk x1 x2 = (fromIntegral x1 `shiftL` 8) .|. fromIntegral x2
+
+-- | Split a password into two 16-bit words, suitable for writing
+-- into reserved memory.
+passwordToWords :: GEN2_Password -> [Word16]
+passwordToWords pwd = map fromIntegral [pwd `shiftR` 16, pwd .&. 0xffff]
+
+-- | Create a 'TagFilterGen2' with the most common settings
+mkFilterGen2 :: GEN2_Bank    -- ^ The bank to filter on
+             -> Word32       -- ^ The location (in bits) at which to begin
+                             -- comparing the mask
+             -> B.ByteString -- ^ The mask value to compare with the specified
+                             -- region of tag memory
+             -> TagFilter
+mkFilterGen2 bank bitPointer mask =
+  TagFilterGen2
+  { tfInvert = False
+  , tfFilterOn = FilterOnBank bank
+  , tfBitPointer = bitPointer
+  , tfMaskBitLength = fromIntegral $ 8 * B.length mask
+  , tfMask = mask
+  }
+
+-- | Word address of kill password in reserved memory.
+killPasswordAddress :: Word32
+killPasswordAddress = 0
+
+-- | Word address of access password in reserved memory.
+accessPasswordAddress :: Word32
+accessPasswordAddress = 2
diff --git a/src/System/Hardware/MercuryApi/Enums.hsc b/src/System/Hardware/MercuryApi/Enums.hsc
new file mode 100644
--- /dev/null
+++ b/src/System/Hardware/MercuryApi/Enums.hsc
@@ -0,0 +1,967 @@
+-- Automatically generated by util/generate-tmr-hsc.pl
+{-# LANGUAGE OverloadedStrings, FlexibleInstances, DeriveDataTypeable #-}
+module System.Hardware.MercuryApi.Enums where
+
+import Data.Hashable ( Hashable(..) )
+import Data.Int ( Int8, Int16, Int32 )
+import Data.Monoid ( (<>) )
+import Data.Text (Text)
+import qualified Data.Text as T ( pack )
+import Data.Word ( Word8, Word16, Word32 )
+import Text.Printf ( printf )
+
+#include <tm_reader.h>
+#include <serial_reader_imp.h>
+#include <glue.h>
+
+-- | Indicates a general category of error.
+data StatusType =
+    SUCCESS_TYPE
+  | ERROR_TYPE_COMM
+  | ERROR_TYPE_CODE
+  | ERROR_TYPE_MISC
+  | ERROR_TYPE_LLRP
+  | ERROR_TYPE_BINDING -- ^ An error which originates from the Haskell binding, not the underlying C library.
+  | ERROR_TYPE_UNKNOWN -- ^ Not a recognized status type
+  deriving (Eq, Ord, Show, Read, Bounded, Enum)
+
+toStatusType :: Word32 -> StatusType
+toStatusType #{const TMR_SUCCESS_TYPE} = SUCCESS_TYPE
+toStatusType #{const TMR_ERROR_TYPE_COMM} = ERROR_TYPE_COMM
+toStatusType #{const TMR_ERROR_TYPE_CODE} = ERROR_TYPE_CODE
+toStatusType #{const TMR_ERROR_TYPE_MISC} = ERROR_TYPE_MISC
+toStatusType #{const TMR_ERROR_TYPE_LLRP} = ERROR_TYPE_LLRP
+toStatusType #{const ERROR_TYPE_BINDING} = ERROR_TYPE_BINDING
+toStatusType _ = ERROR_TYPE_UNKNOWN
+
+-- | A specific error encountered by the C API or the Haskell binding.
+data Status =
+    SUCCESS -- ^ Success!  (Never thrown in an exception)
+  | ERROR_MSG_WRONG_NUMBER_OF_DATA -- ^ Invalid number of arguments
+  | ERROR_INVALID_OPCODE -- ^ Command opcode not recognized.
+  | ERROR_UNIMPLEMENTED_OPCODE -- ^ Command opcode recognized, but is not supported.
+  | ERROR_MSG_POWER_TOO_HIGH -- ^ Requested power setting is above the allowed maximum.
+  | ERROR_MSG_INVALID_FREQ_RECEIVED -- ^ Requested frequency is outside the allowed range.
+  | ERROR_MSG_INVALID_PARAMETER_VALUE -- ^ Parameter value is outside the allowed range.
+  | ERROR_MSG_POWER_TOO_LOW -- ^ Requested power setting is below the allowed minimum.
+  | ERROR_UNIMPLEMENTED_FEATURE -- ^ Command not supported.
+  | ERROR_INVALID_BAUD_RATE -- ^ Requested serial speed is not supported.
+  | ERROR_INVALID_REGION -- ^ Region is not supported.
+  | ERROR_INVALID_LICENSE_KEY -- ^  License key code is invalid
+  | ERROR_BL_INVALID_IMAGE_CRC -- ^ Firmware is corrupt: Checksum doesn\'t match content.
+  | ERROR_BL_INVALID_APP_END_ADDR -- ^ Serial protocol status code for this exception.
+  | ERROR_FLASH_BAD_ERASE_PASSWORD -- ^ Internal reader error.  Contact support.
+  | ERROR_FLASH_BAD_WRITE_PASSWORD -- ^ Internal reader error.  Contact support.
+  | ERROR_FLASH_UNDEFINED_SECTOR -- ^ Internal reader error.  Contact support.
+  | ERROR_FLASH_ILLEGAL_SECTOR -- ^ Internal reader error.  Contact support.
+  | ERROR_FLASH_WRITE_TO_NON_ERASED_AREA -- ^ Internal reader error.  Contact support.
+  | ERROR_FLASH_WRITE_TO_ILLEGAL_SECTOR -- ^ Internal reader error.  Contact support.
+  | ERROR_FLASH_VERIFY_FAILED -- ^ Internal reader error.  Contact support.
+  | ERROR_NO_TAGS_FOUND -- ^ Reader was asked to find tags, but none were detected.
+  | ERROR_NO_PROTOCOL_DEFINED -- ^ RFID protocol has not been configured.
+  | ERROR_INVALID_PROTOCOL_SPECIFIED -- ^ Requested RFID protocol is not recognized.
+  | ERROR_WRITE_PASSED_LOCK_FAILED -- ^ Lock failed after write operation
+  | ERROR_PROTOCOL_NO_DATA_READ -- ^ Tag data was requested, but could not be read.
+  | ERROR_AFE_NOT_ON -- ^ AFE not on - reader not sufficiently configured
+  | ERROR_PROTOCOL_WRITE_FAILED -- ^ Write to tag failed.
+  | ERROR_NOT_IMPLEMENTED_FOR_THIS_PROTOCOL -- ^ Command is not supported in the current RFID protocol.
+  | ERROR_PROTOCOL_INVALID_WRITE_DATA -- ^ Data does not conform to protocol standards.
+  | ERROR_PROTOCOL_INVALID_ADDRESS -- ^ Requested data address is outside the valid range.
+  | ERROR_GENERAL_TAG_ERROR -- ^ Unknown error during RFID operation.
+  | ERROR_DATA_TOO_LARGE -- ^ Read Tag Data was asked for more data than it supports.
+  | ERROR_PROTOCOL_INVALID_KILL_PASSWORD -- ^ Incorrect password was provided to Kill Tag.
+  | ERROR_PROTOCOL_KILL_FAILED -- ^ Kill failed for unknown reason.
+  | ERROR_PROTOCOL_BIT_DECODING_FAILED -- ^ Internal reader error.  Contact support.
+  | ERROR_PROTOCOL_INVALID_EPC -- ^ Internal reader error.  Contact support.
+  | ERROR_PROTOCOL_INVALID_NUM_DATA -- ^ Internal reader error.  Contact support.
+  | ERROR_GEN2_PROTOCOL_OTHER_ERROR -- ^ Internal reader error.  Contact support.
+  | ERROR_GEN2_PROTOCOL_MEMORY_OVERRUN_BAD_PC -- ^ Internal reader error.  Contact support.
+  | ERROR_GEN2_PROTOCOL_MEMORY_LOCKED -- ^ Internal reader error.  Contact support.
+  | ERROR_GEN2_PROTOCOL_V2_AUTHEN_FAILED -- ^ Authentication failed with specified key.
+  | ERROR_GEN2_PROTOCOL_V2_UNTRACE_FAILED -- ^  Untrace operation failed.
+  | ERROR_GEN2_PROTOCOL_INSUFFICIENT_POWER -- ^ Internal reader error.  Contact support.
+  | ERROR_GEN2_PROTOCOL_NON_SPECIFIC_ERROR -- ^ Internal reader error.  Contact support.
+  | ERROR_GEN2_PROTOCOL_UNKNOWN_ERROR -- ^ Internal reader error.  Contact support.
+  | ERROR_AHAL_INVALID_FREQ -- ^ A command was received to set a frequency outside the specified range.
+  | ERROR_AHAL_CHANNEL_OCCUPIED -- ^ With LBT enabled an attempt was made to set the frequency to an occupied channel.
+  | ERROR_AHAL_TRANSMITTER_ON -- ^ Checking antenna status while CW is on is not allowed.
+  | ERROR_ANTENNA_NOT_CONNECTED -- ^  Antenna not detected during pre-transmit safety test.
+  | ERROR_TEMPERATURE_EXCEED_LIMITS -- ^ Reader temperature outside safe range.
+  | ERROR_HIGH_RETURN_LOSS -- ^  Excess power detected at transmitter port, usually due to antenna tuning mismatch.
+  | ERROR_INVALID_ANTENNA_CONFIG -- ^ Invalid antenna configuration
+  | ERROR_TAG_ID_BUFFER_NOT_ENOUGH_TAGS_AVAILABLE -- ^ Asked for more tags than were available in the buffer.
+  | ERROR_TAG_ID_BUFFER_FULL -- ^ Too many tags are in buffer.  Remove some with Get Tag ID Buffer or Clear Tag ID Buffer.
+  | ERROR_TAG_ID_BUFFER_REPEATED_TAG_ID -- ^ Internal error -- reader is trying to insert a duplicate tag record.  Contact support.
+  | ERROR_TAG_ID_BUFFER_NUM_TAG_TOO_LARGE -- ^ Asked for tags than a single transaction can handle.
+  | ERROR_TAG_ID_BUFFER_AUTH_REQUEST -- ^ Blocked response to get additional data from host.
+  | ERROR_SYSTEM_UNKNOWN_ERROR -- ^ Internal reader error.  Contact support.
+  | ERROR_TM_ASSERT_FAILED -- ^ Internal reader error.  Contact support.
+  | ERROR_TIMEOUT -- ^ Timeout
+  | ERROR_NO_HOST -- ^ No matching host found
+  | ERROR_LLRP -- ^ LLRP error
+  | ERROR_PARSE -- ^ Error parsing device response
+  | ERROR_DEVICE_RESET -- ^ Device was reset externally
+  | ERROR_CRC_ERROR -- ^ CRC Error
+  | ERROR_INVALID -- ^ Invalid argument
+  | ERROR_UNIMPLEMENTED -- ^ Unimplemented operation
+  | ERROR_UNSUPPORTED -- ^ Unsupported operation
+  | ERROR_NO_ANTENNA -- ^ No antenna or invalid antenna
+  | ERROR_READONLY -- ^ Value is read-only
+  | ERROR_TOO_BIG -- ^ Value too big
+  | ERROR_NO_THREADS -- ^ Thread initialization failed
+  | ERROR_NO_TAGS -- ^ No tags to be retrieved
+  | ERROR_NOT_FOUND -- ^ Key not found
+  | ERROR_FIRMWARE_FORMAT -- ^ Size or format of firmware image is incorrect
+  | ERROR_TRYAGAIN -- ^ Temporary error, try again
+  | ERROR_OUT_OF_MEMORY -- ^ Out of memory
+  | ERROR_INVALID_WRITE_MODE -- ^ Invalid write mode
+  | ERROR_ILLEGAL_VALUE -- ^ Illegal value
+  | ERROR_END_OF_READING
+  | ERROR_UNSUPPORTED_READER_TYPE -- ^ Unsupported reader type
+  | ERROR_BUFFER_OVERFLOW -- ^ Buffer overflow
+  | ERROR_LOADSAVE_CONFIG
+  | ERROR_AUTOREAD_ENABLED -- ^ Autonomous mode is enabled on reader. Please disable it
+  | ERROR_FIRMWARE_UPDATE_ON_AUTOREAD -- ^ Firmware update is successful. Autonomous mode is already enabled on reader
+  | ERROR_TIMESTAMP_NULL -- ^ Timestamp cannot be null
+  | ERROR_LLRP_GETTYPEREGISTRY -- ^ LLRP Reader GetTypeRegistry Failed
+  | ERROR_LLRP_CONNECTIONFAILED -- ^ LLRP Reader Connection attempt is failed
+  | ERROR_LLRP_SENDIO_ERROR -- ^ LLRP Reader Send Messages failed
+  | ERROR_LLRP_RECEIVEIO_ERROR -- ^ LLRP Reader Receive Messages failed
+  | ERROR_LLRP_RECEIVE_TIMEOUT -- ^ LLRP Reader Receive Messages Timeout
+  | ERROR_LLRP_MSG_PARSE_ERROR -- ^ Error parsing LLRP message
+  | ERROR_LLRP_ALREADY_CONNECTED -- ^ Already connected to reader
+  | ERROR_LLRP_INVALID_RFMODE -- ^ Specified RF Mode operation is not supported
+  | ERROR_LLRP_UNDEFINED_VALUE -- ^ Undefined Value
+  | ERROR_LLRP_READER_ERROR -- ^ LLRP reader unknown error
+  | ERROR_LLRP_READER_CONNECTION_LOST -- ^ LLRP reader connection lost
+  | ERROR_LLRP_CLIENT_CONNECTION_EXISTS -- ^ LLRP Reader Connection attempt is failed, A Client initiated connection already exists
+  | ERROR_ALREADY_DESTROYED -- ^ Attempt to use reader after it was destroyed.
+  | ERROR_INVALID_PARAM_TYPE -- ^ The parameter value was not of the type expected.
+  | ERROR_UNIMPLEMENTED_PARAM -- ^ The given parameter is not yet implemented in the Haskell binding.
+  | ERROR_UNKNOWN Word32 -- ^ C API returned an unrecognized status code
+  deriving (Eq, Ord, Show, Read)
+
+toStatus :: Word32 -> Status
+toStatus #{const TMR_SUCCESS} = SUCCESS
+toStatus #{const TMR_ERROR_MSG_WRONG_NUMBER_OF_DATA} = ERROR_MSG_WRONG_NUMBER_OF_DATA
+toStatus #{const TMR_ERROR_INVALID_OPCODE} = ERROR_INVALID_OPCODE
+toStatus #{const TMR_ERROR_UNIMPLEMENTED_OPCODE} = ERROR_UNIMPLEMENTED_OPCODE
+toStatus #{const TMR_ERROR_MSG_POWER_TOO_HIGH} = ERROR_MSG_POWER_TOO_HIGH
+toStatus #{const TMR_ERROR_MSG_INVALID_FREQ_RECEIVED} = ERROR_MSG_INVALID_FREQ_RECEIVED
+toStatus #{const TMR_ERROR_MSG_INVALID_PARAMETER_VALUE} = ERROR_MSG_INVALID_PARAMETER_VALUE
+toStatus #{const TMR_ERROR_MSG_POWER_TOO_LOW} = ERROR_MSG_POWER_TOO_LOW
+toStatus #{const TMR_ERROR_UNIMPLEMENTED_FEATURE} = ERROR_UNIMPLEMENTED_FEATURE
+toStatus #{const TMR_ERROR_INVALID_BAUD_RATE} = ERROR_INVALID_BAUD_RATE
+toStatus #{const TMR_ERROR_INVALID_REGION} = ERROR_INVALID_REGION
+toStatus #{const TMR_ERROR_INVALID_LICENSE_KEY} = ERROR_INVALID_LICENSE_KEY
+toStatus #{const TMR_ERROR_BL_INVALID_IMAGE_CRC} = ERROR_BL_INVALID_IMAGE_CRC
+toStatus #{const TMR_ERROR_BL_INVALID_APP_END_ADDR} = ERROR_BL_INVALID_APP_END_ADDR
+toStatus #{const TMR_ERROR_FLASH_BAD_ERASE_PASSWORD} = ERROR_FLASH_BAD_ERASE_PASSWORD
+toStatus #{const TMR_ERROR_FLASH_BAD_WRITE_PASSWORD} = ERROR_FLASH_BAD_WRITE_PASSWORD
+toStatus #{const TMR_ERROR_FLASH_UNDEFINED_SECTOR} = ERROR_FLASH_UNDEFINED_SECTOR
+toStatus #{const TMR_ERROR_FLASH_ILLEGAL_SECTOR} = ERROR_FLASH_ILLEGAL_SECTOR
+toStatus #{const TMR_ERROR_FLASH_WRITE_TO_NON_ERASED_AREA} = ERROR_FLASH_WRITE_TO_NON_ERASED_AREA
+toStatus #{const TMR_ERROR_FLASH_WRITE_TO_ILLEGAL_SECTOR} = ERROR_FLASH_WRITE_TO_ILLEGAL_SECTOR
+toStatus #{const TMR_ERROR_FLASH_VERIFY_FAILED} = ERROR_FLASH_VERIFY_FAILED
+toStatus #{const TMR_ERROR_NO_TAGS_FOUND} = ERROR_NO_TAGS_FOUND
+toStatus #{const TMR_ERROR_NO_PROTOCOL_DEFINED} = ERROR_NO_PROTOCOL_DEFINED
+toStatus #{const TMR_ERROR_INVALID_PROTOCOL_SPECIFIED} = ERROR_INVALID_PROTOCOL_SPECIFIED
+toStatus #{const TMR_ERROR_WRITE_PASSED_LOCK_FAILED} = ERROR_WRITE_PASSED_LOCK_FAILED
+toStatus #{const TMR_ERROR_PROTOCOL_NO_DATA_READ} = ERROR_PROTOCOL_NO_DATA_READ
+toStatus #{const TMR_ERROR_AFE_NOT_ON} = ERROR_AFE_NOT_ON
+toStatus #{const TMR_ERROR_PROTOCOL_WRITE_FAILED} = ERROR_PROTOCOL_WRITE_FAILED
+toStatus #{const TMR_ERROR_NOT_IMPLEMENTED_FOR_THIS_PROTOCOL} = ERROR_NOT_IMPLEMENTED_FOR_THIS_PROTOCOL
+toStatus #{const TMR_ERROR_PROTOCOL_INVALID_WRITE_DATA} = ERROR_PROTOCOL_INVALID_WRITE_DATA
+toStatus #{const TMR_ERROR_PROTOCOL_INVALID_ADDRESS} = ERROR_PROTOCOL_INVALID_ADDRESS
+toStatus #{const TMR_ERROR_GENERAL_TAG_ERROR} = ERROR_GENERAL_TAG_ERROR
+toStatus #{const TMR_ERROR_DATA_TOO_LARGE} = ERROR_DATA_TOO_LARGE
+toStatus #{const TMR_ERROR_PROTOCOL_INVALID_KILL_PASSWORD} = ERROR_PROTOCOL_INVALID_KILL_PASSWORD
+toStatus #{const TMR_ERROR_PROTOCOL_KILL_FAILED} = ERROR_PROTOCOL_KILL_FAILED
+toStatus #{const TMR_ERROR_PROTOCOL_BIT_DECODING_FAILED} = ERROR_PROTOCOL_BIT_DECODING_FAILED
+toStatus #{const TMR_ERROR_PROTOCOL_INVALID_EPC} = ERROR_PROTOCOL_INVALID_EPC
+toStatus #{const TMR_ERROR_PROTOCOL_INVALID_NUM_DATA} = ERROR_PROTOCOL_INVALID_NUM_DATA
+toStatus #{const TMR_ERROR_GEN2_PROTOCOL_OTHER_ERROR} = ERROR_GEN2_PROTOCOL_OTHER_ERROR
+toStatus #{const TMR_ERROR_GEN2_PROTOCOL_MEMORY_OVERRUN_BAD_PC} = ERROR_GEN2_PROTOCOL_MEMORY_OVERRUN_BAD_PC
+toStatus #{const TMR_ERROR_GEN2_PROTOCOL_MEMORY_LOCKED} = ERROR_GEN2_PROTOCOL_MEMORY_LOCKED
+toStatus #{const TMR_ERROR_GEN2_PROTOCOL_V2_AUTHEN_FAILED} = ERROR_GEN2_PROTOCOL_V2_AUTHEN_FAILED
+toStatus #{const TMR_ERROR_GEN2_PROTOCOL_V2_UNTRACE_FAILED} = ERROR_GEN2_PROTOCOL_V2_UNTRACE_FAILED
+toStatus #{const TMR_ERROR_GEN2_PROTOCOL_INSUFFICIENT_POWER} = ERROR_GEN2_PROTOCOL_INSUFFICIENT_POWER
+toStatus #{const TMR_ERROR_GEN2_PROTOCOL_NON_SPECIFIC_ERROR} = ERROR_GEN2_PROTOCOL_NON_SPECIFIC_ERROR
+toStatus #{const TMR_ERROR_GEN2_PROTOCOL_UNKNOWN_ERROR} = ERROR_GEN2_PROTOCOL_UNKNOWN_ERROR
+toStatus #{const TMR_ERROR_AHAL_INVALID_FREQ} = ERROR_AHAL_INVALID_FREQ
+toStatus #{const TMR_ERROR_AHAL_CHANNEL_OCCUPIED} = ERROR_AHAL_CHANNEL_OCCUPIED
+toStatus #{const TMR_ERROR_AHAL_TRANSMITTER_ON} = ERROR_AHAL_TRANSMITTER_ON
+toStatus #{const TMR_ERROR_ANTENNA_NOT_CONNECTED} = ERROR_ANTENNA_NOT_CONNECTED
+toStatus #{const TMR_ERROR_TEMPERATURE_EXCEED_LIMITS} = ERROR_TEMPERATURE_EXCEED_LIMITS
+toStatus #{const TMR_ERROR_HIGH_RETURN_LOSS} = ERROR_HIGH_RETURN_LOSS
+toStatus #{const TMR_ERROR_INVALID_ANTENNA_CONFIG} = ERROR_INVALID_ANTENNA_CONFIG
+toStatus #{const TMR_ERROR_TAG_ID_BUFFER_NOT_ENOUGH_TAGS_AVAILABLE} = ERROR_TAG_ID_BUFFER_NOT_ENOUGH_TAGS_AVAILABLE
+toStatus #{const TMR_ERROR_TAG_ID_BUFFER_FULL} = ERROR_TAG_ID_BUFFER_FULL
+toStatus #{const TMR_ERROR_TAG_ID_BUFFER_REPEATED_TAG_ID} = ERROR_TAG_ID_BUFFER_REPEATED_TAG_ID
+toStatus #{const TMR_ERROR_TAG_ID_BUFFER_NUM_TAG_TOO_LARGE} = ERROR_TAG_ID_BUFFER_NUM_TAG_TOO_LARGE
+toStatus #{const TMR_ERROR_TAG_ID_BUFFER_AUTH_REQUEST} = ERROR_TAG_ID_BUFFER_AUTH_REQUEST
+toStatus #{const TMR_ERROR_SYSTEM_UNKNOWN_ERROR} = ERROR_SYSTEM_UNKNOWN_ERROR
+toStatus #{const TMR_ERROR_TM_ASSERT_FAILED} = ERROR_TM_ASSERT_FAILED
+toStatus #{const TMR_ERROR_TIMEOUT} = ERROR_TIMEOUT
+toStatus #{const TMR_ERROR_NO_HOST} = ERROR_NO_HOST
+toStatus #{const TMR_ERROR_LLRP} = ERROR_LLRP
+toStatus #{const TMR_ERROR_PARSE} = ERROR_PARSE
+toStatus #{const TMR_ERROR_DEVICE_RESET} = ERROR_DEVICE_RESET
+toStatus #{const TMR_ERROR_CRC_ERROR} = ERROR_CRC_ERROR
+toStatus #{const TMR_ERROR_INVALID} = ERROR_INVALID
+toStatus #{const TMR_ERROR_UNIMPLEMENTED} = ERROR_UNIMPLEMENTED
+toStatus #{const TMR_ERROR_UNSUPPORTED} = ERROR_UNSUPPORTED
+toStatus #{const TMR_ERROR_NO_ANTENNA} = ERROR_NO_ANTENNA
+toStatus #{const TMR_ERROR_READONLY} = ERROR_READONLY
+toStatus #{const TMR_ERROR_TOO_BIG} = ERROR_TOO_BIG
+toStatus #{const TMR_ERROR_NO_THREADS} = ERROR_NO_THREADS
+toStatus #{const TMR_ERROR_NO_TAGS} = ERROR_NO_TAGS
+toStatus #{const TMR_ERROR_NOT_FOUND} = ERROR_NOT_FOUND
+toStatus #{const TMR_ERROR_FIRMWARE_FORMAT} = ERROR_FIRMWARE_FORMAT
+toStatus #{const TMR_ERROR_TRYAGAIN} = ERROR_TRYAGAIN
+toStatus #{const TMR_ERROR_OUT_OF_MEMORY} = ERROR_OUT_OF_MEMORY
+toStatus #{const TMR_ERROR_INVALID_WRITE_MODE} = ERROR_INVALID_WRITE_MODE
+toStatus #{const TMR_ERROR_ILLEGAL_VALUE} = ERROR_ILLEGAL_VALUE
+toStatus #{const TMR_ERROR_END_OF_READING} = ERROR_END_OF_READING
+toStatus #{const TMR_ERROR_UNSUPPORTED_READER_TYPE} = ERROR_UNSUPPORTED_READER_TYPE
+toStatus #{const TMR_ERROR_BUFFER_OVERFLOW} = ERROR_BUFFER_OVERFLOW
+toStatus #{const TMR_ERROR_LOADSAVE_CONFIG} = ERROR_LOADSAVE_CONFIG
+toStatus #{const TMR_ERROR_AUTOREAD_ENABLED} = ERROR_AUTOREAD_ENABLED
+toStatus #{const TMR_ERROR_FIRMWARE_UPDATE_ON_AUTOREAD} = ERROR_FIRMWARE_UPDATE_ON_AUTOREAD
+toStatus #{const TMR_ERROR_TIMESTAMP_NULL} = ERROR_TIMESTAMP_NULL
+toStatus #{const TMR_ERROR_LLRP_GETTYPEREGISTRY} = ERROR_LLRP_GETTYPEREGISTRY
+toStatus #{const TMR_ERROR_LLRP_CONNECTIONFAILED} = ERROR_LLRP_CONNECTIONFAILED
+toStatus #{const TMR_ERROR_LLRP_SENDIO_ERROR} = ERROR_LLRP_SENDIO_ERROR
+toStatus #{const TMR_ERROR_LLRP_RECEIVEIO_ERROR} = ERROR_LLRP_RECEIVEIO_ERROR
+toStatus #{const TMR_ERROR_LLRP_RECEIVE_TIMEOUT} = ERROR_LLRP_RECEIVE_TIMEOUT
+toStatus #{const TMR_ERROR_LLRP_MSG_PARSE_ERROR} = ERROR_LLRP_MSG_PARSE_ERROR
+toStatus #{const TMR_ERROR_LLRP_ALREADY_CONNECTED} = ERROR_LLRP_ALREADY_CONNECTED
+toStatus #{const TMR_ERROR_LLRP_INVALID_RFMODE} = ERROR_LLRP_INVALID_RFMODE
+toStatus #{const TMR_ERROR_LLRP_UNDEFINED_VALUE} = ERROR_LLRP_UNDEFINED_VALUE
+toStatus #{const TMR_ERROR_LLRP_READER_ERROR} = ERROR_LLRP_READER_ERROR
+toStatus #{const TMR_ERROR_LLRP_READER_CONNECTION_LOST} = ERROR_LLRP_READER_CONNECTION_LOST
+toStatus #{const TMR_ERROR_LLRP_CLIENT_CONNECTION_EXISTS} = ERROR_LLRP_CLIENT_CONNECTION_EXISTS
+toStatus #{const ERROR_ALREADY_DESTROYED} = ERROR_ALREADY_DESTROYED
+toStatus x = ERROR_UNKNOWN x
+
+type RawRegion = #{type TMR_Region}
+
+-- | RFID regulatory regions
+data Region =
+    REGION_NONE -- ^ Unspecified region
+  | REGION_NA -- ^ North America
+  | REGION_EU -- ^ European Union
+  | REGION_KR -- ^ Korea
+  | REGION_IN -- ^ India
+  | REGION_JP -- ^ Japan
+  | REGION_PRC -- ^ People\'s Republic of China
+  | REGION_EU2 -- ^ European Union 2
+  | REGION_EU3 -- ^ European Union 3
+  | REGION_KR2 -- ^ Korea 2
+  | REGION_PRC2 -- ^ People\'s Republic of China(840MHZ)
+  | REGION_AU -- ^ Australia
+  | REGION_NZ -- ^ New Zealand !!EXPERIMENTAL!!
+  | REGION_NA2 -- ^ Reduced FCC region
+  | REGION_NA3 -- ^ 5MHZ FCC band
+  | REGION_IS -- ^ Israel
+  | REGION_OPEN -- ^ Open
+  deriving (Eq, Ord, Show, Read, Bounded, Enum)
+
+toRegion :: RawRegion -> Region
+toRegion #{const TMR_REGION_NONE} = REGION_NONE
+toRegion #{const TMR_REGION_NA} = REGION_NA
+toRegion #{const TMR_REGION_EU} = REGION_EU
+toRegion #{const TMR_REGION_KR} = REGION_KR
+toRegion #{const TMR_REGION_IN} = REGION_IN
+toRegion #{const TMR_REGION_JP} = REGION_JP
+toRegion #{const TMR_REGION_PRC} = REGION_PRC
+toRegion #{const TMR_REGION_EU2} = REGION_EU2
+toRegion #{const TMR_REGION_EU3} = REGION_EU3
+toRegion #{const TMR_REGION_KR2} = REGION_KR2
+toRegion #{const TMR_REGION_PRC2} = REGION_PRC2
+toRegion #{const TMR_REGION_AU} = REGION_AU
+toRegion #{const TMR_REGION_NZ} = REGION_NZ
+toRegion #{const TMR_REGION_NA2} = REGION_NA2
+toRegion #{const TMR_REGION_NA3} = REGION_NA3
+toRegion #{const TMR_REGION_IS} = REGION_IS
+toRegion #{const TMR_REGION_OPEN} = REGION_OPEN
+toRegion _ = REGION_NONE
+
+fromRegion :: Region -> RawRegion
+fromRegion REGION_NONE = #{const TMR_REGION_NONE}
+fromRegion REGION_NA = #{const TMR_REGION_NA}
+fromRegion REGION_EU = #{const TMR_REGION_EU}
+fromRegion REGION_KR = #{const TMR_REGION_KR}
+fromRegion REGION_IN = #{const TMR_REGION_IN}
+fromRegion REGION_JP = #{const TMR_REGION_JP}
+fromRegion REGION_PRC = #{const TMR_REGION_PRC}
+fromRegion REGION_EU2 = #{const TMR_REGION_EU2}
+fromRegion REGION_EU3 = #{const TMR_REGION_EU3}
+fromRegion REGION_KR2 = #{const TMR_REGION_KR2}
+fromRegion REGION_PRC2 = #{const TMR_REGION_PRC2}
+fromRegion REGION_AU = #{const TMR_REGION_AU}
+fromRegion REGION_NZ = #{const TMR_REGION_NZ}
+fromRegion REGION_NA2 = #{const TMR_REGION_NA2}
+fromRegion REGION_NA3 = #{const TMR_REGION_NA3}
+fromRegion REGION_IS = #{const TMR_REGION_IS}
+fromRegion REGION_OPEN = #{const TMR_REGION_OPEN}
+
+-- | A description of the given region, useful for a user interface.
+displayRegionDescription :: Region -> Text
+displayRegionDescription REGION_NONE = "Unspecified region"
+displayRegionDescription REGION_NA = "North America"
+displayRegionDescription REGION_EU = "European Union"
+displayRegionDescription REGION_KR = "Korea"
+displayRegionDescription REGION_IN = "India"
+displayRegionDescription REGION_JP = "Japan"
+displayRegionDescription REGION_PRC = "People's Republic of China"
+displayRegionDescription REGION_EU2 = "European Union 2"
+displayRegionDescription REGION_EU3 = "European Union 3"
+displayRegionDescription REGION_KR2 = "Korea 2"
+displayRegionDescription REGION_PRC2 = "People's Republic of China(840MHZ)"
+displayRegionDescription REGION_AU = "Australia"
+displayRegionDescription REGION_NZ = "New Zealand !!EXPERIMENTAL!!"
+displayRegionDescription REGION_NA2 = "Reduced FCC region"
+displayRegionDescription REGION_NA3 = "5MHZ FCC band"
+displayRegionDescription REGION_IS = "Israel"
+displayRegionDescription REGION_OPEN = "Open"
+
+type RawTagProtocol = #{type TMR_TagProtocol}
+
+-- | The protocol used by an RFID tag.  Only 'TAG_PROTOCOL_GEN2'
+-- is supported by the M6e Nano, and therefore the Haskell
+-- binding currently only supports that protocol.
+data TagProtocol =
+    TAG_PROTOCOL_NONE
+  | TAG_PROTOCOL_ISO180006B
+  | TAG_PROTOCOL_GEN2
+  | TAG_PROTOCOL_ISO180006B_UCODE
+  | TAG_PROTOCOL_IPX64
+  | TAG_PROTOCOL_IPX256
+  | TAG_PROTOCOL_ATA
+  deriving (Eq, Ord, Show, Read, Bounded, Enum)
+
+toTagProtocol :: RawTagProtocol -> TagProtocol
+toTagProtocol #{const TMR_TAG_PROTOCOL_NONE} = TAG_PROTOCOL_NONE
+toTagProtocol #{const TMR_TAG_PROTOCOL_ISO180006B} = TAG_PROTOCOL_ISO180006B
+toTagProtocol #{const TMR_TAG_PROTOCOL_GEN2} = TAG_PROTOCOL_GEN2
+toTagProtocol #{const TMR_TAG_PROTOCOL_ISO180006B_UCODE} = TAG_PROTOCOL_ISO180006B_UCODE
+toTagProtocol #{const TMR_TAG_PROTOCOL_IPX64} = TAG_PROTOCOL_IPX64
+toTagProtocol #{const TMR_TAG_PROTOCOL_IPX256} = TAG_PROTOCOL_IPX256
+toTagProtocol #{const TMR_TAG_PROTOCOL_ATA} = TAG_PROTOCOL_ATA
+toTagProtocol _ = TAG_PROTOCOL_NONE
+
+fromTagProtocol :: TagProtocol -> RawTagProtocol
+fromTagProtocol TAG_PROTOCOL_NONE = #{const TMR_TAG_PROTOCOL_NONE}
+fromTagProtocol TAG_PROTOCOL_ISO180006B = #{const TMR_TAG_PROTOCOL_ISO180006B}
+fromTagProtocol TAG_PROTOCOL_GEN2 = #{const TMR_TAG_PROTOCOL_GEN2}
+fromTagProtocol TAG_PROTOCOL_ISO180006B_UCODE = #{const TMR_TAG_PROTOCOL_ISO180006B_UCODE}
+fromTagProtocol TAG_PROTOCOL_IPX64 = #{const TMR_TAG_PROTOCOL_IPX64}
+fromTagProtocol TAG_PROTOCOL_IPX256 = #{const TMR_TAG_PROTOCOL_IPX256}
+fromTagProtocol TAG_PROTOCOL_ATA = #{const TMR_TAG_PROTOCOL_ATA}
+
+type RawMetadataFlag = #{type TMR_TRD_MetadataFlag}
+
+-- | Various metadata parameters which can be requested
+-- in 'PARAM_METADATAFLAG'.
+data MetadataFlag =
+    METADATA_FLAG_READCOUNT
+  | METADATA_FLAG_RSSI
+  | METADATA_FLAG_ANTENNAID
+  | METADATA_FLAG_FREQUENCY
+  | METADATA_FLAG_TIMESTAMP
+  | METADATA_FLAG_PHASE
+  | METADATA_FLAG_PROTOCOL
+  | METADATA_FLAG_DATA
+  | METADATA_FLAG_GPIO_STATUS
+  deriving (Eq, Ord, Show, Read, Bounded, Enum)
+
+fromMetadataFlag :: MetadataFlag -> RawMetadataFlag
+fromMetadataFlag METADATA_FLAG_READCOUNT = #{const TMR_TRD_METADATA_FLAG_READCOUNT}
+fromMetadataFlag METADATA_FLAG_RSSI = #{const TMR_TRD_METADATA_FLAG_RSSI}
+fromMetadataFlag METADATA_FLAG_ANTENNAID = #{const TMR_TRD_METADATA_FLAG_ANTENNAID}
+fromMetadataFlag METADATA_FLAG_FREQUENCY = #{const TMR_TRD_METADATA_FLAG_FREQUENCY}
+fromMetadataFlag METADATA_FLAG_TIMESTAMP = #{const TMR_TRD_METADATA_FLAG_TIMESTAMP}
+fromMetadataFlag METADATA_FLAG_PHASE = #{const TMR_TRD_METADATA_FLAG_PHASE}
+fromMetadataFlag METADATA_FLAG_PROTOCOL = #{const TMR_TRD_METADATA_FLAG_PROTOCOL}
+fromMetadataFlag METADATA_FLAG_DATA = #{const TMR_TRD_METADATA_FLAG_DATA}
+fromMetadataFlag METADATA_FLAG_GPIO_STATUS = #{const TMR_TRD_METADATA_FLAG_GPIO_STATUS}
+
+type RawBank = #{type TMR_GEN2_Bank}
+
+-- | Gen2 memory banks
+data GEN2_Bank =
+    GEN2_BANK_RESERVED -- ^ Reserved bank (kill and access passwords)
+  | GEN2_BANK_EPC -- ^ EPC memory bank
+  | GEN2_BANK_TID -- ^ TID memory bank
+  | GEN2_BANK_USER -- ^ User memory bank
+  deriving (Eq, Ord, Show, Read, Bounded, Enum)
+
+fromBank :: GEN2_Bank -> RawBank
+fromBank GEN2_BANK_RESERVED = #{const TMR_GEN2_BANK_RESERVED}
+fromBank GEN2_BANK_EPC = #{const TMR_GEN2_BANK_EPC}
+fromBank GEN2_BANK_TID = #{const TMR_GEN2_BANK_TID}
+fromBank GEN2_BANK_USER = #{const TMR_GEN2_BANK_USER}
+
+toBank :: RawBank -> GEN2_Bank
+toBank #{const TMR_GEN2_BANK_RESERVED} = GEN2_BANK_RESERVED
+toBank #{const TMR_GEN2_BANK_EPC} = GEN2_BANK_EPC
+toBank #{const TMR_GEN2_BANK_TID} = GEN2_BANK_TID
+toBank #{const TMR_GEN2_BANK_USER} = GEN2_BANK_USER
+toBank x = error $ "didn't expect bank to be " ++ show x
+
+fromExtraBank :: GEN2_Bank -> RawBank
+fromExtraBank GEN2_BANK_RESERVED = #{const TMR_GEN2_BANK_RESERVED_ENABLED}
+fromExtraBank GEN2_BANK_EPC = #{const TMR_GEN2_BANK_EPC_ENABLED}
+fromExtraBank GEN2_BANK_TID = #{const TMR_GEN2_BANK_TID_ENABLED}
+fromExtraBank GEN2_BANK_USER = #{const TMR_GEN2_BANK_USER_ENABLED}
+
+type RawLockBits = #{type TMR_GEN2_LockBits}
+
+-- | Memory lock bits
+data GEN2_LockBits =
+    GEN2_LOCK_BITS_USER_PERM -- ^ User memory bank lock permalock bit
+  | GEN2_LOCK_BITS_USER -- ^ User memory bank lock bit
+  | GEN2_LOCK_BITS_TID_PERM -- ^ TID memory bank lock permalock bit
+  | GEN2_LOCK_BITS_TID -- ^ TID memory bank lock bit
+  | GEN2_LOCK_BITS_EPC_PERM -- ^ EPC memory bank lock permalock bit
+  | GEN2_LOCK_BITS_EPC -- ^ EPC memory bank lock bit
+  | GEN2_LOCK_BITS_ACCESS_PERM -- ^ Access password lock permalock bit
+  | GEN2_LOCK_BITS_ACCESS -- ^ Access password lock bit
+  | GEN2_LOCK_BITS_KILL_PERM -- ^ Kill password lock permalock bit
+  | GEN2_LOCK_BITS_KILL -- ^ Kill password lock bit
+  deriving (Eq, Ord, Show, Read, Bounded, Enum)
+
+fromLockBits :: GEN2_LockBits -> RawLockBits
+fromLockBits GEN2_LOCK_BITS_USER_PERM = #{const TMR_GEN2_LOCK_BITS_USER_PERM}
+fromLockBits GEN2_LOCK_BITS_USER = #{const TMR_GEN2_LOCK_BITS_USER}
+fromLockBits GEN2_LOCK_BITS_TID_PERM = #{const TMR_GEN2_LOCK_BITS_TID_PERM}
+fromLockBits GEN2_LOCK_BITS_TID = #{const TMR_GEN2_LOCK_BITS_TID}
+fromLockBits GEN2_LOCK_BITS_EPC_PERM = #{const TMR_GEN2_LOCK_BITS_EPC_PERM}
+fromLockBits GEN2_LOCK_BITS_EPC = #{const TMR_GEN2_LOCK_BITS_EPC}
+fromLockBits GEN2_LOCK_BITS_ACCESS_PERM = #{const TMR_GEN2_LOCK_BITS_ACCESS_PERM}
+fromLockBits GEN2_LOCK_BITS_ACCESS = #{const TMR_GEN2_LOCK_BITS_ACCESS}
+fromLockBits GEN2_LOCK_BITS_KILL_PERM = #{const TMR_GEN2_LOCK_BITS_KILL_PERM}
+fromLockBits GEN2_LOCK_BITS_KILL = #{const TMR_GEN2_LOCK_BITS_KILL}
+
+opcodeName :: Word8 -> Text
+opcodeName #{const TMR_SR_OPCODE_WRITE_FLASH} = "WRITE_FLASH"
+opcodeName #{const TMR_SR_OPCODE_READ_FLASH} = "READ_FLASH"
+opcodeName #{const TMR_SR_OPCODE_VERSION} = "VERSION"
+opcodeName #{const TMR_SR_OPCODE_BOOT_FIRMWARE} = "BOOT_FIRMWARE"
+opcodeName #{const TMR_SR_OPCODE_SET_BAUD_RATE} = "SET_BAUD_RATE"
+opcodeName #{const TMR_SR_OPCODE_ERASE_FLASH} = "ERASE_FLASH"
+opcodeName #{const TMR_SR_OPCODE_VERIFY_IMAGE_CRC} = "VERIFY_IMAGE_CRC"
+opcodeName #{const TMR_SR_OPCODE_BOOT_BOOTLOADER} = "BOOT_BOOTLOADER"
+opcodeName #{const TMR_SR_OPCODE_HW_VERSION} = "HW_VERSION"
+opcodeName #{const TMR_SR_OPCODE_MODIFY_FLASH} = "MODIFY_FLASH"
+opcodeName #{const TMR_SR_OPCODE_GET_DSP_SILICON_ID} = "GET_DSP_SILICON_ID"
+opcodeName #{const TMR_SR_OPCODE_GET_CURRENT_PROGRAM} = "GET_CURRENT_PROGRAM"
+opcodeName #{const TMR_SR_OPCODE_WRITE_FLASH_SECTOR} = "WRITE_FLASH_SECTOR"
+opcodeName #{const TMR_SR_OPCODE_GET_SECTOR_SIZE} = "GET_SECTOR_SIZE"
+opcodeName #{const TMR_SR_OPCODE_MODIFY_FLASH_SECTOR} = "MODIFY_FLASH_SECTOR"
+opcodeName #{const TMR_SR_OPCODE_READ_TAG_ID_SINGLE} = "READ_TAG_ID_SINGLE"
+opcodeName #{const TMR_SR_OPCODE_READ_TAG_ID_MULTIPLE} = "READ_TAG_ID_MULTIPLE"
+opcodeName #{const TMR_SR_OPCODE_WRITE_TAG_ID} = "WRITE_TAG_ID"
+opcodeName #{const TMR_SR_OPCODE_WRITE_TAG_DATA} = "WRITE_TAG_DATA"
+opcodeName #{const TMR_SR_OPCODE_LOCK_TAG} = "LOCK_TAG"
+opcodeName #{const TMR_SR_OPCODE_KILL_TAG} = "KILL_TAG"
+opcodeName #{const TMR_SR_OPCODE_READ_TAG_DATA} = "READ_TAG_DATA"
+opcodeName #{const TMR_SR_OPCODE_GET_TAG_ID_BUFFER} = "GET_TAG_ID_BUFFER"
+opcodeName #{const TMR_SR_OPCODE_CLEAR_TAG_ID_BUFFER} = "CLEAR_TAG_ID_BUFFER"
+opcodeName #{const TMR_SR_OPCODE_WRITE_TAG_SPECIFIC} = "WRITE_TAG_SPECIFIC"
+opcodeName #{const TMR_SR_OPCODE_ERASE_BLOCK_TAG_SPECIFIC} = "ERASE_BLOCK_TAG_SPECIFIC"
+opcodeName #{const TMR_SR_OPCODE_MULTI_PROTOCOL_TAG_OP} = "MULTI_PROTOCOL_TAG_OP"
+opcodeName #{const TMR_SR_OPCODE_GET_ANTENNA_PORT} = "GET_ANTENNA_PORT"
+opcodeName #{const TMR_SR_OPCODE_GET_READ_TX_POWER} = "GET_READ_TX_POWER"
+opcodeName #{const TMR_SR_OPCODE_GET_TAG_PROTOCOL} = "GET_TAG_PROTOCOL"
+opcodeName #{const TMR_SR_OPCODE_GET_WRITE_TX_POWER} = "GET_WRITE_TX_POWER"
+opcodeName #{const TMR_SR_OPCODE_GET_FREQ_HOP_TABLE} = "GET_FREQ_HOP_TABLE"
+opcodeName #{const TMR_SR_OPCODE_GET_USER_GPIO_INPUTS} = "GET_USER_GPIO_INPUTS"
+opcodeName #{const TMR_SR_OPCODE_GET_REGION} = "GET_REGION"
+opcodeName #{const TMR_SR_OPCODE_GET_POWER_MODE} = "GET_POWER_MODE"
+opcodeName #{const TMR_SR_OPCODE_GET_USER_MODE} = "GET_USER_MODE"
+opcodeName #{const TMR_SR_OPCODE_GET_READER_OPTIONAL_PARAMS} = "GET_READER_OPTIONAL_PARAMS"
+opcodeName #{const TMR_SR_OPCODE_GET_PROTOCOL_PARAM} = "GET_PROTOCOL_PARAM"
+opcodeName #{const TMR_SR_OPCODE_GET_READER_STATS} = "GET_READER_STATS"
+opcodeName #{const TMR_SR_OPCODE_GET_USER_PROFILE} = "GET_USER_PROFILE"
+opcodeName #{const TMR_SR_OPCODE_GET_AVAILABLE_PROTOCOLS} = "GET_AVAILABLE_PROTOCOLS"
+opcodeName #{const TMR_SR_OPCODE_GET_AVAILABLE_REGIONS} = "GET_AVAILABLE_REGIONS"
+opcodeName #{const TMR_SR_OPCODE_GET_TEMPERATURE} = "GET_TEMPERATURE"
+opcodeName #{const TMR_SR_OPCODE_SET_ANTENNA_PORT} = "SET_ANTENNA_PORT"
+opcodeName #{const TMR_SR_OPCODE_SET_READ_TX_POWER} = "SET_READ_TX_POWER"
+opcodeName #{const TMR_SR_OPCODE_SET_TAG_PROTOCOL} = "SET_TAG_PROTOCOL"
+opcodeName #{const TMR_SR_OPCODE_SET_WRITE_TX_POWER} = "SET_WRITE_TX_POWER"
+opcodeName #{const TMR_SR_OPCODE_SET_FREQ_HOP_TABLE} = "SET_FREQ_HOP_TABLE"
+opcodeName #{const TMR_SR_OPCODE_SET_USER_GPIO_OUTPUTS} = "SET_USER_GPIO_OUTPUTS"
+opcodeName #{const TMR_SR_OPCODE_SET_REGION} = "SET_REGION"
+opcodeName #{const TMR_SR_OPCODE_SET_POWER_MODE} = "SET_POWER_MODE"
+opcodeName #{const TMR_SR_OPCODE_SET_USER_MODE} = "SET_USER_MODE"
+opcodeName #{const TMR_SR_OPCODE_SET_READER_OPTIONAL_PARAMS} = "SET_READER_OPTIONAL_PARAMS"
+opcodeName #{const TMR_SR_OPCODE_SET_PROTOCOL_PARAM} = "SET_PROTOCOL_PARAM"
+opcodeName #{const TMR_SR_OPCODE_SET_USER_PROFILE} = "SET_USER_PROFILE"
+opcodeName #{const TMR_SR_OPCODE_SET_PROTOCOL_LICENSEKEY} = "SET_PROTOCOL_LICENSEKEY"
+opcodeName #{const TMR_SR_OPCODE_SET_OPERATING_FREQ} = "SET_OPERATING_FREQ"
+opcodeName #{const TMR_SR_OPCODE_TX_CW_SIGNAL} = "TX_CW_SIGNAL"
+opcodeName x = "Unknown opcode " <> T.pack (printf "0x%02X" x)
+
+type RawWriteMode = #{type TMR_GEN2_WriteMode}
+
+-- | Whether to use word write or block write for
+-- 'System.Hardware.MercuryApi.TagOp_GEN2_WriteData'.
+data GEN2_WriteMode =
+    GEN2_WORD_ONLY
+  | GEN2_BLOCK_ONLY
+  | GEN2_BLOCK_FALLBACK
+  deriving (Eq, Ord, Show, Read, Bounded, Enum)
+
+fromWriteMode :: GEN2_WriteMode -> RawWriteMode
+fromWriteMode GEN2_WORD_ONLY = #{const TMR_GEN2_WORD_ONLY}
+fromWriteMode GEN2_BLOCK_ONLY = #{const TMR_GEN2_BLOCK_ONLY}
+fromWriteMode GEN2_BLOCK_FALLBACK = #{const TMR_GEN2_BLOCK_FALLBACK}
+
+toWriteMode :: RawWriteMode -> GEN2_WriteMode
+toWriteMode #{const TMR_GEN2_WORD_ONLY} = GEN2_WORD_ONLY
+toWriteMode #{const TMR_GEN2_BLOCK_ONLY} = GEN2_BLOCK_ONLY
+toWriteMode #{const TMR_GEN2_BLOCK_FALLBACK} = GEN2_BLOCK_FALLBACK
+toWriteMode x = error $ "didn't expect WriteMode to be " ++ show x
+
+type RawPowerMode = #{type TMR_SR_PowerMode}
+
+-- | Value for parameter 'PARAM_POWERMODE'.  On the M6e Nano,
+-- 'POWER_MODE_MINSAVE', 'POWER_MODE_MEDSAVE', and
+-- 'POWER_MODE_MAXSAVE' are all the same.
+data PowerMode =
+    POWER_MODE_FULL
+  | POWER_MODE_MINSAVE
+  | POWER_MODE_MEDSAVE
+  | POWER_MODE_MAXSAVE
+  | POWER_MODE_SLEEP
+  deriving (Eq, Ord, Show, Read, Bounded, Enum)
+
+fromPowerMode :: PowerMode -> RawPowerMode
+fromPowerMode POWER_MODE_FULL = #{const TMR_SR_POWER_MODE_FULL}
+fromPowerMode POWER_MODE_MINSAVE = #{const TMR_SR_POWER_MODE_MINSAVE}
+fromPowerMode POWER_MODE_MEDSAVE = #{const TMR_SR_POWER_MODE_MEDSAVE}
+fromPowerMode POWER_MODE_MAXSAVE = #{const TMR_SR_POWER_MODE_MAXSAVE}
+fromPowerMode POWER_MODE_SLEEP = #{const TMR_SR_POWER_MODE_SLEEP}
+
+toPowerMode :: RawPowerMode -> PowerMode
+toPowerMode #{const TMR_SR_POWER_MODE_FULL} = POWER_MODE_FULL
+toPowerMode #{const TMR_SR_POWER_MODE_MINSAVE} = POWER_MODE_MINSAVE
+toPowerMode #{const TMR_SR_POWER_MODE_MEDSAVE} = POWER_MODE_MEDSAVE
+toPowerMode #{const TMR_SR_POWER_MODE_MAXSAVE} = POWER_MODE_MAXSAVE
+toPowerMode #{const TMR_SR_POWER_MODE_SLEEP} = POWER_MODE_SLEEP
+toPowerMode x = error $ "didn't expect PowerMode to be " ++ show x
+
+type RawParam = #{type TMR_Param}
+
+-- | Reader parameters which you can get and set.  The names
+-- are the same as the names of the enum in the C API.
+-- (Unfortunately, these do not correspond to the
+-- \"path\"-style names in any systematic way.)
+-- Each parameter is listed with its \"path\", and the
+-- Haskell type which is used to store it.  Some parameters
+-- are also listed with the physical units the parameter
+-- is in.  Not all parameters are implemented in the Haskell
+-- binding.  Please file a Github issue if there is a parameter
+-- you need which is not implemented.
+data Param =
+    PARAM_NONE -- ^ No such parameter - used as a return value from 'System.Hardware.MercuryApi.paramID'.
+  | PARAM_BAUDRATE -- ^ @\/reader\/baudRate@ 'Word32'
+  | PARAM_COMMANDTIMEOUT -- ^ @\/reader\/commandTimeout@ 'Word32' (milliseconds)
+  | PARAM_CURRENTTIME -- ^ @\/reader\/currentTime@ (Not yet implemented)
+  | PARAM_READER_DESCRIPTION -- ^ @\/reader\/description@ 'Text'
+  | PARAM_EXTENDEDEPC -- ^ @\/reader\/extendedEpc@ 'Bool'
+  | PARAM_READER_HOSTNAME -- ^ @\/reader\/hostname@ 'Text'
+  | PARAM_LICENSE_KEY -- ^ @\/reader\/licenseKey@ ['Word8']
+  | PARAM_LICENSED_FEATURES -- ^ @\/reader\/licensedFeatures@ ['Word8']
+  | PARAM_METADATAFLAG -- ^ @\/reader\/metadataflags@ ['MetadataFlag']
+  | PARAM_POWERMODE -- ^ @\/reader\/powerMode@ 'PowerMode'
+  | PARAM_PROBEBAUDRATES -- ^ @\/reader\/probeBaudRates@ ['Word32']
+  | PARAM_READER_STATISTICS -- ^ @\/reader\/statistics@ (Not yet implemented)
+  | PARAM_READER_STATS -- ^ @\/reader\/stats@ (Not yet implemented)
+  | PARAM_TRANSPORTTIMEOUT -- ^ @\/reader\/transportTimeout@ 'Word32' (milliseconds)
+  | PARAM_URI -- ^ @\/reader\/uri@ 'Text' (read-only)
+  | PARAM_USER_CONFIG -- ^ @\/reader\/userConfig@ (Not yet implemented)
+  | PARAM_USERMODE -- ^ @\/reader\/userMode@ (Not yet implemented)
+  | PARAM_ANTENNA_CHECKPORT -- ^ @\/reader\/antenna\/checkPort@ 'Bool'
+  | PARAM_ANTENNA_CONNECTEDPORTLIST -- ^ @\/reader\/antenna\/connectedPortList@ ['Word8'], or typedef ['System.Hardware.MercuryApi.AntennaPort'] (read-only)
+  | PARAM_ANTENNA_PORTLIST -- ^ @\/reader\/antenna\/portList@ ['Word8'], or typedef ['System.Hardware.MercuryApi.AntennaPort'] (read-only)
+  | PARAM_ANTENNA_PORTSWITCHGPOS -- ^ @\/reader\/antenna\/portSwitchGpos@ ['Word8'], or typedef ['System.Hardware.MercuryApi.PinNumber']
+  | PARAM_ANTENNA_RETURNLOSS -- ^ @\/reader\/antenna\/returnLoss@ (Not yet implemented)
+  | PARAM_ANTENNA_SETTLINGTIMELIST -- ^ @\/reader\/antenna\/settlingTimeList@ (Not yet implemented)
+  | PARAM_ANTENNA_TXRXMAP -- ^ @\/reader\/antenna\/txRxMap@ (Not yet implemented)
+  | PARAM_GEN2_BLF -- ^ @\/reader\/gen2\/BLF@ (Not yet implemented)
+  | PARAM_GEN2_ACCESSPASSWORD -- ^ @\/reader\/gen2\/accessPassword@ 'Word32', or typedef 'System.Hardware.MercuryApi.GEN2_Password'
+  | PARAM_GEN2_BAP -- ^ @\/reader\/gen2\/bap@ (Not yet implemented)
+  | PARAM_GEN2_PROTOCOLEXTENSION -- ^ @\/reader\/gen2\/protocolExtension@ (Not yet implemented)
+  | PARAM_GEN2_Q -- ^ @\/reader\/gen2\/q@ (Not yet implemented)
+  | PARAM_GEN2_SESSION -- ^ @\/reader\/gen2\/session@ (Not yet implemented)
+  | PARAM_GEN2_TAGENCODING -- ^ @\/reader\/gen2\/tagEncoding@ (Not yet implemented)
+  | PARAM_GEN2_TARGET -- ^ @\/reader\/gen2\/target@ (Not yet implemented)
+  | PARAM_GEN2_TARI -- ^ @\/reader\/gen2\/tari@ (Not yet implemented)
+  | PARAM_READER_WRITE_EARLY_EXIT -- ^ @\/reader\/gen2\/writeEarlyExit@ 'Bool'
+  | PARAM_GEN2_WRITEMODE -- ^ @\/reader\/gen2\/writeMode@ 'GEN2_WriteMode'
+  | PARAM_READER_WRITE_REPLY_TIMEOUT -- ^ @\/reader\/gen2\/writeReplyTimeout@ 'Word16' (microseconds)
+  | PARAM_GPIO_INPUTLIST -- ^ @\/reader\/gpio\/inputList@ ['Word8'], or typedef ['System.Hardware.MercuryApi.PinNumber']
+  | PARAM_GPIO_OUTPUTLIST -- ^ @\/reader\/gpio\/outputList@ ['Word8'], or typedef ['System.Hardware.MercuryApi.PinNumber']
+  | PARAM_ISO180006B_BLF -- ^ @\/reader\/iso180006b\/BLF@ (Not yet implemented)
+  | PARAM_ISO180006B_DELIMITER -- ^ @\/reader\/iso180006b\/delimiter@ (Not yet implemented)
+  | PARAM_ISO180006B_MODULATION_DEPTH -- ^ @\/reader\/iso180006b\/modulationDepth@ (Not yet implemented)
+  | PARAM_RADIO_ENABLEPOWERSAVE -- ^ @\/reader\/radio\/enablePowerSave@ 'Bool'
+  | PARAM_RADIO_ENABLESJC -- ^ @\/reader\/radio\/enableSJC@ 'Bool'
+  | PARAM_RADIO_PORTREADPOWERLIST -- ^ @\/reader\/radio\/portReadPowerList@ (Not yet implemented)
+  | PARAM_RADIO_PORTWRITEPOWERLIST -- ^ @\/reader\/radio\/portWritePowerList@ (Not yet implemented)
+  | PARAM_RADIO_POWERMAX -- ^ @\/reader\/radio\/powerMax@ 'Int16' (centi-dBm, read-only)
+  | PARAM_RADIO_POWERMIN -- ^ @\/reader\/radio\/powerMin@ 'Int16' (centi-dBm, read-only)
+  | PARAM_RADIO_READPOWER -- ^ @\/reader\/radio\/readPower@ 'Int32' (centi-dBm)
+  | PARAM_RADIO_TEMPERATURE -- ^ @\/reader\/radio\/temperature@ 'Int8' (degrees C, read-only)
+  | PARAM_RADIO_WRITEPOWER -- ^ @\/reader\/radio\/writePower@ 'Int32' (centi-dBm)
+  | PARAM_READ_ASYNCOFFTIME -- ^ @\/reader\/read\/asyncOffTime@ 'Word32' (milliseconds)
+  | PARAM_READ_ASYNCONTIME -- ^ @\/reader\/read\/asyncOnTime@ 'Word32' (milliseconds)
+  | PARAM_READ_PLAN -- ^ @\/reader\/read\/plan@ 'System.Hardware.MercuryApi.ReadPlan'
+  | PARAM_REGION_HOPTABLE -- ^ @\/reader\/region\/hopTable@ ['Word32'] (kHz)
+  | PARAM_REGION_HOPTIME -- ^ @\/reader\/region\/hopTime@ 'Word32' (milliseconds)
+  | PARAM_REGION_ID -- ^ @\/reader\/region\/id@ 'Region'
+  | PARAM_REGION_SUPPORTEDREGIONS -- ^ @\/reader\/region\/supportedRegions@ ['Region'] (read-only)
+  | PARAM_REGION_LBT_ENABLE -- ^ @\/reader\/region\/lbt\/enable@ 'Bool'
+  | PARAM_READER_STATS_ENABLE -- ^ @\/reader\/stats\/enable@ (Not yet implemented)
+  | PARAM_STATUS_ENABLE_ANTENNAREPORT -- ^ @\/reader\/status\/antennaEnable@ 'Bool'
+  | PARAM_STATUS_ENABLE_FREQUENCYREPORT -- ^ @\/reader\/status\/frequencyEnable@ 'Bool'
+  | PARAM_STATUS_ENABLE_TEMPERATUREREPORT -- ^ @\/reader\/status\/temperatureEnable@ 'Bool'
+  | PARAM_TAGREADDATA_ENABLEREADFILTER -- ^ @\/reader\/tagReadData\/enableReadFilter@ 'Bool'
+  | PARAM_TAGREADDATA_READFILTERTIMEOUT -- ^ @\/reader\/tagReadData\/readFilterTimeout@ 'Int32'
+  | PARAM_TAGREADDATA_RECORDHIGHESTRSSI -- ^ @\/reader\/tagReadData\/recordHighestRssi@ 'Bool'
+  | PARAM_TAGREADDATA_REPORTRSSIINDBM -- ^ @\/reader\/tagReadData\/reportRssiInDbm@ 'Bool'
+  | PARAM_TAGREADATA_TAGOPFAILURECOUNT -- ^ @\/reader\/tagReadData\/tagopFailures@ 'Word16' (read-only)
+  | PARAM_TAGREADATA_TAGOPSUCCESSCOUNT -- ^ @\/reader\/tagReadData\/tagopSuccesses@ 'Word16' (read-only)
+  | PARAM_TAGREADDATA_UNIQUEBYANTENNA -- ^ @\/reader\/tagReadData\/uniqueByAntenna@ 'Bool'
+  | PARAM_TAGREADDATA_UNIQUEBYDATA -- ^ @\/reader\/tagReadData\/uniqueByData@ 'Bool'
+  | PARAM_TAGREADDATA_UNIQUEBYPROTOCOL -- ^ @\/reader\/tagReadData\/uniqueByProtocol@ 'Bool'
+  | PARAM_TAGOP_ANTENNA -- ^ @\/reader\/tagop\/antenna@ 'Word8', or typedef 'System.Hardware.MercuryApi.AntennaPort'
+  | PARAM_TAGOP_PROTOCOL -- ^ @\/reader\/tagop\/protocol@ 'TagProtocol'
+  | PARAM_TRIGGER_READ_GPI -- ^ @\/reader\/trigger\/read\/Gpi@ ['Word8'], or typedef ['System.Hardware.MercuryApi.PinNumber']
+  | PARAM_VERSION_HARDWARE -- ^ @\/reader\/version\/hardware@ 'Text' (read-only)
+  | PARAM_VERSION_MODEL -- ^ @\/reader\/version\/model@ 'Text' (read-only)
+  | PARAM_PRODUCT_GROUP -- ^ @\/reader\/version\/productGroup@ 'Text' (read-only)
+  | PARAM_PRODUCT_GROUP_ID -- ^ @\/reader\/version\/productGroupID@ 'Word16' (read-only)
+  | PARAM_PRODUCT_ID -- ^ @\/reader\/version\/productID@ 'Word16' (read-only)
+  | PARAM_VERSION_SERIAL -- ^ @\/reader\/version\/serial@ 'Text'
+  | PARAM_VERSION_SOFTWARE -- ^ @\/reader\/version\/software@ 'Text' (read-only)
+  | PARAM_VERSION_SUPPORTEDPROTOCOLS -- ^ @\/reader\/version\/supportedProtocols@ ['TagProtocol'] (read-only)
+  | PARAM_SELECTED_PROTOCOLS
+  deriving (Eq, Ord, Show, Read, Bounded, Enum)
+
+instance Hashable Param where
+  hash = fromEnum
+  salt `hashWithSalt` p = salt `hashWithSalt` fromEnum p
+
+toParam :: RawParam -> Param
+toParam #{const TMR_PARAM_NONE} = PARAM_NONE
+toParam #{const TMR_PARAM_BAUDRATE} = PARAM_BAUDRATE
+toParam #{const TMR_PARAM_PROBEBAUDRATES} = PARAM_PROBEBAUDRATES
+toParam #{const TMR_PARAM_COMMANDTIMEOUT} = PARAM_COMMANDTIMEOUT
+toParam #{const TMR_PARAM_TRANSPORTTIMEOUT} = PARAM_TRANSPORTTIMEOUT
+toParam #{const TMR_PARAM_POWERMODE} = PARAM_POWERMODE
+toParam #{const TMR_PARAM_USERMODE} = PARAM_USERMODE
+toParam #{const TMR_PARAM_ANTENNA_CHECKPORT} = PARAM_ANTENNA_CHECKPORT
+toParam #{const TMR_PARAM_ANTENNA_PORTLIST} = PARAM_ANTENNA_PORTLIST
+toParam #{const TMR_PARAM_ANTENNA_CONNECTEDPORTLIST} = PARAM_ANTENNA_CONNECTEDPORTLIST
+toParam #{const TMR_PARAM_ANTENNA_PORTSWITCHGPOS} = PARAM_ANTENNA_PORTSWITCHGPOS
+toParam #{const TMR_PARAM_ANTENNA_SETTLINGTIMELIST} = PARAM_ANTENNA_SETTLINGTIMELIST
+toParam #{const TMR_PARAM_ANTENNA_RETURNLOSS} = PARAM_ANTENNA_RETURNLOSS
+toParam #{const TMR_PARAM_ANTENNA_TXRXMAP} = PARAM_ANTENNA_TXRXMAP
+toParam #{const TMR_PARAM_GPIO_INPUTLIST} = PARAM_GPIO_INPUTLIST
+toParam #{const TMR_PARAM_GPIO_OUTPUTLIST} = PARAM_GPIO_OUTPUTLIST
+toParam #{const TMR_PARAM_GEN2_ACCESSPASSWORD} = PARAM_GEN2_ACCESSPASSWORD
+toParam #{const TMR_PARAM_GEN2_Q} = PARAM_GEN2_Q
+toParam #{const TMR_PARAM_GEN2_TAGENCODING} = PARAM_GEN2_TAGENCODING
+toParam #{const TMR_PARAM_GEN2_SESSION} = PARAM_GEN2_SESSION
+toParam #{const TMR_PARAM_GEN2_TARGET} = PARAM_GEN2_TARGET
+toParam #{const TMR_PARAM_GEN2_BLF} = PARAM_GEN2_BLF
+toParam #{const TMR_PARAM_GEN2_TARI} = PARAM_GEN2_TARI
+toParam #{const TMR_PARAM_GEN2_WRITEMODE} = PARAM_GEN2_WRITEMODE
+toParam #{const TMR_PARAM_GEN2_BAP} = PARAM_GEN2_BAP
+toParam #{const TMR_PARAM_GEN2_PROTOCOLEXTENSION} = PARAM_GEN2_PROTOCOLEXTENSION
+toParam #{const TMR_PARAM_ISO180006B_BLF} = PARAM_ISO180006B_BLF
+toParam #{const TMR_PARAM_ISO180006B_MODULATION_DEPTH} = PARAM_ISO180006B_MODULATION_DEPTH
+toParam #{const TMR_PARAM_ISO180006B_DELIMITER} = PARAM_ISO180006B_DELIMITER
+toParam #{const TMR_PARAM_READ_ASYNCOFFTIME} = PARAM_READ_ASYNCOFFTIME
+toParam #{const TMR_PARAM_READ_ASYNCONTIME} = PARAM_READ_ASYNCONTIME
+toParam #{const TMR_PARAM_READ_PLAN} = PARAM_READ_PLAN
+toParam #{const TMR_PARAM_RADIO_ENABLEPOWERSAVE} = PARAM_RADIO_ENABLEPOWERSAVE
+toParam #{const TMR_PARAM_RADIO_POWERMAX} = PARAM_RADIO_POWERMAX
+toParam #{const TMR_PARAM_RADIO_POWERMIN} = PARAM_RADIO_POWERMIN
+toParam #{const TMR_PARAM_RADIO_PORTREADPOWERLIST} = PARAM_RADIO_PORTREADPOWERLIST
+toParam #{const TMR_PARAM_RADIO_PORTWRITEPOWERLIST} = PARAM_RADIO_PORTWRITEPOWERLIST
+toParam #{const TMR_PARAM_RADIO_READPOWER} = PARAM_RADIO_READPOWER
+toParam #{const TMR_PARAM_RADIO_WRITEPOWER} = PARAM_RADIO_WRITEPOWER
+toParam #{const TMR_PARAM_RADIO_TEMPERATURE} = PARAM_RADIO_TEMPERATURE
+toParam #{const TMR_PARAM_TAGREADDATA_RECORDHIGHESTRSSI} = PARAM_TAGREADDATA_RECORDHIGHESTRSSI
+toParam #{const TMR_PARAM_TAGREADDATA_REPORTRSSIINDBM} = PARAM_TAGREADDATA_REPORTRSSIINDBM
+toParam #{const TMR_PARAM_TAGREADDATA_UNIQUEBYANTENNA} = PARAM_TAGREADDATA_UNIQUEBYANTENNA
+toParam #{const TMR_PARAM_TAGREADDATA_UNIQUEBYDATA} = PARAM_TAGREADDATA_UNIQUEBYDATA
+toParam #{const TMR_PARAM_TAGOP_ANTENNA} = PARAM_TAGOP_ANTENNA
+toParam #{const TMR_PARAM_TAGOP_PROTOCOL} = PARAM_TAGOP_PROTOCOL
+toParam #{const TMR_PARAM_VERSION_HARDWARE} = PARAM_VERSION_HARDWARE
+toParam #{const TMR_PARAM_VERSION_SERIAL} = PARAM_VERSION_SERIAL
+toParam #{const TMR_PARAM_VERSION_MODEL} = PARAM_VERSION_MODEL
+toParam #{const TMR_PARAM_VERSION_SOFTWARE} = PARAM_VERSION_SOFTWARE
+toParam #{const TMR_PARAM_VERSION_SUPPORTEDPROTOCOLS} = PARAM_VERSION_SUPPORTEDPROTOCOLS
+toParam #{const TMR_PARAM_REGION_HOPTABLE} = PARAM_REGION_HOPTABLE
+toParam #{const TMR_PARAM_REGION_HOPTIME} = PARAM_REGION_HOPTIME
+toParam #{const TMR_PARAM_REGION_ID} = PARAM_REGION_ID
+toParam #{const TMR_PARAM_REGION_SUPPORTEDREGIONS} = PARAM_REGION_SUPPORTEDREGIONS
+toParam #{const TMR_PARAM_REGION_LBT_ENABLE} = PARAM_REGION_LBT_ENABLE
+toParam #{const TMR_PARAM_LICENSE_KEY} = PARAM_LICENSE_KEY
+toParam #{const TMR_PARAM_USER_CONFIG} = PARAM_USER_CONFIG
+toParam #{const TMR_PARAM_RADIO_ENABLESJC} = PARAM_RADIO_ENABLESJC
+toParam #{const TMR_PARAM_EXTENDEDEPC} = PARAM_EXTENDEDEPC
+toParam #{const TMR_PARAM_READER_STATISTICS} = PARAM_READER_STATISTICS
+toParam #{const TMR_PARAM_READER_STATS} = PARAM_READER_STATS
+toParam #{const TMR_PARAM_URI} = PARAM_URI
+toParam #{const TMR_PARAM_PRODUCT_GROUP_ID} = PARAM_PRODUCT_GROUP_ID
+toParam #{const TMR_PARAM_PRODUCT_GROUP} = PARAM_PRODUCT_GROUP
+toParam #{const TMR_PARAM_PRODUCT_ID} = PARAM_PRODUCT_ID
+toParam #{const TMR_PARAM_TAGREADATA_TAGOPSUCCESSCOUNT} = PARAM_TAGREADATA_TAGOPSUCCESSCOUNT
+toParam #{const TMR_PARAM_TAGREADATA_TAGOPFAILURECOUNT} = PARAM_TAGREADATA_TAGOPFAILURECOUNT
+toParam #{const TMR_PARAM_STATUS_ENABLE_ANTENNAREPORT} = PARAM_STATUS_ENABLE_ANTENNAREPORT
+toParam #{const TMR_PARAM_STATUS_ENABLE_FREQUENCYREPORT} = PARAM_STATUS_ENABLE_FREQUENCYREPORT
+toParam #{const TMR_PARAM_STATUS_ENABLE_TEMPERATUREREPORT} = PARAM_STATUS_ENABLE_TEMPERATUREREPORT
+toParam #{const TMR_PARAM_TAGREADDATA_ENABLEREADFILTER} = PARAM_TAGREADDATA_ENABLEREADFILTER
+toParam #{const TMR_PARAM_TAGREADDATA_READFILTERTIMEOUT} = PARAM_TAGREADDATA_READFILTERTIMEOUT
+toParam #{const TMR_PARAM_TAGREADDATA_UNIQUEBYPROTOCOL} = PARAM_TAGREADDATA_UNIQUEBYPROTOCOL
+toParam #{const TMR_PARAM_READER_DESCRIPTION} = PARAM_READER_DESCRIPTION
+toParam #{const TMR_PARAM_READER_HOSTNAME} = PARAM_READER_HOSTNAME
+toParam #{const TMR_PARAM_CURRENTTIME} = PARAM_CURRENTTIME
+toParam #{const TMR_PARAM_READER_WRITE_REPLY_TIMEOUT} = PARAM_READER_WRITE_REPLY_TIMEOUT
+toParam #{const TMR_PARAM_READER_WRITE_EARLY_EXIT} = PARAM_READER_WRITE_EARLY_EXIT
+toParam #{const TMR_PARAM_READER_STATS_ENABLE} = PARAM_READER_STATS_ENABLE
+toParam #{const TMR_PARAM_TRIGGER_READ_GPI} = PARAM_TRIGGER_READ_GPI
+toParam #{const TMR_PARAM_METADATAFLAG} = PARAM_METADATAFLAG
+toParam #{const TMR_PARAM_LICENSED_FEATURES} = PARAM_LICENSED_FEATURES
+toParam #{const TMR_PARAM_SELECTED_PROTOCOLS} = PARAM_SELECTED_PROTOCOLS
+toParam _ = PARAM_NONE
+
+fromParam :: Param -> RawParam
+fromParam PARAM_NONE = #{const TMR_PARAM_NONE}
+fromParam PARAM_BAUDRATE = #{const TMR_PARAM_BAUDRATE}
+fromParam PARAM_PROBEBAUDRATES = #{const TMR_PARAM_PROBEBAUDRATES}
+fromParam PARAM_COMMANDTIMEOUT = #{const TMR_PARAM_COMMANDTIMEOUT}
+fromParam PARAM_TRANSPORTTIMEOUT = #{const TMR_PARAM_TRANSPORTTIMEOUT}
+fromParam PARAM_POWERMODE = #{const TMR_PARAM_POWERMODE}
+fromParam PARAM_USERMODE = #{const TMR_PARAM_USERMODE}
+fromParam PARAM_ANTENNA_CHECKPORT = #{const TMR_PARAM_ANTENNA_CHECKPORT}
+fromParam PARAM_ANTENNA_PORTLIST = #{const TMR_PARAM_ANTENNA_PORTLIST}
+fromParam PARAM_ANTENNA_CONNECTEDPORTLIST = #{const TMR_PARAM_ANTENNA_CONNECTEDPORTLIST}
+fromParam PARAM_ANTENNA_PORTSWITCHGPOS = #{const TMR_PARAM_ANTENNA_PORTSWITCHGPOS}
+fromParam PARAM_ANTENNA_SETTLINGTIMELIST = #{const TMR_PARAM_ANTENNA_SETTLINGTIMELIST}
+fromParam PARAM_ANTENNA_RETURNLOSS = #{const TMR_PARAM_ANTENNA_RETURNLOSS}
+fromParam PARAM_ANTENNA_TXRXMAP = #{const TMR_PARAM_ANTENNA_TXRXMAP}
+fromParam PARAM_GPIO_INPUTLIST = #{const TMR_PARAM_GPIO_INPUTLIST}
+fromParam PARAM_GPIO_OUTPUTLIST = #{const TMR_PARAM_GPIO_OUTPUTLIST}
+fromParam PARAM_GEN2_ACCESSPASSWORD = #{const TMR_PARAM_GEN2_ACCESSPASSWORD}
+fromParam PARAM_GEN2_Q = #{const TMR_PARAM_GEN2_Q}
+fromParam PARAM_GEN2_TAGENCODING = #{const TMR_PARAM_GEN2_TAGENCODING}
+fromParam PARAM_GEN2_SESSION = #{const TMR_PARAM_GEN2_SESSION}
+fromParam PARAM_GEN2_TARGET = #{const TMR_PARAM_GEN2_TARGET}
+fromParam PARAM_GEN2_BLF = #{const TMR_PARAM_GEN2_BLF}
+fromParam PARAM_GEN2_TARI = #{const TMR_PARAM_GEN2_TARI}
+fromParam PARAM_GEN2_WRITEMODE = #{const TMR_PARAM_GEN2_WRITEMODE}
+fromParam PARAM_GEN2_BAP = #{const TMR_PARAM_GEN2_BAP}
+fromParam PARAM_GEN2_PROTOCOLEXTENSION = #{const TMR_PARAM_GEN2_PROTOCOLEXTENSION}
+fromParam PARAM_ISO180006B_BLF = #{const TMR_PARAM_ISO180006B_BLF}
+fromParam PARAM_ISO180006B_MODULATION_DEPTH = #{const TMR_PARAM_ISO180006B_MODULATION_DEPTH}
+fromParam PARAM_ISO180006B_DELIMITER = #{const TMR_PARAM_ISO180006B_DELIMITER}
+fromParam PARAM_READ_ASYNCOFFTIME = #{const TMR_PARAM_READ_ASYNCOFFTIME}
+fromParam PARAM_READ_ASYNCONTIME = #{const TMR_PARAM_READ_ASYNCONTIME}
+fromParam PARAM_READ_PLAN = #{const TMR_PARAM_READ_PLAN}
+fromParam PARAM_RADIO_ENABLEPOWERSAVE = #{const TMR_PARAM_RADIO_ENABLEPOWERSAVE}
+fromParam PARAM_RADIO_POWERMAX = #{const TMR_PARAM_RADIO_POWERMAX}
+fromParam PARAM_RADIO_POWERMIN = #{const TMR_PARAM_RADIO_POWERMIN}
+fromParam PARAM_RADIO_PORTREADPOWERLIST = #{const TMR_PARAM_RADIO_PORTREADPOWERLIST}
+fromParam PARAM_RADIO_PORTWRITEPOWERLIST = #{const TMR_PARAM_RADIO_PORTWRITEPOWERLIST}
+fromParam PARAM_RADIO_READPOWER = #{const TMR_PARAM_RADIO_READPOWER}
+fromParam PARAM_RADIO_WRITEPOWER = #{const TMR_PARAM_RADIO_WRITEPOWER}
+fromParam PARAM_RADIO_TEMPERATURE = #{const TMR_PARAM_RADIO_TEMPERATURE}
+fromParam PARAM_TAGREADDATA_RECORDHIGHESTRSSI = #{const TMR_PARAM_TAGREADDATA_RECORDHIGHESTRSSI}
+fromParam PARAM_TAGREADDATA_REPORTRSSIINDBM = #{const TMR_PARAM_TAGREADDATA_REPORTRSSIINDBM}
+fromParam PARAM_TAGREADDATA_UNIQUEBYANTENNA = #{const TMR_PARAM_TAGREADDATA_UNIQUEBYANTENNA}
+fromParam PARAM_TAGREADDATA_UNIQUEBYDATA = #{const TMR_PARAM_TAGREADDATA_UNIQUEBYDATA}
+fromParam PARAM_TAGOP_ANTENNA = #{const TMR_PARAM_TAGOP_ANTENNA}
+fromParam PARAM_TAGOP_PROTOCOL = #{const TMR_PARAM_TAGOP_PROTOCOL}
+fromParam PARAM_VERSION_HARDWARE = #{const TMR_PARAM_VERSION_HARDWARE}
+fromParam PARAM_VERSION_SERIAL = #{const TMR_PARAM_VERSION_SERIAL}
+fromParam PARAM_VERSION_MODEL = #{const TMR_PARAM_VERSION_MODEL}
+fromParam PARAM_VERSION_SOFTWARE = #{const TMR_PARAM_VERSION_SOFTWARE}
+fromParam PARAM_VERSION_SUPPORTEDPROTOCOLS = #{const TMR_PARAM_VERSION_SUPPORTEDPROTOCOLS}
+fromParam PARAM_REGION_HOPTABLE = #{const TMR_PARAM_REGION_HOPTABLE}
+fromParam PARAM_REGION_HOPTIME = #{const TMR_PARAM_REGION_HOPTIME}
+fromParam PARAM_REGION_ID = #{const TMR_PARAM_REGION_ID}
+fromParam PARAM_REGION_SUPPORTEDREGIONS = #{const TMR_PARAM_REGION_SUPPORTEDREGIONS}
+fromParam PARAM_REGION_LBT_ENABLE = #{const TMR_PARAM_REGION_LBT_ENABLE}
+fromParam PARAM_LICENSE_KEY = #{const TMR_PARAM_LICENSE_KEY}
+fromParam PARAM_USER_CONFIG = #{const TMR_PARAM_USER_CONFIG}
+fromParam PARAM_RADIO_ENABLESJC = #{const TMR_PARAM_RADIO_ENABLESJC}
+fromParam PARAM_EXTENDEDEPC = #{const TMR_PARAM_EXTENDEDEPC}
+fromParam PARAM_READER_STATISTICS = #{const TMR_PARAM_READER_STATISTICS}
+fromParam PARAM_READER_STATS = #{const TMR_PARAM_READER_STATS}
+fromParam PARAM_URI = #{const TMR_PARAM_URI}
+fromParam PARAM_PRODUCT_GROUP_ID = #{const TMR_PARAM_PRODUCT_GROUP_ID}
+fromParam PARAM_PRODUCT_GROUP = #{const TMR_PARAM_PRODUCT_GROUP}
+fromParam PARAM_PRODUCT_ID = #{const TMR_PARAM_PRODUCT_ID}
+fromParam PARAM_TAGREADATA_TAGOPSUCCESSCOUNT = #{const TMR_PARAM_TAGREADATA_TAGOPSUCCESSCOUNT}
+fromParam PARAM_TAGREADATA_TAGOPFAILURECOUNT = #{const TMR_PARAM_TAGREADATA_TAGOPFAILURECOUNT}
+fromParam PARAM_STATUS_ENABLE_ANTENNAREPORT = #{const TMR_PARAM_STATUS_ENABLE_ANTENNAREPORT}
+fromParam PARAM_STATUS_ENABLE_FREQUENCYREPORT = #{const TMR_PARAM_STATUS_ENABLE_FREQUENCYREPORT}
+fromParam PARAM_STATUS_ENABLE_TEMPERATUREREPORT = #{const TMR_PARAM_STATUS_ENABLE_TEMPERATUREREPORT}
+fromParam PARAM_TAGREADDATA_ENABLEREADFILTER = #{const TMR_PARAM_TAGREADDATA_ENABLEREADFILTER}
+fromParam PARAM_TAGREADDATA_READFILTERTIMEOUT = #{const TMR_PARAM_TAGREADDATA_READFILTERTIMEOUT}
+fromParam PARAM_TAGREADDATA_UNIQUEBYPROTOCOL = #{const TMR_PARAM_TAGREADDATA_UNIQUEBYPROTOCOL}
+fromParam PARAM_READER_DESCRIPTION = #{const TMR_PARAM_READER_DESCRIPTION}
+fromParam PARAM_READER_HOSTNAME = #{const TMR_PARAM_READER_HOSTNAME}
+fromParam PARAM_CURRENTTIME = #{const TMR_PARAM_CURRENTTIME}
+fromParam PARAM_READER_WRITE_REPLY_TIMEOUT = #{const TMR_PARAM_READER_WRITE_REPLY_TIMEOUT}
+fromParam PARAM_READER_WRITE_EARLY_EXIT = #{const TMR_PARAM_READER_WRITE_EARLY_EXIT}
+fromParam PARAM_READER_STATS_ENABLE = #{const TMR_PARAM_READER_STATS_ENABLE}
+fromParam PARAM_TRIGGER_READ_GPI = #{const TMR_PARAM_TRIGGER_READ_GPI}
+fromParam PARAM_METADATAFLAG = #{const TMR_PARAM_METADATAFLAG}
+fromParam PARAM_LICENSED_FEATURES = #{const TMR_PARAM_LICENSED_FEATURES}
+fromParam PARAM_SELECTED_PROTOCOLS = #{const TMR_PARAM_SELECTED_PROTOCOLS}
+
+paramMax :: RawParam
+paramMax = #{const TMR_PARAM_MAX}
+
+-- | For parameters which are expressed in physical units,
+-- returns a string describing the units.  Returns 'Nothing'
+-- for parameters which are not expressed in physical units.
+-- This can be useful for displaying in a user interface,
+-- for example.
+paramUnits :: Param -> Maybe Text
+paramUnits PARAM_COMMANDTIMEOUT = Just "milliseconds"
+paramUnits PARAM_TRANSPORTTIMEOUT = Just "milliseconds"
+paramUnits PARAM_GEN2_BLF = Just "kHz"
+paramUnits PARAM_READ_ASYNCOFFTIME = Just "milliseconds"
+paramUnits PARAM_READ_ASYNCONTIME = Just "milliseconds"
+paramUnits PARAM_RADIO_POWERMAX = Just "centi-dBm"
+paramUnits PARAM_RADIO_POWERMIN = Just "centi-dBm"
+paramUnits PARAM_RADIO_PORTREADPOWERLIST = Just "centi-dBm"
+paramUnits PARAM_RADIO_PORTWRITEPOWERLIST = Just "centi-dBm"
+paramUnits PARAM_RADIO_READPOWER = Just "centi-dBm"
+paramUnits PARAM_RADIO_WRITEPOWER = Just "centi-dBm"
+paramUnits PARAM_RADIO_TEMPERATURE = Just "degrees C"
+paramUnits PARAM_REGION_HOPTABLE = Just "kHz"
+paramUnits PARAM_REGION_HOPTIME = Just "milliseconds"
+paramUnits PARAM_READER_WRITE_REPLY_TIMEOUT = Just "microseconds"
+paramUnits _ = Nothing
+
+-- | The Haskell data type expected for a particular parameter.
+data ParamType =
+    ParamTypeBool
+  | ParamTypeGEN2_WriteMode
+  | ParamTypeInt16
+  | ParamTypeInt32
+  | ParamTypeInt8
+  | ParamTypeMetadataFlagList
+  | ParamTypePowerMode
+  | ParamTypeReadPlan
+  | ParamTypeRegion
+  | ParamTypeRegionList
+  | ParamTypeTagProtocol
+  | ParamTypeTagProtocolList
+  | ParamTypeText
+  | ParamTypeWord16
+  | ParamTypeWord32
+  | ParamTypeWord32List
+  | ParamTypeWord8
+  | ParamTypeWord8List
+  | ParamTypeUnimplemented
+  deriving (Eq, Ord, Show, Read, Bounded, Enum)
+
+-- | Indicates the type expected for a given parameter.
+paramType :: Param -> ParamType
+paramType PARAM_BAUDRATE = ParamTypeWord32
+paramType PARAM_PROBEBAUDRATES = ParamTypeWord32List
+paramType PARAM_COMMANDTIMEOUT = ParamTypeWord32
+paramType PARAM_TRANSPORTTIMEOUT = ParamTypeWord32
+paramType PARAM_POWERMODE = ParamTypePowerMode
+paramType PARAM_ANTENNA_CHECKPORT = ParamTypeBool
+paramType PARAM_ANTENNA_PORTLIST = ParamTypeWord8List
+paramType PARAM_ANTENNA_CONNECTEDPORTLIST = ParamTypeWord8List
+paramType PARAM_ANTENNA_PORTSWITCHGPOS = ParamTypeWord8List
+paramType PARAM_GPIO_INPUTLIST = ParamTypeWord8List
+paramType PARAM_GPIO_OUTPUTLIST = ParamTypeWord8List
+paramType PARAM_GEN2_ACCESSPASSWORD = ParamTypeWord32
+paramType PARAM_GEN2_WRITEMODE = ParamTypeGEN2_WriteMode
+paramType PARAM_READ_ASYNCOFFTIME = ParamTypeWord32
+paramType PARAM_READ_ASYNCONTIME = ParamTypeWord32
+paramType PARAM_READ_PLAN = ParamTypeReadPlan
+paramType PARAM_RADIO_ENABLEPOWERSAVE = ParamTypeBool
+paramType PARAM_RADIO_POWERMAX = ParamTypeInt16
+paramType PARAM_RADIO_POWERMIN = ParamTypeInt16
+paramType PARAM_RADIO_READPOWER = ParamTypeInt32
+paramType PARAM_RADIO_WRITEPOWER = ParamTypeInt32
+paramType PARAM_RADIO_TEMPERATURE = ParamTypeInt8
+paramType PARAM_TAGREADDATA_RECORDHIGHESTRSSI = ParamTypeBool
+paramType PARAM_TAGREADDATA_REPORTRSSIINDBM = ParamTypeBool
+paramType PARAM_TAGREADDATA_UNIQUEBYANTENNA = ParamTypeBool
+paramType PARAM_TAGREADDATA_UNIQUEBYDATA = ParamTypeBool
+paramType PARAM_TAGOP_ANTENNA = ParamTypeWord8
+paramType PARAM_TAGOP_PROTOCOL = ParamTypeTagProtocol
+paramType PARAM_VERSION_HARDWARE = ParamTypeText
+paramType PARAM_VERSION_SERIAL = ParamTypeText
+paramType PARAM_VERSION_MODEL = ParamTypeText
+paramType PARAM_VERSION_SOFTWARE = ParamTypeText
+paramType PARAM_VERSION_SUPPORTEDPROTOCOLS = ParamTypeTagProtocolList
+paramType PARAM_REGION_HOPTABLE = ParamTypeWord32List
+paramType PARAM_REGION_HOPTIME = ParamTypeWord32
+paramType PARAM_REGION_ID = ParamTypeRegion
+paramType PARAM_REGION_SUPPORTEDREGIONS = ParamTypeRegionList
+paramType PARAM_REGION_LBT_ENABLE = ParamTypeBool
+paramType PARAM_LICENSE_KEY = ParamTypeWord8List
+paramType PARAM_RADIO_ENABLESJC = ParamTypeBool
+paramType PARAM_EXTENDEDEPC = ParamTypeBool
+paramType PARAM_URI = ParamTypeText
+paramType PARAM_PRODUCT_GROUP_ID = ParamTypeWord16
+paramType PARAM_PRODUCT_GROUP = ParamTypeText
+paramType PARAM_PRODUCT_ID = ParamTypeWord16
+paramType PARAM_TAGREADATA_TAGOPSUCCESSCOUNT = ParamTypeWord16
+paramType PARAM_TAGREADATA_TAGOPFAILURECOUNT = ParamTypeWord16
+paramType PARAM_STATUS_ENABLE_ANTENNAREPORT = ParamTypeBool
+paramType PARAM_STATUS_ENABLE_FREQUENCYREPORT = ParamTypeBool
+paramType PARAM_STATUS_ENABLE_TEMPERATUREREPORT = ParamTypeBool
+paramType PARAM_TAGREADDATA_ENABLEREADFILTER = ParamTypeBool
+paramType PARAM_TAGREADDATA_READFILTERTIMEOUT = ParamTypeInt32
+paramType PARAM_TAGREADDATA_UNIQUEBYPROTOCOL = ParamTypeBool
+paramType PARAM_READER_DESCRIPTION = ParamTypeText
+paramType PARAM_READER_HOSTNAME = ParamTypeText
+paramType PARAM_READER_WRITE_REPLY_TIMEOUT = ParamTypeWord16
+paramType PARAM_READER_WRITE_EARLY_EXIT = ParamTypeBool
+paramType PARAM_TRIGGER_READ_GPI = ParamTypeWord8List
+paramType PARAM_METADATAFLAG = ParamTypeMetadataFlagList
+paramType PARAM_LICENSED_FEATURES = ParamTypeWord8List
+paramType _ = ParamTypeUnimplemented
+
+-- | A textual representation of the Haskell type corresponding
+-- to a particular 'ParamType'.
+displayParamType :: ParamType -> Text
+displayParamType ParamTypeBool = "Bool"
+displayParamType ParamTypeGEN2_WriteMode = "GEN2_WriteMode"
+displayParamType ParamTypeInt16 = "Int16"
+displayParamType ParamTypeInt32 = "Int32"
+displayParamType ParamTypeInt8 = "Int8"
+displayParamType ParamTypePowerMode = "PowerMode"
+displayParamType ParamTypeReadPlan = "ReadPlan"
+displayParamType ParamTypeRegion = "Region"
+displayParamType ParamTypeTagProtocol = "TagProtocol"
+displayParamType ParamTypeText = "Text"
+displayParamType ParamTypeWord16 = "Word16"
+displayParamType ParamTypeWord32 = "Word32"
+displayParamType ParamTypeWord8 = "Word8"
+displayParamType ParamTypeMetadataFlagList = "[MetadataFlag]"
+displayParamType ParamTypeRegionList = "[Region]"
+displayParamType ParamTypeTagProtocolList = "[TagProtocol]"
+displayParamType ParamTypeWord32List = "[Word32]"
+displayParamType ParamTypeWord8List = "[Word8]"
+displayParamType _ = "(Not yet implemented)"
diff --git a/src/System/Hardware/MercuryApi/ParamValue.hs b/src/System/Hardware/MercuryApi/ParamValue.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Hardware/MercuryApi/ParamValue.hs
@@ -0,0 +1,145 @@
+{-# LANGUAGE OverloadedStrings, FlexibleInstances, DeriveDataTypeable #-}
+module System.Hardware.MercuryApi.ParamValue where
+
+import Control.Applicative ( (<$>) )
+import Control.Exception ( bracketOnError )
+import qualified Data.ByteString as B ( useAsCString, length )
+import Data.Text (Text)
+import Data.Word ( Word8, Word16, Word32 )
+import Foreign
+    ( Int8,
+      Int16,
+      Int32,
+      Ptr,
+      Storable(peek, poke),
+      castPtr,
+      with,
+      toBool,
+      new,
+      fromBool,
+      free,
+      allocaBytes,
+      alloca )
+
+import System.Hardware.MercuryApi.Enums
+import System.Hardware.MercuryApi.Records
+
+-- | A class for types which can be used as parameter values.
+class ParamValue a where
+  pType :: a -> ParamType
+  pGet :: (Ptr () -> IO ()) -> IO a
+  pSet :: a -> (Ptr () -> IO ()) -> IO ()
+
+instance ParamValue Bool where
+  pType _ = ParamTypeBool
+  pGet f = alloca $ \p -> f (castPtr (p :: Ptr CBool)) >> toBool <$> peek p
+  pSet x f = alloca $ \p -> poke p (fromBool x :: CBool) >> f (castPtr p)
+
+instance ParamValue GEN2_WriteMode where
+  pType _ = ParamTypeGEN2_WriteMode
+  pGet f = alloca $ \p -> f (castPtr p) >> toWriteMode <$> peek p
+  pSet x f = alloca $ \p -> poke p (fromWriteMode x) >> f (castPtr p)
+
+instance ParamValue Int16 where
+  pType _ = ParamTypeInt16
+  pGet f = alloca $ \p -> f (castPtr p) >> peek p
+  pSet x f = alloca $ \p -> poke p x >> f (castPtr p)
+
+instance ParamValue Int32 where
+  pType _ = ParamTypeInt32
+  pGet f = alloca $ \p -> f (castPtr p) >> peek p
+  pSet x f = alloca $ \p -> poke p x >> f (castPtr p)
+
+instance ParamValue Int8 where
+  pType _ = ParamTypeInt8
+  pGet f = alloca $ \p -> f (castPtr p) >> peek p
+  pSet x f = alloca $ \p -> poke p x >> f (castPtr p)
+
+instance ParamValue PowerMode where
+  pType _ = ParamTypePowerMode
+  pGet f = alloca $ \p -> f (castPtr p) >> toPowerMode <$> peek p
+  pSet x f = alloca $ \p -> poke p (fromPowerMode x) >> f (castPtr p)
+
+instance ParamValue ReadPlan where
+  pType _ = ParamTypeReadPlan
+  pGet f = alloca $ \p -> f (castPtr p) >> peek p
+  -- Unlike all the other cases, in this case we transfer ownership
+  -- to the C code, which will free it later.
+  pSet x f = bracketOnError (new x) free (f . castPtr)
+
+instance ParamValue Region where
+  pType _ = ParamTypeRegion
+  pGet f = alloca $ \p -> f (castPtr p) >> toRegion <$> peek p
+  pSet x f = alloca $ \p -> poke p (fromRegion x) >> f (castPtr p)
+
+instance ParamValue TagProtocol where
+  pType _ = ParamTypeTagProtocol
+  pGet f = alloca $ \p -> f (castPtr p) >> toTagProtocol <$> peek p
+  pSet x f = alloca $ \p -> poke p (fromTagProtocol x) >> f (castPtr p)
+
+instance ParamValue Text where
+  pType _ = ParamTypeText
+
+  pGet f = do
+    let maxLen = maxBound :: Word16
+    allocaBytes (fromIntegral maxLen) $ \storage -> do
+      let lst = List16
+                { l16_list = castPtr storage
+                , l16_max = maxLen
+                , l16_len = 0 -- unused for TMR_String
+                }
+      with lst $ \p -> do
+        f (castPtr p)
+        textFromCString storage
+
+  pSet x f = do
+    let bs = textToBS x
+    B.useAsCString bs $ \cs -> do
+      len' <- castLen "Text" (1 + B.length bs)
+      let lst = List16
+                { l16_list = castPtr cs
+                , l16_max = len'
+                , l16_len = 0 -- unused for TMR_String
+                }
+      with lst $ \p -> f (castPtr p)
+
+instance ParamValue Word16 where
+  pType _ = ParamTypeWord16
+  pGet f = alloca $ \p -> f (castPtr p) >> peek p
+  pSet x f = alloca $ \p -> poke p x >> f (castPtr p)
+
+instance ParamValue Word32 where
+  pType _ = ParamTypeWord32
+  pGet f = alloca $ \p -> f (castPtr p) >> peek p
+  pSet x f = alloca $ \p -> poke p x >> f (castPtr p)
+
+instance ParamValue Word8 where
+  pType _ = ParamTypeWord8
+  pGet f = alloca $ \p -> f (castPtr p) >> peek p
+  pSet x f = alloca $ \p -> poke p x >> f (castPtr p)
+
+instance ParamValue [MetadataFlag] where
+  pType _ = ParamTypeMetadataFlagList
+  pGet f = alloca $ \p -> f (castPtr p) >> unpackFlags <$> peek p
+  pSet x f = alloca $ \p -> poke p (packFlags x) >> f (castPtr p)
+
+instance ParamValue [Region] where
+  pType _ = ParamTypeRegionList
+  pGet f = map toRegion <$> getList8 f
+  pSet x f = setList8 "[Region]" (map fromRegion x) f
+
+instance ParamValue [TagProtocol] where
+  pType _ = ParamTypeTagProtocolList
+  pGet f = map toTagProtocol <$> getList8 f
+  pSet x f = setList8 "[TagProtocol]" (map fromTagProtocol x) f
+
+instance ParamValue [Word32] where
+  pType _ = ParamTypeWord32List
+  pGet = getList16
+  pSet = setList16 "[Word32]"
+
+instance ParamValue [Word8] where
+  pType _ = ParamTypeWord8List
+  pGet = getList16
+  pSet = setList16 "[Word8]"
+
diff --git a/src/System/Hardware/MercuryApi/Params.hs b/src/System/Hardware/MercuryApi/Params.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Hardware/MercuryApi/Params.hs
@@ -0,0 +1,613 @@
+-- Automatically generated by util/generate-tmr-hsc.pl
+{-|
+Module      : System.Hardware.MercuryApi.Params
+Description : Type-safe parameter access
+Copyright   : © Patrick Pelletier, 2017
+License     : MIT
+Maintainer  : code@funwithsoftware.org
+Portability : POSIX, Windows
+
+Individual functions to get and set parameters.  These are
+type-checked at compile time, unlike 'paramGet' and 'paramSet',
+which are type-checked at runtime.
+-}
+module System.Hardware.MercuryApi.Params
+  ( -- * Type-safe getters and setters
+    -- ** \/reader
+    paramGetBaudRate
+  , paramSetBaudRate
+  , paramGetCommandTimeout
+  , paramSetCommandTimeout
+  , paramGetDescription
+  , paramSetDescription
+  , paramGetExtendedEpc
+  , paramSetExtendedEpc
+  , paramGetHostname
+  , paramSetHostname
+  , paramGetLicenseKey
+  , paramSetLicenseKey
+  , paramGetLicensedFeatures
+  , paramSetLicensedFeatures
+  , paramGetMetadataflags
+  , paramSetMetadataflags
+  , paramGetPowerMode
+  , paramSetPowerMode
+  , paramGetProbeBaudRates
+  , paramSetProbeBaudRates
+  , paramGetTransportTimeout
+  , paramSetTransportTimeout
+  , paramGetUri
+    -- ** \/reader\/antenna
+  , paramGetAntennaCheckPort
+  , paramSetAntennaCheckPort
+  , paramGetAntennaConnectedPortList
+  , paramGetAntennaPortList
+  , paramGetAntennaPortSwitchGpos
+  , paramSetAntennaPortSwitchGpos
+    -- ** \/reader\/gen2
+  , paramGetGen2AccessPassword
+  , paramSetGen2AccessPassword
+  , paramGetGen2WriteEarlyExit
+  , paramSetGen2WriteEarlyExit
+  , paramGetGen2WriteMode
+  , paramSetGen2WriteMode
+  , paramGetGen2WriteReplyTimeout
+  , paramSetGen2WriteReplyTimeout
+    -- ** \/reader\/gpio
+  , paramGetGpioInputList
+  , paramSetGpioInputList
+  , paramGetGpioOutputList
+  , paramSetGpioOutputList
+    -- ** \/reader\/radio
+  , paramGetRadioEnablePowerSave
+  , paramSetRadioEnablePowerSave
+  , paramGetRadioEnableSJC
+  , paramSetRadioEnableSJC
+  , paramGetRadioPowerMax
+  , paramGetRadioPowerMin
+  , paramGetRadioReadPower
+  , paramSetRadioReadPower
+  , paramGetRadioTemperature
+  , paramGetRadioWritePower
+  , paramSetRadioWritePower
+    -- ** \/reader\/read
+  , paramGetReadAsyncOffTime
+  , paramSetReadAsyncOffTime
+  , paramGetReadAsyncOnTime
+  , paramSetReadAsyncOnTime
+  , paramGetReadPlan
+  , paramSetReadPlan
+    -- ** \/reader\/region
+  , paramGetRegionHopTable
+  , paramSetRegionHopTable
+  , paramGetRegionHopTime
+  , paramSetRegionHopTime
+  , paramGetRegionId
+  , paramSetRegionId
+  , paramGetRegionSupportedRegions
+    -- ** \/reader\/region\/lbt
+  , paramGetRegionLbtEnable
+  , paramSetRegionLbtEnable
+    -- ** \/reader\/status
+  , paramGetStatusAntennaEnable
+  , paramSetStatusAntennaEnable
+  , paramGetStatusFrequencyEnable
+  , paramSetStatusFrequencyEnable
+  , paramGetStatusTemperatureEnable
+  , paramSetStatusTemperatureEnable
+    -- ** \/reader\/tagReadData
+  , paramGetTagReadDataEnableReadFilter
+  , paramSetTagReadDataEnableReadFilter
+  , paramGetTagReadDataReadFilterTimeout
+  , paramSetTagReadDataReadFilterTimeout
+  , paramGetTagReadDataRecordHighestRssi
+  , paramSetTagReadDataRecordHighestRssi
+  , paramGetTagReadDataReportRssiInDbm
+  , paramSetTagReadDataReportRssiInDbm
+  , paramGetTagReadDataTagopFailures
+  , paramGetTagReadDataTagopSuccesses
+  , paramGetTagReadDataUniqueByAntenna
+  , paramSetTagReadDataUniqueByAntenna
+  , paramGetTagReadDataUniqueByData
+  , paramSetTagReadDataUniqueByData
+  , paramGetTagReadDataUniqueByProtocol
+  , paramSetTagReadDataUniqueByProtocol
+    -- ** \/reader\/tagop
+  , paramGetTagopAntenna
+  , paramSetTagopAntenna
+  , paramGetTagopProtocol
+  , paramSetTagopProtocol
+    -- ** \/reader\/trigger\/read
+  , paramGetTriggerReadGpi
+  , paramSetTriggerReadGpi
+    -- ** \/reader\/version
+  , paramGetVersionHardware
+  , paramGetVersionModel
+  , paramGetVersionProductGroup
+  , paramGetVersionProductGroupID
+  , paramGetVersionProductID
+  , paramGetVersionSerial
+  , paramSetVersionSerial
+  , paramGetVersionSoftware
+  , paramGetVersionSupportedProtocols
+    -- * As strings
+  , paramGetString
+  , paramSetString
+  ) where
+
+import Control.Applicative ( (<$>) )
+import Data.Int ( Int8, Int16, Int32 )
+import Data.Text (Text)
+import qualified Data.Text as T ( unpack, pack )
+import Data.Word ( Word8, Word16, Word32 )
+
+import System.Hardware.MercuryApi hiding (read)
+
+-- | Set parameter 'PARAM_BAUDRATE' (@\/reader\/baudRate@)
+paramSetBaudRate :: Reader -> Word32 -> IO ()
+paramSetBaudRate rdr = paramSet rdr PARAM_BAUDRATE
+
+-- | Get parameter 'PARAM_BAUDRATE' (@\/reader\/baudRate@)
+paramGetBaudRate :: Reader -> IO Word32
+paramGetBaudRate rdr = paramGet rdr PARAM_BAUDRATE
+
+-- | Set parameter 'PARAM_PROBEBAUDRATES' (@\/reader\/probeBaudRates@)
+paramSetProbeBaudRates :: Reader -> [Word32] -> IO ()
+paramSetProbeBaudRates rdr = paramSet rdr PARAM_PROBEBAUDRATES
+
+-- | Get parameter 'PARAM_PROBEBAUDRATES' (@\/reader\/probeBaudRates@)
+paramGetProbeBaudRates :: Reader -> IO [Word32]
+paramGetProbeBaudRates rdr = paramGet rdr PARAM_PROBEBAUDRATES
+
+-- | Set parameter 'PARAM_COMMANDTIMEOUT' (@\/reader\/commandTimeout@) (milliseconds)
+paramSetCommandTimeout :: Reader -> Word32 -> IO ()
+paramSetCommandTimeout rdr = paramSet rdr PARAM_COMMANDTIMEOUT
+
+-- | Get parameter 'PARAM_COMMANDTIMEOUT' (@\/reader\/commandTimeout@) (milliseconds)
+paramGetCommandTimeout :: Reader -> IO Word32
+paramGetCommandTimeout rdr = paramGet rdr PARAM_COMMANDTIMEOUT
+
+-- | Set parameter 'PARAM_TRANSPORTTIMEOUT' (@\/reader\/transportTimeout@) (milliseconds)
+paramSetTransportTimeout :: Reader -> Word32 -> IO ()
+paramSetTransportTimeout rdr = paramSet rdr PARAM_TRANSPORTTIMEOUT
+
+-- | Get parameter 'PARAM_TRANSPORTTIMEOUT' (@\/reader\/transportTimeout@) (milliseconds)
+paramGetTransportTimeout :: Reader -> IO Word32
+paramGetTransportTimeout rdr = paramGet rdr PARAM_TRANSPORTTIMEOUT
+
+-- | Set parameter 'PARAM_POWERMODE' (@\/reader\/powerMode@)
+paramSetPowerMode :: Reader -> PowerMode -> IO ()
+paramSetPowerMode rdr = paramSet rdr PARAM_POWERMODE
+
+-- | Get parameter 'PARAM_POWERMODE' (@\/reader\/powerMode@)
+paramGetPowerMode :: Reader -> IO PowerMode
+paramGetPowerMode rdr = paramGet rdr PARAM_POWERMODE
+
+-- | Set parameter 'PARAM_ANTENNA_CHECKPORT' (@\/reader\/antenna\/checkPort@)
+paramSetAntennaCheckPort :: Reader -> Bool -> IO ()
+paramSetAntennaCheckPort rdr = paramSet rdr PARAM_ANTENNA_CHECKPORT
+
+-- | Get parameter 'PARAM_ANTENNA_CHECKPORT' (@\/reader\/antenna\/checkPort@)
+paramGetAntennaCheckPort :: Reader -> IO Bool
+paramGetAntennaCheckPort rdr = paramGet rdr PARAM_ANTENNA_CHECKPORT
+
+-- | Get parameter 'PARAM_ANTENNA_PORTLIST' (@\/reader\/antenna\/portList@)
+paramGetAntennaPortList :: Reader -> IO [AntennaPort]
+paramGetAntennaPortList rdr = paramGet rdr PARAM_ANTENNA_PORTLIST
+
+-- | Get parameter 'PARAM_ANTENNA_CONNECTEDPORTLIST' (@\/reader\/antenna\/connectedPortList@)
+paramGetAntennaConnectedPortList :: Reader -> IO [AntennaPort]
+paramGetAntennaConnectedPortList rdr = paramGet rdr PARAM_ANTENNA_CONNECTEDPORTLIST
+
+-- | Set parameter 'PARAM_ANTENNA_PORTSWITCHGPOS' (@\/reader\/antenna\/portSwitchGpos@)
+paramSetAntennaPortSwitchGpos :: Reader -> [PinNumber] -> IO ()
+paramSetAntennaPortSwitchGpos rdr = paramSet rdr PARAM_ANTENNA_PORTSWITCHGPOS
+
+-- | Get parameter 'PARAM_ANTENNA_PORTSWITCHGPOS' (@\/reader\/antenna\/portSwitchGpos@)
+paramGetAntennaPortSwitchGpos :: Reader -> IO [PinNumber]
+paramGetAntennaPortSwitchGpos rdr = paramGet rdr PARAM_ANTENNA_PORTSWITCHGPOS
+
+-- | Set parameter 'PARAM_GPIO_INPUTLIST' (@\/reader\/gpio\/inputList@)
+paramSetGpioInputList :: Reader -> [PinNumber] -> IO ()
+paramSetGpioInputList rdr = paramSet rdr PARAM_GPIO_INPUTLIST
+
+-- | Get parameter 'PARAM_GPIO_INPUTLIST' (@\/reader\/gpio\/inputList@)
+paramGetGpioInputList :: Reader -> IO [PinNumber]
+paramGetGpioInputList rdr = paramGet rdr PARAM_GPIO_INPUTLIST
+
+-- | Set parameter 'PARAM_GPIO_OUTPUTLIST' (@\/reader\/gpio\/outputList@)
+paramSetGpioOutputList :: Reader -> [PinNumber] -> IO ()
+paramSetGpioOutputList rdr = paramSet rdr PARAM_GPIO_OUTPUTLIST
+
+-- | Get parameter 'PARAM_GPIO_OUTPUTLIST' (@\/reader\/gpio\/outputList@)
+paramGetGpioOutputList :: Reader -> IO [PinNumber]
+paramGetGpioOutputList rdr = paramGet rdr PARAM_GPIO_OUTPUTLIST
+
+-- | Set parameter 'PARAM_GEN2_ACCESSPASSWORD' (@\/reader\/gen2\/accessPassword@)
+paramSetGen2AccessPassword :: Reader -> GEN2_Password -> IO ()
+paramSetGen2AccessPassword rdr = paramSet rdr PARAM_GEN2_ACCESSPASSWORD
+
+-- | Get parameter 'PARAM_GEN2_ACCESSPASSWORD' (@\/reader\/gen2\/accessPassword@)
+paramGetGen2AccessPassword :: Reader -> IO GEN2_Password
+paramGetGen2AccessPassword rdr = paramGet rdr PARAM_GEN2_ACCESSPASSWORD
+
+-- | Set parameter 'PARAM_GEN2_WRITEMODE' (@\/reader\/gen2\/writeMode@)
+paramSetGen2WriteMode :: Reader -> GEN2_WriteMode -> IO ()
+paramSetGen2WriteMode rdr = paramSet rdr PARAM_GEN2_WRITEMODE
+
+-- | Get parameter 'PARAM_GEN2_WRITEMODE' (@\/reader\/gen2\/writeMode@)
+paramGetGen2WriteMode :: Reader -> IO GEN2_WriteMode
+paramGetGen2WriteMode rdr = paramGet rdr PARAM_GEN2_WRITEMODE
+
+-- | Set parameter 'PARAM_READ_ASYNCOFFTIME' (@\/reader\/read\/asyncOffTime@) (milliseconds)
+paramSetReadAsyncOffTime :: Reader -> Word32 -> IO ()
+paramSetReadAsyncOffTime rdr = paramSet rdr PARAM_READ_ASYNCOFFTIME
+
+-- | Get parameter 'PARAM_READ_ASYNCOFFTIME' (@\/reader\/read\/asyncOffTime@) (milliseconds)
+paramGetReadAsyncOffTime :: Reader -> IO Word32
+paramGetReadAsyncOffTime rdr = paramGet rdr PARAM_READ_ASYNCOFFTIME
+
+-- | Set parameter 'PARAM_READ_ASYNCONTIME' (@\/reader\/read\/asyncOnTime@) (milliseconds)
+paramSetReadAsyncOnTime :: Reader -> Word32 -> IO ()
+paramSetReadAsyncOnTime rdr = paramSet rdr PARAM_READ_ASYNCONTIME
+
+-- | Get parameter 'PARAM_READ_ASYNCONTIME' (@\/reader\/read\/asyncOnTime@) (milliseconds)
+paramGetReadAsyncOnTime :: Reader -> IO Word32
+paramGetReadAsyncOnTime rdr = paramGet rdr PARAM_READ_ASYNCONTIME
+
+-- | Set parameter 'PARAM_READ_PLAN' (@\/reader\/read\/plan@)
+paramSetReadPlan :: Reader -> ReadPlan -> IO ()
+paramSetReadPlan rdr = paramSet rdr PARAM_READ_PLAN
+
+-- | Get parameter 'PARAM_READ_PLAN' (@\/reader\/read\/plan@)
+paramGetReadPlan :: Reader -> IO ReadPlan
+paramGetReadPlan rdr = paramGet rdr PARAM_READ_PLAN
+
+-- | Set parameter 'PARAM_RADIO_ENABLEPOWERSAVE' (@\/reader\/radio\/enablePowerSave@)
+paramSetRadioEnablePowerSave :: Reader -> Bool -> IO ()
+paramSetRadioEnablePowerSave rdr = paramSet rdr PARAM_RADIO_ENABLEPOWERSAVE
+
+-- | Get parameter 'PARAM_RADIO_ENABLEPOWERSAVE' (@\/reader\/radio\/enablePowerSave@)
+paramGetRadioEnablePowerSave :: Reader -> IO Bool
+paramGetRadioEnablePowerSave rdr = paramGet rdr PARAM_RADIO_ENABLEPOWERSAVE
+
+-- | Get parameter 'PARAM_RADIO_POWERMAX' (@\/reader\/radio\/powerMax@) (centi-dBm)
+paramGetRadioPowerMax :: Reader -> IO Int16
+paramGetRadioPowerMax rdr = paramGet rdr PARAM_RADIO_POWERMAX
+
+-- | Get parameter 'PARAM_RADIO_POWERMIN' (@\/reader\/radio\/powerMin@) (centi-dBm)
+paramGetRadioPowerMin :: Reader -> IO Int16
+paramGetRadioPowerMin rdr = paramGet rdr PARAM_RADIO_POWERMIN
+
+-- | Set parameter 'PARAM_RADIO_READPOWER' (@\/reader\/radio\/readPower@) (centi-dBm)
+paramSetRadioReadPower :: Reader -> Int32 -> IO ()
+paramSetRadioReadPower rdr = paramSet rdr PARAM_RADIO_READPOWER
+
+-- | Get parameter 'PARAM_RADIO_READPOWER' (@\/reader\/radio\/readPower@) (centi-dBm)
+paramGetRadioReadPower :: Reader -> IO Int32
+paramGetRadioReadPower rdr = paramGet rdr PARAM_RADIO_READPOWER
+
+-- | Set parameter 'PARAM_RADIO_WRITEPOWER' (@\/reader\/radio\/writePower@) (centi-dBm)
+paramSetRadioWritePower :: Reader -> Int32 -> IO ()
+paramSetRadioWritePower rdr = paramSet rdr PARAM_RADIO_WRITEPOWER
+
+-- | Get parameter 'PARAM_RADIO_WRITEPOWER' (@\/reader\/radio\/writePower@) (centi-dBm)
+paramGetRadioWritePower :: Reader -> IO Int32
+paramGetRadioWritePower rdr = paramGet rdr PARAM_RADIO_WRITEPOWER
+
+-- | Get parameter 'PARAM_RADIO_TEMPERATURE' (@\/reader\/radio\/temperature@) (degrees C)
+paramGetRadioTemperature :: Reader -> IO Int8
+paramGetRadioTemperature rdr = paramGet rdr PARAM_RADIO_TEMPERATURE
+
+-- | Set parameter 'PARAM_TAGREADDATA_RECORDHIGHESTRSSI' (@\/reader\/tagReadData\/recordHighestRssi@)
+paramSetTagReadDataRecordHighestRssi :: Reader -> Bool -> IO ()
+paramSetTagReadDataRecordHighestRssi rdr = paramSet rdr PARAM_TAGREADDATA_RECORDHIGHESTRSSI
+
+-- | Get parameter 'PARAM_TAGREADDATA_RECORDHIGHESTRSSI' (@\/reader\/tagReadData\/recordHighestRssi@)
+paramGetTagReadDataRecordHighestRssi :: Reader -> IO Bool
+paramGetTagReadDataRecordHighestRssi rdr = paramGet rdr PARAM_TAGREADDATA_RECORDHIGHESTRSSI
+
+-- | Set parameter 'PARAM_TAGREADDATA_REPORTRSSIINDBM' (@\/reader\/tagReadData\/reportRssiInDbm@)
+paramSetTagReadDataReportRssiInDbm :: Reader -> Bool -> IO ()
+paramSetTagReadDataReportRssiInDbm rdr = paramSet rdr PARAM_TAGREADDATA_REPORTRSSIINDBM
+
+-- | Get parameter 'PARAM_TAGREADDATA_REPORTRSSIINDBM' (@\/reader\/tagReadData\/reportRssiInDbm@)
+paramGetTagReadDataReportRssiInDbm :: Reader -> IO Bool
+paramGetTagReadDataReportRssiInDbm rdr = paramGet rdr PARAM_TAGREADDATA_REPORTRSSIINDBM
+
+-- | Set parameter 'PARAM_TAGREADDATA_UNIQUEBYANTENNA' (@\/reader\/tagReadData\/uniqueByAntenna@)
+paramSetTagReadDataUniqueByAntenna :: Reader -> Bool -> IO ()
+paramSetTagReadDataUniqueByAntenna rdr = paramSet rdr PARAM_TAGREADDATA_UNIQUEBYANTENNA
+
+-- | Get parameter 'PARAM_TAGREADDATA_UNIQUEBYANTENNA' (@\/reader\/tagReadData\/uniqueByAntenna@)
+paramGetTagReadDataUniqueByAntenna :: Reader -> IO Bool
+paramGetTagReadDataUniqueByAntenna rdr = paramGet rdr PARAM_TAGREADDATA_UNIQUEBYANTENNA
+
+-- | Set parameter 'PARAM_TAGREADDATA_UNIQUEBYDATA' (@\/reader\/tagReadData\/uniqueByData@)
+paramSetTagReadDataUniqueByData :: Reader -> Bool -> IO ()
+paramSetTagReadDataUniqueByData rdr = paramSet rdr PARAM_TAGREADDATA_UNIQUEBYDATA
+
+-- | Get parameter 'PARAM_TAGREADDATA_UNIQUEBYDATA' (@\/reader\/tagReadData\/uniqueByData@)
+paramGetTagReadDataUniqueByData :: Reader -> IO Bool
+paramGetTagReadDataUniqueByData rdr = paramGet rdr PARAM_TAGREADDATA_UNIQUEBYDATA
+
+-- | Set parameter 'PARAM_TAGOP_ANTENNA' (@\/reader\/tagop\/antenna@)
+paramSetTagopAntenna :: Reader -> AntennaPort -> IO ()
+paramSetTagopAntenna rdr = paramSet rdr PARAM_TAGOP_ANTENNA
+
+-- | Get parameter 'PARAM_TAGOP_ANTENNA' (@\/reader\/tagop\/antenna@)
+paramGetTagopAntenna :: Reader -> IO AntennaPort
+paramGetTagopAntenna rdr = paramGet rdr PARAM_TAGOP_ANTENNA
+
+-- | Set parameter 'PARAM_TAGOP_PROTOCOL' (@\/reader\/tagop\/protocol@)
+paramSetTagopProtocol :: Reader -> TagProtocol -> IO ()
+paramSetTagopProtocol rdr = paramSet rdr PARAM_TAGOP_PROTOCOL
+
+-- | Get parameter 'PARAM_TAGOP_PROTOCOL' (@\/reader\/tagop\/protocol@)
+paramGetTagopProtocol :: Reader -> IO TagProtocol
+paramGetTagopProtocol rdr = paramGet rdr PARAM_TAGOP_PROTOCOL
+
+-- | Get parameter 'PARAM_VERSION_HARDWARE' (@\/reader\/version\/hardware@)
+paramGetVersionHardware :: Reader -> IO Text
+paramGetVersionHardware rdr = paramGet rdr PARAM_VERSION_HARDWARE
+
+-- | Set parameter 'PARAM_VERSION_SERIAL' (@\/reader\/version\/serial@)
+paramSetVersionSerial :: Reader -> Text -> IO ()
+paramSetVersionSerial rdr = paramSet rdr PARAM_VERSION_SERIAL
+
+-- | Get parameter 'PARAM_VERSION_SERIAL' (@\/reader\/version\/serial@)
+paramGetVersionSerial :: Reader -> IO Text
+paramGetVersionSerial rdr = paramGet rdr PARAM_VERSION_SERIAL
+
+-- | Get parameter 'PARAM_VERSION_MODEL' (@\/reader\/version\/model@)
+paramGetVersionModel :: Reader -> IO Text
+paramGetVersionModel rdr = paramGet rdr PARAM_VERSION_MODEL
+
+-- | Get parameter 'PARAM_VERSION_SOFTWARE' (@\/reader\/version\/software@)
+paramGetVersionSoftware :: Reader -> IO Text
+paramGetVersionSoftware rdr = paramGet rdr PARAM_VERSION_SOFTWARE
+
+-- | Get parameter 'PARAM_VERSION_SUPPORTEDPROTOCOLS' (@\/reader\/version\/supportedProtocols@)
+paramGetVersionSupportedProtocols :: Reader -> IO [TagProtocol]
+paramGetVersionSupportedProtocols rdr = paramGet rdr PARAM_VERSION_SUPPORTEDPROTOCOLS
+
+-- | Set parameter 'PARAM_REGION_HOPTABLE' (@\/reader\/region\/hopTable@) (kHz)
+paramSetRegionHopTable :: Reader -> [Word32] -> IO ()
+paramSetRegionHopTable rdr = paramSet rdr PARAM_REGION_HOPTABLE
+
+-- | Get parameter 'PARAM_REGION_HOPTABLE' (@\/reader\/region\/hopTable@) (kHz)
+paramGetRegionHopTable :: Reader -> IO [Word32]
+paramGetRegionHopTable rdr = paramGet rdr PARAM_REGION_HOPTABLE
+
+-- | Set parameter 'PARAM_REGION_HOPTIME' (@\/reader\/region\/hopTime@) (milliseconds)
+paramSetRegionHopTime :: Reader -> Word32 -> IO ()
+paramSetRegionHopTime rdr = paramSet rdr PARAM_REGION_HOPTIME
+
+-- | Get parameter 'PARAM_REGION_HOPTIME' (@\/reader\/region\/hopTime@) (milliseconds)
+paramGetRegionHopTime :: Reader -> IO Word32
+paramGetRegionHopTime rdr = paramGet rdr PARAM_REGION_HOPTIME
+
+-- | Set parameter 'PARAM_REGION_ID' (@\/reader\/region\/id@)
+paramSetRegionId :: Reader -> Region -> IO ()
+paramSetRegionId rdr = paramSet rdr PARAM_REGION_ID
+
+-- | Get parameter 'PARAM_REGION_ID' (@\/reader\/region\/id@)
+paramGetRegionId :: Reader -> IO Region
+paramGetRegionId rdr = paramGet rdr PARAM_REGION_ID
+
+-- | Get parameter 'PARAM_REGION_SUPPORTEDREGIONS' (@\/reader\/region\/supportedRegions@)
+paramGetRegionSupportedRegions :: Reader -> IO [Region]
+paramGetRegionSupportedRegions rdr = paramGet rdr PARAM_REGION_SUPPORTEDREGIONS
+
+-- | Set parameter 'PARAM_REGION_LBT_ENABLE' (@\/reader\/region\/lbt\/enable@)
+paramSetRegionLbtEnable :: Reader -> Bool -> IO ()
+paramSetRegionLbtEnable rdr = paramSet rdr PARAM_REGION_LBT_ENABLE
+
+-- | Get parameter 'PARAM_REGION_LBT_ENABLE' (@\/reader\/region\/lbt\/enable@)
+paramGetRegionLbtEnable :: Reader -> IO Bool
+paramGetRegionLbtEnable rdr = paramGet rdr PARAM_REGION_LBT_ENABLE
+
+-- | Set parameter 'PARAM_LICENSE_KEY' (@\/reader\/licenseKey@)
+paramSetLicenseKey :: Reader -> [Word8] -> IO ()
+paramSetLicenseKey rdr = paramSet rdr PARAM_LICENSE_KEY
+
+-- | Get parameter 'PARAM_LICENSE_KEY' (@\/reader\/licenseKey@)
+paramGetLicenseKey :: Reader -> IO [Word8]
+paramGetLicenseKey rdr = paramGet rdr PARAM_LICENSE_KEY
+
+-- | Set parameter 'PARAM_RADIO_ENABLESJC' (@\/reader\/radio\/enableSJC@)
+paramSetRadioEnableSJC :: Reader -> Bool -> IO ()
+paramSetRadioEnableSJC rdr = paramSet rdr PARAM_RADIO_ENABLESJC
+
+-- | Get parameter 'PARAM_RADIO_ENABLESJC' (@\/reader\/radio\/enableSJC@)
+paramGetRadioEnableSJC :: Reader -> IO Bool
+paramGetRadioEnableSJC rdr = paramGet rdr PARAM_RADIO_ENABLESJC
+
+-- | Set parameter 'PARAM_EXTENDEDEPC' (@\/reader\/extendedEpc@)
+paramSetExtendedEpc :: Reader -> Bool -> IO ()
+paramSetExtendedEpc rdr = paramSet rdr PARAM_EXTENDEDEPC
+
+-- | Get parameter 'PARAM_EXTENDEDEPC' (@\/reader\/extendedEpc@)
+paramGetExtendedEpc :: Reader -> IO Bool
+paramGetExtendedEpc rdr = paramGet rdr PARAM_EXTENDEDEPC
+
+-- | Get parameter 'PARAM_URI' (@\/reader\/uri@)
+paramGetUri :: Reader -> IO Text
+paramGetUri rdr = paramGet rdr PARAM_URI
+
+-- | Get parameter 'PARAM_PRODUCT_GROUP_ID' (@\/reader\/version\/productGroupID@)
+paramGetVersionProductGroupID :: Reader -> IO Word16
+paramGetVersionProductGroupID rdr = paramGet rdr PARAM_PRODUCT_GROUP_ID
+
+-- | Get parameter 'PARAM_PRODUCT_GROUP' (@\/reader\/version\/productGroup@)
+paramGetVersionProductGroup :: Reader -> IO Text
+paramGetVersionProductGroup rdr = paramGet rdr PARAM_PRODUCT_GROUP
+
+-- | Get parameter 'PARAM_PRODUCT_ID' (@\/reader\/version\/productID@)
+paramGetVersionProductID :: Reader -> IO Word16
+paramGetVersionProductID rdr = paramGet rdr PARAM_PRODUCT_ID
+
+-- | Get parameter 'PARAM_TAGREADATA_TAGOPSUCCESSCOUNT' (@\/reader\/tagReadData\/tagopSuccesses@)
+paramGetTagReadDataTagopSuccesses :: Reader -> IO Word16
+paramGetTagReadDataTagopSuccesses rdr = paramGet rdr PARAM_TAGREADATA_TAGOPSUCCESSCOUNT
+
+-- | Get parameter 'PARAM_TAGREADATA_TAGOPFAILURECOUNT' (@\/reader\/tagReadData\/tagopFailures@)
+paramGetTagReadDataTagopFailures :: Reader -> IO Word16
+paramGetTagReadDataTagopFailures rdr = paramGet rdr PARAM_TAGREADATA_TAGOPFAILURECOUNT
+
+-- | Set parameter 'PARAM_STATUS_ENABLE_ANTENNAREPORT' (@\/reader\/status\/antennaEnable@)
+paramSetStatusAntennaEnable :: Reader -> Bool -> IO ()
+paramSetStatusAntennaEnable rdr = paramSet rdr PARAM_STATUS_ENABLE_ANTENNAREPORT
+
+-- | Get parameter 'PARAM_STATUS_ENABLE_ANTENNAREPORT' (@\/reader\/status\/antennaEnable@)
+paramGetStatusAntennaEnable :: Reader -> IO Bool
+paramGetStatusAntennaEnable rdr = paramGet rdr PARAM_STATUS_ENABLE_ANTENNAREPORT
+
+-- | Set parameter 'PARAM_STATUS_ENABLE_FREQUENCYREPORT' (@\/reader\/status\/frequencyEnable@)
+paramSetStatusFrequencyEnable :: Reader -> Bool -> IO ()
+paramSetStatusFrequencyEnable rdr = paramSet rdr PARAM_STATUS_ENABLE_FREQUENCYREPORT
+
+-- | Get parameter 'PARAM_STATUS_ENABLE_FREQUENCYREPORT' (@\/reader\/status\/frequencyEnable@)
+paramGetStatusFrequencyEnable :: Reader -> IO Bool
+paramGetStatusFrequencyEnable rdr = paramGet rdr PARAM_STATUS_ENABLE_FREQUENCYREPORT
+
+-- | Set parameter 'PARAM_STATUS_ENABLE_TEMPERATUREREPORT' (@\/reader\/status\/temperatureEnable@)
+paramSetStatusTemperatureEnable :: Reader -> Bool -> IO ()
+paramSetStatusTemperatureEnable rdr = paramSet rdr PARAM_STATUS_ENABLE_TEMPERATUREREPORT
+
+-- | Get parameter 'PARAM_STATUS_ENABLE_TEMPERATUREREPORT' (@\/reader\/status\/temperatureEnable@)
+paramGetStatusTemperatureEnable :: Reader -> IO Bool
+paramGetStatusTemperatureEnable rdr = paramGet rdr PARAM_STATUS_ENABLE_TEMPERATUREREPORT
+
+-- | Set parameter 'PARAM_TAGREADDATA_ENABLEREADFILTER' (@\/reader\/tagReadData\/enableReadFilter@)
+paramSetTagReadDataEnableReadFilter :: Reader -> Bool -> IO ()
+paramSetTagReadDataEnableReadFilter rdr = paramSet rdr PARAM_TAGREADDATA_ENABLEREADFILTER
+
+-- | Get parameter 'PARAM_TAGREADDATA_ENABLEREADFILTER' (@\/reader\/tagReadData\/enableReadFilter@)
+paramGetTagReadDataEnableReadFilter :: Reader -> IO Bool
+paramGetTagReadDataEnableReadFilter rdr = paramGet rdr PARAM_TAGREADDATA_ENABLEREADFILTER
+
+-- | Set parameter 'PARAM_TAGREADDATA_READFILTERTIMEOUT' (@\/reader\/tagReadData\/readFilterTimeout@)
+paramSetTagReadDataReadFilterTimeout :: Reader -> Int32 -> IO ()
+paramSetTagReadDataReadFilterTimeout rdr = paramSet rdr PARAM_TAGREADDATA_READFILTERTIMEOUT
+
+-- | Get parameter 'PARAM_TAGREADDATA_READFILTERTIMEOUT' (@\/reader\/tagReadData\/readFilterTimeout@)
+paramGetTagReadDataReadFilterTimeout :: Reader -> IO Int32
+paramGetTagReadDataReadFilterTimeout rdr = paramGet rdr PARAM_TAGREADDATA_READFILTERTIMEOUT
+
+-- | Set parameter 'PARAM_TAGREADDATA_UNIQUEBYPROTOCOL' (@\/reader\/tagReadData\/uniqueByProtocol@)
+paramSetTagReadDataUniqueByProtocol :: Reader -> Bool -> IO ()
+paramSetTagReadDataUniqueByProtocol rdr = paramSet rdr PARAM_TAGREADDATA_UNIQUEBYPROTOCOL
+
+-- | Get parameter 'PARAM_TAGREADDATA_UNIQUEBYPROTOCOL' (@\/reader\/tagReadData\/uniqueByProtocol@)
+paramGetTagReadDataUniqueByProtocol :: Reader -> IO Bool
+paramGetTagReadDataUniqueByProtocol rdr = paramGet rdr PARAM_TAGREADDATA_UNIQUEBYPROTOCOL
+
+-- | Set parameter 'PARAM_READER_DESCRIPTION' (@\/reader\/description@)
+paramSetDescription :: Reader -> Text -> IO ()
+paramSetDescription rdr = paramSet rdr PARAM_READER_DESCRIPTION
+
+-- | Get parameter 'PARAM_READER_DESCRIPTION' (@\/reader\/description@)
+paramGetDescription :: Reader -> IO Text
+paramGetDescription rdr = paramGet rdr PARAM_READER_DESCRIPTION
+
+-- | Set parameter 'PARAM_READER_HOSTNAME' (@\/reader\/hostname@)
+paramSetHostname :: Reader -> Text -> IO ()
+paramSetHostname rdr = paramSet rdr PARAM_READER_HOSTNAME
+
+-- | Get parameter 'PARAM_READER_HOSTNAME' (@\/reader\/hostname@)
+paramGetHostname :: Reader -> IO Text
+paramGetHostname rdr = paramGet rdr PARAM_READER_HOSTNAME
+
+-- | Set parameter 'PARAM_READER_WRITE_REPLY_TIMEOUT' (@\/reader\/gen2\/writeReplyTimeout@) (microseconds)
+paramSetGen2WriteReplyTimeout :: Reader -> Word16 -> IO ()
+paramSetGen2WriteReplyTimeout rdr = paramSet rdr PARAM_READER_WRITE_REPLY_TIMEOUT
+
+-- | Get parameter 'PARAM_READER_WRITE_REPLY_TIMEOUT' (@\/reader\/gen2\/writeReplyTimeout@) (microseconds)
+paramGetGen2WriteReplyTimeout :: Reader -> IO Word16
+paramGetGen2WriteReplyTimeout rdr = paramGet rdr PARAM_READER_WRITE_REPLY_TIMEOUT
+
+-- | Set parameter 'PARAM_READER_WRITE_EARLY_EXIT' (@\/reader\/gen2\/writeEarlyExit@)
+paramSetGen2WriteEarlyExit :: Reader -> Bool -> IO ()
+paramSetGen2WriteEarlyExit rdr = paramSet rdr PARAM_READER_WRITE_EARLY_EXIT
+
+-- | Get parameter 'PARAM_READER_WRITE_EARLY_EXIT' (@\/reader\/gen2\/writeEarlyExit@)
+paramGetGen2WriteEarlyExit :: Reader -> IO Bool
+paramGetGen2WriteEarlyExit rdr = paramGet rdr PARAM_READER_WRITE_EARLY_EXIT
+
+-- | Set parameter 'PARAM_TRIGGER_READ_GPI' (@\/reader\/trigger\/read\/Gpi@)
+paramSetTriggerReadGpi :: Reader -> [PinNumber] -> IO ()
+paramSetTriggerReadGpi rdr = paramSet rdr PARAM_TRIGGER_READ_GPI
+
+-- | Get parameter 'PARAM_TRIGGER_READ_GPI' (@\/reader\/trigger\/read\/Gpi@)
+paramGetTriggerReadGpi :: Reader -> IO [PinNumber]
+paramGetTriggerReadGpi rdr = paramGet rdr PARAM_TRIGGER_READ_GPI
+
+-- | Set parameter 'PARAM_METADATAFLAG' (@\/reader\/metadataflags@)
+paramSetMetadataflags :: Reader -> [MetadataFlag] -> IO ()
+paramSetMetadataflags rdr = paramSet rdr PARAM_METADATAFLAG
+
+-- | Get parameter 'PARAM_METADATAFLAG' (@\/reader\/metadataflags@)
+paramGetMetadataflags :: Reader -> IO [MetadataFlag]
+paramGetMetadataflags rdr = paramGet rdr PARAM_METADATAFLAG
+
+-- | Set parameter 'PARAM_LICENSED_FEATURES' (@\/reader\/licensedFeatures@)
+paramSetLicensedFeatures :: Reader -> [Word8] -> IO ()
+paramSetLicensedFeatures rdr = paramSet rdr PARAM_LICENSED_FEATURES
+
+-- | Get parameter 'PARAM_LICENSED_FEATURES' (@\/reader\/licensedFeatures@)
+paramGetLicensedFeatures :: Reader -> IO [Word8]
+paramGetLicensedFeatures rdr = paramGet rdr PARAM_LICENSED_FEATURES
+
+-- | Version of 'paramSet' which converts its argument from a
+-- string to the proper type using 'read'.
+paramSetString :: Reader -> Param -> Text -> IO ()
+paramSetString rdr param txt = do
+  let str = T.unpack txt
+  case paramType param of
+    ParamTypeBool -> paramSet rdr param (read str :: Bool)
+    ParamTypeGEN2_WriteMode -> paramSet rdr param (read str :: GEN2_WriteMode)
+    ParamTypeInt16 -> paramSet rdr param (read str :: Int16)
+    ParamTypeInt32 -> paramSet rdr param (read str :: Int32)
+    ParamTypeInt8 -> paramSet rdr param (read str :: Int8)
+    ParamTypePowerMode -> paramSet rdr param (read str :: PowerMode)
+    ParamTypeReadPlan -> paramSet rdr param (read str :: ReadPlan)
+    ParamTypeRegion -> paramSet rdr param (read str :: Region)
+    ParamTypeTagProtocol -> paramSet rdr param (read str :: TagProtocol)
+    ParamTypeText -> paramSet rdr param (read str :: Text)
+    ParamTypeWord16 -> paramSet rdr param (read str :: Word16)
+    ParamTypeWord32 -> paramSet rdr param (read str :: Word32)
+    ParamTypeWord8 -> paramSet rdr param (read str :: Word8)
+    ParamTypeMetadataFlagList -> paramSet rdr param (read str :: [MetadataFlag])
+    ParamTypeRegionList -> paramSet rdr param (read str :: [Region])
+    ParamTypeTagProtocolList -> paramSet rdr param (read str :: [TagProtocol])
+    ParamTypeWord32List -> paramSet rdr param (read str :: [Word32])
+    ParamTypeWord8List -> paramSet rdr param (read str :: [Word8])
+    _ -> paramSet rdr param (undefined :: Bool) -- force ERROR_UNIMPLEMENTED_PARAM
+
+-- | Version of 'paramGet' which converts its result to a
+-- string using 'show'.
+paramGetString :: Reader -> Param -> IO Text
+paramGetString rdr param =
+  T.pack <$>
+  case paramType param of
+    ParamTypeBool -> show <$> (paramGet rdr param :: IO Bool)
+    ParamTypeGEN2_WriteMode -> show <$> (paramGet rdr param :: IO GEN2_WriteMode)
+    ParamTypeInt16 -> show <$> (paramGet rdr param :: IO Int16)
+    ParamTypeInt32 -> show <$> (paramGet rdr param :: IO Int32)
+    ParamTypeInt8 -> show <$> (paramGet rdr param :: IO Int8)
+    ParamTypePowerMode -> show <$> (paramGet rdr param :: IO PowerMode)
+    ParamTypeReadPlan -> show <$> (paramGet rdr param :: IO ReadPlan)
+    ParamTypeRegion -> show <$> (paramGet rdr param :: IO Region)
+    ParamTypeTagProtocol -> show <$> (paramGet rdr param :: IO TagProtocol)
+    ParamTypeText -> show <$> (paramGet rdr param :: IO Text)
+    ParamTypeWord16 -> show <$> (paramGet rdr param :: IO Word16)
+    ParamTypeWord32 -> show <$> (paramGet rdr param :: IO Word32)
+    ParamTypeWord8 -> show <$> (paramGet rdr param :: IO Word8)
+    ParamTypeMetadataFlagList -> show <$> (paramGet rdr param :: IO [MetadataFlag])
+    ParamTypeRegionList -> show <$> (paramGet rdr param :: IO [Region])
+    ParamTypeTagProtocolList -> show <$> (paramGet rdr param :: IO [TagProtocol])
+    ParamTypeWord32List -> show <$> (paramGet rdr param :: IO [Word32])
+    ParamTypeWord8List -> show <$> (paramGet rdr param :: IO [Word8])
+    _ -> show <$> (paramGet rdr param :: IO Bool) -- force ERROR_UNIMPLEMENTED_PARAM
+
diff --git a/src/System/Hardware/MercuryApi/Records.hsc b/src/System/Hardware/MercuryApi/Records.hsc
new file mode 100644
--- /dev/null
+++ b/src/System/Hardware/MercuryApi/Records.hsc
@@ -0,0 +1,828 @@
+{-# LANGUAGE OverloadedStrings, FlexibleInstances, DeriveDataTypeable #-}
+module System.Hardware.MercuryApi.Records where
+
+import Control.Applicative ( Applicative((<*>)), (<$>) )
+import Control.Exception ( Exception, throwIO )
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as B
+import Data.Maybe ( mapMaybe, fromMaybe )
+import Data.Monoid ( (<>) )
+import Data.Text (Text)
+import qualified Data.Text as T ( pack )
+import qualified Data.Text.Encoding as T
+    ( encodeUtf8, decodeUtf8With )
+import qualified Data.Text.Encoding.Error as T ( lenientDecode )
+import Data.Typeable ( Typeable )
+import Data.Word ( Word8, Word16, Word32, Word64 )
+import Foreign
+    ( Int32,
+      Ptr,
+      nullPtr,
+      plusPtr,
+      Storable(alignment, peek, peekByteOff, poke, pokeByteOff, sizeOf),
+      Bits((.&.), (.|.), shiftL),
+      castPtr,
+      with,
+      toBool,
+      fromBool,
+      withArrayLen,
+      pokeArray,
+      peekArray,
+      copyArray,
+      allocaArray )
+import Foreign.C ( CString )
+
+import System.Hardware.MercuryApi.Enums
+
+#include <tm_reader.h>
+#include <glue.h>
+#include <stdbool.h>
+
+-- | A GPIO pin number.  On the M6e Nano, these are numbered 1-4.
+type PinNumber = Word8
+
+-- | An antenna number.  On the
+-- <https://www.sparkfun.com/products/14066 SparkFun Simultaneous RFID Reader>,
+-- there is a single antenna with the number 1.
+type AntennaPort = Word8
+
+-- | A 32-bit password (access or kill) in the Gen2 protocol.
+type GEN2_Password = Word32
+
+-- | milliseconds since 1\/1\/1970 UTC
+type MillisecondsSinceEpoch = Word64
+
+-- | Version number of the Mercury API C library.
+apiVersion :: Text
+apiVersion = #{const_str TMR_VERSION}
+
+type CBool = #{type bool}
+newtype ReaderEtc = ReaderEtc ()
+
+cFalse, cTrue :: CBool
+cFalse = 0
+cTrue = 1
+
+toBool' :: CBool -> Bool
+toBool' = toBool
+
+fromBool' :: Bool -> CBool
+fromBool' = fromBool
+
+sizeofReaderEtc :: Int
+sizeofReaderEtc = #{size ReaderEtc}
+
+uriPtr :: Ptr ReaderEtc -> CString
+uriPtr = #{ptr ReaderEtc, uri}
+
+-- I'm not sure what encoding MercuryApi uses for its strings.
+-- I'm guessing UTF-8 for now, but the encoding is encapsulated in
+-- these two functions (textFromBS and textToBS) so it can be
+-- easily changed.
+textFromBS :: ByteString -> Text
+textFromBS = T.decodeUtf8With T.lenientDecode
+
+textToBS :: Text -> ByteString
+textToBS = T.encodeUtf8
+
+textFromCString :: CString -> IO Text
+textFromCString cs = textFromBS <$> B.packCString cs
+
+-- | Indicates whether to read or write the lock bits in
+-- 'TagOp_GEN2_BlockPermaLock'.
+data ReadWrite = Read !Int       -- ^ number of words of lock bits to read
+               | Write ![Word16] -- ^ lock bits to write
+               deriving (Eq, Ord, Show, Read)
+
+fromReadWrite :: ReadWrite -> (Word8, [Word16])
+fromReadWrite (Read n) = (0, replicate n 0)
+fromReadWrite (Write ws) = (1, ws)
+
+toReadWrite :: (Word8, [Word16]) -> ReadWrite
+toReadWrite (0, ws) = Read $ length ws
+toReadWrite (1, ws) = Write ws
+toReadWrite (x, _)  = error $ "didn't expect ReadWrite to be " ++ show x
+
+-- This exception is never seen by the user.  It is caught
+-- internally and turned into a MercuryException (with some added fields).
+data ParamException = ParamException StatusType Status Text
+  deriving (Eq, Ord, Show, Read, Typeable)
+
+instance Exception ParamException
+
+castLen' :: Integral a => a -> Text -> Int -> IO a
+castLen' bound description x = do
+  let tShow = T.pack . show
+      maxLen = fromIntegral bound
+  if x > maxLen
+    then throwIO ( ParamException ERROR_TYPE_MISC ERROR_TOO_BIG $
+                   description <> " had length " <> tShow x <>
+                   " but maximum is " <> tShow maxLen )
+    else return $ fromIntegral x
+
+castLen :: (Integral a, Bounded a) => Text -> Int -> IO a
+castLen = castLen' maxBound
+
+-- | A ReadPlan record specifies the antennas, protocols, and filters
+-- to use for a search (read).
+--
+-- Currently, only @SimpleReadPlan@ is supported.
+data ReadPlan =
+  SimpleReadPlan
+  { rpWeight        :: !Word32          -- ^ The relative weight of this read plan
+  , rpEnableAutonomousRead :: !Bool     -- ^ Option for Autonomous read
+  , rpAntennas      :: ![AntennaPort]   -- ^ The list of antennas to read on
+  , rpProtocol      :: !TagProtocol     -- ^ The protocol to use for reading
+  , rpFilter        :: !(Maybe TagFilter) -- ^ The filter to apply to reading
+  , rpTagop         :: !(Maybe TagOp)   -- ^ The tag operation to apply to
+                                        -- each read tag
+  , rpUseFastSearch :: !Bool            -- ^ Option to use the FastSearch
+  , rpStopOnCount   :: !(Maybe Word32)  -- ^ Number of tags to be read
+  , rpTriggerRead   :: !(Maybe [Word8]) -- ^ The list of GPI ports which should
+                                        -- be used to trigger the read
+  } deriving (Eq, Ord, Show, Read)
+
+antennasInfo :: Ptr ReadPlan -> (Ptr List16, Word16, Ptr Word8, Text)
+antennasInfo rp =
+  ( #{ptr ReadPlanEtc, plan.u.simple.antennas} rp
+  , #{const GLUE_MAX_ANTENNAS}
+  , #{ptr ReadPlanEtc, antennas} rp
+  , "rpAntennas"
+  )
+
+gpiListInfo :: Ptr ReadPlan -> (Ptr List16, Word16, Ptr Word8, Text)
+gpiListInfo rp =
+  ( #{ptr ReadPlanEtc, plan.u.simple.triggerRead.gpiList} rp
+  , #{const GLUE_MAX_GPIPORTS}
+  , #{ptr ReadPlanEtc, gpiPorts} rp
+  , "rpTriggerRead"
+  )
+
+readPlanTypeSimple :: #{type TMR_ReadPlanType}
+readPlanTypeSimple = #{const TMR_READ_PLAN_TYPE_SIMPLE}
+
+instance Storable ReadPlan where
+  sizeOf _ = #{size ReadPlanEtc}
+  alignment _ = 8
+
+  poke p x = do
+    #{poke ReadPlanEtc, plan.type} p readPlanTypeSimple
+    #{poke ReadPlanEtc, plan.weight} p (rpWeight x)
+    #{poke ReadPlanEtc, plan.enableAutonomousRead} p
+      (fromBool' $ rpEnableAutonomousRead x)
+    pokeList16 (antennasInfo p) (rpAntennas x)
+    #{poke ReadPlanEtc, plan.u.simple.protocol} p
+      (fromTagProtocol $ rpProtocol x)
+    case rpFilter x of
+      Nothing -> #{poke ReadPlanEtc, plan.u.simple.filter} p nullPtr
+      Just f -> do
+        #{poke ReadPlanEtc, filter} p f
+        #{poke ReadPlanEtc, plan.u.simple.filter} p (#{ptr ReadPlanEtc, filter} p)
+    case rpTagop x of
+      Nothing -> #{poke ReadPlanEtc, plan.u.simple.tagop} p nullPtr
+      Just op -> do
+        #{poke ReadPlanEtc, tagop} p op
+        #{poke ReadPlanEtc, plan.u.simple.tagop} p (#{ptr ReadPlanEtc, tagop} p)
+    #{poke ReadPlanEtc, plan.u.simple.useFastSearch} p
+      (fromBool' $ rpUseFastSearch x)
+    let (stop, nTags) = case rpStopOnCount x of
+                          Nothing -> (cFalse, 0)
+                          Just n -> (cTrue, n)
+    #{poke ReadPlanEtc, plan.u.simple.stopOnCount.stopNTriggerStatus} p stop
+    #{poke ReadPlanEtc, plan.u.simple.stopOnCount.noOfTags} p nTags
+    let (enable, ports) = case rpTriggerRead x of
+                            Nothing -> (cFalse, [])
+                            Just ps -> (cTrue, ps)
+    #{poke ReadPlanEtc, plan.u.simple.triggerRead.enable} p enable
+    pokeList16 (gpiListInfo p) ports
+
+  peek p = do
+    weight <- #{peek ReadPlanEtc, plan.weight} p
+    enableAutonomousRead <- #{peek ReadPlanEtc, plan.enableAutonomousRead} p
+    antennas <- peekList16 (antennasInfo p)
+    protocol <- #{peek ReadPlanEtc, plan.u.simple.protocol} p
+    fPtr <- #{peek ReadPlanEtc, plan.u.simple.filter} p
+    filt <- if fPtr == nullPtr
+            then return Nothing
+            else Just <$> peek fPtr
+    opPtr <- #{peek ReadPlanEtc, plan.u.simple.tagop} p
+    op <- if opPtr == nullPtr
+          then return Nothing
+          else Just <$> peek opPtr
+    useFastSearch <- #{peek ReadPlanEtc, plan.u.simple.useFastSearch} p
+    stop <- #{peek ReadPlanEtc, plan.u.simple.stopOnCount.stopNTriggerStatus} p
+    stopOnCount <- if toBool' stop
+                   then Just <$> #{peek ReadPlanEtc, plan.u.simple.stopOnCount.noOfTags} p
+                   else return Nothing
+    enable <- #{peek ReadPlanEtc, plan.u.simple.triggerRead.enable} p
+    triggerRead <- if toBool' enable
+                   then Just <$> peekList16 (gpiListInfo p)
+                   else return Nothing
+    return $ SimpleReadPlan
+      { rpWeight = weight
+      , rpEnableAutonomousRead = toBool' enableAutonomousRead
+      , rpAntennas = antennas
+      , rpProtocol = toTagProtocol protocol
+      , rpFilter = filt
+      , rpTagop = op
+      , rpUseFastSearch = toBool' useFastSearch
+      , rpStopOnCount = stopOnCount
+      , rpTriggerRead = triggerRead
+      }
+
+-- | Filter on EPC length, or on a Gen2 bank.
+data FilterOn = FilterOnBank GEN2_Bank
+              | FilterOnEpcLength
+              deriving (Eq, Ord, Show, Read)
+
+instance Storable FilterOn where
+  sizeOf _ = #{size TMR_GEN2_Bank}
+  alignment _ = 8
+
+  poke p FilterOnEpcLength = do
+    let p' = castPtr p :: Ptr RawBank
+    poke p' #{const TMR_GEN2_EPC_LENGTH_FILTER}
+
+  poke p (FilterOnBank bank) = do
+    let p' = castPtr p :: Ptr RawBank
+    poke p' (fromBank bank)
+
+  peek p = do
+    x <- peek (castPtr p)
+    if x == #{const TMR_GEN2_EPC_LENGTH_FILTER}
+      then return FilterOnEpcLength
+      else return $ FilterOnBank $ toBank x
+
+-- | Filter on EPC data, or on Gen2-specific information.
+data TagFilter = TagFilterEPC TagData
+               | TagFilterGen2
+               { tfInvert        :: !Bool        -- ^ Whether to invert the
+                                                 -- selection (deselect tags
+                                                 -- that meet the comparison)
+               , tfFilterOn      :: !FilterOn    -- ^ The memory bank in which
+                                                 -- to compare the mask
+               , tfBitPointer    :: !Word32      -- ^ The location (in bits) at
+                                                 -- which to begin comparing
+                                                 -- the mask
+               , tfMaskBitLength :: !Word16      -- ^ The length (in bits) of
+                                                 -- the mask
+               , tfMask          :: !ByteString  -- ^ The mask value to compare
+                                                 -- with the specified region
+                                                 -- of tag memory, MSB first
+               }
+               deriving (Eq, Ord, Show, Read)
+
+instance Storable TagFilter where
+  sizeOf _ = #{size TagFilterEtc}
+  alignment _ = 8
+
+  poke p (TagFilterEPC td) = do
+    #{poke TagFilterEtc, filter.type} p
+      (#{const TMR_FILTER_TYPE_TAG_DATA} :: #{type TMR_FilterType})
+    #{poke TagFilterEtc, filter.u.tagData} p td
+
+  poke p tf@(TagFilterGen2 {}) = do
+    #{poke TagFilterEtc, filter.type} p
+      (#{const TMR_FILTER_TYPE_GEN2_SELECT} :: #{type TMR_FilterType})
+    #{poke TagFilterEtc, filter.u.gen2Select.invert} p (fromBool' $ tfInvert tf)
+    #{poke TagFilterEtc, filter.u.gen2Select.bank} p (tfFilterOn tf)
+    #{poke TagFilterEtc, filter.u.gen2Select.bitPointer} p (tfBitPointer tf)
+    #{poke TagFilterEtc, filter.u.gen2Select.maskBitLength} p (tfMaskBitLength tf)
+    let maskLenBytes = fromIntegral $ (tfMaskBitLength tf + 7) `div` 8
+        origLen = B.length (tfMask tf)
+        bs = if origLen < maskLenBytes
+               then tfMask tf <> B.pack (replicate (maskLenBytes - origLen) 0)
+               else tfMask tf
+    B.useAsCStringLen bs $ \(cs, len) -> do
+      len' <- castLen' #{const GLUE_MAX_MASK} "tfMask" len
+      copyArray (#{ptr TagFilterEtc, mask} p) cs (fromIntegral len')
+    #{poke TagFilterEtc, filter.u.gen2Select.mask} p (#{ptr TagFilterEtc, mask} p)
+
+  peek p = do
+    ft <- #{peek TagFilterEtc, filter.type} p :: IO #{type TMR_FilterType}
+    case ft of
+      #{const TMR_FILTER_TYPE_TAG_DATA} ->
+        TagFilterEPC <$> #{peek TagFilterEtc, filter.u.tagData} p
+      #{const TMR_FILTER_TYPE_GEN2_SELECT} ->
+        TagFilterGen2
+        <$> (toBool' <$> #{peek TagFilterEtc, filter.u.gen2Select.invert} p)
+        <*> #{peek TagFilterEtc, filter.u.gen2Select.bank} p
+        <*> #{peek TagFilterEtc, filter.u.gen2Select.bitPointer} p
+        <*> #{peek TagFilterEtc, filter.u.gen2Select.maskBitLength} p
+        <*> peekMask p
+
+peekMask :: Ptr TagFilter -> IO ByteString
+peekMask p = do
+  bitLength <- #{peek TagFilterEtc, filter.u.gen2Select.maskBitLength} p :: IO Word32
+  let len = fromIntegral $ (bitLength + 7) `div` 8
+  maskPtr <- #{peek TagFilterEtc, filter.u.gen2Select.mask} p
+  B.packCStringLen (maskPtr, len)
+
+packBits :: Num b => (a -> b) -> [a] -> b
+packBits from flags = sum $ map from flags
+
+unpackBits :: (Bounded a, Enum a, Num b, Bits b) => (a -> b) -> b -> [a]
+unpackBits from x = mapMaybe f [minBound..maxBound]
+  where f flag = if (x .&. from flag) == 0
+                 then Nothing
+                 else Just flag
+
+packFlags :: [MetadataFlag] -> RawMetadataFlag
+packFlags = packBits fromMetadataFlag
+
+unpackFlags :: RawMetadataFlag -> [MetadataFlag]
+unpackFlags = unpackBits fromMetadataFlag
+
+packFlags16 :: [MetadataFlag] -> Word16
+packFlags16 = fromIntegral . packFlags
+
+unpackFlags16 :: Word16 -> [MetadataFlag]
+unpackFlags16 = unpackFlags . fromIntegral
+
+packExtraBanks :: [GEN2_Bank] -> RawBank
+packExtraBanks = packBits fromExtraBank
+
+unpackExtraBanks :: RawBank -> [GEN2_Bank]
+unpackExtraBanks = unpackBits fromExtraBank
+
+packLockBits :: [GEN2_LockBits] -> RawLockBits
+packLockBits = packBits fromLockBits
+
+unpackLockBits :: RawLockBits -> [GEN2_LockBits]
+unpackLockBits = unpackBits fromLockBits
+
+packLockBits16 :: [GEN2_LockBits] -> Word16
+packLockBits16 = fromIntegral . packLockBits
+
+unpackLockBits16 :: Word16 -> [GEN2_LockBits]
+unpackLockBits16 = unpackLockBits . fromIntegral
+
+peekArrayAsByteString :: Ptr Word8 -> Ptr Word8 -> IO ByteString
+peekArrayAsByteString arrayPtr lenPtr = do
+  len <- peek lenPtr
+  B.packCStringLen (castPtr arrayPtr, fromIntegral len)
+
+pokeArrayAsByteString :: Text
+                      -> Word8
+                      -> Ptr Word8
+                      -> Ptr Word8
+                      -> ByteString
+                      -> IO ()
+pokeArrayAsByteString desc maxLen arrayPtr lenPtr bs = do
+  B.useAsCStringLen bs $ \(cs, len) -> do
+    len' <- castLen' maxLen desc len
+    copyArray arrayPtr (castPtr cs) (fromIntegral len')
+    poke lenPtr len'
+
+peekListAsByteString :: Ptr List16 -> IO ByteString
+peekListAsByteString listPtr = do
+  lst <- peek listPtr
+  B.packCStringLen (castPtr $ l16_list lst, fromIntegral $ l16_len lst)
+
+peekArrayAsList :: Storable a => Ptr a -> Ptr Word8 -> IO [a]
+peekArrayAsList arrayPtr lenPtr = do
+  len <- peek lenPtr
+  peekArray (fromIntegral len) arrayPtr
+
+peekListAsList :: Storable a => Ptr List16 -> Ptr a -> IO [a]
+peekListAsList listPtr _ = do
+  lst <- peek listPtr
+  peekArray (fromIntegral $ l16_len lst) (castPtr $ l16_list lst)
+
+pokeListAsList :: Storable a
+               => Text
+               -> Word16
+               -> Ptr List16
+               -> Ptr a
+               -> [a]
+               -> IO ()
+pokeListAsList desc maxLen listPtr storage xs = do
+  withArrayLen xs $ \len tmpPtr -> do
+    len' <- castLen' maxLen desc len
+    copyArray storage tmpPtr len
+    let lst = List16
+              { l16_list = castPtr storage
+              , l16_max = maxLen
+              , l16_len = len'
+              }
+    poke listPtr lst
+
+peekMaybe :: (Storable a, Storable b)
+          => (Ptr a -> IO a)
+          -> (b -> Bool)
+          -> Ptr a
+          -> Ptr b
+          -> IO (Maybe a)
+peekMaybe oldPeek cond justP condP = do
+  c <- peek condP
+  if cond c
+    then Just <$> oldPeek justP
+    else return Nothing
+
+pokeGen2TagData :: Ptr GEN2_TagData
+                -> Ptr RawTagProtocol
+                -> Maybe GEN2_TagData
+                -> IO ()
+pokeGen2TagData pGen2 _ mGen2 = do
+  let gen2 = fromMaybe (GEN2_TagData B.empty) mGen2
+  poke pGen2 gen2
+
+peekSplit64 :: Ptr Word32 -> Ptr Word32 -> IO Word64
+peekSplit64 pLow pHigh = do
+  lo <- fromIntegral <$> peek pLow
+  hi <- fromIntegral <$> peek pHigh
+  return $ lo .|. (hi `shiftL` 32)
+
+peekPtr :: Storable a => Ptr (Ptr a) -> Ptr a -> IO a
+peekPtr pp _ = do
+  p <- peek pp
+  peek p
+
+pokePtr :: Storable a => Ptr (Ptr a) -> Ptr a -> a -> IO ()
+pokePtr pp p x = do
+  poke p x
+  poke pp p
+
+pokeOr :: (Storable a, Bits a) => Ptr a -> a -> IO ()
+pokeOr p x = do
+  old <- peek p
+  poke p (x .|. old)
+
+data List16 =
+  List16
+  { l16_list :: !(Ptr ())
+  , l16_max :: !(Word16)
+  , l16_len :: !(Word16)
+  }
+
+instance Storable List16 where
+  sizeOf _ = #{size List16}
+  alignment _ = 8
+  peek p = List16
+           <$> #{peek List16, list} p
+           <*> #{peek List16, max} p
+           <*> #{peek List16, len} p
+  poke p x = do
+    #{poke List16, list} p (l16_list x)
+    #{poke List16, max} p (l16_max x)
+    #{poke List16, len} p (l16_len x)
+
+getList16 :: Storable a => (Ptr () -> IO ()) -> IO [a]
+getList16 f = do
+  let maxLen = maxBound :: Word16
+  allocaArray (fromIntegral maxLen) $ \storage -> do
+    let lst = List16
+              { l16_list = castPtr storage
+              , l16_max = maxLen
+              , l16_len = 0
+              }
+    with lst $ \p -> do
+      f (castPtr p)
+      lst' <- peek p
+      peekArray (fromIntegral (l16_len lst')) storage
+
+setList16 :: Storable a => Text -> [a] -> (Ptr () -> IO ()) -> IO ()
+setList16 t x f = do
+  withArrayLen x $ \len storage -> do
+    len' <- castLen t len
+    let lst = List16
+              { l16_list = castPtr storage
+              , l16_max = len'
+              , l16_len = len'
+              }
+    with lst $ \p -> f (castPtr p)
+
+pokeList16 :: Storable a => (Ptr List16, Word16, Ptr a, Text) -> [a] -> IO ()
+pokeList16 (lp, maxLen, storage, name) ws = do
+  len <- castLen' maxLen name (length ws)
+  poke lp $ List16
+    { l16_list = castPtr storage
+    , l16_max = maxLen
+    , l16_len = len
+    }
+  pokeArray storage ws
+
+peekList16 :: Storable a => (Ptr List16, Word16, Ptr a, Text) -> IO [a]
+peekList16 (lp, _, _, _) = do
+  lst <- peek lp
+  peekArray (fromIntegral $ l16_len lst) (castPtr $ l16_list lst)
+
+data List8 =
+  List8
+  { l8_list :: !(Ptr ())
+  , l8_max :: !(Word8)
+  , l8_len :: !(Word8)
+  }
+
+instance Storable List8 where
+  sizeOf _ = #{size List8}
+  alignment _ = 8
+  peek p = List8
+           <$> #{peek List8, list} p
+           <*> #{peek List8, max} p
+           <*> #{peek List8, len} p
+  poke p x = do
+    #{poke List8, list} p (l8_list x)
+    #{poke List8, max} p (l8_max x)
+    #{poke List8, len} p (l8_len x)
+
+getList8 :: Storable a => (Ptr () -> IO ()) -> IO [a]
+getList8 f = do
+  let maxLen = maxBound :: Word8
+  allocaArray (fromIntegral maxLen) $ \storage -> do
+    let lst = List8
+              { l8_list = castPtr storage
+              , l8_max = maxLen
+              , l8_len = 0
+              }
+    with lst $ \p -> do
+      f (castPtr p)
+      lst' <- peek p
+      peekArray (fromIntegral (l8_len lst')) storage
+
+setList8 :: Storable a => Text -> [a] -> (Ptr () -> IO ()) -> IO ()
+setList8 t x f = do
+  withArrayLen x $ \len storage -> do
+    len' <- castLen t len
+    let lst = List8
+              { l8_list = castPtr storage
+              , l8_max = len'
+              , l8_len = len'
+              }
+    with lst $ \p -> f (castPtr p)
+
+pokeList8 :: Storable a => (Ptr List8, Word8, Ptr a, Text) -> [a] -> IO ()
+pokeList8 (lp, maxLen, storage, name) ws = do
+  len <- castLen' maxLen name (length ws)
+  poke lp $ List8
+    { l8_list = castPtr storage
+    , l8_max = maxLen
+    , l8_len = len
+    }
+  pokeArray storage ws
+
+peekList8 :: Storable a => (Ptr List8, Word8, Ptr a, Text) -> IO [a]
+peekList8 (lp, _, _, _) = do
+  lst <- peek lp
+  peekArray (fromIntegral $ l8_len lst) (castPtr $ l8_list lst)
+
+-- | Gen2-specific per-tag data
+newtype GEN2_TagData =
+  GEN2_TagData
+  { g2Pc :: ByteString -- ^ Tag PC
+  } deriving (Eq, Ord, Show, Read)
+
+instance Storable GEN2_TagData where
+  sizeOf _ = #{size TMR_GEN2_TagData}
+  alignment _ = 8
+
+  peek p =
+    GEN2_TagData
+      <$> peekArrayAsByteString (#{ptr TMR_GEN2_TagData, pc} p) (#{ptr TMR_GEN2_TagData, pcByteCount} p)
+
+  poke p x = do
+    pokeArrayAsByteString "pc" #{const TMR_GEN2_MAX_PC_BYTE_COUNT} (#{ptr TMR_GEN2_TagData, pc} p) (#{ptr TMR_GEN2_TagData, pcByteCount} p) (g2Pc x)
+
+-- | A record to represent RFID tags.
+data TagData =
+  TagData
+  { tdEpc :: !ByteString -- ^ Tag EPC
+  , tdProtocol :: !TagProtocol -- ^ Protocol of the tag
+  , tdCrc :: !Word16 -- ^ Tag CRC
+  , tdGen2 :: !(Maybe (GEN2_TagData)) -- ^ Gen2-specific tag information
+  } deriving (Eq, Ord, Show, Read)
+
+instance Storable TagData where
+  sizeOf _ = #{size TMR_TagData}
+  alignment _ = 8
+
+  peek p =
+    TagData
+      <$> peekArrayAsByteString (#{ptr TMR_TagData, epc} p) (#{ptr TMR_TagData, epcByteCount} p)
+      <*> (toTagProtocol <$> #{peek TMR_TagData, protocol} p)
+      <*> #{peek TMR_TagData, crc} p
+      <*> peekMaybe (peek) (== (#{const TMR_TAG_PROTOCOL_GEN2} :: RawTagProtocol)) (#{ptr TMR_TagData, u.gen2} p) (#{ptr TMR_TagData, protocol} p)
+
+  poke p x = do
+    pokeArrayAsByteString "epc" #{const TMR_MAX_EPC_BYTE_COUNT} (#{ptr TMR_TagData, epc} p) (#{ptr TMR_TagData, epcByteCount} p) (tdEpc x)
+    #{poke TMR_TagData, protocol} p (fromTagProtocol $ tdProtocol x)
+    #{poke TMR_TagData, crc} p (tdCrc x)
+    pokeGen2TagData (#{ptr TMR_TagData, u.gen2} p) (#{ptr TMR_TagData, protocol} p) (tdGen2 x)
+
+-- | The identity and state of a single GPIO pin.
+data GpioPin =
+  GpioPin
+  { gpId :: !PinNumber -- ^ The ID number of the pin.
+  , gpHigh :: !Bool -- ^ Whether the pin is in the high state.
+  , gpOutput :: !Bool -- ^ The direction of the pin
+  } deriving (Eq, Ord, Show, Read)
+
+instance Storable GpioPin where
+  sizeOf _ = #{size TMR_GpioPin}
+  alignment _ = 8
+
+  peek p =
+    GpioPin
+      <$> #{peek TMR_GpioPin, id} p
+      <*> (toBool' <$> #{peek TMR_GpioPin, high} p)
+      <*> (toBool' <$> #{peek TMR_GpioPin, output} p)
+
+  poke p x = do
+    #{poke TMR_GpioPin, id} p (gpId x)
+    #{poke TMR_GpioPin, high} p (fromBool' $ gpHigh x)
+    #{poke TMR_GpioPin, output} p (fromBool' $ gpOutput x)
+
+-- | A record to represent a read of an RFID tag.
+-- Provides access to the metadata of the read event,
+-- such as the time of the read, the antenna that read the tag,
+-- and the number of times the tag was seen by the air protocol.
+data TagReadData =
+  TagReadData
+  { trTag :: !TagData -- ^ The tag that was read
+  , trMetadataFlags :: ![MetadataFlag] -- ^ The set of metadata items below that are valid
+  , trPhase :: !Word16 -- ^ Tag response phase
+  , trAntenna :: !AntennaPort -- ^ Antenna where the tag was read
+  , trGpio :: ![GpioPin] -- ^ State of GPIO pins at the moment of the tag read
+  , trReadCount :: !Word32 -- ^ Number of times the tag was read
+  , trRssi :: !Int32 -- ^ Strength of the signal received from the tag
+  , trFrequency :: !Word32 -- ^ RF carrier frequency the tag was read with
+  , trTimestamp :: !MillisecondsSinceEpoch -- ^ Absolute time of the read, in milliseconds since 1\/1\/1970 UTC
+  , trData :: !ByteString -- ^ Data read from the tag
+  , trEpcMemData :: !ByteString -- ^ Read EPC bank data bytes  (Only if 'GEN2_BANK_EPC' is present in 'opExtraBanks')
+  , trTidMemData :: !ByteString -- ^ Read TID bank data bytes  (Only if 'GEN2_BANK_TID' is present in 'opExtraBanks')
+  , trUserMemData :: !ByteString -- ^ Read USER bank data bytes  (Only if 'GEN2_BANK_USER' is present in 'opExtraBanks')
+  , trReservedMemData :: !ByteString -- ^ Read RESERVED bank data bytes  (Only if 'GEN2_BANK_RESERVED' is present in 'opExtraBanks')
+  } deriving (Eq, Ord, Show, Read)
+
+instance Storable TagReadData where
+  sizeOf _ = #{size TMR_TagReadData}
+  alignment _ = 8
+
+  peek p =
+    TagReadData
+      <$> #{peek TMR_TagReadData, tag} p
+      <*> (unpackFlags16 <$> #{peek TMR_TagReadData, metadataFlags} p)
+      <*> #{peek TMR_TagReadData, phase} p
+      <*> #{peek TMR_TagReadData, antenna} p
+      <*> peekArrayAsList (#{ptr TMR_TagReadData, gpio} p) (#{ptr TMR_TagReadData, gpioCount} p)
+      <*> #{peek TMR_TagReadData, readCount} p
+      <*> #{peek TMR_TagReadData, rssi} p
+      <*> #{peek TMR_TagReadData, frequency} p
+      <*> peekSplit64 (#{ptr TMR_TagReadData, timestampLow} p) (#{ptr TMR_TagReadData, timestampHigh} p)
+      <*> peekListAsByteString (#{ptr TMR_TagReadData, data} p)
+      <*> peekListAsByteString (#{ptr TMR_TagReadData, epcMemData} p)
+      <*> peekListAsByteString (#{ptr TMR_TagReadData, tidMemData} p)
+      <*> peekListAsByteString (#{ptr TMR_TagReadData, userMemData} p)
+      <*> peekListAsByteString (#{ptr TMR_TagReadData, reservedMemData} p)
+
+  poke p x = error "poke not implemented for TagReadData"
+
+-- | An operation that can be performed on a tag.  Can be used
+-- as an argument to 'System.Hardware.MercuryApi.executeTagOp',
+-- or can be embedded into a 'System.Hardware.MercuryApi.ReadPlan'.
+-- (However, on the M6e Nano, only 'TagOp_GEN2_ReadData' may be
+-- embedded in a 'System.Hardware.MercuryApi.ReadPlan'.)
+data TagOp =
+    TagOp_GEN2_ReadData
+    { opBank :: !GEN2_Bank -- ^ Gen2 memory bank to operate on
+    , opExtraBanks :: ![GEN2_Bank] -- ^ Additional Gen2 memory banks to read from  (seems buggy, though; I\'ve had strange results with it)
+    , opWordAddress :: !Word32 -- ^ Word address to start at
+    , opLen :: !Word8 -- ^ Number of words to read
+    }
+  | TagOp_GEN2_WriteTag
+    { opEpc :: !TagData -- ^ Tag EPC
+    }
+  | TagOp_GEN2_WriteData
+    { opBank :: !GEN2_Bank -- ^ Gen2 memory bank to operate on
+    , opWordAddress :: !Word32 -- ^ Word address to start at
+    , opData :: ![Word16] -- ^ Data to write
+    }
+  | TagOp_GEN2_Lock
+    { opMask :: ![GEN2_LockBits] -- ^ Bitmask indicating which lock bits to change
+    , opAction :: ![GEN2_LockBits] -- ^ New values of each bit specified in the mask
+    , opAccessPassword :: !GEN2_Password -- ^ Access Password to use to lock the tag
+    }
+  | TagOp_GEN2_Kill
+    { opPassword :: !GEN2_Password -- ^ Kill password to use to kill the tag
+    }
+  | TagOp_GEN2_BlockWrite
+    { opBank :: !GEN2_Bank -- ^ Gen2 memory bank to operate on
+    , opWordPtr :: !Word32 -- ^ The word address to start at
+    , opData :: ![Word16] -- ^ The data to write
+    }
+  | TagOp_GEN2_BlockErase
+    { opBank :: !GEN2_Bank -- ^ Gen2 memory bank to operate on
+    , opWordPtr :: !Word32 -- ^ The word address to start at
+    , opWordCount :: !Word8 -- ^ Number of words to erase
+    }
+  | TagOp_GEN2_BlockPermaLock
+    { opBank :: !GEN2_Bank -- ^ Gen2 memory bank to operate on
+    , opBlockPtr :: !Word32 -- ^ The starting word address to lock
+    , opReadWrite :: !ReadWrite -- ^ Read lock status or write it?
+    }
+  deriving (Eq, Ord, Show, Read)
+
+instance Storable TagOp where
+  sizeOf _ = #{size TagOpEtc}
+  alignment _ = 8
+
+  peek p = do
+    x <- #{peek TagOpEtc, tagop.type} p :: IO #{type TMR_TagOpType}
+    case x of
+      #{const TMR_TAGOP_GEN2_READDATA} -> do
+        TagOp_GEN2_ReadData
+          <$> ((toBank . (.&. 3)) <$> #{peek TagOpEtc, tagop.u.gen2.u.readData.bank} p)
+          <*> (unpackExtraBanks <$> #{peek TagOpEtc, tagop.u.gen2.u.readData.bank} p)
+          <*> #{peek TagOpEtc, tagop.u.gen2.u.readData.wordAddress} p
+          <*> #{peek TagOpEtc, tagop.u.gen2.u.readData.len} p
+      #{const TMR_TAGOP_GEN2_WRITETAG} -> do
+        TagOp_GEN2_WriteTag
+          <$> peekPtr (#{ptr TagOpEtc, tagop.u.gen2.u.writeTag.epcptr} p) (#{ptr TagOpEtc, u.epc} p)
+      #{const TMR_TAGOP_GEN2_WRITEDATA} -> do
+        TagOp_GEN2_WriteData
+          <$> ((toBank . (.&. 3)) <$> #{peek TagOpEtc, tagop.u.gen2.u.writeData.bank} p)
+          <*> #{peek TagOpEtc, tagop.u.gen2.u.writeData.wordAddress} p
+          <*> peekListAsList (#{ptr TagOpEtc, tagop.u.gen2.u.writeData.data} p) (#{ptr TagOpEtc, u.data16} p)
+      #{const TMR_TAGOP_GEN2_LOCK} -> do
+        TagOp_GEN2_Lock
+          <$> (unpackLockBits16 <$> #{peek TagOpEtc, tagop.u.gen2.u.lock.mask} p)
+          <*> (unpackLockBits16 <$> #{peek TagOpEtc, tagop.u.gen2.u.lock.action} p)
+          <*> #{peek TagOpEtc, tagop.u.gen2.u.lock.accessPassword} p
+      #{const TMR_TAGOP_GEN2_KILL} -> do
+        TagOp_GEN2_Kill
+          <$> #{peek TagOpEtc, tagop.u.gen2.u.kill.password} p
+      #{const TMR_TAGOP_GEN2_BLOCKWRITE} -> do
+        TagOp_GEN2_BlockWrite
+          <$> ((toBank . (.&. 3)) <$> #{peek TagOpEtc, tagop.u.gen2.u.blockWrite.bank} p)
+          <*> #{peek TagOpEtc, tagop.u.gen2.u.blockWrite.wordPtr} p
+          <*> peekListAsList (#{ptr TagOpEtc, tagop.u.gen2.u.blockWrite.data} p) (#{ptr TagOpEtc, u.data16} p)
+      #{const TMR_TAGOP_GEN2_BLOCKERASE} -> do
+        TagOp_GEN2_BlockErase
+          <$> ((toBank . (.&. 3)) <$> #{peek TagOpEtc, tagop.u.gen2.u.blockErase.bank} p)
+          <*> #{peek TagOpEtc, tagop.u.gen2.u.blockErase.wordPtr} p
+          <*> #{peek TagOpEtc, tagop.u.gen2.u.blockErase.wordCount} p
+      #{const TMR_TAGOP_GEN2_BLOCKPERMALOCK} -> do
+        rw <- #{peek TagOpEtc, tagop.u.gen2.u.blockPermaLock.readLock} p
+        ws <- peekListAsList (#{ptr TagOpEtc, tagop.u.gen2.u.blockPermaLock.mask} p) (#{ptr TagOpEtc, u.data16} p)
+        TagOp_GEN2_BlockPermaLock
+          <$> ((toBank . (.&. 3)) <$> #{peek TagOpEtc, tagop.u.gen2.u.blockPermaLock.bank} p)
+          <*> #{peek TagOpEtc, tagop.u.gen2.u.blockPermaLock.blockPtr} p
+          <*> (return $ toReadWrite (rw, ws))
+
+  poke p x@(TagOp_GEN2_ReadData {}) = do
+    #{poke TagOpEtc, tagop.type} p (#{const TMR_TAGOP_GEN2_READDATA} :: #{type TMR_TagOpType})
+    #{poke TagOpEtc, tagop.u.gen2.u.readData.bank} p (fromBank $ opBank x)
+    pokeOr (#{ptr TagOpEtc, tagop.u.gen2.u.readData.bank} p) (packExtraBanks $ opExtraBanks x)
+    #{poke TagOpEtc, tagop.u.gen2.u.readData.wordAddress} p (opWordAddress x)
+    #{poke TagOpEtc, tagop.u.gen2.u.readData.len} p (opLen x)
+
+  poke p x@(TagOp_GEN2_WriteTag {}) = do
+    #{poke TagOpEtc, tagop.type} p (#{const TMR_TAGOP_GEN2_WRITETAG} :: #{type TMR_TagOpType})
+    pokePtr (#{ptr TagOpEtc, tagop.u.gen2.u.writeTag.epcptr} p) (#{ptr TagOpEtc, u.epc} p) (opEpc x)
+
+  poke p x@(TagOp_GEN2_WriteData {}) = do
+    #{poke TagOpEtc, tagop.type} p (#{const TMR_TAGOP_GEN2_WRITEDATA} :: #{type TMR_TagOpType})
+    #{poke TagOpEtc, tagop.u.gen2.u.writeData.bank} p (fromBank $ opBank x)
+    #{poke TagOpEtc, tagop.u.gen2.u.writeData.wordAddress} p (opWordAddress x)
+    pokeListAsList "data" #{const GLUE_MAX_DATA16} (#{ptr TagOpEtc, tagop.u.gen2.u.writeData.data} p) (#{ptr TagOpEtc, u.data16} p) (opData x)
+
+  poke p x@(TagOp_GEN2_Lock {}) = do
+    #{poke TagOpEtc, tagop.type} p (#{const TMR_TAGOP_GEN2_LOCK} :: #{type TMR_TagOpType})
+    #{poke TagOpEtc, tagop.u.gen2.u.lock.mask} p (packLockBits16 $ opMask x)
+    #{poke TagOpEtc, tagop.u.gen2.u.lock.action} p (packLockBits16 $ opAction x)
+    #{poke TagOpEtc, tagop.u.gen2.u.lock.accessPassword} p (opAccessPassword x)
+
+  poke p x@(TagOp_GEN2_Kill {}) = do
+    #{poke TagOpEtc, tagop.type} p (#{const TMR_TAGOP_GEN2_KILL} :: #{type TMR_TagOpType})
+    #{poke TagOpEtc, tagop.u.gen2.u.kill.password} p (opPassword x)
+
+  poke p x@(TagOp_GEN2_BlockWrite {}) = do
+    #{poke TagOpEtc, tagop.type} p (#{const TMR_TAGOP_GEN2_BLOCKWRITE} :: #{type TMR_TagOpType})
+    #{poke TagOpEtc, tagop.u.gen2.u.blockWrite.bank} p (fromBank $ opBank x)
+    #{poke TagOpEtc, tagop.u.gen2.u.blockWrite.wordPtr} p (opWordPtr x)
+    pokeListAsList "data" #{const GLUE_MAX_DATA16} (#{ptr TagOpEtc, tagop.u.gen2.u.blockWrite.data} p) (#{ptr TagOpEtc, u.data16} p) (opData x)
+
+  poke p x@(TagOp_GEN2_BlockErase {}) = do
+    #{poke TagOpEtc, tagop.type} p (#{const TMR_TAGOP_GEN2_BLOCKERASE} :: #{type TMR_TagOpType})
+    #{poke TagOpEtc, tagop.u.gen2.u.blockErase.bank} p (fromBank $ opBank x)
+    #{poke TagOpEtc, tagop.u.gen2.u.blockErase.wordPtr} p (opWordPtr x)
+    #{poke TagOpEtc, tagop.u.gen2.u.blockErase.wordCount} p (opWordCount x)
+
+  poke p x@(TagOp_GEN2_BlockPermaLock {}) = do
+    let (rw, ws) = fromReadWrite $ opReadWrite x
+    #{poke TagOpEtc, tagop.type} p (#{const TMR_TAGOP_GEN2_BLOCKPERMALOCK} :: #{type TMR_TagOpType})
+    #{poke TagOpEtc, tagop.u.gen2.u.blockPermaLock.readLock} p rw
+    #{poke TagOpEtc, tagop.u.gen2.u.blockPermaLock.bank} p (fromBank $ opBank x)
+    #{poke TagOpEtc, tagop.u.gen2.u.blockPermaLock.blockPtr} p (opBlockPtr x)
+    pokeListAsList "mask" #{const GLUE_MAX_DATA16} (#{ptr TagOpEtc, tagop.u.gen2.u.blockPermaLock.mask} p) (#{ptr TagOpEtc, u.data16} p) ws
+
+tagOpName :: TagOp -> Text
+tagOpName TagOp_GEN2_ReadData {} = "TagOp_GEN2_ReadData"
+tagOpName TagOp_GEN2_WriteTag {} = "TagOp_GEN2_WriteTag"
+tagOpName TagOp_GEN2_WriteData {} = "TagOp_GEN2_WriteData"
+tagOpName TagOp_GEN2_Lock {} = "TagOp_GEN2_Lock"
+tagOpName TagOp_GEN2_Kill {} = "TagOp_GEN2_Kill"
+tagOpName TagOp_GEN2_BlockWrite {} = "TagOp_GEN2_BlockWrite"
+tagOpName TagOp_GEN2_BlockErase {} = "TagOp_GEN2_BlockErase"
+tagOpName TagOp_GEN2_BlockPermaLock {} = "TagOp_GEN2_BlockPermaLock"
+
diff --git a/src/System/Hardware/MercuryApi/Testing.hsc b/src/System/Hardware/MercuryApi/Testing.hsc
new file mode 100644
--- /dev/null
+++ b/src/System/Hardware/MercuryApi/Testing.hsc
@@ -0,0 +1,320 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# OPTIONS_HADDOCK hide #-}
+{-|
+Module      : System.Hardware.MercuryApi.Testing
+Description : A serial transport for MercuryApi which replays data from a file
+Copyright   : © Patrick Pelletier, 2017
+License     : MIT
+Maintainer  : code@funwithsoftware.org
+
+This module is not meant to be used by the end user.  It exists for the
+automated tests.  It provides a handler for URIs of the form
+test:///path/to/file, where the file is in the format produced by
+'opcodeListener'.  When Mercury API reads from the transport, the data
+from a "Received:" line is returned.  When Mercury API writes to the
+transport, the data is compared to the data in the "Sending:" line.
+If the data does not match, an error message is printed, and
+TMR_ERROR_TIMEOUT is returned.  (Timeout was chosen because it's the only
+error that seems to be consistently propagated from the transport by
+Mercury API.)
+-}
+
+module System.Hardware.MercuryApi.Testing
+  ( registerTransportInit
+  ) where
+
+import Control.Applicative ( Applicative((<*>)), (<$>) )
+import Control.Concurrent ( threadDelay )
+import Control.Exception ( IOException, try )
+import Control.Monad ( when )
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Char8 as B8 ( unpack )
+import Data.Char ( isDigit )
+import Data.IORef ( IORef, writeIORef, readIORef, newIORef )
+import Data.Monoid ( (<>) )
+import qualified Data.Text as T
+import qualified Data.Text.Encoding as T ( encodeUtf8 )
+import qualified Data.Text.IO as T ( readFile, putStrLn )
+import Data.Word ( Word8, Word32 )
+import Foreign
+    ( newStablePtr,
+      Ptr,
+      FunPtr,
+      nullPtr,
+      Storable(alignment, peek, peekByteOff, poke, pokeByteOff, sizeOf),
+      freeStablePtr,
+      deRefStablePtr,
+      castStablePtrToPtr,
+      castPtrToStablePtr,
+      nullFunPtr,
+      castPtr,
+      copyArray )
+import Foreign.C ( CString, withCAString, peekCAString )
+import System.Info ( os )
+import qualified System.IO.Unsafe as U ( unsafePerformIO )
+
+import System.Hardware.MercuryApi hiding (read)
+
+#include <tm_reader.h>
+#include <glue.h>
+
+type RawStatus = Word32
+
+successStatus :: RawStatus
+successStatus = #{const TMR_SUCCESS}
+
+failureStatus :: RawStatus
+failureStatus = #{const TMR_ERROR_TIMEOUT}
+
+data SerialState =
+  SerialState
+  { ssFilename :: String
+  , ssNext :: IORef [T.Text]
+  , ssLeftover :: IORef B.ByteString
+  , ssSendTime :: IORef Double
+  }
+
+data SerialTransport =
+  SerialTransport
+  { stCookie :: Ptr ()
+  , stOpen :: FunPtr (Ptr SerialTransport -> IO RawStatus)
+  , stSendBytes :: FunPtr (Ptr SerialTransport -> Word32 -> Ptr Word8 -> Word32 -> IO RawStatus)
+  , stReceiveBytes :: FunPtr (Ptr SerialTransport -> Word32 -> Ptr Word32 -> Ptr Word8 -> Word32 -> IO RawStatus)
+  , stSetBaudRate :: FunPtr (Ptr SerialTransport -> Word32 -> IO RawStatus)
+  , stShutdown :: FunPtr (Ptr SerialTransport -> IO RawStatus)
+  , stFlush :: FunPtr (Ptr SerialTransport -> IO RawStatus)
+  }
+
+instance Storable SerialTransport where
+  sizeOf _ = #{size TMR_SR_SerialTransport}
+  alignment _ = 8
+
+  peek p =
+    SerialTransport
+    <$> #{peek TMR_SR_SerialTransport, cookie}       p
+    <*> #{peek TMR_SR_SerialTransport, open}         p
+    <*> #{peek TMR_SR_SerialTransport, sendBytes}    p
+    <*> #{peek TMR_SR_SerialTransport, receiveBytes} p
+    <*> #{peek TMR_SR_SerialTransport, setBaudRate}  p
+    <*> #{peek TMR_SR_SerialTransport, shutdown}     p
+    <*> #{peek TMR_SR_SerialTransport, flush}        p
+
+  poke p x = do
+    #{poke TMR_SR_SerialTransport, cookie}       p (stCookie x)
+    #{poke TMR_SR_SerialTransport, open}         p (stOpen x)
+    #{poke TMR_SR_SerialTransport, sendBytes}    p (stSendBytes x)
+    #{poke TMR_SR_SerialTransport, receiveBytes} p (stReceiveBytes x)
+    #{poke TMR_SR_SerialTransport, setBaudRate}  p (stSetBaudRate x)
+    #{poke TMR_SR_SerialTransport, shutdown}     p (stShutdown x)
+    #{poke TMR_SR_SerialTransport, flush}        p (stFlush x)
+
+foreign import ccall "tm_reader.h TMR_setSerialTransport"
+    c_TMR_setSerialTransport :: CString
+                             -> FunPtr (Ptr SerialTransport -> Ptr () -> CString -> IO RawStatus)
+                             -> IO RawStatus
+
+foreign import ccall "wrapper"
+    wrapOneArg :: (Ptr SerialTransport -> IO RawStatus)
+               -> IO (FunPtr (Ptr SerialTransport -> IO RawStatus))
+
+foreign import ccall "wrapper"
+    wrapSendBytes :: (Ptr SerialTransport -> Word32 -> Ptr Word8 -> Word32 -> IO RawStatus)
+                  -> IO (FunPtr (Ptr SerialTransport -> Word32 -> Ptr Word8 -> Word32 -> IO RawStatus))
+
+foreign import ccall "wrapper"
+    wrapReceiveBytes :: (Ptr SerialTransport -> Word32 -> Ptr Word32 -> Ptr Word8 -> Word32 -> IO RawStatus)
+                     -> IO (FunPtr (Ptr SerialTransport -> Word32 -> Ptr Word32 -> Ptr Word8 -> Word32 -> IO RawStatus))
+
+foreign import ccall "wrapper"
+    wrapInit :: (Ptr SerialTransport -> Ptr () -> CString -> IO RawStatus)
+             -> IO (FunPtr (Ptr SerialTransport -> Ptr () -> CString -> IO RawStatus))
+
+funOpen :: FunPtr (Ptr SerialTransport -> IO RawStatus)
+{-# NOINLINE funOpen #-}
+funOpen = U.unsafePerformIO $ wrapOneArg testOpen
+
+funSendBytes :: FunPtr (Ptr SerialTransport -> Word32 -> Ptr Word8 -> Word32 -> IO RawStatus)
+{-# NOINLINE funSendBytes #-}
+funSendBytes = U.unsafePerformIO $ wrapSendBytes testSendBytes
+
+funReceiveBytes :: FunPtr (Ptr SerialTransport -> Word32 -> Ptr Word32 -> Ptr Word8 -> Word32 -> IO RawStatus)
+{-# NOINLINE funReceiveBytes #-}
+funReceiveBytes = U.unsafePerformIO $ wrapReceiveBytes testReceiveBytes
+
+funShutdown :: FunPtr (Ptr SerialTransport -> IO RawStatus)
+{-# NOINLINE funShutdown #-}
+funShutdown = U.unsafePerformIO $ wrapOneArg testShutdown
+
+funFlush :: FunPtr (Ptr SerialTransport -> IO RawStatus)
+{-# NOINLINE funFlush #-}
+funFlush = U.unsafePerformIO $ wrapOneArg testFlush
+
+funTransportInit :: FunPtr (Ptr SerialTransport -> Ptr () -> CString -> IO RawStatus)
+{-# NOINLINE funTransportInit #-}
+funTransportInit = U.unsafePerformIO $ wrapInit testTransportInit
+
+mkSerialTransport :: Ptr () -> SerialTransport
+mkSerialTransport cookie =
+  SerialTransport
+  { stCookie = cookie
+  , stOpen = funOpen
+  , stSendBytes = funSendBytes
+  , stReceiveBytes = funReceiveBytes
+  , stSetBaudRate = nullFunPtr
+  , stShutdown = funShutdown
+  , stFlush = funFlush
+  }
+
+getState :: Ptr SerialTransport -> IO SerialState
+getState p = do
+  st <- peek p
+  let stable = castPtrToStablePtr $ stCookie st
+  deRefStablePtr stable
+
+printIOException :: IOException -> IO ()
+printIOException = print
+
+testOpen :: Ptr SerialTransport -> IO RawStatus
+testOpen p = do
+  ss <- getState p
+  eth <- try $ T.readFile (ssFilename ss)
+  case eth of
+    Left exc -> do
+      printIOException exc
+      return failureStatus
+    Right txt -> do
+      writeIORef (ssNext ss) (T.lines txt)
+      return successStatus
+
+parseTransportLine :: T.Text -> (Maybe TransportDirection, B.ByteString)
+parseTransportLine txt =
+  let txt' = T.takeWhile (/= '|') txt
+      f d = if d == "Sending" then Tx else Rx
+      (dir, mbs) = case T.splitOn ":" txt' of
+                     [x] -> (Nothing, hexToBytes $ T.filter (/= ' ') x)
+                     [d, x] -> (Just (f d),
+                                Just $ T.encodeUtf8 $ T.dropWhile (not . isDigit) x)
+                     _ -> (Nothing, Just "")
+  in case mbs of
+       Nothing -> (dir, "barf!")
+       Just bs -> (dir, bs)
+
+parseTransport :: [T.Text]
+               -> Maybe (TransportDirection, B.ByteString, Double, [T.Text])
+parseTransport [] = Nothing
+parseTransport (t:ts) =
+  let (Just dir, bs) = parseTransportLine t
+      rest = takeWhile ((== Nothing) . fst) $ map parseTransportLine ts
+      leftover = drop (length rest) ts
+      bss = map snd rest
+      tm = read $ B8.unpack bs
+  in Just (dir, B.concat bss, tm, leftover)
+
+takeNext :: SerialState -> IO (Maybe (TransportDirection, B.ByteString, Double))
+takeNext ss = do
+  let ref = ssNext ss
+  ts <- readIORef ref
+  let result = parseTransport ts
+  case result of
+    Nothing -> return Nothing
+    Just (dir, bs, tm, ts') -> do
+      writeIORef ref ts'
+      return $ Just (dir, bs, tm)
+
+testSendBytes :: Ptr SerialTransport
+              -> Word32
+              -> Ptr Word8
+              -> Word32
+              -> IO RawStatus
+testSendBytes p len msg _ = do
+  ss <- getState p
+  nxt <- takeNext ss
+  case nxt of
+    Just (Tx, expected, tm) -> do
+      writeIORef (ssSendTime ss) tm
+      actual <- B.packCStringLen (castPtr msg, fromIntegral len)
+      if actual == expected
+        then return successStatus
+        else do
+        T.putStrLn ("expected <" <> bytesToHex expected <>
+                    ">, but got <" <> bytesToHex actual <> ">")
+        return failureStatus
+    x -> do
+      putStrLn $ "expected Tx, but got " ++ show x
+      return failureStatus
+
+computeDelay :: Double -> Double -> Int
+computeDelay oldTime newTime =
+  -- convert seconds to microseconds, and add a fudge factor of 10%
+  ceiling $ (newTime - oldTime) * 1.1e6
+
+getNextBytes :: SerialState -> IO (Either RawStatus B.ByteString)
+getNextBytes ss = do
+  leftover <- readIORef (ssLeftover ss)
+  if B.null leftover
+    then do
+    nxt <- takeNext ss
+    case nxt of
+      Just (Rx, bs, tm) -> do
+        sendTime <- readIORef (ssSendTime ss)
+        threadDelay $ computeDelay sendTime tm
+        return $ Right bs
+      x -> do
+        putStrLn $ "expected Rx, but got " ++ show x
+        return $ Left failureStatus
+    else return $ Right leftover
+
+testReceiveBytes :: Ptr SerialTransport
+                 -> Word32
+                 -> Ptr Word32
+                 -> Ptr Word8
+                 -> Word32
+                 -> IO RawStatus
+testReceiveBytes p len returnLen msg _ = do
+  ss <- getState p
+  eth <- getNextBytes ss
+  case eth of
+    Left status -> return status
+    Right bs -> do
+      let (bs1, bs2) = B.splitAt (fromIntegral len) bs
+      B.useAsCStringLen bs1 $ \(pChar, bsLen) -> do
+        poke returnLen (fromIntegral len)
+        copyArray msg (castPtr pChar) bsLen
+      writeIORef (ssLeftover ss) bs2
+      return successStatus
+
+testFlush :: Ptr SerialTransport -> IO RawStatus
+testFlush _ = return successStatus
+
+testShutdown :: Ptr SerialTransport -> IO RawStatus
+testShutdown p = do
+  st <- peek p
+  let stable = castPtrToStablePtr $ stCookie st
+  freeStablePtr stable
+  poke p st { stCookie = nullPtr }
+  return successStatus
+
+-- Somehow in Windows, we end up with an absolute path that
+-- starts with "/C:", which doesn't work, so we need to strip
+-- the leading slash.
+hackPath :: String -> String -> String
+hackPath "mingw32" = dropWhile (== '/')
+hackPath _ = id
+
+testTransportInit :: Ptr SerialTransport -> Ptr () -> CString -> IO RawStatus
+testTransportInit p _ cstr = do
+  fname <- hackPath os <$> peekCAString cstr
+  ref <- newIORef []
+  ref2 <- newIORef ""
+  ref3 <- newIORef 0
+  let ss = SerialState fname ref ref2 ref3
+  stable <- newStablePtr ss
+  let st = mkSerialTransport $ castStablePtrToPtr stable
+  poke p st
+  return successStatus
+
+registerTransportInit :: IO ()
+registerTransportInit = do
+  withCAString "test" $ \name -> do
+    status <- c_TMR_setSerialTransport name funTransportInit
+    when (status /= successStatus) $ fail "TMR_setSerialTransport failed"
diff --git a/tests/blockErase.result b/tests/blockErase.result
new file mode 100644
--- /dev/null
+++ b/tests/blockErase.result
@@ -0,0 +1,5 @@
+Right 1
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NULQ\134\SOH\a\SOH\135\ap\196\193", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 47646, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 18, trRssi = -44, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right ""
+Right 1
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NULQ\134\SOH\a\SOH\135\ap\196\193", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 47646, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 22, trRssi = -40, trFrequency = 918400, trTimestamp = 0, trData = "\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
diff --git a/tests/blockErase.transport b/tests/blockErase.transport
new file mode 100644
--- /dev/null
+++ b/tests/blockErase.transport
@@ -0,0 +1,118 @@
+Sending: VERSION                       1733450.679602521
+         ff 00 03 1d 0c                                    |.....|
+Received:VERSION                       1733450.684134700
+         ff 14 03 00 00 14 12 08  00 30 00 00 02 20 16 12  |.........0... ..|
+         13 01 07 01 02 00 00 00  10 1b 05                 |...........|
+Sending: GET_CURRENT_PROGRAM           1733450.684657205
+         ff 00 0c 1d 03                                    |.....|
+Received:GET_CURRENT_PROGRAM           1733450.686277606
+         ff 01 0c 00 00 52 63 03                           |.....Rc.|
+Sending: GET_POWER_MODE                1733450.686375908
+         ff 00 68 1d 67                                    |..h.g|
+Received:GET_POWER_MODE                1733450.688135301
+         ff 01 68 00 00 00 a4 bf                           |..h.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1733450.688284351
+         ff 02 6a 01 0e 2e 40                              |..j...@|
+Received:GET_READER_OPTIONAL_PARAMS    1733450.690435237
+         ff 03 6a 00 00 01 0e 00  30 44                    |..j.....0D|
+Sending: GET_READER_OPTIONAL_PARAMS    1733450.698289611
+         ff 02 6a 01 12 2e 5c                              |..j...\|
+Received:GET_READER_OPTIONAL_PARAMS    1733450.700384916
+         ff 04 6a 00 00 01 12 00  00 69 af                 |..j......i.|
+Sending: GET_TAG_PROTOCOL              1733450.700490046
+         ff 00 63 1d 6c                                    |..c.l|
+Received:GET_TAG_PROTOCOL              1733450.702188454
+         ff 02 63 00 00 00 05 21  46                       |..c....!F|
+Sending: GET_ANTENNA_PORT              1733450.702288657
+         ff 01 61 05 bd b8                                 |..a...|
+Received:GET_ANTENNA_PORT              1733450.704364082
+         ff 03 61 00 00 05 01 00  61 df                    |..a.....a.|
+Sending: GET_READER_OPTIONAL_PARAMS    1733450.704576636
+         ff 02 6a 01 0c 2e 42                              |..j...B|
+Received:GET_READER_OPTIONAL_PARAMS    1733450.706714766
+         ff 03 6a 00 00 01 0c 01  32 45                    |..j.....2E|
+Sending: GET_READER_OPTIONAL_PARAMS    1733450.706873798
+         ff 02 6a 01 0d 2e 43                              |..j...C|
+Received:GET_READER_OPTIONAL_PARAMS    1733450.709308529
+         ff 06 6a 00 00 01 0d 00  00 00 00 15 43           |..j.........C|
+Sending: SET_REGION                    1733450.709501081
+         ff 01 97 0d 4b b0                                 |....K.|
+Received:SET_REGION                    1733450.711348767
+         ff 00 97 00 00 77 9e                              |.....w.|
+Sending: SET_READ_TX_POWER             1733450.711558562
+         ff 02 92 08 98 49 c1                              |.....I.|
+Received:SET_READ_TX_POWER             1733450.713440798
+         ff 00 92 00 00 27 3b                              |.....';|
+Sending: SET_WRITE_TX_POWER            1733450.713578366
+         ff 02 94 08 98 29 07                              |.....).|
+Received:SET_WRITE_TX_POWER            1733450.715466506
+         ff 00 94 00 00 47 fd                              |.....G.|
+Sending: SET_ANTENNA_PORT              1733450.715640398
+         ff 02 91 01 01 70 3b                              |.....p;|
+Received:SET_ANTENNA_PORT              1733450.717565537
+         ff 00 91 00 00 17 58                              |......X|
+Sending: SET_READER_OPTIONAL_PARAMS    1733450.717697069
+         ff 03 9a 01 06 01 a9 5c                           |.......\|
+Received:SET_READER_OPTIONAL_PARAMS    1733450.719718857
+         ff 00 9a 00 00 a6 33                              |......3|
+Sending: GET_READER_STATS              1733450.719880829
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1733450.722077569
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1733450.722247530
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1733450.723941906
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1733450.724084225
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1733450.726101108
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1733450.726243987
+         ff 16 22 03 00 13 03 e8  00 00 00 00 00 00 00 00  |..".............|
+         40 00 01 02 03 04 05 06  07 8f 1e                 |@..........|
+Received:READ_TAG_ID_MULTIPLE          1733451.734947047
+         ff 07 22 00 00 03 00 13  00 00 00 01 65 8a        |..".........e.|
+Sending: GET_TAG_ID_BUFFER             1733451.735124397
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1733451.740349899
+         ff 26 29 00 00 01 ff 00  01 12 d4 11 0e 13 e8 00  |.&).............|
+         00 03 07 00 ae 05 00 00  00 00 80 30 00 e2 00 51  |...........0...Q|
+         86 01 07 01 87 07 70 c4  c1 ba 1e 47 2c           |......p....G,|
+Sending: ERASE_BLOCK_TAG_SPECIFIC      1733451.740792941
+         ff 1c 2e 03 e8 00 41 00  00 00 00 00 60 e2 00 51  |......A.....`..Q|
+         86 01 07 01 87 07 70 c4  c1 00 00 00 00 03 04 36  |......p........6|
+         2a                                                |*|
+Received:ERASE_BLOCK_TAG_SPECIFIC      1733451.774187155
+         ff 00 2e 00 00 41 6c                              |.....Al|
+Sending: GET_READER_STATS              1733451.774381812
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1733451.776784092
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1733451.776983355
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1733451.778708021
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1733451.778890524
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1733451.780914629
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1733451.781081920
+         ff 11 22 00 00 17 03 e8  01 09 28 07 d0 00 03 00  |..".......(.....|
+         00 00 00 20 49 70                                 |... Ip|
+Received:READ_TAG_ID_MULTIPLE          1733452.808667838
+         ff 4d 22 00 00 00 00 17  00 00 00 01 01 28 00 16  |.M"..........(..|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 e4 bf                                       |....|
+Sending: GET_TAG_ID_BUFFER             1733452.809593767
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1733452.820884567
+         ff 66 29 00 00 01 ff 00  01 16 d8 11 0e 03 80 00  |.f).............|
+         00 01 8f 00 ae 05 02 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 80 30 00 e2 00 51  |...........0...Q|
+         86 01 07 01 87 07 70 c4  c1 ba 1e 4b f7           |......p....K.|
diff --git a/tests/blockPermalockRead.result b/tests/blockPermalockRead.result
new file mode 100644
--- /dev/null
+++ b/tests/blockPermalockRead.result
@@ -0,0 +1,3 @@
+Right 1
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\SOH\134\DLEP\178\ENQ", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 17157, tdGen2 = Just (GEN2_TagData {g2Pc = "4\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 29, trRssi = -36, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right "\NUL\NUL"
diff --git a/tests/blockPermalockRead.transport b/tests/blockPermalockRead.transport
new file mode 100644
--- /dev/null
+++ b/tests/blockPermalockRead.transport
@@ -0,0 +1,86 @@
+Sending: VERSION                       1829051.749487169
+         ff 00 03 1d 0c                                    |.....|
+Received:VERSION                       1829051.754158098
+         ff 14 03 00 00 14 12 08  00 30 00 00 02 20 16 12  |.........0... ..|
+         13 01 07 01 02 00 00 00  10 1b 05                 |...........|
+Sending: GET_CURRENT_PROGRAM           1829051.754732547
+         ff 00 0c 1d 03                                    |.....|
+Received:GET_CURRENT_PROGRAM           1829051.756325310
+         ff 01 0c 00 00 52 63 03                           |.....Rc.|
+Sending: GET_POWER_MODE                1829051.756433837
+         ff 00 68 1d 67                                    |..h.g|
+Received:GET_POWER_MODE                1829051.758001346
+         ff 01 68 00 00 00 a4 bf                           |..h.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1829051.758097441
+         ff 02 6a 01 0e 2e 40                              |..j...@|
+Received:GET_READER_OPTIONAL_PARAMS    1829051.760214239
+         ff 03 6a 00 00 01 0e 00  30 44                    |..j.....0D|
+Sending: GET_READER_OPTIONAL_PARAMS    1829051.768183546
+         ff 02 6a 01 12 2e 5c                              |..j...\|
+Received:GET_READER_OPTIONAL_PARAMS    1829051.770281602
+         ff 04 6a 00 00 01 12 00  00 69 af                 |..j......i.|
+Sending: GET_TAG_PROTOCOL              1829051.770397735
+         ff 00 63 1d 6c                                    |..c.l|
+Received:GET_TAG_PROTOCOL              1829051.772015315
+         ff 02 63 00 00 00 05 21  46                       |..c....!F|
+Sending: GET_ANTENNA_PORT              1829051.772120484
+         ff 01 61 05 bd b8                                 |..a...|
+Received:GET_ANTENNA_PORT              1829051.774081569
+         ff 03 61 00 00 05 01 00  61 df                    |..a.....a.|
+Sending: GET_READER_OPTIONAL_PARAMS    1829051.774218216
+         ff 02 6a 01 0c 2e 42                              |..j...B|
+Received:GET_READER_OPTIONAL_PARAMS    1829051.776219065
+         ff 03 6a 00 00 01 0c 01  32 45                    |..j.....2E|
+Sending: GET_READER_OPTIONAL_PARAMS    1829051.776383680
+         ff 02 6a 01 0d 2e 43                              |..j...C|
+Received:GET_READER_OPTIONAL_PARAMS    1829051.778820450
+         ff 06 6a 00 00 01 0d 00  00 00 00 15 43           |..j.........C|
+Sending: SET_REGION                    1829051.779002895
+         ff 01 97 0d 4b b0                                 |....K.|
+Received:SET_REGION                    1829051.780904919
+         ff 00 97 00 00 77 9e                              |.....w.|
+Sending: SET_READ_TX_POWER             1829051.781086964
+         ff 02 92 08 98 49 c1                              |.....I.|
+Received:SET_READ_TX_POWER             1829051.782951692
+         ff 00 92 00 00 27 3b                              |.....';|
+Sending: SET_WRITE_TX_POWER            1829051.783084670
+         ff 02 94 08 98 29 07                              |.....).|
+Received:SET_WRITE_TX_POWER            1829051.784973813
+         ff 00 94 00 00 47 fd                              |.....G.|
+Sending: SET_ANTENNA_PORT              1829051.785227705
+         ff 02 91 01 01 70 3b                              |.....p;|
+Received:SET_ANTENNA_PORT              1829051.787167999
+         ff 00 91 00 00 17 58                              |......X|
+Sending: SET_READER_OPTIONAL_PARAMS    1829051.787303537
+         ff 03 9a 01 06 01 a9 5c                           |.......\|
+Received:SET_READER_OPTIONAL_PARAMS    1829051.789354238
+         ff 00 9a 00 00 a6 33                              |......3|
+Sending: GET_READER_STATS              1829051.789507837
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1829051.791778681
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1829051.791937775
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1829051.793646752
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1829051.793796892
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1829051.795843593
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1829051.795998706
+         ff 1a 22 03 00 13 03 e8  00 00 00 00 00 00 00 00  |..".............|
+         60 70 65 72 6d 61 6c 6f  63 6b 20 6d 65 0d 10     |`permalock me..|
+Received:READ_TAG_ID_MULTIPLE          1829052.807263318
+         ff 07 22 00 00 03 00 13  00 00 00 01 65 8a        |..".........e.|
+Sending: GET_TAG_ID_BUFFER             1829052.807500776
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1829052.813042126
+         ff 26 29 00 00 01 ff 00  01 1d dc 11 0e 13 e8 00  |.&).............|
+         00 03 66 00 ae 05 00 00  00 00 80 34 00 e2 00 00  |..f........4....|
+         15 86 0e 01 86 10 50 b2  05 43 05 c6 5e           |......P..C..^|
+Sending: ERASE_BLOCK_TAG_SPECIFIC      1829052.816943258
+         ff 1e 2e 03 e8 00 41 01  00 00 00 00 60 e2 00 00  |......A.....`...|
+         15 86 0e 01 86 10 50 b2  05 00 00 03 00 00 00 00  |......P.........|
+         01 66 1b                                          |.f.|
+Received:ERASE_BLOCK_TAG_SPECIFIC      1829052.840513132
+         ff 04 2e 00 00 41 01 00  00 de 5f                 |.....A...._|
diff --git a/tests/blockPermalockWrite.result b/tests/blockPermalockWrite.result
new file mode 100644
--- /dev/null
+++ b/tests/blockPermalockWrite.result
@@ -0,0 +1,38 @@
+Right 1
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\SOH\134\DLEP\178\ENQ", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 17157, tdGen2 = Just (GEN2_TagData {g2Pc = "4\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 29, trRssi = -36, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right ""
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Right ""
+Right ""
+Right ""
+Right ""
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Right ""
+Right ""
+Right ""
+Right ""
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Right ""
+Right ""
+Right ""
+Right ""
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Right ""
+Right ""
+Right ""
+Right ""
+Right 1
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\SOH\134\DLEP\178\ENQ", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 17157, tdGen2 = Just (GEN2_TagData {g2Pc = "4\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 22, trRssi = -34, trFrequency = 921600, trTimestamp = 0, trData = "permaloc\NUL\EOT\NUL\ENQ\NUL\ACK\NUL\a        \NUL\f\NUL\r\NUL\SO\NUL\SI        \NUL\DC4\NUL\NAK\NUL\SYN\NUL\ETB        \NUL\FS\NUL\GS\NUL\RS\NUL\US", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right "\170\NUL"
diff --git a/tests/blockPermalockWrite.transport b/tests/blockPermalockWrite.transport
new file mode 100644
--- /dev/null
+++ b/tests/blockPermalockWrite.transport
@@ -0,0 +1,284 @@
+Sending: VERSION                       1829749.010225401
+         ff 00 03 1d 0c                                    |.....|
+Received:VERSION                       1829749.013984210
+         ff 14 03 00 00 14 12 08  00 30 00 00 02 20 16 12  |.........0... ..|
+         13 01 07 01 02 00 00 00  10 1b 05                 |...........|
+Sending: GET_CURRENT_PROGRAM           1829749.014793598
+         ff 00 0c 1d 03                                    |.....|
+Received:GET_CURRENT_PROGRAM           1829749.016562806
+         ff 01 0c 00 00 52 63 03                           |.....Rc.|
+Sending: GET_POWER_MODE                1829749.016810252
+         ff 00 68 1d 67                                    |..h.g|
+Received:GET_POWER_MODE                1829749.018482575
+         ff 01 68 00 00 00 a4 bf                           |..h.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1829749.018608322
+         ff 02 6a 01 0e 2e 40                              |..j...@|
+Received:GET_READER_OPTIONAL_PARAMS    1829749.020623429
+         ff 03 6a 00 00 01 0e 00  30 44                    |..j.....0D|
+Sending: GET_READER_OPTIONAL_PARAMS    1829749.021754159
+         ff 02 6a 01 12 2e 5c                              |..j...\|
+Received:GET_READER_OPTIONAL_PARAMS    1829749.023878015
+         ff 04 6a 00 00 01 12 00  00 69 af                 |..j......i.|
+Sending: GET_TAG_PROTOCOL              1829749.024026326
+         ff 00 63 1d 6c                                    |..c.l|
+Received:GET_TAG_PROTOCOL              1829749.025740344
+         ff 02 63 00 00 00 05 21  46                       |..c....!F|
+Sending: GET_ANTENNA_PORT              1829749.025881277
+         ff 01 61 05 bd b8                                 |..a...|
+Received:GET_ANTENNA_PORT              1829749.027831871
+         ff 03 61 00 00 05 01 00  61 df                    |..a.....a.|
+Sending: GET_READER_OPTIONAL_PARAMS    1829749.027988101
+         ff 02 6a 01 0c 2e 42                              |..j...B|
+Received:GET_READER_OPTIONAL_PARAMS    1829749.029953161
+         ff 03 6a 00 00 01 0c 01  32 45                    |..j.....2E|
+Sending: GET_READER_OPTIONAL_PARAMS    1829749.030069038
+         ff 02 6a 01 0d 2e 43                              |..j...C|
+Received:GET_READER_OPTIONAL_PARAMS    1829749.032468987
+         ff 06 6a 00 00 01 0d 00  00 00 00 15 43           |..j.........C|
+Sending: SET_REGION                    1829749.032668048
+         ff 01 97 0d 4b b0                                 |....K.|
+Received:SET_REGION                    1829749.034531357
+         ff 00 97 00 00 77 9e                              |.....w.|
+Sending: SET_READ_TX_POWER             1829749.034720522
+         ff 02 92 08 98 49 c1                              |.....I.|
+Received:SET_READ_TX_POWER             1829749.036607567
+         ff 00 92 00 00 27 3b                              |.....';|
+Sending: SET_WRITE_TX_POWER            1829749.036735988
+         ff 02 94 08 98 29 07                              |.....).|
+Received:SET_WRITE_TX_POWER            1829749.038506907
+         ff 00 94 00 00 47 fd                              |.....G.|
+Sending: SET_ANTENNA_PORT              1829749.038650766
+         ff 02 91 01 01 70 3b                              |.....p;|
+Received:SET_ANTENNA_PORT              1829749.040334163
+         ff 00 91 00 00 17 58                              |......X|
+Sending: SET_READER_OPTIONAL_PARAMS    1829749.040436892
+         ff 03 9a 01 06 01 a9 5c                           |.......\|
+Received:SET_READER_OPTIONAL_PARAMS    1829749.042469035
+         ff 00 9a 00 00 a6 33                              |......3|
+Sending: GET_READER_STATS              1829749.042628435
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1829749.044924815
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1829749.045087626
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1829749.046781026
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1829749.046931097
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1829749.048977941
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1829749.049135083
+         ff 1a 22 03 00 13 03 e8  00 00 00 00 00 00 00 00  |..".............|
+         60 70 65 72 6d 61 6c 6f  63 6b 20 6d 65 0d 10     |`permalock me..|
+Received:READ_TAG_ID_MULTIPLE          1829750.056628187
+         ff 07 22 00 00 03 00 13  00 00 00 01 65 8a        |..".........e.|
+Sending: GET_TAG_ID_BUFFER             1829750.056804295
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1829750.062018018
+         ff 26 29 00 00 01 ff 00  01 1d dc 11 0e 13 e8 00  |.&).............|
+         00 03 0b 00 ae 05 00 00  00 00 80 34 00 e2 00 00  |...........4....|
+         15 86 0e 01 86 10 50 b2  05 43 05 9e 57           |......P..C..W|
+Sending: ERASE_BLOCK_TAG_SPECIFIC      1829750.065369420
+         ff 20 2e 03 e8 00 41 01  00 00 00 00 60 e2 00 00  |. ....A.....`...|
+         15 86 0e 01 86 10 50 b2  05 00 01 03 00 00 00 00  |......P.........|
+         01 aa 00 60 1e                                    |...`.|
+Received:ERASE_BLOCK_TAG_SPECIFIC      1829750.112401542
+         ff 00 2e 00 00 41 6c                              |.....Al|
+Sending: WRITE_TAG_DATA                1829750.112821077
+         ff 1b 24 03 e8 01 00 00  00 00 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 00 12 f7  |.........P......|
+Received:WRITE_TAG_DATA                1829751.142148716
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829751.142397556
+         ff 1b 24 03 e8 01 00 00  00 01 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 01 cc e9  |.........P......|
+Received:WRITE_TAG_DATA                1829752.152142164
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829752.152418941
+         ff 1b 24 03 e8 01 00 00  00 02 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 02 be ea  |.........P......|
+Received:WRITE_TAG_DATA                1829753.171222351
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829753.171502860
+         ff 1b 24 03 e8 01 00 00  00 03 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 03 60 f4  |.........P....`.|
+Received:WRITE_TAG_DATA                1829754.193508531
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829754.193796103
+         ff 1b 24 03 e8 01 00 00  00 04 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 04 5a ec  |.........P....Z.|
+Received:WRITE_TAG_DATA                1829754.222549247
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829754.222738514
+         ff 1b 24 03 e8 01 00 00  00 05 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 05 84 f2  |.........P......|
+Received:WRITE_TAG_DATA                1829754.251609957
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829754.251872514
+         ff 1b 24 03 e8 01 00 00  00 06 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 06 f6 f1  |.........P......|
+Received:WRITE_TAG_DATA                1829754.280762468
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829754.281006941
+         ff 1b 24 03 e8 01 00 00  00 07 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 07 28 ef  |.........P....(.|
+Received:WRITE_TAG_DATA                1829754.309970159
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829754.310172608
+         ff 1b 24 03 e8 01 00 00  00 08 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 08 82 c1  |.........P......|
+Received:WRITE_TAG_DATA                1829755.346791842
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829755.347092306
+         ff 1b 24 03 e8 01 00 00  00 09 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 09 5c df  |.........P....\.|
+Received:WRITE_TAG_DATA                1829756.380042974
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829756.380287524
+         ff 1b 24 03 e8 01 00 00  00 0a 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 0a 2e dc  |.........P......|
+Received:WRITE_TAG_DATA                1829757.407129848
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829757.407368360
+         ff 1b 24 03 e8 01 00 00  00 0b 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 0b f0 c2  |.........P......|
+Received:WRITE_TAG_DATA                1829758.440289154
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829758.440490255
+         ff 1b 24 03 e8 01 00 00  00 0c 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 0c ca da  |.........P......|
+Received:WRITE_TAG_DATA                1829758.469259190
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829758.469522032
+         ff 1b 24 03 e8 01 00 00  00 0d 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 0d 14 c4  |.........P......|
+Received:WRITE_TAG_DATA                1829758.498531273
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829758.498805425
+         ff 1b 24 03 e8 01 00 00  00 0e 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 0e 66 c7  |.........P....f.|
+Received:WRITE_TAG_DATA                1829758.527733252
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829758.527982849
+         ff 1b 24 03 e8 01 00 00  00 0f 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 0f b8 d9  |.........P......|
+Received:WRITE_TAG_DATA                1829758.556692351
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829758.556900495
+         ff 1b 24 03 e8 01 00 00  00 10 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 10 22 ba  |.........P....".|
+Received:WRITE_TAG_DATA                1829759.593563381
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829759.593731843
+         ff 1b 24 03 e8 01 00 00  00 11 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 11 fc a4  |.........P......|
+Received:WRITE_TAG_DATA                1829760.623955751
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829760.624235451
+         ff 1b 24 03 e8 01 00 00  00 12 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 12 8e a7  |.........P......|
+Received:WRITE_TAG_DATA                1829761.652961247
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829761.653243691
+         ff 1b 24 03 e8 01 00 00  00 13 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 13 50 b9  |.........P....P.|
+Received:WRITE_TAG_DATA                1829762.665276942
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829762.665494236
+         ff 1b 24 03 e8 01 00 00  00 14 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 14 6a a1  |.........P....j.|
+Received:WRITE_TAG_DATA                1829762.694120598
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829762.694383889
+         ff 1b 24 03 e8 01 00 00  00 15 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 15 b4 bf  |.........P......|
+Received:WRITE_TAG_DATA                1829762.751451949
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829762.751713427
+         ff 1b 24 03 e8 01 00 00  00 16 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 16 c6 bc  |.........P......|
+Received:WRITE_TAG_DATA                1829762.780199308
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829762.780457877
+         ff 1b 24 03 e8 01 00 00  00 17 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 17 18 a2  |.........P......|
+Received:WRITE_TAG_DATA                1829762.809239881
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829762.809503379
+         ff 1b 24 03 e8 01 00 00  00 18 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 18 b2 8c  |.........P......|
+Received:WRITE_TAG_DATA                1829763.842151363
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829763.842308880
+         ff 1b 24 03 e8 01 00 00  00 19 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 19 6c 92  |.........P....l.|
+Received:WRITE_TAG_DATA                1829764.873162970
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829764.873443541
+         ff 1b 24 03 e8 01 00 00  00 1a 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 1a 1e 91  |.........P......|
+Received:WRITE_TAG_DATA                1829765.879579000
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829765.879851392
+         ff 1b 24 03 e8 01 00 00  00 1b 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 1b c0 8f  |.........P......|
+Received:WRITE_TAG_DATA                1829766.888892450
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: WRITE_TAG_DATA                1829766.889180097
+         ff 1b 24 03 e8 01 00 00  00 1c 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 1c fa 97  |.........P......|
+Received:WRITE_TAG_DATA                1829766.918023959
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829766.918292458
+         ff 1b 24 03 e8 01 00 00  00 1d 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 1d 24 89  |.........P....$.|
+Received:WRITE_TAG_DATA                1829766.946906138
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829766.947094131
+         ff 1b 24 03 e8 01 00 00  00 1e 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 1e 56 8a  |.........P....V.|
+Received:WRITE_TAG_DATA                1829766.975771316
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: WRITE_TAG_DATA                1829766.976106491
+         ff 1b 24 03 e8 01 00 00  00 1f 03 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 00 1f 88 94  |.........P......|
+Received:WRITE_TAG_DATA                1829767.004705226
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: GET_READER_STATS              1829767.004898988
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1829767.007163224
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1829767.007420284
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1829767.009235148
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1829767.009451929
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1829767.011452983
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1829767.011619788
+         ff 11 22 00 00 17 03 e8  01 09 28 07 d0 00 03 00  |..".......(.....|
+         00 00 00 20 49 70                                 |... Ip|
+Received:READ_TAG_ID_MULTIPLE          1829768.032941727
+         ff 4d 22 00 00 00 00 17  00 00 00 01 01 28 00 16  |.M"..........(..|
+         00 00 70 65 72 6d 61 6c  6f 63 00 04 00 05 00 06  |..permaloc......|
+         00 07 20 20 20 20 20 20  20 20 00 0c 00 0d 00 0e  |..        ......|
+         00 0f 20 20 20 20 20 20  20 20 00 14 00 15 00 16  |..        ......|
+         00 17 20 20 20 20 20 20  20 20 00 1c 00 1d 00 1e  |..        ......|
+         00 1f c4 38                                       |...8|
+Sending: GET_TAG_ID_BUFFER             1829768.033538854
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1829768.044502944
+         ff 66 29 00 00 01 ff 00  01 16 de 11 0e 10 00 00  |.f).............|
+         00 00 16 00 ae 05 02 00  70 65 72 6d 61 6c 6f 63  |........permaloc|
+         00 04 00 05 00 06 00 07  20 20 20 20 20 20 20 20  |........        |
+         00 0c 00 0d 00 0e 00 0f  20 20 20 20 20 20 20 20  |........        |
+         00 14 00 15 00 16 00 17  20 20 20 20 20 20 20 20  |........        |
+         00 1c 00 1d 00 1e 00 1f  00 00 80 34 00 e2 00 00  |...........4....|
+         15 86 0e 01 86 10 50 b2  05 43 05 90 67           |......P..C..g|
+Sending: ERASE_BLOCK_TAG_SPECIFIC      1829768.045283520
+         ff 1e 2e 03 e8 00 41 01  00 00 00 00 60 e2 00 00  |......A.....`...|
+         15 86 0e 01 86 10 50 b2  05 00 00 03 00 00 00 00  |......P.........|
+         01 66 1b                                          |.f.|
+Received:ERASE_BLOCK_TAG_SPECIFIC      1829768.068511562
+         ff 04 2e 00 00 41 01 aa  00 74 5f                 |.....A...t_|
diff --git a/tests/blockWrite.result b/tests/blockWrite.result
new file mode 100644
--- /dev/null
+++ b/tests/blockWrite.result
@@ -0,0 +1,5 @@
+Right 1
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NULQ\134\SOH\a\SOH\135\ap\196\193", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 47646, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 22, trRssi = -42, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right ""
+Right 1
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NULQ\134\SOH\a\SOH\135\ap\196\193", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 47646, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 21, trRssi = -40, trFrequency = 918400, trTimestamp = 0, trData = "\NUL\SOH\STX\ETX\EOT\ENQ\ACK\a\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL456789:;<=>?", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
diff --git a/tests/blockWrite.transport b/tests/blockWrite.transport
new file mode 100644
--- /dev/null
+++ b/tests/blockWrite.transport
@@ -0,0 +1,118 @@
+Sending: VERSION                       1733235.445865270
+         ff 00 03 1d 0c                                    |.....|
+Received:VERSION                       1733235.450593149
+         ff 14 03 00 00 14 12 08  00 30 00 00 02 20 16 12  |.........0... ..|
+         13 01 07 01 02 00 00 00  10 1b 05                 |...........|
+Sending: GET_CURRENT_PROGRAM           1733235.451166815
+         ff 00 0c 1d 03                                    |.....|
+Received:GET_CURRENT_PROGRAM           1733235.452792849
+         ff 01 0c 00 00 52 63 03                           |.....Rc.|
+Sending: GET_POWER_MODE                1733235.452909508
+         ff 00 68 1d 67                                    |..h.g|
+Received:GET_POWER_MODE                1733235.454483132
+         ff 01 68 00 00 00 a4 bf                           |..h.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1733235.454584834
+         ff 02 6a 01 0e 2e 40                              |..j...@|
+Received:GET_READER_OPTIONAL_PARAMS    1733235.456720836
+         ff 03 6a 00 00 01 0e 00  30 44                    |..j.....0D|
+Sending: GET_READER_OPTIONAL_PARAMS    1733235.464524663
+         ff 02 6a 01 12 2e 5c                              |..j...\|
+Received:GET_READER_OPTIONAL_PARAMS    1733235.466891122
+         ff 04 6a 00 00 01 12 00  00 69 af                 |..j......i.|
+Sending: GET_TAG_PROTOCOL              1733235.467046237
+         ff 00 63 1d 6c                                    |..c.l|
+Received:GET_TAG_PROTOCOL              1733235.468960694
+         ff 02 63 00 00 00 05 21  46                       |..c....!F|
+Sending: GET_ANTENNA_PORT              1733235.469176660
+         ff 01 61 05 bd b8                                 |..a...|
+Received:GET_ANTENNA_PORT              1733235.471205061
+         ff 03 61 00 00 05 01 00  61 df                    |..a.....a.|
+Sending: GET_READER_OPTIONAL_PARAMS    1733235.471393661
+         ff 02 6a 01 0c 2e 42                              |..j...B|
+Received:GET_READER_OPTIONAL_PARAMS    1733235.473331463
+         ff 03 6a 00 00 01 0c 01  32 45                    |..j.....2E|
+Sending: GET_READER_OPTIONAL_PARAMS    1733235.473436213
+         ff 02 6a 01 0d 2e 43                              |..j...C|
+Received:GET_READER_OPTIONAL_PARAMS    1733235.475652405
+         ff 06 6a 00 00 01 0d 00  00 00 00 15 43           |..j.........C|
+Sending: SET_REGION                    1733235.475787800
+         ff 01 97 0d 4b b0                                 |....K.|
+Received:SET_REGION                    1733235.477440297
+         ff 00 97 00 00 77 9e                              |.....w.|
+Sending: SET_READ_TX_POWER             1733235.477572174
+         ff 02 92 08 98 49 c1                              |.....I.|
+Received:SET_READ_TX_POWER             1733235.479231984
+         ff 00 92 00 00 27 3b                              |.....';|
+Sending: SET_WRITE_TX_POWER            1733235.479325942
+         ff 02 94 08 98 29 07                              |.....).|
+Received:SET_WRITE_TX_POWER            1733235.480974365
+         ff 00 94 00 00 47 fd                              |.....G.|
+Sending: SET_ANTENNA_PORT              1733235.481085977
+         ff 02 91 01 01 70 3b                              |.....p;|
+Received:SET_ANTENNA_PORT              1733235.482945579
+         ff 00 91 00 00 17 58                              |......X|
+Sending: SET_READER_OPTIONAL_PARAMS    1733235.483086775
+         ff 03 9a 01 06 01 a9 5c                           |.......\|
+Received:SET_READER_OPTIONAL_PARAMS    1733235.485124382
+         ff 00 9a 00 00 a6 33                              |......3|
+Sending: GET_READER_STATS              1733235.485409960
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1733235.487718897
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1733235.487877132
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1733235.489434618
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1733235.489576531
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1733235.491653350
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1733235.491795994
+         ff 10 22 03 00 13 03 e8  00 00 00 00 00 00 00 00  |..".............|
+         10 00 00 86 a3                                    |.....|
+Received:READ_TAG_ID_MULTIPLE          1733236.497741270
+         ff 07 22 00 00 03 00 13  00 00 00 01 65 8a        |..".........e.|
+Sending: GET_TAG_ID_BUFFER             1733236.498026395
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1733236.503600010
+         ff 26 29 00 00 01 ff 00  01 16 d6 11 0e 13 e8 00  |.&).............|
+         00 03 29 00 ae 05 00 00  00 00 80 30 00 e2 00 51  |..)........0...Q|
+         86 01 07 01 87 07 70 c4  c1 ba 1e 08 aa           |......p......|
+Sending: WRITE_TAG_SPECIFIC            1733236.504361013
+         ff 26 2d 03 e8 00 41 00  c7 00 00 00 00 60 e2 00  |.&-...A......`..|
+         51 86 01 07 01 87 07 70  c4 c1 00 03 00 00 00 00  |Q......p........|
+         04 00 01 02 03 04 05 06  07 f3 66                 |..........f|
+Received:WRITE_TAG_SPECIFIC            1733236.536904406
+         ff 04 2d 00 00 00 41 00  c7 46 73                 |..-...A..Fs|
+Sending: GET_READER_STATS              1733236.537262949
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1733236.539475858
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1733236.539649148
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1733236.541393558
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1733236.541581880
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1733236.543666695
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1733236.543972909
+         ff 11 22 00 00 17 03 e8  01 09 28 07 d0 00 03 00  |..".......(.....|
+         00 00 00 20 49 70                                 |... Ip|
+Received:READ_TAG_ID_MULTIPLE          1733237.559689784
+         ff 4d 22 00 00 00 00 17  00 00 00 01 01 28 00 15  |.M"..........(..|
+         00 00 00 01 02 03 04 05  06 07 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 34 35  36 37 38 39 3a 3b 3c 3d  |......456789:;<=|
+         3e 3f 14 7a                                       |>?.z|
+Sending: GET_TAG_ID_BUFFER             1733237.560562427
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1733237.571772759
+         ff 66 29 00 00 01 ff 00  01 15 d8 11 0e 03 80 00  |.f).............|
+         00 01 a1 00 ae 05 02 00  00 01 02 03 04 05 06 07  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 34 35 36 37  |............4567|
+         38 39 3a 3b 3c 3d 3e 3f  00 00 80 30 00 e2 00 51  |89:;<=>?...0...Q|
+         86 01 07 01 87 07 70 c4  c1 ba 1e 59 6d           |......p....Ym|
diff --git a/tests/gpi.result b/tests/gpi.result
new file mode 100644
--- /dev/null
+++ b/tests/gpi.result
@@ -0,0 +1,1 @@
+Right [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = True, gpOutput = False}]
diff --git a/tests/gpi.transport b/tests/gpi.transport
new file mode 100644
--- /dev/null
+++ b/tests/gpi.transport
@@ -0,0 +1,58 @@
+Sending: VERSION                       1618349.830532032
+         ff 00 03 1d 0c                                    |.....|
+Received:VERSION                       1618349.834088647
+         ff 14 03 00 00 14 12 08  00 30 00 00 02 20 16 12  |.........0... ..|
+         13 01 07 01 02 00 00 00  10 1b 05                 |...........|
+Sending: GET_CURRENT_PROGRAM           1618349.834651661
+         ff 00 0c 1d 03                                    |.....|
+Received:GET_CURRENT_PROGRAM           1618349.836219541
+         ff 01 0c 00 00 52 63 03                           |.....Rc.|
+Sending: GET_POWER_MODE                1618349.836338063
+         ff 00 68 1d 67                                    |..h.g|
+Received:GET_POWER_MODE                1618349.838107299
+         ff 01 68 00 00 00 a4 bf                           |..h.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1618349.838259128
+         ff 02 6a 01 0e 2e 40                              |..j...@|
+Received:GET_READER_OPTIONAL_PARAMS    1618349.840405018
+         ff 03 6a 00 00 01 0e 00  30 44                    |..j.....0D|
+Sending: GET_READER_OPTIONAL_PARAMS    1618349.841446339
+         ff 02 6a 01 12 2e 5c                              |..j...\|
+Received:GET_READER_OPTIONAL_PARAMS    1618349.843738766
+         ff 04 6a 00 00 01 12 00  00 69 af                 |..j......i.|
+Sending: GET_TAG_PROTOCOL              1618349.843921112
+         ff 00 63 1d 6c                                    |..c.l|
+Received:GET_TAG_PROTOCOL              1618349.845804952
+         ff 02 63 00 00 00 05 21  46                       |..c....!F|
+Sending: GET_ANTENNA_PORT              1618349.845969838
+         ff 01 61 05 bd b8                                 |..a...|
+Received:GET_ANTENNA_PORT              1618349.848073650
+         ff 03 61 00 00 05 01 00  61 df                    |..a.....a.|
+Sending: GET_READER_OPTIONAL_PARAMS    1618349.848306062
+         ff 02 6a 01 0c 2e 42                              |..j...B|
+Received:GET_READER_OPTIONAL_PARAMS    1618349.850482317
+         ff 03 6a 00 00 01 0c 01  32 45                    |..j.....2E|
+Sending: GET_READER_OPTIONAL_PARAMS    1618349.850695273
+         ff 02 6a 01 0d 2e 43                              |..j...C|
+Received:GET_READER_OPTIONAL_PARAMS    1618349.853152056
+         ff 06 6a 00 00 01 0d 00  00 00 00 15 43           |..j.........C|
+Sending: SET_USER_GPIO_OUTPUTS         1618349.853335246
+         ff 04 96 01 01 00 00 2d  68                       |.......-h|
+Received:SET_USER_GPIO_OUTPUTS         1618349.855303359
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618349.855484441
+         ff 04 96 01 02 00 00 1d  0b                       |.........|
+Received:SET_USER_GPIO_OUTPUTS         1618349.857372145
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618349.857457353
+         ff 04 96 01 03 00 00 0d  2a                       |........*|
+Received:SET_USER_GPIO_OUTPUTS         1618349.859481273
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618349.859607401
+         ff 04 96 01 04 00 00 7d  cd                       |.......}.|
+Received:SET_USER_GPIO_OUTPUTS         1618349.861699382
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: GET_USER_GPIO_INPUTS          1618349.861992903
+         ff 01 66 01 ba bc                                 |..f...|
+Received:GET_USER_GPIO_INPUTS          1618349.864881787
+         ff 0d 66 00 00 01 01 00  00 02 00 00 03 00 00 04  |..f.............|
+         00 01 64 46                                       |..dF|
diff --git a/tests/gpo.result b/tests/gpo.result
new file mode 100644
--- /dev/null
+++ b/tests/gpo.result
diff --git a/tests/gpo.transport b/tests/gpo.transport
new file mode 100644
--- /dev/null
+++ b/tests/gpo.transport
@@ -0,0 +1,117 @@
+Sending: VERSION                       1618318.942992850
+         ff 00 03 1d 0c                                    |.....|
+Received:VERSION                       1618318.946535066
+         ff 14 03 00 00 14 12 08  00 30 00 00 02 20 16 12  |.........0... ..|
+         13 01 07 01 02 00 00 00  10 1b 05                 |...........|
+Sending: GET_CURRENT_PROGRAM           1618318.947020444
+         ff 00 0c 1d 03                                    |.....|
+Received:GET_CURRENT_PROGRAM           1618318.948566726
+         ff 01 0c 00 00 52 63 03                           |.....Rc.|
+Sending: GET_POWER_MODE                1618318.948717066
+         ff 00 68 1d 67                                    |..h.g|
+Received:GET_POWER_MODE                1618318.950309705
+         ff 01 68 00 00 00 a4 bf                           |..h.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1618318.950404769
+         ff 02 6a 01 0e 2e 40                              |..j...@|
+Received:GET_READER_OPTIONAL_PARAMS    1618318.952376555
+         ff 03 6a 00 00 01 0e 00  30 44                    |..j.....0D|
+Sending: GET_READER_OPTIONAL_PARAMS    1618318.953236827
+         ff 02 6a 01 12 2e 5c                              |..j...\|
+Received:GET_READER_OPTIONAL_PARAMS    1618318.955499201
+         ff 04 6a 00 00 01 12 00  00 69 af                 |..j......i.|
+Sending: GET_TAG_PROTOCOL              1618318.955666882
+         ff 00 63 1d 6c                                    |..c.l|
+Received:GET_TAG_PROTOCOL              1618318.957566645
+         ff 02 63 00 00 00 05 21  46                       |..c....!F|
+Sending: GET_ANTENNA_PORT              1618318.957735305
+         ff 01 61 05 bd b8                                 |..a...|
+Received:GET_ANTENNA_PORT              1618318.959879076
+         ff 03 61 00 00 05 01 00  61 df                    |..a.....a.|
+Sending: GET_READER_OPTIONAL_PARAMS    1618318.960104443
+         ff 02 6a 01 0c 2e 42                              |..j...B|
+Received:GET_READER_OPTIONAL_PARAMS    1618318.962299514
+         ff 03 6a 00 00 01 0c 01  32 45                    |..j.....2E|
+Sending: GET_READER_OPTIONAL_PARAMS    1618318.962561529
+         ff 02 6a 01 0d 2e 43                              |..j...C|
+Received:GET_READER_OPTIONAL_PARAMS    1618318.965031538
+         ff 06 6a 00 00 01 0d 00  00 00 00 15 43           |..j.........C|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.965276377
+         ff 04 96 01 01 01 00 2c  68                       |.......,h|
+Received:SET_USER_GPIO_OUTPUTS         1618318.967228964
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.967416136
+         ff 04 96 01 02 01 00 1c  0b                       |.........|
+Received:SET_USER_GPIO_OUTPUTS         1618318.969281000
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.969370599
+         ff 04 96 01 03 01 00 0c  2a                       |........*|
+Received:SET_USER_GPIO_OUTPUTS         1618318.971406485
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.971538137
+         ff 04 96 01 04 01 00 7c  cd                       |.......|.|
+Received:SET_USER_GPIO_OUTPUTS         1618318.973585255
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.973773431
+         ff 02 96 01 01 00 dc                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618318.975520311
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.975658272
+         ff 02 96 02 00 03 dd                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618318.977385363
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.977471678
+         ff 02 96 03 00 02 dd                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618318.979121138
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.979212246
+         ff 02 96 04 00 05 dd                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618318.981086248
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.981222933
+         ff 02 96 01 00 00 dd                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618318.983093686
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.983221881
+         ff 02 96 02 01 03 dc                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618318.985118247
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.985257581
+         ff 02 96 03 00 02 dd                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618318.987180140
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.987332353
+         ff 02 96 04 00 05 dd                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618318.989201090
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.989345414
+         ff 02 96 01 00 00 dd                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618318.991214250
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.991343106
+         ff 02 96 02 00 03 dd                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618318.993198749
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.993376145
+         ff 02 96 03 01 02 dc                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618318.995161980
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.995420491
+         ff 02 96 04 00 05 dd                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618318.997327262
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.997461552
+         ff 02 96 01 00 00 dd                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618318.999330677
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618318.999462362
+         ff 02 96 02 00 03 dd                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618319.001219823
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618319.001349635
+         ff 02 96 03 00 02 dd                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618319.002983389
+         ff 00 96 00 00 67 bf                              |.....g.|
+Sending: SET_USER_GPIO_OUTPUTS         1618319.003060700
+         ff 02 96 04 01 05 dc                              |.......|
+Received:SET_USER_GPIO_OUTPUTS         1618319.004690734
+         ff 00 96 00 00 67 bf                              |.....g.|
diff --git a/tests/kill.result b/tests/kill.result
new file mode 100644
--- /dev/null
+++ b/tests/kill.result
@@ -0,0 +1,5 @@
+Right 1
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\SOH\134\DLEP\178\ENQ", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 17157, tdGen2 = Just (GEN2_TagData {g2Pc = "4\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 27, trRssi = -36, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right ""
+Right ""
+Right 0
diff --git a/tests/kill.transport b/tests/kill.transport
new file mode 100644
--- /dev/null
+++ b/tests/kill.transport
@@ -0,0 +1,111 @@
+Sending: VERSION                       1831074.447420502
+         ff 00 03 1d 0c                                    |.....|
+Received:VERSION                       1831074.452022120
+         ff 14 03 00 00 14 12 08  00 30 00 00 02 20 16 12  |.........0... ..|
+         13 01 07 01 02 00 00 00  10 1b 05                 |...........|
+Sending: GET_CURRENT_PROGRAM           1831074.452559544
+         ff 00 0c 1d 03                                    |.....|
+Received:GET_CURRENT_PROGRAM           1831074.454340797
+         ff 01 0c 00 00 52 63 03                           |.....Rc.|
+Sending: GET_POWER_MODE                1831074.454531231
+         ff 00 68 1d 67                                    |..h.g|
+Received:GET_POWER_MODE                1831074.456343322
+         ff 01 68 00 00 00 a4 bf                           |..h.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1831074.456488564
+         ff 02 6a 01 0e 2e 40                              |..j...@|
+Received:GET_READER_OPTIONAL_PARAMS    1831074.458682283
+         ff 03 6a 00 00 01 0e 00  30 44                    |..j.....0D|
+Sending: GET_READER_OPTIONAL_PARAMS    1831074.466612730
+         ff 02 6a 01 12 2e 5c                              |..j...\|
+Received:GET_READER_OPTIONAL_PARAMS    1831074.468769754
+         ff 04 6a 00 00 01 12 00  00 69 af                 |..j......i.|
+Sending: GET_TAG_PROTOCOL              1831074.468885509
+         ff 00 63 1d 6c                                    |..c.l|
+Received:GET_TAG_PROTOCOL              1831074.470567920
+         ff 02 63 00 00 00 05 21  46                       |..c....!F|
+Sending: GET_ANTENNA_PORT              1831074.470671618
+         ff 01 61 05 bd b8                                 |..a...|
+Received:GET_ANTENNA_PORT              1831074.472597812
+         ff 03 61 00 00 05 01 00  61 df                    |..a.....a.|
+Sending: GET_READER_OPTIONAL_PARAMS    1831074.472737097
+         ff 02 6a 01 0c 2e 42                              |..j...B|
+Received:GET_READER_OPTIONAL_PARAMS    1831074.474854214
+         ff 03 6a 00 00 01 0c 01  32 45                    |..j.....2E|
+Sending: GET_READER_OPTIONAL_PARAMS    1831074.475006893
+         ff 02 6a 01 0d 2e 43                              |..j...C|
+Received:GET_READER_OPTIONAL_PARAMS    1831074.477456734
+         ff 06 6a 00 00 01 0d 00  00 00 00 15 43           |..j.........C|
+Sending: SET_REGION                    1831074.477619146
+         ff 01 97 0d 4b b0                                 |....K.|
+Received:SET_REGION                    1831074.479492124
+         ff 00 97 00 00 77 9e                              |.....w.|
+Sending: SET_READ_TX_POWER             1831074.479681964
+         ff 02 92 08 98 49 c1                              |.....I.|
+Received:SET_READ_TX_POWER             1831074.481432960
+         ff 00 92 00 00 27 3b                              |.....';|
+Sending: SET_WRITE_TX_POWER            1831074.481527235
+         ff 02 94 08 98 29 07                              |.....).|
+Received:SET_WRITE_TX_POWER            1831074.483390045
+         ff 00 94 00 00 47 fd                              |.....G.|
+Sending: SET_ANTENNA_PORT              1831074.483543623
+         ff 02 91 01 01 70 3b                              |.....p;|
+Received:SET_ANTENNA_PORT              1831074.485442387
+         ff 00 91 00 00 17 58                              |......X|
+Sending: SET_READER_OPTIONAL_PARAMS    1831074.485576255
+         ff 03 9a 01 06 01 a9 5c                           |.......\|
+Received:SET_READER_OPTIONAL_PARAMS    1831074.487606924
+         ff 00 9a 00 00 a6 33                              |......3|
+Sending: GET_READER_STATS              1831074.487818404
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1831074.490136003
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1831074.490291027
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1831074.492017214
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1831074.492271773
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1831074.494357801
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1831074.494526919
+         ff 1e 22 03 00 13 03 e8  00 00 00 00 00 00 00 00  |..".............|
+         80 70 65 72 6d 61 6c 6f  63 00 04 00 05 00 06 00  |.permaloc.......|
+         07 3b 60                                          |.;`|
+Received:READ_TAG_ID_MULTIPLE          1831075.503599087
+         ff 07 22 00 00 03 00 13  00 00 00 01 65 8a        |..".........e.|
+Sending: GET_TAG_ID_BUFFER             1831075.503916938
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1831075.509398749
+         ff 26 29 00 00 01 ff 00  01 1b dc 11 0e 13 e8 00  |.&).............|
+         00 03 08 00 ae 05 00 00  00 00 80 34 00 e2 00 00  |...........4....|
+         15 86 0e 01 86 10 50 b2  05 43 05 f6 ff           |......P..C...|
+Sending: WRITE_TAG_DATA                1831075.513325167
+         ff 1d 24 03 e8 01 00 00  00 00 00 00 00 00 00 60  |..$............`|
+         e2 00 00 15 86 0e 01 86  10 50 b2 05 be ad ea d1  |.........P......|
+         15 be                                             |..|
+Received:WRITE_TAG_DATA                1831075.551566490
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: KILL_TAG                      1831075.551883959
+         ff 15 26 03 e8 01 be ad  ea d1 00 60 e2 00 00 15  |..&........`....|
+         86 0e 01 86 10 50 b2 05  9f 2a                    |.....P...*|
+Received:KILL_TAG                      1831075.605610474
+         ff 00 26 00 00 c0 64                              |..&...d|
+Sending: GET_READER_STATS              1831075.605904821
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1831075.608102121
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1831075.608299737
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1831075.610065410
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1831075.610229640
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1831075.612277145
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1831075.612456260
+         ff 22 22 01 00 17 03 e8  00 00 00 00 60 e2 00 00  |."".........`...|
+         15 86 0e 01 86 10 50 b2  05 01 09 28 07 d0 00 03  |......P....(....|
+         00 00 00 00 20 88 da                              |.... ..|
+Received:READ_TAG_ID_MULTIPLE          1831076.620853129
+         ff 0d 22 04 00 01 00 17  00 00 00 00 01 28 00 00  |.."..........(..|
+         00 00 d8 88                                       |....|
diff --git a/tests/lock.result b/tests/lock.result
new file mode 100644
--- /dev/null
+++ b/tests/lock.result
@@ -0,0 +1,7 @@
+Right 1
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NULQ\134\SOH\a\SOH\135\ap\196\193", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 47646, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 21, trRssi = -41, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right ""
+Right ""
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_PROTOCOL_WRITE_FAILED, meMessage = "Tag write operation failed", meLocation = "executeTagOp", meParam = "TagOp_GEN2_WriteData", meUri = ""})
+Right ""
+Right ""
diff --git a/tests/lock.transport b/tests/lock.transport
new file mode 100644
--- /dev/null
+++ b/tests/lock.transport
@@ -0,0 +1,109 @@
+Sending: VERSION                       1790605.584555826
+         ff 00 03 1d 0c                                    |.....|
+Received:VERSION                       1790605.588060962
+         ff 14 03 00 00 14 12 08  00 30 00 00 02 20 16 12  |.........0... ..|
+         13 01 07 01 02 00 00 00  10 1b 05                 |...........|
+Sending: GET_CURRENT_PROGRAM           1790605.588579065
+         ff 00 0c 1d 03                                    |.....|
+Received:GET_CURRENT_PROGRAM           1790605.590133584
+         ff 01 0c 00 00 52 63 03                           |.....Rc.|
+Sending: GET_POWER_MODE                1790605.590279389
+         ff 00 68 1d 67                                    |..h.g|
+Received:GET_POWER_MODE                1790605.591896715
+         ff 01 68 00 00 00 a4 bf                           |..h.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1790605.591990509
+         ff 02 6a 01 0e 2e 40                              |..j...@|
+Received:GET_READER_OPTIONAL_PARAMS    1790605.593926208
+         ff 03 6a 00 00 01 0e 00  30 44                    |..j.....0D|
+Sending: GET_READER_OPTIONAL_PARAMS    1790605.594787483
+         ff 02 6a 01 12 2e 5c                              |..j...\|
+Received:GET_READER_OPTIONAL_PARAMS    1790605.597048243
+         ff 04 6a 00 00 01 12 00  00 69 af                 |..j......i.|
+Sending: GET_TAG_PROTOCOL              1790605.597237617
+         ff 00 63 1d 6c                                    |..c.l|
+Received:GET_TAG_PROTOCOL              1790605.599164222
+         ff 02 63 00 00 00 05 21  46                       |..c....!F|
+Sending: GET_ANTENNA_PORT              1790605.599333871
+         ff 01 61 05 bd b8                                 |..a...|
+Received:GET_ANTENNA_PORT              1790605.601513969
+         ff 03 61 00 00 05 01 00  61 df                    |..a.....a.|
+Sending: GET_READER_OPTIONAL_PARAMS    1790605.601889295
+         ff 02 6a 01 0c 2e 42                              |..j...B|
+Received:GET_READER_OPTIONAL_PARAMS    1790605.604146998
+         ff 03 6a 00 00 01 0c 01  32 45                    |..j.....2E|
+Sending: GET_READER_OPTIONAL_PARAMS    1790605.604339750
+         ff 02 6a 01 0d 2e 43                              |..j...C|
+Received:GET_READER_OPTIONAL_PARAMS    1790605.606640416
+         ff 06 6a 00 00 01 0d 00  00 00 00 15 43           |..j.........C|
+Sending: SET_REGION                    1790605.606780094
+         ff 01 97 0d 4b b0                                 |....K.|
+Received:SET_REGION                    1790605.608595882
+         ff 00 97 00 00 77 9e                              |.....w.|
+Sending: SET_READ_TX_POWER             1790605.608799467
+         ff 02 92 08 98 49 c1                              |.....I.|
+Received:SET_READ_TX_POWER             1790605.610710783
+         ff 00 92 00 00 27 3b                              |.....';|
+Sending: SET_WRITE_TX_POWER            1790605.610861534
+         ff 02 94 08 98 29 07                              |.....).|
+Received:SET_WRITE_TX_POWER            1790605.612720664
+         ff 00 94 00 00 47 fd                              |.....G.|
+Sending: SET_ANTENNA_PORT              1790605.612904299
+         ff 02 91 01 01 70 3b                              |.....p;|
+Received:SET_ANTENNA_PORT              1790605.614647207
+         ff 00 91 00 00 17 58                              |......X|
+Sending: SET_READER_OPTIONAL_PARAMS    1790605.614754132
+         ff 03 9a 01 06 01 a9 5c                           |.......\|
+Received:SET_READER_OPTIONAL_PARAMS    1790605.616556454
+         ff 00 9a 00 00 a6 33                              |......3|
+Sending: GET_READER_STATS              1790605.616652209
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1790605.618851953
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1790605.619014686
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1790605.620740423
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1790605.620890824
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1790605.622843141
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1790605.623000323
+         ff 10 22 03 00 13 03 e8  00 00 00 00 00 00 00 00  |..".............|
+         10 00 00 86 a3                                    |.....|
+Received:READ_TAG_ID_MULTIPLE          1790606.630500088
+         ff 07 22 00 00 03 00 13  00 00 00 01 65 8a        |..".........e.|
+Sending: GET_TAG_ID_BUFFER             1790606.630747461
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1790606.636238404
+         ff 26 29 00 00 01 ff 00  01 15 d7 11 0e 13 e8 00  |.&).............|
+         00 03 cd 00 ae 05 00 00  00 00 80 30 00 e2 00 51  |...........0...Q|
+         86 01 07 01 87 07 70 c4  c1 ba 1e db e1           |......p......|
+Sending: WRITE_TAG_DATA                1790606.636934933
+         ff 1d 24 03 e8 01 00 00  00 02 00 00 00 00 00 60  |..$............`|
+         e2 00 51 86 01 07 01 87  07 70 c4 c1 00 00 30 39  |..Q......p....09|
+         a7 0f                                             |..|
+Received:WRITE_TAG_DATA                1790606.677344468
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: LOCK_TAG                      1790606.677604774
+         ff 18 25 03 e8 01 00 00  30 39 00 02 00 02 60 e2  |..%.....09....`.|
+         00 51 86 01 07 01 87 07  70 c4 c1 eb 70           |.Q......p...p|
+Received:LOCK_TAG                      1790606.736355478
+         ff 00 25 00 00 f0 07                              |..%....|
+Sending: WRITE_TAG_DATA                1790606.736556271
+         ff 29 24 03 e8 01 00 00  00 00 03 00 00 00 00 60  |.)$............`|
+         e2 00 51 86 01 07 01 87  07 70 c4 c1 54 68 69 73  |..Q......p..This|
+         20 73 68 6f 75 6c 64 20  66 61 69 6c dd 94        | should fail..|
+Received:WRITE_TAG_DATA                1790607.750972661
+         ff 00 24 04 06 e4 20                              |..$... |
+Sending: LOCK_TAG                      1790607.751291468
+         ff 18 25 03 e8 01 00 00  30 39 00 02 00 00 60 e2  |..%.....09....`.|
+         00 51 86 01 07 01 87 07  70 c4 c1 ed 9a           |.Q......p....|
+Received:LOCK_TAG                      1790607.821038416
+         ff 00 25 00 00 f0 07                              |..%....|
+Sending: WRITE_TAG_DATA                1790607.821243325
+         ff 2d 24 03 e8 01 00 00  00 00 03 00 00 00 00 60  |.-$............`|
+         e2 00 51 86 01 07 01 87  07 70 c4 c1 54 68 69 73  |..Q......p..This|
+         20 73 68 6f 75 6c 64 20  73 75 63 63 65 65 64 00  | should succeed.|
+         69 0c                                             |i.|
+Received:WRITE_TAG_DATA                1790607.950912849
+         ff 00 24 00 00 e0 26                              |..$...&|
diff --git a/tests/param-test.hs b/tests/param-test.hs
new file mode 100644
--- /dev/null
+++ b/tests/param-test.hs
@@ -0,0 +1,832 @@
+-- Automatically generated by util/generate-tmr-hsc.pl
+{-# LANGUAGE OverloadedStrings #-}
+
+import Test.HUnit ( Test(..), runTestTT, assertEqual )
+
+import qualified System.Hardware.MercuryApi as TMR
+
+main = runTestTT tests
+
+testBaudRate :: Test
+testBaudRate = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_BAUDRATE"
+    "/reader/baudRate"
+    (TMR.paramName TMR.PARAM_BAUDRATE)
+  assertEqual "TMR.paramID \"/reader/baudRate\""
+    TMR.PARAM_BAUDRATE
+    (TMR.paramID "/reader/baudRate")
+
+testProbeBaudRates :: Test
+testProbeBaudRates = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_PROBEBAUDRATES"
+    "/reader/probeBaudRates"
+    (TMR.paramName TMR.PARAM_PROBEBAUDRATES)
+  assertEqual "TMR.paramID \"/reader/probeBaudRates\""
+    TMR.PARAM_PROBEBAUDRATES
+    (TMR.paramID "/reader/probeBaudRates")
+
+testCommandTimeout :: Test
+testCommandTimeout = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_COMMANDTIMEOUT"
+    "/reader/commandTimeout"
+    (TMR.paramName TMR.PARAM_COMMANDTIMEOUT)
+  assertEqual "TMR.paramID \"/reader/commandTimeout\""
+    TMR.PARAM_COMMANDTIMEOUT
+    (TMR.paramID "/reader/commandTimeout")
+
+testTransportTimeout :: Test
+testTransportTimeout = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_TRANSPORTTIMEOUT"
+    "/reader/transportTimeout"
+    (TMR.paramName TMR.PARAM_TRANSPORTTIMEOUT)
+  assertEqual "TMR.paramID \"/reader/transportTimeout\""
+    TMR.PARAM_TRANSPORTTIMEOUT
+    (TMR.paramID "/reader/transportTimeout")
+
+testPowerMode :: Test
+testPowerMode = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_POWERMODE"
+    "/reader/powerMode"
+    (TMR.paramName TMR.PARAM_POWERMODE)
+  assertEqual "TMR.paramID \"/reader/powerMode\""
+    TMR.PARAM_POWERMODE
+    (TMR.paramID "/reader/powerMode")
+
+testUserMode :: Test
+testUserMode = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_USERMODE"
+    "/reader/userMode"
+    (TMR.paramName TMR.PARAM_USERMODE)
+  assertEqual "TMR.paramID \"/reader/userMode\""
+    TMR.PARAM_USERMODE
+    (TMR.paramID "/reader/userMode")
+
+testAntennaCheckPort :: Test
+testAntennaCheckPort = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_ANTENNA_CHECKPORT"
+    "/reader/antenna/checkPort"
+    (TMR.paramName TMR.PARAM_ANTENNA_CHECKPORT)
+  assertEqual "TMR.paramID \"/reader/antenna/checkPort\""
+    TMR.PARAM_ANTENNA_CHECKPORT
+    (TMR.paramID "/reader/antenna/checkPort")
+
+testAntennaPortList :: Test
+testAntennaPortList = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_ANTENNA_PORTLIST"
+    "/reader/antenna/portList"
+    (TMR.paramName TMR.PARAM_ANTENNA_PORTLIST)
+  assertEqual "TMR.paramID \"/reader/antenna/portList\""
+    TMR.PARAM_ANTENNA_PORTLIST
+    (TMR.paramID "/reader/antenna/portList")
+
+testAntennaConnectedPortList :: Test
+testAntennaConnectedPortList = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_ANTENNA_CONNECTEDPORTLIST"
+    "/reader/antenna/connectedPortList"
+    (TMR.paramName TMR.PARAM_ANTENNA_CONNECTEDPORTLIST)
+  assertEqual "TMR.paramID \"/reader/antenna/connectedPortList\""
+    TMR.PARAM_ANTENNA_CONNECTEDPORTLIST
+    (TMR.paramID "/reader/antenna/connectedPortList")
+
+testAntennaPortSwitchGpos :: Test
+testAntennaPortSwitchGpos = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_ANTENNA_PORTSWITCHGPOS"
+    "/reader/antenna/portSwitchGpos"
+    (TMR.paramName TMR.PARAM_ANTENNA_PORTSWITCHGPOS)
+  assertEqual "TMR.paramID \"/reader/antenna/portSwitchGpos\""
+    TMR.PARAM_ANTENNA_PORTSWITCHGPOS
+    (TMR.paramID "/reader/antenna/portSwitchGpos")
+
+testAntennaSettlingTimeList :: Test
+testAntennaSettlingTimeList = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_ANTENNA_SETTLINGTIMELIST"
+    "/reader/antenna/settlingTimeList"
+    (TMR.paramName TMR.PARAM_ANTENNA_SETTLINGTIMELIST)
+  assertEqual "TMR.paramID \"/reader/antenna/settlingTimeList\""
+    TMR.PARAM_ANTENNA_SETTLINGTIMELIST
+    (TMR.paramID "/reader/antenna/settlingTimeList")
+
+testAntennaReturnLoss :: Test
+testAntennaReturnLoss = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_ANTENNA_RETURNLOSS"
+    "/reader/antenna/returnLoss"
+    (TMR.paramName TMR.PARAM_ANTENNA_RETURNLOSS)
+  assertEqual "TMR.paramID \"/reader/antenna/returnLoss\""
+    TMR.PARAM_ANTENNA_RETURNLOSS
+    (TMR.paramID "/reader/antenna/returnLoss")
+
+testAntennaTxRxMap :: Test
+testAntennaTxRxMap = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_ANTENNA_TXRXMAP"
+    "/reader/antenna/txRxMap"
+    (TMR.paramName TMR.PARAM_ANTENNA_TXRXMAP)
+  assertEqual "TMR.paramID \"/reader/antenna/txRxMap\""
+    TMR.PARAM_ANTENNA_TXRXMAP
+    (TMR.paramID "/reader/antenna/txRxMap")
+
+testGpioInputList :: Test
+testGpioInputList = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_GPIO_INPUTLIST"
+    "/reader/gpio/inputList"
+    (TMR.paramName TMR.PARAM_GPIO_INPUTLIST)
+  assertEqual "TMR.paramID \"/reader/gpio/inputList\""
+    TMR.PARAM_GPIO_INPUTLIST
+    (TMR.paramID "/reader/gpio/inputList")
+
+testGpioOutputList :: Test
+testGpioOutputList = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_GPIO_OUTPUTLIST"
+    "/reader/gpio/outputList"
+    (TMR.paramName TMR.PARAM_GPIO_OUTPUTLIST)
+  assertEqual "TMR.paramID \"/reader/gpio/outputList\""
+    TMR.PARAM_GPIO_OUTPUTLIST
+    (TMR.paramID "/reader/gpio/outputList")
+
+testGen2AccessPassword :: Test
+testGen2AccessPassword = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_GEN2_ACCESSPASSWORD"
+    "/reader/gen2/accessPassword"
+    (TMR.paramName TMR.PARAM_GEN2_ACCESSPASSWORD)
+  assertEqual "TMR.paramID \"/reader/gen2/accessPassword\""
+    TMR.PARAM_GEN2_ACCESSPASSWORD
+    (TMR.paramID "/reader/gen2/accessPassword")
+
+testGen2Q :: Test
+testGen2Q = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_GEN2_Q"
+    "/reader/gen2/q"
+    (TMR.paramName TMR.PARAM_GEN2_Q)
+  assertEqual "TMR.paramID \"/reader/gen2/q\""
+    TMR.PARAM_GEN2_Q
+    (TMR.paramID "/reader/gen2/q")
+
+testGen2TagEncoding :: Test
+testGen2TagEncoding = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_GEN2_TAGENCODING"
+    "/reader/gen2/tagEncoding"
+    (TMR.paramName TMR.PARAM_GEN2_TAGENCODING)
+  assertEqual "TMR.paramID \"/reader/gen2/tagEncoding\""
+    TMR.PARAM_GEN2_TAGENCODING
+    (TMR.paramID "/reader/gen2/tagEncoding")
+
+testGen2Session :: Test
+testGen2Session = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_GEN2_SESSION"
+    "/reader/gen2/session"
+    (TMR.paramName TMR.PARAM_GEN2_SESSION)
+  assertEqual "TMR.paramID \"/reader/gen2/session\""
+    TMR.PARAM_GEN2_SESSION
+    (TMR.paramID "/reader/gen2/session")
+
+testGen2Target :: Test
+testGen2Target = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_GEN2_TARGET"
+    "/reader/gen2/target"
+    (TMR.paramName TMR.PARAM_GEN2_TARGET)
+  assertEqual "TMR.paramID \"/reader/gen2/target\""
+    TMR.PARAM_GEN2_TARGET
+    (TMR.paramID "/reader/gen2/target")
+
+testGen2BLF :: Test
+testGen2BLF = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_GEN2_BLF"
+    "/reader/gen2/BLF"
+    (TMR.paramName TMR.PARAM_GEN2_BLF)
+  assertEqual "TMR.paramID \"/reader/gen2/BLF\""
+    TMR.PARAM_GEN2_BLF
+    (TMR.paramID "/reader/gen2/BLF")
+
+testGen2Tari :: Test
+testGen2Tari = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_GEN2_TARI"
+    "/reader/gen2/tari"
+    (TMR.paramName TMR.PARAM_GEN2_TARI)
+  assertEqual "TMR.paramID \"/reader/gen2/tari\""
+    TMR.PARAM_GEN2_TARI
+    (TMR.paramID "/reader/gen2/tari")
+
+testGen2WriteMode :: Test
+testGen2WriteMode = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_GEN2_WRITEMODE"
+    "/reader/gen2/writeMode"
+    (TMR.paramName TMR.PARAM_GEN2_WRITEMODE)
+  assertEqual "TMR.paramID \"/reader/gen2/writeMode\""
+    TMR.PARAM_GEN2_WRITEMODE
+    (TMR.paramID "/reader/gen2/writeMode")
+
+testGen2Bap :: Test
+testGen2Bap = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_GEN2_BAP"
+    "/reader/gen2/bap"
+    (TMR.paramName TMR.PARAM_GEN2_BAP)
+  assertEqual "TMR.paramID \"/reader/gen2/bap\""
+    TMR.PARAM_GEN2_BAP
+    (TMR.paramID "/reader/gen2/bap")
+
+testGen2ProtocolExtension :: Test
+testGen2ProtocolExtension = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_GEN2_PROTOCOLEXTENSION"
+    "/reader/gen2/protocolExtension"
+    (TMR.paramName TMR.PARAM_GEN2_PROTOCOLEXTENSION)
+  assertEqual "TMR.paramID \"/reader/gen2/protocolExtension\""
+    TMR.PARAM_GEN2_PROTOCOLEXTENSION
+    (TMR.paramID "/reader/gen2/protocolExtension")
+
+testIso180006bBLF :: Test
+testIso180006bBLF = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_ISO180006B_BLF"
+    "/reader/iso180006b/BLF"
+    (TMR.paramName TMR.PARAM_ISO180006B_BLF)
+  assertEqual "TMR.paramID \"/reader/iso180006b/BLF\""
+    TMR.PARAM_ISO180006B_BLF
+    (TMR.paramID "/reader/iso180006b/BLF")
+
+testIso180006bModulationDepth :: Test
+testIso180006bModulationDepth = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_ISO180006B_MODULATION_DEPTH"
+    "/reader/iso180006b/modulationDepth"
+    (TMR.paramName TMR.PARAM_ISO180006B_MODULATION_DEPTH)
+  assertEqual "TMR.paramID \"/reader/iso180006b/modulationDepth\""
+    TMR.PARAM_ISO180006B_MODULATION_DEPTH
+    (TMR.paramID "/reader/iso180006b/modulationDepth")
+
+testIso180006bDelimiter :: Test
+testIso180006bDelimiter = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_ISO180006B_DELIMITER"
+    "/reader/iso180006b/delimiter"
+    (TMR.paramName TMR.PARAM_ISO180006B_DELIMITER)
+  assertEqual "TMR.paramID \"/reader/iso180006b/delimiter\""
+    TMR.PARAM_ISO180006B_DELIMITER
+    (TMR.paramID "/reader/iso180006b/delimiter")
+
+testReadAsyncOffTime :: Test
+testReadAsyncOffTime = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_READ_ASYNCOFFTIME"
+    "/reader/read/asyncOffTime"
+    (TMR.paramName TMR.PARAM_READ_ASYNCOFFTIME)
+  assertEqual "TMR.paramID \"/reader/read/asyncOffTime\""
+    TMR.PARAM_READ_ASYNCOFFTIME
+    (TMR.paramID "/reader/read/asyncOffTime")
+
+testReadAsyncOnTime :: Test
+testReadAsyncOnTime = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_READ_ASYNCONTIME"
+    "/reader/read/asyncOnTime"
+    (TMR.paramName TMR.PARAM_READ_ASYNCONTIME)
+  assertEqual "TMR.paramID \"/reader/read/asyncOnTime\""
+    TMR.PARAM_READ_ASYNCONTIME
+    (TMR.paramID "/reader/read/asyncOnTime")
+
+testReadPlan :: Test
+testReadPlan = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_READ_PLAN"
+    "/reader/read/plan"
+    (TMR.paramName TMR.PARAM_READ_PLAN)
+  assertEqual "TMR.paramID \"/reader/read/plan\""
+    TMR.PARAM_READ_PLAN
+    (TMR.paramID "/reader/read/plan")
+
+testRadioEnablePowerSave :: Test
+testRadioEnablePowerSave = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_RADIO_ENABLEPOWERSAVE"
+    "/reader/radio/enablePowerSave"
+    (TMR.paramName TMR.PARAM_RADIO_ENABLEPOWERSAVE)
+  assertEqual "TMR.paramID \"/reader/radio/enablePowerSave\""
+    TMR.PARAM_RADIO_ENABLEPOWERSAVE
+    (TMR.paramID "/reader/radio/enablePowerSave")
+
+testRadioPowerMax :: Test
+testRadioPowerMax = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_RADIO_POWERMAX"
+    "/reader/radio/powerMax"
+    (TMR.paramName TMR.PARAM_RADIO_POWERMAX)
+  assertEqual "TMR.paramID \"/reader/radio/powerMax\""
+    TMR.PARAM_RADIO_POWERMAX
+    (TMR.paramID "/reader/radio/powerMax")
+
+testRadioPowerMin :: Test
+testRadioPowerMin = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_RADIO_POWERMIN"
+    "/reader/radio/powerMin"
+    (TMR.paramName TMR.PARAM_RADIO_POWERMIN)
+  assertEqual "TMR.paramID \"/reader/radio/powerMin\""
+    TMR.PARAM_RADIO_POWERMIN
+    (TMR.paramID "/reader/radio/powerMin")
+
+testRadioPortReadPowerList :: Test
+testRadioPortReadPowerList = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_RADIO_PORTREADPOWERLIST"
+    "/reader/radio/portReadPowerList"
+    (TMR.paramName TMR.PARAM_RADIO_PORTREADPOWERLIST)
+  assertEqual "TMR.paramID \"/reader/radio/portReadPowerList\""
+    TMR.PARAM_RADIO_PORTREADPOWERLIST
+    (TMR.paramID "/reader/radio/portReadPowerList")
+
+testRadioPortWritePowerList :: Test
+testRadioPortWritePowerList = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_RADIO_PORTWRITEPOWERLIST"
+    "/reader/radio/portWritePowerList"
+    (TMR.paramName TMR.PARAM_RADIO_PORTWRITEPOWERLIST)
+  assertEqual "TMR.paramID \"/reader/radio/portWritePowerList\""
+    TMR.PARAM_RADIO_PORTWRITEPOWERLIST
+    (TMR.paramID "/reader/radio/portWritePowerList")
+
+testRadioReadPower :: Test
+testRadioReadPower = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_RADIO_READPOWER"
+    "/reader/radio/readPower"
+    (TMR.paramName TMR.PARAM_RADIO_READPOWER)
+  assertEqual "TMR.paramID \"/reader/radio/readPower\""
+    TMR.PARAM_RADIO_READPOWER
+    (TMR.paramID "/reader/radio/readPower")
+
+testRadioWritePower :: Test
+testRadioWritePower = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_RADIO_WRITEPOWER"
+    "/reader/radio/writePower"
+    (TMR.paramName TMR.PARAM_RADIO_WRITEPOWER)
+  assertEqual "TMR.paramID \"/reader/radio/writePower\""
+    TMR.PARAM_RADIO_WRITEPOWER
+    (TMR.paramID "/reader/radio/writePower")
+
+testRadioTemperature :: Test
+testRadioTemperature = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_RADIO_TEMPERATURE"
+    "/reader/radio/temperature"
+    (TMR.paramName TMR.PARAM_RADIO_TEMPERATURE)
+  assertEqual "TMR.paramID \"/reader/radio/temperature\""
+    TMR.PARAM_RADIO_TEMPERATURE
+    (TMR.paramID "/reader/radio/temperature")
+
+testTagReadDataRecordHighestRssi :: Test
+testTagReadDataRecordHighestRssi = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_TAGREADDATA_RECORDHIGHESTRSSI"
+    "/reader/tagReadData/recordHighestRssi"
+    (TMR.paramName TMR.PARAM_TAGREADDATA_RECORDHIGHESTRSSI)
+  assertEqual "TMR.paramID \"/reader/tagReadData/recordHighestRssi\""
+    TMR.PARAM_TAGREADDATA_RECORDHIGHESTRSSI
+    (TMR.paramID "/reader/tagReadData/recordHighestRssi")
+
+testTagReadDataReportRssiInDbm :: Test
+testTagReadDataReportRssiInDbm = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_TAGREADDATA_REPORTRSSIINDBM"
+    "/reader/tagReadData/reportRssiInDbm"
+    (TMR.paramName TMR.PARAM_TAGREADDATA_REPORTRSSIINDBM)
+  assertEqual "TMR.paramID \"/reader/tagReadData/reportRssiInDbm\""
+    TMR.PARAM_TAGREADDATA_REPORTRSSIINDBM
+    (TMR.paramID "/reader/tagReadData/reportRssiInDbm")
+
+testTagReadDataUniqueByAntenna :: Test
+testTagReadDataUniqueByAntenna = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_TAGREADDATA_UNIQUEBYANTENNA"
+    "/reader/tagReadData/uniqueByAntenna"
+    (TMR.paramName TMR.PARAM_TAGREADDATA_UNIQUEBYANTENNA)
+  assertEqual "TMR.paramID \"/reader/tagReadData/uniqueByAntenna\""
+    TMR.PARAM_TAGREADDATA_UNIQUEBYANTENNA
+    (TMR.paramID "/reader/tagReadData/uniqueByAntenna")
+
+testTagReadDataUniqueByData :: Test
+testTagReadDataUniqueByData = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_TAGREADDATA_UNIQUEBYDATA"
+    "/reader/tagReadData/uniqueByData"
+    (TMR.paramName TMR.PARAM_TAGREADDATA_UNIQUEBYDATA)
+  assertEqual "TMR.paramID \"/reader/tagReadData/uniqueByData\""
+    TMR.PARAM_TAGREADDATA_UNIQUEBYDATA
+    (TMR.paramID "/reader/tagReadData/uniqueByData")
+
+testTagopAntenna :: Test
+testTagopAntenna = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_TAGOP_ANTENNA"
+    "/reader/tagop/antenna"
+    (TMR.paramName TMR.PARAM_TAGOP_ANTENNA)
+  assertEqual "TMR.paramID \"/reader/tagop/antenna\""
+    TMR.PARAM_TAGOP_ANTENNA
+    (TMR.paramID "/reader/tagop/antenna")
+
+testTagopProtocol :: Test
+testTagopProtocol = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_TAGOP_PROTOCOL"
+    "/reader/tagop/protocol"
+    (TMR.paramName TMR.PARAM_TAGOP_PROTOCOL)
+  assertEqual "TMR.paramID \"/reader/tagop/protocol\""
+    TMR.PARAM_TAGOP_PROTOCOL
+    (TMR.paramID "/reader/tagop/protocol")
+
+testVersionHardware :: Test
+testVersionHardware = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_VERSION_HARDWARE"
+    "/reader/version/hardware"
+    (TMR.paramName TMR.PARAM_VERSION_HARDWARE)
+  assertEqual "TMR.paramID \"/reader/version/hardware\""
+    TMR.PARAM_VERSION_HARDWARE
+    (TMR.paramID "/reader/version/hardware")
+
+testVersionSerial :: Test
+testVersionSerial = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_VERSION_SERIAL"
+    "/reader/version/serial"
+    (TMR.paramName TMR.PARAM_VERSION_SERIAL)
+  assertEqual "TMR.paramID \"/reader/version/serial\""
+    TMR.PARAM_VERSION_SERIAL
+    (TMR.paramID "/reader/version/serial")
+
+testVersionModel :: Test
+testVersionModel = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_VERSION_MODEL"
+    "/reader/version/model"
+    (TMR.paramName TMR.PARAM_VERSION_MODEL)
+  assertEqual "TMR.paramID \"/reader/version/model\""
+    TMR.PARAM_VERSION_MODEL
+    (TMR.paramID "/reader/version/model")
+
+testVersionSoftware :: Test
+testVersionSoftware = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_VERSION_SOFTWARE"
+    "/reader/version/software"
+    (TMR.paramName TMR.PARAM_VERSION_SOFTWARE)
+  assertEqual "TMR.paramID \"/reader/version/software\""
+    TMR.PARAM_VERSION_SOFTWARE
+    (TMR.paramID "/reader/version/software")
+
+testVersionSupportedProtocols :: Test
+testVersionSupportedProtocols = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_VERSION_SUPPORTEDPROTOCOLS"
+    "/reader/version/supportedProtocols"
+    (TMR.paramName TMR.PARAM_VERSION_SUPPORTEDPROTOCOLS)
+  assertEqual "TMR.paramID \"/reader/version/supportedProtocols\""
+    TMR.PARAM_VERSION_SUPPORTEDPROTOCOLS
+    (TMR.paramID "/reader/version/supportedProtocols")
+
+testRegionHopTable :: Test
+testRegionHopTable = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_REGION_HOPTABLE"
+    "/reader/region/hopTable"
+    (TMR.paramName TMR.PARAM_REGION_HOPTABLE)
+  assertEqual "TMR.paramID \"/reader/region/hopTable\""
+    TMR.PARAM_REGION_HOPTABLE
+    (TMR.paramID "/reader/region/hopTable")
+
+testRegionHopTime :: Test
+testRegionHopTime = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_REGION_HOPTIME"
+    "/reader/region/hopTime"
+    (TMR.paramName TMR.PARAM_REGION_HOPTIME)
+  assertEqual "TMR.paramID \"/reader/region/hopTime\""
+    TMR.PARAM_REGION_HOPTIME
+    (TMR.paramID "/reader/region/hopTime")
+
+testRegionId :: Test
+testRegionId = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_REGION_ID"
+    "/reader/region/id"
+    (TMR.paramName TMR.PARAM_REGION_ID)
+  assertEqual "TMR.paramID \"/reader/region/id\""
+    TMR.PARAM_REGION_ID
+    (TMR.paramID "/reader/region/id")
+
+testRegionSupportedRegions :: Test
+testRegionSupportedRegions = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_REGION_SUPPORTEDREGIONS"
+    "/reader/region/supportedRegions"
+    (TMR.paramName TMR.PARAM_REGION_SUPPORTEDREGIONS)
+  assertEqual "TMR.paramID \"/reader/region/supportedRegions\""
+    TMR.PARAM_REGION_SUPPORTEDREGIONS
+    (TMR.paramID "/reader/region/supportedRegions")
+
+testRegionLbtEnable :: Test
+testRegionLbtEnable = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_REGION_LBT_ENABLE"
+    "/reader/region/lbt/enable"
+    (TMR.paramName TMR.PARAM_REGION_LBT_ENABLE)
+  assertEqual "TMR.paramID \"/reader/region/lbt/enable\""
+    TMR.PARAM_REGION_LBT_ENABLE
+    (TMR.paramID "/reader/region/lbt/enable")
+
+testLicenseKey :: Test
+testLicenseKey = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_LICENSE_KEY"
+    "/reader/licenseKey"
+    (TMR.paramName TMR.PARAM_LICENSE_KEY)
+  assertEqual "TMR.paramID \"/reader/licenseKey\""
+    TMR.PARAM_LICENSE_KEY
+    (TMR.paramID "/reader/licenseKey")
+
+testUserConfig :: Test
+testUserConfig = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_USER_CONFIG"
+    "/reader/userConfig"
+    (TMR.paramName TMR.PARAM_USER_CONFIG)
+  assertEqual "TMR.paramID \"/reader/userConfig\""
+    TMR.PARAM_USER_CONFIG
+    (TMR.paramID "/reader/userConfig")
+
+testRadioEnableSJC :: Test
+testRadioEnableSJC = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_RADIO_ENABLESJC"
+    "/reader/radio/enableSJC"
+    (TMR.paramName TMR.PARAM_RADIO_ENABLESJC)
+  assertEqual "TMR.paramID \"/reader/radio/enableSJC\""
+    TMR.PARAM_RADIO_ENABLESJC
+    (TMR.paramID "/reader/radio/enableSJC")
+
+testExtendedEpc :: Test
+testExtendedEpc = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_EXTENDEDEPC"
+    "/reader/extendedEpc"
+    (TMR.paramName TMR.PARAM_EXTENDEDEPC)
+  assertEqual "TMR.paramID \"/reader/extendedEpc\""
+    TMR.PARAM_EXTENDEDEPC
+    (TMR.paramID "/reader/extendedEpc")
+
+testStatistics :: Test
+testStatistics = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_READER_STATISTICS"
+    "/reader/statistics"
+    (TMR.paramName TMR.PARAM_READER_STATISTICS)
+  assertEqual "TMR.paramID \"/reader/statistics\""
+    TMR.PARAM_READER_STATISTICS
+    (TMR.paramID "/reader/statistics")
+
+testStats :: Test
+testStats = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_READER_STATS"
+    "/reader/stats"
+    (TMR.paramName TMR.PARAM_READER_STATS)
+  assertEqual "TMR.paramID \"/reader/stats\""
+    TMR.PARAM_READER_STATS
+    (TMR.paramID "/reader/stats")
+
+testUri :: Test
+testUri = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_URI"
+    "/reader/uri"
+    (TMR.paramName TMR.PARAM_URI)
+  assertEqual "TMR.paramID \"/reader/uri\""
+    TMR.PARAM_URI
+    (TMR.paramID "/reader/uri")
+
+testVersionProductGroupID :: Test
+testVersionProductGroupID = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_PRODUCT_GROUP_ID"
+    "/reader/version/productGroupID"
+    (TMR.paramName TMR.PARAM_PRODUCT_GROUP_ID)
+  assertEqual "TMR.paramID \"/reader/version/productGroupID\""
+    TMR.PARAM_PRODUCT_GROUP_ID
+    (TMR.paramID "/reader/version/productGroupID")
+
+testVersionProductGroup :: Test
+testVersionProductGroup = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_PRODUCT_GROUP"
+    "/reader/version/productGroup"
+    (TMR.paramName TMR.PARAM_PRODUCT_GROUP)
+  assertEqual "TMR.paramID \"/reader/version/productGroup\""
+    TMR.PARAM_PRODUCT_GROUP
+    (TMR.paramID "/reader/version/productGroup")
+
+testVersionProductID :: Test
+testVersionProductID = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_PRODUCT_ID"
+    "/reader/version/productID"
+    (TMR.paramName TMR.PARAM_PRODUCT_ID)
+  assertEqual "TMR.paramID \"/reader/version/productID\""
+    TMR.PARAM_PRODUCT_ID
+    (TMR.paramID "/reader/version/productID")
+
+testTagReadDataTagopSuccesses :: Test
+testTagReadDataTagopSuccesses = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_TAGREADATA_TAGOPSUCCESSCOUNT"
+    "/reader/tagReadData/tagopSuccesses"
+    (TMR.paramName TMR.PARAM_TAGREADATA_TAGOPSUCCESSCOUNT)
+  assertEqual "TMR.paramID \"/reader/tagReadData/tagopSuccesses\""
+    TMR.PARAM_TAGREADATA_TAGOPSUCCESSCOUNT
+    (TMR.paramID "/reader/tagReadData/tagopSuccesses")
+
+testTagReadDataTagopFailures :: Test
+testTagReadDataTagopFailures = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_TAGREADATA_TAGOPFAILURECOUNT"
+    "/reader/tagReadData/tagopFailures"
+    (TMR.paramName TMR.PARAM_TAGREADATA_TAGOPFAILURECOUNT)
+  assertEqual "TMR.paramID \"/reader/tagReadData/tagopFailures\""
+    TMR.PARAM_TAGREADATA_TAGOPFAILURECOUNT
+    (TMR.paramID "/reader/tagReadData/tagopFailures")
+
+testStatusAntennaEnable :: Test
+testStatusAntennaEnable = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_STATUS_ENABLE_ANTENNAREPORT"
+    "/reader/status/antennaEnable"
+    (TMR.paramName TMR.PARAM_STATUS_ENABLE_ANTENNAREPORT)
+  assertEqual "TMR.paramID \"/reader/status/antennaEnable\""
+    TMR.PARAM_STATUS_ENABLE_ANTENNAREPORT
+    (TMR.paramID "/reader/status/antennaEnable")
+
+testStatusFrequencyEnable :: Test
+testStatusFrequencyEnable = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_STATUS_ENABLE_FREQUENCYREPORT"
+    "/reader/status/frequencyEnable"
+    (TMR.paramName TMR.PARAM_STATUS_ENABLE_FREQUENCYREPORT)
+  assertEqual "TMR.paramID \"/reader/status/frequencyEnable\""
+    TMR.PARAM_STATUS_ENABLE_FREQUENCYREPORT
+    (TMR.paramID "/reader/status/frequencyEnable")
+
+testStatusTemperatureEnable :: Test
+testStatusTemperatureEnable = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_STATUS_ENABLE_TEMPERATUREREPORT"
+    "/reader/status/temperatureEnable"
+    (TMR.paramName TMR.PARAM_STATUS_ENABLE_TEMPERATUREREPORT)
+  assertEqual "TMR.paramID \"/reader/status/temperatureEnable\""
+    TMR.PARAM_STATUS_ENABLE_TEMPERATUREREPORT
+    (TMR.paramID "/reader/status/temperatureEnable")
+
+testTagReadDataEnableReadFilter :: Test
+testTagReadDataEnableReadFilter = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_TAGREADDATA_ENABLEREADFILTER"
+    "/reader/tagReadData/enableReadFilter"
+    (TMR.paramName TMR.PARAM_TAGREADDATA_ENABLEREADFILTER)
+  assertEqual "TMR.paramID \"/reader/tagReadData/enableReadFilter\""
+    TMR.PARAM_TAGREADDATA_ENABLEREADFILTER
+    (TMR.paramID "/reader/tagReadData/enableReadFilter")
+
+testTagReadDataReadFilterTimeout :: Test
+testTagReadDataReadFilterTimeout = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_TAGREADDATA_READFILTERTIMEOUT"
+    "/reader/tagReadData/readFilterTimeout"
+    (TMR.paramName TMR.PARAM_TAGREADDATA_READFILTERTIMEOUT)
+  assertEqual "TMR.paramID \"/reader/tagReadData/readFilterTimeout\""
+    TMR.PARAM_TAGREADDATA_READFILTERTIMEOUT
+    (TMR.paramID "/reader/tagReadData/readFilterTimeout")
+
+testTagReadDataUniqueByProtocol :: Test
+testTagReadDataUniqueByProtocol = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_TAGREADDATA_UNIQUEBYPROTOCOL"
+    "/reader/tagReadData/uniqueByProtocol"
+    (TMR.paramName TMR.PARAM_TAGREADDATA_UNIQUEBYPROTOCOL)
+  assertEqual "TMR.paramID \"/reader/tagReadData/uniqueByProtocol\""
+    TMR.PARAM_TAGREADDATA_UNIQUEBYPROTOCOL
+    (TMR.paramID "/reader/tagReadData/uniqueByProtocol")
+
+testDescription :: Test
+testDescription = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_READER_DESCRIPTION"
+    "/reader/description"
+    (TMR.paramName TMR.PARAM_READER_DESCRIPTION)
+  assertEqual "TMR.paramID \"/reader/description\""
+    TMR.PARAM_READER_DESCRIPTION
+    (TMR.paramID "/reader/description")
+
+testHostname :: Test
+testHostname = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_READER_HOSTNAME"
+    "/reader/hostname"
+    (TMR.paramName TMR.PARAM_READER_HOSTNAME)
+  assertEqual "TMR.paramID \"/reader/hostname\""
+    TMR.PARAM_READER_HOSTNAME
+    (TMR.paramID "/reader/hostname")
+
+testCurrentTime :: Test
+testCurrentTime = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_CURRENTTIME"
+    "/reader/currentTime"
+    (TMR.paramName TMR.PARAM_CURRENTTIME)
+  assertEqual "TMR.paramID \"/reader/currentTime\""
+    TMR.PARAM_CURRENTTIME
+    (TMR.paramID "/reader/currentTime")
+
+testGen2WriteReplyTimeout :: Test
+testGen2WriteReplyTimeout = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_READER_WRITE_REPLY_TIMEOUT"
+    "/reader/gen2/writeReplyTimeout"
+    (TMR.paramName TMR.PARAM_READER_WRITE_REPLY_TIMEOUT)
+  assertEqual "TMR.paramID \"/reader/gen2/writeReplyTimeout\""
+    TMR.PARAM_READER_WRITE_REPLY_TIMEOUT
+    (TMR.paramID "/reader/gen2/writeReplyTimeout")
+
+testGen2WriteEarlyExit :: Test
+testGen2WriteEarlyExit = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_READER_WRITE_EARLY_EXIT"
+    "/reader/gen2/writeEarlyExit"
+    (TMR.paramName TMR.PARAM_READER_WRITE_EARLY_EXIT)
+  assertEqual "TMR.paramID \"/reader/gen2/writeEarlyExit\""
+    TMR.PARAM_READER_WRITE_EARLY_EXIT
+    (TMR.paramID "/reader/gen2/writeEarlyExit")
+
+testStatsEnable :: Test
+testStatsEnable = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_READER_STATS_ENABLE"
+    "/reader/stats/enable"
+    (TMR.paramName TMR.PARAM_READER_STATS_ENABLE)
+  assertEqual "TMR.paramID \"/reader/stats/enable\""
+    TMR.PARAM_READER_STATS_ENABLE
+    (TMR.paramID "/reader/stats/enable")
+
+testTriggerReadGpi :: Test
+testTriggerReadGpi = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_TRIGGER_READ_GPI"
+    "/reader/trigger/read/Gpi"
+    (TMR.paramName TMR.PARAM_TRIGGER_READ_GPI)
+  assertEqual "TMR.paramID \"/reader/trigger/read/Gpi\""
+    TMR.PARAM_TRIGGER_READ_GPI
+    (TMR.paramID "/reader/trigger/read/Gpi")
+
+testMetadataflags :: Test
+testMetadataflags = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_METADATAFLAG"
+    "/reader/metadataflags"
+    (TMR.paramName TMR.PARAM_METADATAFLAG)
+  assertEqual "TMR.paramID \"/reader/metadataflags\""
+    TMR.PARAM_METADATAFLAG
+    (TMR.paramID "/reader/metadataflags")
+
+testLicensedFeatures :: Test
+testLicensedFeatures = TestCase $ do
+  assertEqual "TMR.paramName TMR.PARAM_LICENSED_FEATURES"
+    "/reader/licensedFeatures"
+    (TMR.paramName TMR.PARAM_LICENSED_FEATURES)
+  assertEqual "TMR.paramID \"/reader/licensedFeatures\""
+    TMR.PARAM_LICENSED_FEATURES
+    (TMR.paramID "/reader/licensedFeatures")
+
+tests :: Test
+tests = TestList
+  [ TestLabel "testBaudRate" testBaudRate
+  , TestLabel "testProbeBaudRates" testProbeBaudRates
+  , TestLabel "testCommandTimeout" testCommandTimeout
+  , TestLabel "testTransportTimeout" testTransportTimeout
+  , TestLabel "testPowerMode" testPowerMode
+  , TestLabel "testUserMode" testUserMode
+  , TestLabel "testAntennaCheckPort" testAntennaCheckPort
+  , TestLabel "testAntennaPortList" testAntennaPortList
+  , TestLabel "testAntennaConnectedPortList" testAntennaConnectedPortList
+  , TestLabel "testAntennaPortSwitchGpos" testAntennaPortSwitchGpos
+  , TestLabel "testAntennaSettlingTimeList" testAntennaSettlingTimeList
+  , TestLabel "testAntennaReturnLoss" testAntennaReturnLoss
+  , TestLabel "testAntennaTxRxMap" testAntennaTxRxMap
+  , TestLabel "testGpioInputList" testGpioInputList
+  , TestLabel "testGpioOutputList" testGpioOutputList
+  , TestLabel "testGen2AccessPassword" testGen2AccessPassword
+  , TestLabel "testGen2Q" testGen2Q
+  , TestLabel "testGen2TagEncoding" testGen2TagEncoding
+  , TestLabel "testGen2Session" testGen2Session
+  , TestLabel "testGen2Target" testGen2Target
+  , TestLabel "testGen2BLF" testGen2BLF
+  , TestLabel "testGen2Tari" testGen2Tari
+  , TestLabel "testGen2WriteMode" testGen2WriteMode
+  , TestLabel "testGen2Bap" testGen2Bap
+  , TestLabel "testGen2ProtocolExtension" testGen2ProtocolExtension
+  , TestLabel "testIso180006bBLF" testIso180006bBLF
+  , TestLabel "testIso180006bModulationDepth" testIso180006bModulationDepth
+  , TestLabel "testIso180006bDelimiter" testIso180006bDelimiter
+  , TestLabel "testReadAsyncOffTime" testReadAsyncOffTime
+  , TestLabel "testReadAsyncOnTime" testReadAsyncOnTime
+  , TestLabel "testReadPlan" testReadPlan
+  , TestLabel "testRadioEnablePowerSave" testRadioEnablePowerSave
+  , TestLabel "testRadioPowerMax" testRadioPowerMax
+  , TestLabel "testRadioPowerMin" testRadioPowerMin
+  , TestLabel "testRadioPortReadPowerList" testRadioPortReadPowerList
+  , TestLabel "testRadioPortWritePowerList" testRadioPortWritePowerList
+  , TestLabel "testRadioReadPower" testRadioReadPower
+  , TestLabel "testRadioWritePower" testRadioWritePower
+  , TestLabel "testRadioTemperature" testRadioTemperature
+  , TestLabel "testTagReadDataRecordHighestRssi" testTagReadDataRecordHighestRssi
+  , TestLabel "testTagReadDataReportRssiInDbm" testTagReadDataReportRssiInDbm
+  , TestLabel "testTagReadDataUniqueByAntenna" testTagReadDataUniqueByAntenna
+  , TestLabel "testTagReadDataUniqueByData" testTagReadDataUniqueByData
+  , TestLabel "testTagopAntenna" testTagopAntenna
+  , TestLabel "testTagopProtocol" testTagopProtocol
+  , TestLabel "testVersionHardware" testVersionHardware
+  , TestLabel "testVersionSerial" testVersionSerial
+  , TestLabel "testVersionModel" testVersionModel
+  , TestLabel "testVersionSoftware" testVersionSoftware
+  , TestLabel "testVersionSupportedProtocols" testVersionSupportedProtocols
+  , TestLabel "testRegionHopTable" testRegionHopTable
+  , TestLabel "testRegionHopTime" testRegionHopTime
+  , TestLabel "testRegionId" testRegionId
+  , TestLabel "testRegionSupportedRegions" testRegionSupportedRegions
+  , TestLabel "testRegionLbtEnable" testRegionLbtEnable
+  , TestLabel "testLicenseKey" testLicenseKey
+  , TestLabel "testUserConfig" testUserConfig
+  , TestLabel "testRadioEnableSJC" testRadioEnableSJC
+  , TestLabel "testExtendedEpc" testExtendedEpc
+  , TestLabel "testStatistics" testStatistics
+  , TestLabel "testStats" testStats
+  , TestLabel "testUri" testUri
+  , TestLabel "testVersionProductGroupID" testVersionProductGroupID
+  , TestLabel "testVersionProductGroup" testVersionProductGroup
+  , TestLabel "testVersionProductID" testVersionProductID
+  , TestLabel "testTagReadDataTagopSuccesses" testTagReadDataTagopSuccesses
+  , TestLabel "testTagReadDataTagopFailures" testTagReadDataTagopFailures
+  , TestLabel "testStatusAntennaEnable" testStatusAntennaEnable
+  , TestLabel "testStatusFrequencyEnable" testStatusFrequencyEnable
+  , TestLabel "testStatusTemperatureEnable" testStatusTemperatureEnable
+  , TestLabel "testTagReadDataEnableReadFilter" testTagReadDataEnableReadFilter
+  , TestLabel "testTagReadDataReadFilterTimeout" testTagReadDataReadFilterTimeout
+  , TestLabel "testTagReadDataUniqueByProtocol" testTagReadDataUniqueByProtocol
+  , TestLabel "testDescription" testDescription
+  , TestLabel "testHostname" testHostname
+  , TestLabel "testCurrentTime" testCurrentTime
+  , TestLabel "testGen2WriteReplyTimeout" testGen2WriteReplyTimeout
+  , TestLabel "testGen2WriteEarlyExit" testGen2WriteEarlyExit
+  , TestLabel "testStatsEnable" testStatsEnable
+  , TestLabel "testTriggerReadGpi" testTriggerReadGpi
+  , TestLabel "testMetadataflags" testMetadataflags
+  , TestLabel "testLicensedFeatures" testLicensedFeatures
+  ]
diff --git a/tests/params.result b/tests/params.result
new file mode 100644
--- /dev/null
+++ b/tests/params.result
@@ -0,0 +1,77 @@
+Right [PARAM_BAUDRATE,PARAM_PROBEBAUDRATES,PARAM_COMMANDTIMEOUT,PARAM_TRANSPORTTIMEOUT,PARAM_POWERMODE,PARAM_USERMODE,PARAM_ANTENNA_CHECKPORT,PARAM_ANTENNA_PORTLIST,PARAM_ANTENNA_CONNECTEDPORTLIST,PARAM_ANTENNA_PORTSWITCHGPOS,PARAM_ANTENNA_SETTLINGTIMELIST,PARAM_ANTENNA_RETURNLOSS,PARAM_ANTENNA_TXRXMAP,PARAM_GPIO_INPUTLIST,PARAM_GPIO_OUTPUTLIST,PARAM_GEN2_ACCESSPASSWORD,PARAM_GEN2_Q,PARAM_GEN2_TAGENCODING,PARAM_GEN2_SESSION,PARAM_GEN2_TARGET,PARAM_GEN2_BLF,PARAM_GEN2_TARI,PARAM_GEN2_WRITEMODE,PARAM_GEN2_BAP,PARAM_GEN2_PROTOCOLEXTENSION,PARAM_ISO180006B_MODULATION_DEPTH,PARAM_ISO180006B_DELIMITER,PARAM_READ_ASYNCOFFTIME,PARAM_READ_ASYNCONTIME,PARAM_READ_PLAN,PARAM_RADIO_ENABLEPOWERSAVE,PARAM_RADIO_POWERMAX,PARAM_RADIO_POWERMIN,PARAM_RADIO_PORTREADPOWERLIST,PARAM_RADIO_PORTWRITEPOWERLIST,PARAM_RADIO_READPOWER,PARAM_RADIO_WRITEPOWER,PARAM_RADIO_TEMPERATURE,PARAM_TAGREADDATA_RECORDHIGHESTRSSI,PARAM_TAGREADDATA_REPORTRSSIINDBM,PARAM_TAGREADDATA_UNIQUEBYANTENNA,PARAM_TAGREADDATA_UNIQUEBYDATA,PARAM_TAGOP_ANTENNA,PARAM_TAGOP_PROTOCOL,PARAM_VERSION_HARDWARE,PARAM_VERSION_SERIAL,PARAM_VERSION_MODEL,PARAM_VERSION_SOFTWARE,PARAM_VERSION_SUPPORTEDPROTOCOLS,PARAM_REGION_HOPTABLE,PARAM_REGION_HOPTIME,PARAM_REGION_ID,PARAM_REGION_SUPPORTEDREGIONS,PARAM_REGION_LBT_ENABLE,PARAM_LICENSE_KEY,PARAM_USER_CONFIG,PARAM_RADIO_ENABLESJC,PARAM_EXTENDEDEPC,PARAM_READER_STATISTICS,PARAM_READER_STATS,PARAM_URI,PARAM_PRODUCT_GROUP_ID,PARAM_PRODUCT_GROUP,PARAM_PRODUCT_ID,PARAM_TAGREADATA_TAGOPSUCCESSCOUNT,PARAM_TAGREADATA_TAGOPFAILURECOUNT,PARAM_STATUS_ENABLE_ANTENNAREPORT,PARAM_STATUS_ENABLE_FREQUENCYREPORT,PARAM_STATUS_ENABLE_TEMPERATUREREPORT,PARAM_TAGREADDATA_ENABLEREADFILTER,PARAM_TAGREADDATA_READFILTERTIMEOUT,PARAM_TAGREADDATA_UNIQUEBYPROTOCOL,PARAM_READER_WRITE_REPLY_TIMEOUT,PARAM_READER_WRITE_EARLY_EXIT,PARAM_READER_STATS_ENABLE,PARAM_TRIGGER_READ_GPI,PARAM_METADATAFLAG]
+Right "115200"
+Right "[9600,115200,921600,19200,38400,57600,230400,460800]"
+Right "1000"
+Right "10000"
+Right "POWER_MODE_FULL"
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_USERMODE", meUri = ""})
+Right "False"
+Right "[1]"
+Right "[]"
+Right "[]"
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_ANTENNA_SETTLINGTIMELIST", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_ANTENNA_RETURNLOSS", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_ANTENNA_TXRXMAP", meUri = ""})
+Right "[1,2,3,4]"
+Right "[]"
+Right "0"
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_GEN2_Q", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_GEN2_TAGENCODING", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_GEN2_SESSION", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_GEN2_TARGET", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_GEN2_BLF", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_GEN2_TARI", meUri = ""})
+Right "GEN2_WORD_ONLY"
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_GEN2_BAP", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_GEN2_PROTOCOLEXTENSION", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_ISO180006B_MODULATION_DEPTH", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_ISO180006B_DELIMITER", meUri = ""})
+Right "0"
+Right "250"
+Right "SimpleReadPlan {rpWeight = 1, rpEnableAutonomousRead = False, rpAntennas = [], rpProtocol = TAG_PROTOCOL_GEN2, rpFilter = Nothing, rpTagop = Nothing, rpUseFastSearch = False, rpStopOnCount = Nothing, rpTriggerRead = Nothing}"
+Right "False"
+Right "2700"
+Right "0"
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_RADIO_PORTREADPOWERLIST", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_RADIO_PORTWRITEPOWERLIST", meUri = ""})
+Right "2300"
+Right "2300"
+Right "35"
+Right "False"
+Right "True"
+Right "True"
+Right "False"
+Right "0"
+Right "TAG_PROTOCOL_GEN2"
+Right "\"30.00.00.02\""
+Right "\"45160067701130324A\""
+Right "\"M6e Nano\""
+Right "\"01.07.01.02-20.16.12.13-BL14.12.08.00\""
+Right "[TAG_PROTOCOL_GEN2]"
+Right "[]"
+Right "0"
+Right "REGION_NONE"
+Right "[REGION_NA2,REGION_NA3,REGION_IN,REGION_JP,REGION_PRC,REGION_EU3,REGION_KR2,REGION_AU,REGION_NZ,REGION_OPEN]"
+Right "False"
+Left (MercuryException {meStatusType = ERROR_TYPE_MISC, meStatus = ERROR_UNSUPPORTED, meMessage = "Unsupported operation", meLocation = "paramGet", meParam = "PARAM_LICENSE_KEY", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_USER_CONFIG", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_CODE, meStatus = ERROR_MSG_INVALID_PARAMETER_VALUE, meMessage = "Parameter to command is invalid", meLocation = "paramGet", meParam = "PARAM_RADIO_ENABLESJC", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_MISC, meStatus = ERROR_UNSUPPORTED, meMessage = "Unsupported operation", meLocation = "paramGet", meParam = "PARAM_EXTENDEDEPC", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_READER_STATISTICS", meUri = ""})
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_READER_STATS", meUri = ""})
+Right "0"
+Right "\"Embedded Reader\""
+Right "17"
+Right "0"
+Right "0"
+Right "False"
+Right "False"
+Right "False"
+Right "True"
+Right "-1"
+Right "True"
+Right "20000"
+Right "True"
+Left (MercuryException {meStatusType = ERROR_TYPE_BINDING, meStatus = ERROR_UNIMPLEMENTED_PARAM, meMessage = "The given parameter is not yet implemented in the Haskell binding.", meLocation = "paramGet", meParam = "PARAM_READER_STATS_ENABLE", meUri = ""})
+Right "[]"
+Right "[METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS]"
diff --git a/tests/params.transport b/tests/params.transport
new file mode 100644
--- /dev/null
+++ b/tests/params.transport
@@ -0,0 +1,205 @@
+Sending: VERSION                       1843103.979368518
+         ff 00 03 1d 0c                                    |.....|
+Received:VERSION                       1843103.983059307
+         ff 14 03 00 00 14 12 08  00 30 00 00 02 20 16 12  |.........0... ..|
+         13 01 07 01 02 00 00 00  10 1b 05                 |...........|
+Sending: GET_CURRENT_PROGRAM           1843103.983838682
+         ff 00 0c 1d 03                                    |.....|
+Received:GET_CURRENT_PROGRAM           1843103.985476488
+         ff 01 0c 00 00 52 63 03                           |.....Rc.|
+Sending: GET_POWER_MODE                1843103.985614147
+         ff 00 68 1d 67                                    |..h.g|
+Received:GET_POWER_MODE                1843103.987230565
+         ff 01 68 00 00 00 a4 bf                           |..h.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1843103.987381864
+         ff 02 6a 01 0e 2e 40                              |..j...@|
+Received:GET_READER_OPTIONAL_PARAMS    1843103.989369325
+         ff 03 6a 00 00 01 0e 00  30 44                    |..j.....0D|
+Sending: GET_READER_OPTIONAL_PARAMS    1843103.990399529
+         ff 02 6a 01 12 2e 5c                              |..j...\|
+Received:GET_READER_OPTIONAL_PARAMS    1843103.992509632
+         ff 04 6a 00 00 01 12 00  00 69 af                 |..j......i.|
+Sending: GET_TAG_PROTOCOL              1843103.992625025
+         ff 00 63 1d 6c                                    |..c.l|
+Received:GET_TAG_PROTOCOL              1843103.994284660
+         ff 02 63 00 00 00 05 21  46                       |..c....!F|
+Sending: GET_ANTENNA_PORT              1843103.994386061
+         ff 01 61 05 bd b8                                 |..a...|
+Received:GET_ANTENNA_PORT              1843103.996347817
+         ff 03 61 00 00 05 01 00  61 df                    |..a.....a.|
+Sending: GET_READER_OPTIONAL_PARAMS    1843103.996501945
+         ff 02 6a 01 0c 2e 42                              |..j...B|
+Received:GET_READER_OPTIONAL_PARAMS    1843103.998612904
+         ff 03 6a 00 00 01 0c 01  32 45                    |..j.....2E|
+Sending: GET_READER_OPTIONAL_PARAMS    1843103.998778861
+         ff 02 6a 01 0d 2e 43                              |..j...C|
+Received:GET_READER_OPTIONAL_PARAMS    1843104.001433875
+         ff 06 6a 00 00 01 0d 00  00 00 00 15 43           |..j.........C|
+Sending: GET_PROTOCOL_PARAM            1843104.001631010
+         ff 02 6b 05 10 3a 7f                              |..k..:.|
+Received:GET_PROTOCOL_PARAM            1843104.003624443
+         ff 03 6b 00 00 05 10 00  18 74                    |..k......t|
+Sending: GET_PROTOCOL_PARAM            1843104.003810694
+         ff 02 6b 05 11 3a 7e                              |..k..:~|
+Received:GET_PROTOCOL_PARAM            1843104.005731032
+         ff 03 6b 00 00 05 11 00  19 74                    |..k......t|
+Sending: GET_PROTOCOL_PARAM            1843104.005829147
+         ff 02 6b 03 10 3c 7f                              |..k..<.|
+Received:GET_PROTOCOL_PARAM            1843104.007681136
+         ff 02 6b 04 02 03 10 67  74                       |..k....gt|
+Sending: GET_POWER_MODE                1843104.008160154
+         ff 00 68 1d 67                                    |..h.g|
+Received:GET_POWER_MODE                1843104.009771473
+         ff 01 68 00 00 00 a4 bf                           |..h.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1843104.009907376
+         ff 02 6a 01 04 2e 4a                              |..j...J|
+Received:GET_READER_OPTIONAL_PARAMS    1843104.011909258
+         ff 03 6a 00 00 01 04 00  3a 44                    |..j.....:D|
+Sending: GET_ANTENNA_PORT              1843104.012113365
+         ff 01 61 05 bd b8                                 |..a...|
+Received:GET_ANTENNA_PORT              1843104.014034668
+         ff 03 61 00 00 05 01 00  61 df                    |..a.....a.|
+Sending: GET_READER_OPTIONAL_PARAMS    1843104.014143851
+         ff 02 6a 01 03 2e 4d                              |..j...M|
+Received:GET_READER_OPTIONAL_PARAMS    1843104.016090782
+         ff 03 6a 00 00 01 03 00  3d 44                    |..j.....=D|
+Sending: GET_USER_GPIO_INPUTS          1843104.016234473
+         ff 01 66 01 ba bc                                 |..f...|
+Received:GET_USER_GPIO_INPUTS          1843104.019013964
+         ff 0d 66 00 00 01 01 00  00 02 00 00 03 00 00 04  |..f.............|
+         00 01 64 46                                       |..dF|
+Sending: SET_USER_GPIO_OUTPUTS         1843104.019180809
+         ff 01 96 01 4a bc                                 |....J.|
+Received:SET_USER_GPIO_OUTPUTS         1843104.020925470
+         ff 02 96 00 00 01 00 28  e1                       |.......(.|
+Sending: SET_USER_GPIO_OUTPUTS         1843104.021029058
+         ff 01 96 02 4a bf                                 |....J.|
+Received:SET_USER_GPIO_OUTPUTS         1843104.022778563
+         ff 02 96 00 00 02 00 2b  e1                       |.......+.|
+Sending: SET_USER_GPIO_OUTPUTS         1843104.022877259
+         ff 01 96 03 4a be                                 |....J.|
+Received:SET_USER_GPIO_OUTPUTS         1843104.024651688
+         ff 02 96 00 00 03 00 2a  e1                       |.......*.|
+Sending: SET_USER_GPIO_OUTPUTS         1843104.024743719
+         ff 01 96 04 4a b9                                 |....J.|
+Received:SET_USER_GPIO_OUTPUTS         1843104.026471869
+         ff 02 96 00 00 04 00 2d  e1                       |.......-.|
+Sending: GET_USER_GPIO_INPUTS          1843104.026579568
+         ff 01 66 01 ba bc                                 |..f...|
+Received:GET_USER_GPIO_INPUTS          1843104.029296517
+         ff 0d 66 00 00 01 01 00  00 02 00 00 03 00 00 04  |..f.............|
+         00 01 64 46                                       |..dF|
+Sending: SET_USER_GPIO_OUTPUTS         1843104.029482652
+         ff 01 96 01 4a bc                                 |....J.|
+Received:SET_USER_GPIO_OUTPUTS         1843104.031180966
+         ff 02 96 00 00 01 00 28  e1                       |.......(.|
+Sending: SET_USER_GPIO_OUTPUTS         1843104.031264482
+         ff 01 96 02 4a bf                                 |....J.|
+Received:SET_USER_GPIO_OUTPUTS         1843104.032969922
+         ff 02 96 00 00 02 00 2b  e1                       |.......+.|
+Sending: SET_USER_GPIO_OUTPUTS         1843104.033060371
+         ff 01 96 03 4a be                                 |....J.|
+Received:SET_USER_GPIO_OUTPUTS         1843104.034797771
+         ff 02 96 00 00 03 00 2a  e1                       |.......*.|
+Sending: SET_USER_GPIO_OUTPUTS         1843104.034908477
+         ff 01 96 04 4a b9                                 |....J.|
+Received:SET_USER_GPIO_OUTPUTS         1843104.036642853
+         ff 02 96 00 00 04 00 2d  e1                       |.......-.|
+Sending: GET_READER_OPTIONAL_PARAMS    1843104.037128667
+         ff 02 6a 01 01 2e 4f                              |..j...O|
+Received:GET_READER_OPTIONAL_PARAMS    1843104.039429448
+         ff 03 6a 00 00 01 01 00  3f 44                    |..j.....?D|
+Sending: GET_READ_TX_POWER             1843104.039533356
+         ff 01 62 01 be bc                                 |..b...|
+Received:GET_READ_TX_POWER             1843104.041734922
+         ff 07 62 00 00 01 08 fc  0a 8c 00 00 61 d4        |..b.........a.|
+Sending: GET_READ_TX_POWER             1843104.041857989
+         ff 01 62 01 be bc                                 |..b...|
+Received:GET_READ_TX_POWER             1843104.044036236
+         ff 07 62 00 00 01 08 fc  0a 8c 00 00 61 d4        |..b.........a.|
+Sending: GET_READ_TX_POWER             1843104.044218533
+         ff 01 62 00 be bd                                 |..b...|
+Received:GET_READ_TX_POWER             1843104.046018204
+         ff 03 62 00 00 00 08 fc  a3 5a                    |..b......Z|
+Sending: GET_WRITE_TX_POWER            1843104.046120446
+         ff 01 64 00 b8 bd                                 |..d...|
+Received:GET_WRITE_TX_POWER            1843104.047914131
+         ff 03 64 00 00 00 08 fc  84 c3                    |..d.......|
+Sending: GET_TEMPERATURE               1843104.048045772
+         ff 00 72 1d 7d                                    |..r.}|
+Received:GET_TEMPERATURE               1843104.049703789
+         ff 01 72 00 00 23 48 24                           |..r..#H$|
+Sending: GET_READER_OPTIONAL_PARAMS    1843104.049820007
+         ff 02 6a 01 06 2e 48                              |..j...H|
+Received:GET_READER_OPTIONAL_PARAMS    1843104.051713229
+         ff 03 6a 00 00 01 06 00  38 44                    |..j.....8D|
+Sending: GET_READER_OPTIONAL_PARAMS    1843104.051813518
+         ff 02 6a 01 09 2e 47                              |..j...G|
+Received:GET_READER_OPTIONAL_PARAMS    1843104.053740315
+         ff 03 6a 00 00 01 09 01  37 45                    |..j.....7E|
+Sending: GET_READER_OPTIONAL_PARAMS    1843104.053832664
+         ff 02 6a 01 00 2e 4e                              |..j...N|
+Received:GET_READER_OPTIONAL_PARAMS    1843104.055718413
+         ff 03 6a 00 00 01 00 00  3e 44                    |..j.....>D|
+Sending: GET_READER_OPTIONAL_PARAMS    1843104.055836782
+         ff 02 6a 01 08 2e 46                              |..j...F|
+Received:GET_READER_OPTIONAL_PARAMS    1843104.057753904
+         ff 03 6a 00 00 01 08 01  36 45                    |..j.....6E|
+Sending: HW_VERSION                    1843104.057897168
+         ff 02 10 00 40 f0 d3                              |....@..|
+Received:HW_VERSION                    1843104.061630608
+         ff 16 10 00 00 00 40 40  12 34 35 31 36 30 30 36  |......@@.4516006|
+         37 37 30 31 31 33 30 33  32 34 41 49 5b           |7701130324AI[|
+Sending: GET_AVAILABLE_PROTOCOLS       1843104.061908417
+         ff 00 70 1d 7f                                    |..p..|
+Received:GET_AVAILABLE_PROTOCOLS       1843104.063540235
+         ff 02 70 00 00 00 05 3b  75                       |..p....;u|
+Sending: GET_FREQ_HOP_TABLE            1843104.063639212
+         ff 00 65 1d 6a                                    |..e.j|
+Received:GET_FREQ_HOP_TABLE            1843104.065051814
+         ff 00 65 00 00 b8 c3                              |..e....|
+Sending: GET_FREQ_HOP_TABLE            1843104.065156915
+         ff 01 65 01 b9 bc                                 |..e...|
+Received:GET_FREQ_HOP_TABLE            1843104.067154924
+         ff 05 65 00 00 01 00 00  00 00 4a fc              |..e.......J.|
+Sending: GET_REGION                    1843104.067269349
+         ff 00 67 1d 68                                    |..g.h|
+Received:GET_REGION                    1843104.068830337
+         ff 01 67 00 00 00 b4 81                           |..g.....|
+Sending: GET_AVAILABLE_REGIONS         1843104.068952705
+         ff 00 71 1d 7e                                    |..q.~|
+Received:GET_AVAILABLE_REGIONS         1843104.071334737
+         ff 0a 71 00 00 0d 0e 04  05 06 08 09 0b 0c ff 1f  |..q.............|
+         dd                                                |.|
+Sending: GET_REGION                    1843104.071554255
+         ff 02 67 01 40 ff a3                              |..g.@..|
+Received:GET_REGION                    1843104.073190991
+         ff 00 67 01 05 99 84                              |..g....|
+Sending: GET_READER_OPTIONAL_PARAMS    1843104.073326217
+         ff 02 6a 01 0a 2e 44                              |..j...D|
+Received:GET_READER_OPTIONAL_PARAMS    1843104.075080659
+         ff 01 6a 01 05 01 d7 fd                           |..j.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1843104.075274228
+         ff 02 6a 01 12 2e 5c                              |..j...\|
+Received:GET_READER_OPTIONAL_PARAMS    1843104.077342544
+         ff 04 6a 00 00 01 12 00  00 69 af                 |..j......i.|
+Sending: GET_READER_OPTIONAL_PARAMS    1843104.077450135
+         ff 02 6a 01 13 2e 5d                              |..j...]|
+Received:GET_READER_OPTIONAL_PARAMS    1843104.079492585
+         ff 04 6a 00 00 01 13 00  11 79 9f                 |..j......y.|
+Sending: GET_READER_OPTIONAL_PARAMS    1843104.079611942
+         ff 02 6a 01 0b 2e 45                              |..j...E|
+Received:GET_READER_OPTIONAL_PARAMS    1843104.081555871
+         ff 03 6a 00 00 01 0b 00  35 44                    |..j.....5D|
+Sending: GET_PROTOCOL_PARAM            1843104.081659619
+         ff 02 6b 05 3f 3a 50                              |..k.?:P|
+Received:GET_PROTOCOL_PARAM            1843104.083816779
+         ff 05 6b 00 00 05 3f 00  4e 20 4d 14              |..k...?.N M.|
+Sending: GET_PROTOCOL_PARAM            1843104.083938210
+         ff 02 6b 05 3f 3a 50                              |..k.?:P|
+Received:GET_PROTOCOL_PARAM            1843104.086023365
+         ff 05 6b 00 00 05 3f 00  4e 20 4d 14              |..k...?.N M.|
+Sending: GET_READER_OPTIONAL_PARAMS    1843104.086194598
+         ff 02 6a 01 1e 2e 50                              |..j...P|
+Received:GET_READER_OPTIONAL_PARAMS    1843104.088095725
+         ff 03 6a 00 00 01 1e 00  20 44                    |..j..... D|
diff --git a/tests/read.result b/tests/read.result
new file mode 100644
--- /dev/null
+++ b/tests/read.result
@@ -0,0 +1,17 @@
+Right 16
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\SOH\128\DLE\128\175\207", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 7064, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 10, trRssi = -44, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\SOH\DLE\DLEP\177g", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 19480, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 9, trRssi = -47, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\STX\SYN\DLE\128\176\GS", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 50693, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 10, trRssi = -36, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\STXC\DLE\128\176V", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 2511, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 9, trRssi = -50, trFrequency = 919600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\NULF\DLEP\176\231", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 29622, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 171, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 7, trRssi = -53, trFrequency = 919600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\NUL0\DLEP\176\199", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 34775, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 9, trRssi = -45, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\NUL4\DLEP\176\213", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 15522, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 8, trRssi = -47, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\STX3\DLE\128\176E", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 13851, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 5, trRssi = -50, trFrequency = 919600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\NUL\129\DLEP\177-", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 27885, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 171, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 10, trRssi = -41, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\STXD\DLE\128\176O", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 60675, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 8, trRssi = -46, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\STX\130\DLE\144\174\134", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 14404, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 168, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 4, trRssi = -58, trFrequency = 919600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\NULT\DLEP\176\247", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 8542, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 2, trRssi = -58, trFrequency = 919600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\SOH&\DLEP\177\135", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 28765, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 168, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 6, trRssi = -56, trFrequency = 919600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\NUL%\DLEP\176\189", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 32519, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 171, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 3, trRssi = -54, trFrequency = 919600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\NUL%\DLE`\178\217", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 61666, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 10, trRssi = -48, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\SO\SOH\137\DLEP\177\255", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 49247, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 171, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 3, trRssi = -53, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
diff --git a/tests/read.transport b/tests/read.transport
new file mode 100644
--- /dev/null
+++ b/tests/read.transport
@@ -0,0 +1,119 @@
+Sending: VERSION                       1605291.034818992
+         ff 00 03 1d 0c                                    |.....|
+Received:VERSION                       1605291.039468075
+         ff 14 03 00 00 14 12 08  00 30 00 00 02 20 16 12  |.........0... ..|
+         13 01 07 01 02 00 00 00  10 1b 05                 |...........|
+Sending: GET_CURRENT_PROGRAM           1605291.039998471
+         ff 00 0c 1d 03                                    |.....|
+Received:GET_CURRENT_PROGRAM           1605291.041600004
+         ff 01 0c 00 00 52 63 03                           |.....Rc.|
+Sending: GET_POWER_MODE                1605291.041699340
+         ff 00 68 1d 67                                    |..h.g|
+Received:GET_POWER_MODE                1605291.043273969
+         ff 01 68 00 00 00 a4 bf                           |..h.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1605291.043372336
+         ff 02 6a 01 0e 2e 40                              |..j...@|
+Received:GET_READER_OPTIONAL_PARAMS    1605291.045325490
+         ff 03 6a 00 00 01 0e 00  30 44                    |..j.....0D|
+Sending: GET_READER_OPTIONAL_PARAMS    1605291.045461142
+         ff 02 6a 01 12 2e 5c                              |..j...\|
+Received:GET_READER_OPTIONAL_PARAMS    1605291.052225601
+         ff 04 6a 00 00 01 12 00  00 69 af                 |..j......i.|
+Sending: GET_TAG_PROTOCOL              1605291.052352051
+         ff 00 63 1d 6c                                    |..c.l|
+Received:GET_TAG_PROTOCOL              1605291.053966261
+         ff 02 63 00 00 00 05 21  46                       |..c....!F|
+Sending: GET_ANTENNA_PORT              1605291.054063294
+         ff 01 61 05 bd b8                                 |..a...|
+Received:GET_ANTENNA_PORT              1605291.055938871
+         ff 03 61 00 00 05 01 00  61 df                    |..a.....a.|
+Sending: GET_READER_OPTIONAL_PARAMS    1605291.056043464
+         ff 02 6a 01 0c 2e 42                              |..j...B|
+Received:GET_READER_OPTIONAL_PARAMS    1605291.058027930
+         ff 03 6a 00 00 01 0c 01  32 45                    |..j.....2E|
+Sending: GET_READER_OPTIONAL_PARAMS    1605291.058132382
+         ff 02 6a 01 0d 2e 43                              |..j...C|
+Received:GET_READER_OPTIONAL_PARAMS    1605291.060352548
+         ff 06 6a 00 00 01 0d 00  00 00 00 15 43           |..j.........C|
+Sending: SET_REGION                    1605291.060484598
+         ff 01 97 0d 4b b0                                 |....K.|
+Received:SET_REGION                    1605291.062121507
+         ff 00 97 00 00 77 9e                              |.....w.|
+Sending: SET_READ_TX_POWER             1605291.062221101
+         ff 02 92 08 98 49 c1                              |.....I.|
+Received:SET_READ_TX_POWER             1605291.063918471
+         ff 00 92 00 00 27 3b                              |.....';|
+Sending: SET_WRITE_TX_POWER            1605291.064004619
+         ff 02 94 08 98 29 07                              |.....).|
+Received:SET_WRITE_TX_POWER            1605291.065708786
+         ff 00 94 00 00 47 fd                              |.....G.|
+Sending: SET_ANTENNA_PORT              1605291.065801253
+         ff 02 91 01 01 70 3b                              |.....p;|
+Received:SET_ANTENNA_PORT              1605291.067461716
+         ff 00 91 00 00 17 58                              |......X|
+Sending: SET_READER_OPTIONAL_PARAMS    1605291.067548954
+         ff 03 9a 01 06 01 a9 5c                           |.......\|
+Received:SET_READER_OPTIONAL_PARAMS    1605291.069282407
+         ff 00 9a 00 00 a6 33                              |......3|
+Sending: GET_READER_STATS              1605291.069357329
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1605291.071382570
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1605291.071487748
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1605291.072970630
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1605291.073060872
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1605291.074807197
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1605291.074915830
+         ff 05 22 00 00 13 03 e8  29 05                    |..".....).|
+Received:READ_TAG_ID_MULTIPLE          1605292.082519826
+         ff 07 22 00 00 00 00 13  00 00 00 10 8b 49        |.."..........I|
+Sending: GET_TAG_ID_BUFFER             1605292.082851068
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1605292.106795041
+         ff f2 29 00 00 01 ff 00  07 0a d4 11 0e 13 e8 00  |..).............|
+         00 03 34 00 ae 05 00 00  00 00 80 30 00 e2 00 00  |..4........0....|
+         15 86 0e 01 80 10 80 af  cf 1b 98 09 d1 11 0e 13  |................|
+         e8 00 00 03 23 00 ae 05  00 00 00 00 80 30 00 e2  |....#........0..|
+         00 00 15 86 0e 01 10 10  50 b1 67 4c 18 0a dc 11  |........P.gL....|
+         0e 13 e8 00 00 03 28 00  ae 05 00 00 00 00 80 30  |......(........0|
+         00 e2 00 00 15 86 0e 02  16 10 80 b0 1d c6 05 09  |................|
+         ce 11 0e 08 30 00 00 00  b7 00 ae 05 00 00 00 00  |....0...........|
+         80 30 00 e2 00 00 15 86  0e 02 43 10 80 b0 56 09  |.0........C...V.|
+         cf 07 cb 11 0e 08 30 00  00 00 e8 00 ab 05 00 00  |......0.........|
+         00 00 80 30 00 e2 00 00  15 86 0e 00 46 10 50 b0  |...0........F.P.|
+         e7 73 b6 09 d3 11 0e 13  e8 00 00 03 10 00 ae 05  |.s..............|
+         00 00 00 00 80 30 00 e2  00 00 15 86 0e 00 30 10  |.....0........0.|
+         50 b0 c7 87 d7 08 d1 11  0e 13 e8 00 00 03 5d 00  |P.............].|
+         ae 05 00 00 00 00 80 30  00 e2 00 00 15 86 0e 00  |.......0........|
+         34 10 50 b0 d5 3c a2 14  c0                       |4.P..<...|
+Sending: GET_TAG_ID_BUFFER             1605292.109544685
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1605292.133518195
+         ff f2 29 00 00 01 ff 00  07 05 ce 11 0e 08 30 00  |..)...........0.|
+         00 01 5c 00 ae 05 00 00  00 00 80 30 00 e2 00 00  |..\........0....|
+         15 86 0e 02 33 10 80 b0  45 36 1b 0a d7 11 0e 13  |....3...E6......|
+         e8 00 00 03 16 00 ab 05  00 00 00 00 80 30 00 e2  |.............0..|
+         00 00 15 86 0e 00 81 10  50 b1 2d 6c ed 08 d2 11  |........P.-l....|
+         0e 13 e8 00 00 03 39 00  ae 05 00 00 00 00 80 30  |......9........0|
+         00 e2 00 00 15 86 0e 02  44 10 80 b0 4f ed 03 04  |........D...O...|
+         c6 11 0e 08 30 00 00 00  4d 00 a8 05 00 00 00 00  |....0...M.......|
+         80 30 00 e2 00 00 15 86  0e 02 82 10 90 ae 86 38  |.0.............8|
+         44 02 c6 11 0e 08 30 00  00 00 54 00 ae 05 00 00  |D.....0...T.....|
+         00 00 80 30 00 e2 00 00  15 86 0e 00 54 10 50 b0  |...0........T.P.|
+         f7 21 5e 06 c8 11 0e 08  30 00 00 00 5b 00 a8 05  |.!^.....0...[...|
+         00 00 00 00 80 30 00 e2  00 00 15 86 0e 01 26 10  |.....0........&.|
+         50 b1 87 70 5d 03 ca 11  0e 08 30 00 00 00 64 00  |P..p].....0...d.|
+         ab 05 00 00 00 00 80 30  00 e2 00 00 15 86 0e 00  |.......0........|
+         25 10 50 b0 bd 7f 07 a0  95                       |%.P......|
+Sending: GET_TAG_ID_BUFFER             1605292.136180386
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1605292.144773020
+         ff 48 29 00 00 01 ff 00  02 0a d0 11 0e 13 e8 00  |.H).............|
+         00 03 1b 00 ae 05 00 00  00 00 80 30 00 e2 00 00  |...........0....|
+         15 86 0e 00 25 10 60 b2  d9 f0 e2 03 cb 11 0e 13  |....%.`.........|
+         e8 00 00 03 78 00 ab 05  00 00 00 00 80 30 00 e2  |....x........0..|
+         00 00 15 86 0e 01 89 10  50 b1 ff c0 5f 3f 43     |........P..._?C|
diff --git a/tests/readUser.result b/tests/readUser.result
new file mode 100644
--- /dev/null
+++ b/tests/readUser.result
@@ -0,0 +1,3 @@
+Right 2
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NUL\NUL\NAK\134\DC2\NULu%\DLE\EM|", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 4362, tdGen2 = Just (GEN2_TagData {g2Pc = "4\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 15, trRssi = -46, trFrequency = 924800, trTimestamp = 0, trData = "Engineer's Mini-Notebook: Forumulas, Symbols & Circuits\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NULQ\134\SOH\a\SOH\135\DC4\NUL\135|", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 12577, tdGen2 = Just (GEN2_TagData {g2Pc = "4\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 171, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 13, trRssi = -56, trFrequency = 924800, trTimestamp = 0, trData = "Bananagrams\NUL!\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
diff --git a/tests/readUser.transport b/tests/readUser.transport
new file mode 100644
--- /dev/null
+++ b/tests/readUser.transport
@@ -0,0 +1,95 @@
+Sending: VERSION                       1605849.767314237
+         ff 00 03 1d 0c                                    |.....|
+Received:VERSION                       1605849.771061295
+         ff 14 03 00 00 14 12 08  00 30 00 00 02 20 16 12  |.........0... ..|
+         13 01 07 01 02 00 00 00  10 1b 05                 |...........|
+Sending: GET_CURRENT_PROGRAM           1605849.771844202
+         ff 00 0c 1d 03                                    |.....|
+Received:GET_CURRENT_PROGRAM           1605849.773508249
+         ff 01 0c 00 00 52 63 03                           |.....Rc.|
+Sending: GET_POWER_MODE                1605849.773657114
+         ff 00 68 1d 67                                    |..h.g|
+Received:GET_POWER_MODE                1605849.775283044
+         ff 01 68 00 00 00 a4 bf                           |..h.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1605849.775394058
+         ff 02 6a 01 0e 2e 40                              |..j...@|
+Received:GET_READER_OPTIONAL_PARAMS    1605849.777364867
+         ff 03 6a 00 00 01 0e 00  30 44                    |..j.....0D|
+Sending: GET_READER_OPTIONAL_PARAMS    1605849.778223622
+         ff 02 6a 01 12 2e 5c                              |..j...\|
+Received:GET_READER_OPTIONAL_PARAMS    1605849.780317241
+         ff 04 6a 00 00 01 12 00  00 69 af                 |..j......i.|
+Sending: GET_TAG_PROTOCOL              1605849.780444570
+         ff 00 63 1d 6c                                    |..c.l|
+Received:GET_TAG_PROTOCOL              1605849.782118781
+         ff 02 63 00 00 00 05 21  46                       |..c....!F|
+Sending: GET_ANTENNA_PORT              1605849.782238880
+         ff 01 61 05 bd b8                                 |..a...|
+Received:GET_ANTENNA_PORT              1605849.784171112
+         ff 03 61 00 00 05 01 00  61 df                    |..a.....a.|
+Sending: GET_READER_OPTIONAL_PARAMS    1605849.784313721
+         ff 02 6a 01 0c 2e 42                              |..j...B|
+Received:GET_READER_OPTIONAL_PARAMS    1605849.786271469
+         ff 03 6a 00 00 01 0c 01  32 45                    |..j.....2E|
+Sending: GET_READER_OPTIONAL_PARAMS    1605849.786379534
+         ff 02 6a 01 0d 2e 43                              |..j...C|
+Received:GET_READER_OPTIONAL_PARAMS    1605849.788780013
+         ff 06 6a 00 00 01 0d 00  00 00 00 15 43           |..j.........C|
+Sending: SET_REGION                    1605849.788979855
+         ff 01 97 0d 4b b0                                 |....K.|
+Received:SET_REGION                    1605849.790714839
+         ff 00 97 00 00 77 9e                              |.....w.|
+Sending: SET_READ_TX_POWER             1605849.790866384
+         ff 02 92 08 98 49 c1                              |.....I.|
+Received:SET_READ_TX_POWER             1605849.792519783
+         ff 00 92 00 00 27 3b                              |.....';|
+Sending: SET_WRITE_TX_POWER            1605849.792614109
+         ff 02 94 08 98 29 07                              |.....).|
+Received:SET_WRITE_TX_POWER            1605849.794407465
+         ff 00 94 00 00 47 fd                              |.....G.|
+Sending: SET_ANTENNA_PORT              1605849.794567169
+         ff 02 91 01 01 70 3b                              |.....p;|
+Received:SET_ANTENNA_PORT              1605849.796480969
+         ff 00 91 00 00 17 58                              |......X|
+Sending: SET_READER_OPTIONAL_PARAMS    1605849.796618312
+         ff 03 9a 01 06 01 a9 5c                           |.......\|
+Received:SET_READER_OPTIONAL_PARAMS    1605849.798632728
+         ff 00 9a 00 00 a6 33                              |......3|
+Sending: GET_READER_STATS              1605849.798778108
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1605849.801082510
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1605849.801242465
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1605849.802925103
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1605849.803069867
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1605849.805117395
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1605849.805311145
+         ff 11 22 00 00 17 03 e8  01 09 28 07 d0 00 03 00  |..".......(.....|
+         00 00 00 20 49 70                                 |... Ip|
+Received:READ_TAG_ID_MULTIPLE          1605850.819217037
+         ff 4d 22 00 00 00 00 17  00 00 00 02 01 28 00 1a  |.M"..........(..|
+         00 02 45 6e 67 69 6e 65  65 72 27 73 20 4d 69 6e  |..Engineer's Min|
+         69 2d 4e 6f 74 65 62 6f  6f 6b 3a 20 46 6f 72 75  |i-Notebook: Foru|
+         6d 75 6c 61 73 2c 20 53  79 6d 62 6f 6c 73 20 26  |mulas, Symbols &|
+         20 43 69 72 63 75 69 74  73 00 00 00 00 00 00 00  | Circuits.......|
+         00 00 53 de                                       |..S.|
+Sending: GET_TAG_ID_BUFFER             1605850.820236496
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1605850.840283979
+         ff c8 29 00 00 01 ff 00  02 0f d2 11 0e 1c 80 00  |..).............|
+         00 02 e8 00 ae 05 02 00  45 6e 67 69 6e 65 65 72  |........Engineer|
+         27 73 20 4d 69 6e 69 2d  4e 6f 74 65 62 6f 6f 6b  |'s Mini-Notebook|
+         3a 20 46 6f 72 75 6d 75  6c 61 73 2c 20 53 79 6d  |: Forumulas, Sym|
+         62 6f 6c 73 20 26 20 43  69 72 63 75 69 74 73 00  |bols & Circuits.|
+         00 00 00 00 00 00 00 00  00 00 80 34 00 e2 00 00  |...........4....|
+         15 86 12 00 75 25 10 19  7c 11 0a 0d c8 11 0e 1c  |....u%..|.......|
+         80 00 00 02 ba 00 ab 05  02 00 42 61 6e 61 6e 61  |..........Banana|
+         67 72 61 6d 73 00 21 00  00 00 00 00 00 00 00 00  |grams.!.........|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 80 34 00 e2  |.............4..|
+         00 51 86 01 07 01 87 14  00 87 7c 31 21 76 a4     |.Q........|1!v.|
diff --git a/tests/replay.hs b/tests/replay.hs
new file mode 100644
--- /dev/null
+++ b/tests/replay.hs
@@ -0,0 +1,496 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Control.Exception ( throw, try )
+import Control.Monad ( when, void, forM_ )
+import qualified Data.ByteString as B ( pack )
+import Data.List ( maximumBy, delete )
+import Data.Monoid ( (<>) )
+import Data.Ord ( comparing )
+import qualified Data.Text as T ( empty, pack )
+import Options.Applicative
+    ( Alternative(many),
+      Applicative((<*>)),
+      Parser,
+      helper,
+      execParser,
+      value,
+      switch,
+      strOption,
+      str,
+      short,
+      metavar,
+      long,
+      info,
+      help,
+      header,
+      fullDesc,
+      argument,
+      (<$>) )
+import System.Directory ( makeAbsolute )
+import System.IO
+    ( Handle,
+      IOMode(ReadMode, WriteMode),
+      withFile,
+      hPutStrLn,
+      hGetLine )
+import System.Info ( os )
+
+import qualified System.Hardware.MercuryApi as TMR
+import qualified System.Hardware.MercuryApi.Params as TMR
+import qualified System.Hardware.MercuryApi.Testing as TMR
+
+data TestDirection = Record | Playback
+
+data TestState =
+  TestState
+  { tsDirection :: TestDirection
+  , tsHandle :: Handle
+  }
+
+type TestFunc = TMR.Reader -> TestState -> IO ()
+
+suppressUri :: Either TMR.MercuryException a -> Either TMR.MercuryException a
+suppressUri (Left exc) = Left exc { TMR.meUri = T.empty }
+suppressUri x = x
+
+check :: (Read a, Show a, Eq a) => TestState -> IO a -> IO a
+check ts f = do
+  eth' <- try f
+  let eth = suppressUri eth'
+  case tsDirection ts of
+    Record -> hPutStrLn (tsHandle ts) (show eth)
+    Playback -> do
+      ln <- hGetLine (tsHandle ts)
+      let expected = read ln :: (Read a => Either TMR.MercuryException a)
+      when (expected /= eth) $ do
+        putStrLn "expected:"
+        putStrLn ln
+        putStrLn "but got:"
+        print eth
+        fail "test failed"
+  return $ case eth of
+             Left exc -> throw exc -- only thrown if caller looks at result
+             Right x -> x
+
+runTest :: String -> TestDirection -> String -> TestFunc -> IO ()
+runTest uri dir name func = do
+  putStrLn $ "running test: " ++ name
+  let fname = "tests/" ++ name
+      transportFile = fname ++ ".transport"
+      resultFile = fname ++ ".result"
+  case dir of
+    Record -> do
+      withFile transportFile WriteMode $ \hTransport -> do
+        withFile resultFile WriteMode $ \hResult -> do
+          TMR.withReader (T.pack uri) $ \rdr -> do
+            listener <- TMR.opcodeListener hTransport
+            TMR.addTransportListener rdr listener
+            TMR.paramSetTransportTimeout rdr 10000
+            TMR.connect rdr
+            func rdr (TestState dir hResult)
+    Playback -> do
+      absFile <- makeAbsolute transportFile
+      withFile resultFile ReadMode $ \hResult -> do
+        TMR.withReader (T.pack $ "test://" ++ absFile) $ \rdr -> do
+          TMR.paramSetTransportTimeout rdr 10000
+          TMR.connect rdr
+          func rdr (TestState dir hResult)
+
+setRegionAndPower :: TMR.Reader -> IO ()
+setRegionAndPower rdr = do
+  -- pwr <- TMR.paramGetRadioPowerMax rdr
+  TMR.paramSetBasics rdr TMR.REGION_NA2 2200 TMR.sparkFunAntennas
+  TMR.paramSetTagReadDataRecordHighestRssi rdr True
+
+readUser =
+  TMR.TagOp_GEN2_ReadData
+  { TMR.opBank = TMR.GEN2_BANK_USER
+  , TMR.opExtraBanks = []
+  , TMR.opWordAddress = 0
+  , TMR.opLen = 32
+  }
+
+emptyUserDataFilter :: TMR.TagFilter
+emptyUserDataFilter = TMR.mkFilterGen2 TMR.GEN2_BANK_USER 0 $ B.pack [0, 0]
+
+testParams :: TestFunc
+testParams rdr ts = do
+  params <- check ts $ TMR.paramList rdr
+  let params' = TMR.PARAM_URI `delete` params -- because URI will be different
+  forM_ params' $ \param -> do
+    check ts $ TMR.paramGetString rdr param
+
+testRead :: TestFunc
+testRead rdr ts = do
+  setRegionAndPower rdr
+
+  tags <- TMR.read rdr 1000
+  check ts $ return $ length tags
+  forM_ tags $ \tag -> do
+    check ts $ return tag { TMR.trTimestamp = 0 }
+
+testReadUser :: TestFunc
+testReadUser rdr ts = do
+  setRegionAndPower rdr
+  TMR.paramSetReadPlanTagop rdr (Just readUser)
+
+  tags <- TMR.read rdr 1000
+  check ts $ return $ length tags
+  forM_ tags $ \tag -> do
+    check ts $ return tag { TMR.trTimestamp = 0 }
+
+testWrite :: TestFunc
+testWrite rdr ts = do
+  setRegionAndPower rdr
+  TMR.paramSetReadPlanFilter rdr (Just emptyUserDataFilter)
+
+  tags <- TMR.read rdr 1000
+  check ts $ return $ length tags
+  let trd = maximumBy (comparing TMR.trRssi) tags
+  check ts $ return trd { TMR.trTimestamp = 0 }
+
+  let epcFilt = TMR.TagFilterEPC (TMR.trTag trd)
+      words = TMR.packBytesIntoWords "I am Groot"
+      opWrite = TMR.TagOp_GEN2_WriteData
+                { TMR.opBank = TMR.GEN2_BANK_USER
+                , TMR.opWordAddress = 0
+                , TMR.opData = words
+                }
+  check ts $ TMR.executeTagOp rdr opWrite (Just epcFilt)
+
+  TMR.paramSetReadPlanFilter rdr Nothing
+  TMR.paramSetReadPlanTagop rdr (Just readUser)
+  tags2 <- TMR.read rdr 1000
+  check ts $ return $ length tags2
+  forM_ tags2 $ \tag -> do
+    check ts $ return tag { TMR.trTimestamp = 0 }
+
+testWriteEpc :: TestFunc
+testWriteEpc rdr ts = do
+  setRegionAndPower rdr
+  TMR.paramSetReadPlanFilter rdr (Just emptyUserDataFilter)
+
+  tags <- TMR.read rdr 1000
+  check ts $ return $ length tags
+  let trd = maximumBy (comparing TMR.trRssi) tags
+  check ts $ return trd { TMR.trTimestamp = 0 }
+
+  let tag = TMR.trTag trd
+      epcFilt = TMR.TagFilterEPC tag
+      Just newEpc = TMR.hexToBytes "0123456789abcdef"
+      newTag = tag { TMR.tdEpc = newEpc }
+      opWrite = TMR.TagOp_GEN2_WriteTag newTag
+
+  check ts $ TMR.executeTagOp rdr opWrite (Just epcFilt)
+
+  TMR.paramSetReadPlanFilter rdr Nothing
+  TMR.paramSetReadPlanTagop rdr (Just readUser)
+  tags2 <- TMR.read rdr 1000
+  check ts $ return $ length tags2
+  forM_ tags2 $ \tag -> do
+    check ts $ return tag { TMR.trTimestamp = 0 }
+
+  let epcFilt2 = TMR.TagFilterEPC newTag
+      opWrite2 = TMR.TagOp_GEN2_WriteTag tag
+
+  void $ check ts $ TMR.executeTagOp rdr opWrite2 (Just epcFilt2)
+
+testLock :: TestFunc
+testLock rdr ts = do
+  setRegionAndPower rdr
+  TMR.paramSetReadPlanFilter rdr (Just emptyUserDataFilter)
+
+  -- find a tag
+  tags <- TMR.read rdr 1000
+  check ts $ return $ length tags
+  let trd = maximumBy (comparing TMR.trRssi) tags
+  check ts $ return trd { TMR.trTimestamp = 0 }
+
+  -- write access password
+  let password = 12345
+      epcFilt = TMR.TagFilterEPC (TMR.trTag trd)
+      opWrite = TMR.TagOp_GEN2_WriteData
+                { TMR.opBank = TMR.GEN2_BANK_RESERVED
+                , TMR.opWordAddress = TMR.accessPasswordAddress
+                , TMR.opData = TMR.passwordToWords password
+                }
+  check ts $ TMR.executeTagOp rdr opWrite (Just epcFilt)
+
+  -- lock user bank
+  let opLock = TMR.TagOp_GEN2_Lock
+               { TMR.opMask   = [TMR.GEN2_LOCK_BITS_USER]
+               , TMR.opAction = [TMR.GEN2_LOCK_BITS_USER]
+               , TMR.opAccessPassword = password
+               }
+  check ts $ TMR.executeTagOp rdr opLock (Just epcFilt)
+
+  -- attempt to write data; should fail
+  let opWrite2 = TMR.TagOp_GEN2_WriteData
+                 { TMR.opBank = TMR.GEN2_BANK_USER
+                 , TMR.opWordAddress = 0
+                 , TMR.opData = TMR.packBytesIntoWords "This should fail"
+                 }
+  check ts $ TMR.executeTagOp rdr opWrite2 (Just epcFilt)
+
+  -- unlock user bank
+  let opUnlock = TMR.TagOp_GEN2_Lock
+                 { TMR.opMask   = [TMR.GEN2_LOCK_BITS_USER]
+                 , TMR.opAction = []
+                 , TMR.opAccessPassword = password
+                 }
+  check ts $ TMR.executeTagOp rdr opUnlock (Just epcFilt)
+
+  -- attempt to write data; should succeed
+  let opWrite3 = TMR.TagOp_GEN2_WriteData
+                 { TMR.opBank = TMR.GEN2_BANK_USER
+                 , TMR.opWordAddress = 0
+                 , TMR.opData = TMR.packBytesIntoWords "This should succeed"
+                 }
+  void $ check ts $ TMR.executeTagOp rdr opWrite3 (Just epcFilt)
+
+sequentialBytes = B.pack [0..7]
+
+testBlockWrite :: TestFunc
+testBlockWrite rdr ts = do
+  setRegionAndPower rdr
+  TMR.paramSetReadPlanFilter rdr (Just emptyUserDataFilter)
+
+  tags <- TMR.read rdr 1000
+  check ts $ return $ length tags
+  let trd = maximumBy (comparing TMR.trRssi) tags
+  check ts $ return trd { TMR.trTimestamp = 0 }
+
+  let epcFilt = TMR.TagFilterEPC (TMR.trTag trd)
+      words = TMR.packBytesIntoWords sequentialBytes
+      opWrite = TMR.TagOp_GEN2_BlockWrite
+                { TMR.opBank = TMR.GEN2_BANK_USER
+                , TMR.opWordPtr = 0
+                , TMR.opData = words
+                }
+  check ts $ TMR.executeTagOp rdr opWrite (Just epcFilt)
+
+  TMR.paramSetReadPlanFilter rdr Nothing
+  TMR.paramSetReadPlanTagop rdr (Just readUser)
+  tags2 <- TMR.read rdr 1000
+  check ts $ return $ length tags2
+  forM_ tags2 $ \tag -> do
+    check ts $ return tag { TMR.trTimestamp = 0 }
+
+sequentialUserDataFilter :: TMR.TagFilter
+sequentialUserDataFilter = TMR.mkFilterGen2 TMR.GEN2_BANK_USER 0 sequentialBytes
+
+testBlockErase :: TestFunc
+testBlockErase rdr ts = do
+  setRegionAndPower rdr
+  TMR.paramSetReadPlanFilter rdr (Just sequentialUserDataFilter)
+
+  tags <- TMR.read rdr 1000
+  check ts $ return $ length tags
+  let trd = maximumBy (comparing TMR.trRssi) tags
+  check ts $ return trd { TMR.trTimestamp = 0 }
+
+  let epcFilt = TMR.TagFilterEPC (TMR.trTag trd)
+      opErase = TMR.TagOp_GEN2_BlockErase
+                { TMR.opBank = TMR.GEN2_BANK_USER
+                , TMR.opWordPtr = 0
+                , TMR.opWordCount = 4
+                }
+  check ts $ TMR.executeTagOp rdr opErase (Just epcFilt)
+
+  TMR.paramSetReadPlanFilter rdr Nothing
+  TMR.paramSetReadPlanTagop rdr (Just readUser)
+  tags2 <- TMR.read rdr 1000
+  check ts $ return $ length tags2
+  forM_ tags2 $ \tag -> do
+    check ts $ return tag { TMR.trTimestamp = 0 }
+
+permalockMeFilter :: TMR.TagFilter
+permalockMeFilter = TMR.mkFilterGen2 TMR.GEN2_BANK_USER 0 "permalock me"
+
+testBlockPermalockRead :: TestFunc
+testBlockPermalockRead rdr ts = do
+  setRegionAndPower rdr
+  TMR.paramSetReadPlanFilter rdr (Just permalockMeFilter)
+
+  tags <- TMR.read rdr 1000
+  check ts $ return $ length tags
+  let trd = maximumBy (comparing TMR.trRssi) tags
+  check ts $ return trd { TMR.trTimestamp = 0 }
+
+  let epcFilt = TMR.TagFilterEPC (TMR.trTag trd)
+      opPermalock = TMR.TagOp_GEN2_BlockPermaLock
+                    { TMR.opBank = TMR.GEN2_BANK_USER
+                    , TMR.opBlockPtr = 0
+                    , TMR.opReadWrite = TMR.Read 1
+                    }
+  void $ check ts $ TMR.executeTagOp rdr opPermalock (Just epcFilt)
+
+testBlockPermalockWrite :: TestFunc
+testBlockPermalockWrite rdr ts = do
+  setRegionAndPower rdr
+  TMR.paramSetReadPlanFilter rdr (Just permalockMeFilter)
+
+  tags <- TMR.read rdr 1000
+  check ts $ return $ length tags
+  let trd = maximumBy (comparing TMR.trRssi) tags
+  check ts $ return trd { TMR.trTimestamp = 0 }
+
+  let epcFilt = TMR.TagFilterEPC (TMR.trTag trd)
+      opPermalock = TMR.TagOp_GEN2_BlockPermaLock
+                    { TMR.opBank = TMR.GEN2_BANK_USER
+                    , TMR.opBlockPtr = 0
+                    , TMR.opReadWrite = TMR.Write [0xaa00]
+                    }
+  check ts $ TMR.executeTagOp rdr opPermalock (Just epcFilt)
+
+  forM_ [0..31] $ \word -> do
+    let opWrite = TMR.TagOp_GEN2_WriteData
+                  { TMR.opBank = TMR.GEN2_BANK_USER
+                  , TMR.opWordAddress = word
+                  , TMR.opData = [fromIntegral word]
+                  }
+    check ts $ TMR.executeTagOp rdr opWrite (Just epcFilt)
+
+  TMR.paramSetReadPlanFilter rdr Nothing
+  TMR.paramSetReadPlanTagop rdr (Just readUser)
+  tags2 <- TMR.read rdr 1000
+  check ts $ return $ length tags2
+  forM_ tags2 $ \tag -> do
+    check ts $ return tag { TMR.trTimestamp = 0 }
+
+  let opPermalock2 = TMR.TagOp_GEN2_BlockPermaLock
+                     { TMR.opBank = TMR.GEN2_BANK_USER
+                     , TMR.opBlockPtr = 0
+                     , TMR.opReadWrite = TMR.Read 1
+                     }
+  void $ check ts $ TMR.executeTagOp rdr opPermalock2 (Just epcFilt)
+
+killMeFilter :: TMR.TagFilter
+killMeFilter =
+  TMR.mkFilterGen2 TMR.GEN2_BANK_USER 0 $ "permaloc" <> B.pack [0,4,0,5,0,6,0,7]
+
+testKill :: TestFunc
+testKill rdr ts = do
+  setRegionAndPower rdr
+  TMR.paramSetReadPlanFilter rdr (Just killMeFilter)
+
+  -- find a tag
+  tags <- TMR.read rdr 1000
+  check ts $ return $ length tags
+  let trd = maximumBy (comparing TMR.trRssi) tags
+  check ts $ return trd { TMR.trTimestamp = 0 }
+
+  -- write access password
+  let password = 0xbeadead1
+      epcFilt = TMR.TagFilterEPC (TMR.trTag trd)
+      opWrite = TMR.TagOp_GEN2_WriteData
+                { TMR.opBank = TMR.GEN2_BANK_RESERVED
+                , TMR.opWordAddress = TMR.killPasswordAddress
+                , TMR.opData = TMR.passwordToWords password
+                }
+  check ts $ TMR.executeTagOp rdr opWrite (Just epcFilt)
+
+  -- kill
+  let opKill = TMR.TagOp_GEN2_Kill password
+  check ts $ TMR.executeTagOp rdr opKill (Just epcFilt)
+
+  -- still alive?
+  TMR.paramSetReadPlanFilter rdr (Just epcFilt)
+  TMR.paramSetReadPlanTagop rdr (Just readUser)
+  tags2 <- TMR.read rdr 1000
+  void $ check ts $ return $ length tags2
+
+mkPin :: TMR.PinNumber -> TMR.PinNumber -> TMR.GpioPin
+mkPin highPin pin =
+  TMR.GpioPin
+  { TMR.gpId = pin
+  , TMR.gpHigh = highPin == pin
+  , TMR.gpOutput = True
+  }
+
+testGpo :: TestFunc
+testGpo rdr ts = do
+  let pins = [1..4]
+
+  TMR.paramSetGpioOutputList rdr pins
+  forM_ pins $ \pin -> do
+    TMR.gpoSet rdr $ map (mkPin pin) pins
+
+testGpi :: TestFunc
+testGpi rdr ts = do
+  let pins = [1..4]
+
+  TMR.paramSetGpioInputList rdr pins
+  void $ check ts $ TMR.gpiGet rdr
+
+tests :: [(String, TestFunc)]
+tests =
+  [ ("params", testParams)
+  , ("read", testRead)
+  , ("readUser", testReadUser)
+  , ("write", testWrite)
+  , ("writeEpc", testWriteEpc)
+  , ("lock", testLock)
+  , ("blockWrite", testBlockWrite)
+  , ("blockErase", testBlockErase)
+  , ("blockPermalockRead", testBlockPermalockRead)
+  , ("blockPermalockWrite", testBlockPermalockWrite)
+  , ("kill", testKill)
+  , ("gpo", testGpo)
+  , ("gpi", testGpi)
+  ]
+
+allTests = map fst tests
+
+runTests :: String -> TestDirection -> [String] -> IO ()
+runTests uri dir ts = do
+  forM_ ts $ \t -> do
+    let mf = t `lookup` tests
+    case mf of
+      Nothing -> fail $ "no test named " ++ t
+      Just f -> runTest uri dir t f
+
+defUri :: String
+defUri = case os of
+           "darwin" -> "tmr:///dev/cu.SLAB_USBtoUART"
+           "mingw32" -> "tmr:///COM4"
+           _ -> "tmr:///dev/ttyUSB0"
+
+data Opts = Opts
+  { oUri :: String
+  , oRecord :: Bool
+  , oTests :: [String]
+  }
+
+optUri :: Parser String
+optUri = strOption (long "uri" <>
+                    short 'u' <>
+                    metavar "URI" <>
+                    help ("Reader to connect to (default " ++ defUri ++ ")") <>
+                    value defUri)
+
+optRecord :: Parser Bool
+optRecord = switch (long "record" <>
+                    short 'R' <>
+                    help "record a new test from a physical reader")
+
+opts :: Parser Opts
+opts = Opts
+  <$> optUri
+  <*> optRecord
+  <*> many (argument str (metavar "TESTS..."))
+
+opts' = info (helper <*> opts)
+  ( fullDesc <>
+    header "replay - automated tests that use a simulated reader" )
+
+main = do
+  TMR.registerTransportInit
+  o <- execParser opts'
+
+  let dir = if oRecord o then Record else Playback
+  let ts = case oTests o of
+             [] -> allTests
+             xs -> xs
+
+  runTests (oUri o) dir ts
diff --git a/tests/unit.hs b/tests/unit.hs
new file mode 100644
--- /dev/null
+++ b/tests/unit.hs
@@ -0,0 +1,82 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import qualified Data.ByteString as B ( ByteString )
+import Data.Monoid ((<>))
+import qualified Data.Text as T ( Text )
+import Test.HUnit ( Assertion, Test(..), runTestTT, assertEqual )
+
+import qualified System.Hardware.MercuryApi as TMR
+
+helloWorld :: B.ByteString
+helloWorld = "Hello, World!"
+
+defacedBadFacade :: T.Text
+defacedBadFacade = "DefacedBadFacade"
+
+defacedBadFacadeBin :: B.ByteString
+defacedBadFacadeBin = "\222\250\206\219\173\250\202\222"
+
+-- http://www.adafruit.com/datasheets/CSN-A2%20User%20Manual.pdf
+phrase :: B.ByteString
+phrase = "thoroughly remove the uncommon words of anguish"
+
+testDataHelpers :: Assertion
+testDataHelpers = do
+  assertEqual "TMR.packBytesIntoWords helloWorld"
+    [18533,27756,28460,8279,28530,27748,8448]
+    (TMR.packBytesIntoWords helloWorld)
+  assertEqual "TMR.passwordToWords 0xbeadead1"
+    [0xbead, 0xead1]
+    (TMR.passwordToWords 0xbeadead1)
+
+testHex :: Assertion
+testHex = do
+  assertEqual "TMR.bytesToHex defacedBadFacadeBin"
+    "DEFACEDBADFACADE"
+    (TMR.bytesToHex defacedBadFacadeBin)
+  assertEqual "TMR.bytesToHexWithSpaces defacedBadFacadeBin"
+    "de fa ce db ad fa ca de"
+    (TMR.bytesToHexWithSpaces defacedBadFacadeBin)
+  assertEqual "TMR.hexToBytes defacedBadFacade"
+    (Just defacedBadFacadeBin)
+    (TMR.hexToBytes defacedBadFacade)
+  assertEqual "TMR.hexToBytes $ \"0x\" <> defacedBadFacade"
+    (Just defacedBadFacadeBin)
+    (TMR.hexToBytes $ "0x" <> defacedBadFacade)
+  assertEqual "TMR.hexToBytes \"XXYYZZ\""
+    Nothing
+    (TMR.hexToBytes "XXYYZZ")
+  assertEqual "TMR.hexToBytes \"0dd\""
+    Nothing
+    (TMR.hexToBytes "0dd")
+
+testTimestamp :: Assertion
+testTimestamp = do
+  assertEqual "TMR.displayTimestamp 0"
+    "1970-01-01T00:00:00.000Z"
+    (TMR.displayTimestamp 0)
+  assertEqual "TMR.displayTimestamp 123456789"
+    "1970-01-02T10:17:36.789Z"
+    (TMR.displayTimestamp 123456789)
+  assertEqual "TMR.displayTimestamp 1513728000000"
+    "2017-12-20T00:00:00.000Z"
+    (TMR.displayTimestamp 1513728000000)
+
+testData :: Assertion
+testData = do
+  assertEqual "TMR.displayData phrase"
+    [ "74 68 6f 72 6f 75 67 68  6c 79 20 72 65 6d 6f 76  |thoroughly remov|"
+    , "65 20 74 68 65 20 75 6e  63 6f 6d 6d 6f 6e 20 77  |e the uncommon w|"
+    , "6f 72 64 73 20 6f 66 20  61 6e 67 75 69 73 68     |ords of anguish|"
+    ]
+    (TMR.displayData phrase)
+
+tests :: Test
+tests = TestList
+  [ TestLabel "testDataHelpers" (TestCase testDataHelpers)
+  , TestLabel "testHex" (TestCase testHex)
+  , TestLabel "testTimestamp" (TestCase testTimestamp)
+  , TestLabel "testData" (TestCase testData)
+  ]
+
+main = runTestTT tests
diff --git a/tests/write.result b/tests/write.result
new file mode 100644
--- /dev/null
+++ b/tests/write.result
@@ -0,0 +1,5 @@
+Right 1
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NULQ\134\SOH\a\SOH\135\ap\196\193", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 47646, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 171, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 20, trRssi = -47, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right ""
+Right 1
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NULQ\134\SOH\a\SOH\135\ap\196\193", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 18363, tdGen2 = Just (GEN2_TagData {g2Pc = "4\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 22, trRssi = -44, trFrequency = 918400, trTimestamp = 0, trData = "I am Groot\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
diff --git a/tests/write.transport b/tests/write.transport
new file mode 100644
--- /dev/null
+++ b/tests/write.transport
@@ -0,0 +1,118 @@
+Sending: VERSION                       1608598.103811784
+         ff 00 03 1d 0c                                    |.....|
+Received:VERSION                       1608598.108389815
+         ff 14 03 00 00 14 12 08  00 30 00 00 02 20 16 12  |.........0... ..|
+         13 01 07 01 02 00 00 00  10 1b 05                 |...........|
+Sending: GET_CURRENT_PROGRAM           1608598.108962046
+         ff 00 0c 1d 03                                    |.....|
+Received:GET_CURRENT_PROGRAM           1608598.110812682
+         ff 01 0c 00 00 52 63 03                           |.....Rc.|
+Sending: GET_POWER_MODE                1608598.110958814
+         ff 00 68 1d 67                                    |..h.g|
+Received:GET_POWER_MODE                1608598.112779756
+         ff 01 68 00 00 00 a4 bf                           |..h.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1608598.112934335
+         ff 02 6a 01 0e 2e 40                              |..j...@|
+Received:GET_READER_OPTIONAL_PARAMS    1608598.114918110
+         ff 03 6a 00 00 01 0e 00  30 44                    |..j.....0D|
+Sending: GET_READER_OPTIONAL_PARAMS    1608598.121893539
+         ff 02 6a 01 12 2e 5c                              |..j...\|
+Received:GET_READER_OPTIONAL_PARAMS    1608598.124219487
+         ff 04 6a 00 00 01 12 00  00 69 af                 |..j......i.|
+Sending: GET_TAG_PROTOCOL              1608598.124500941
+         ff 00 63 1d 6c                                    |..c.l|
+Received:GET_TAG_PROTOCOL              1608598.126413019
+         ff 02 63 00 00 00 05 21  46                       |..c....!F|
+Sending: GET_ANTENNA_PORT              1608598.126563793
+         ff 01 61 05 bd b8                                 |..a...|
+Received:GET_ANTENNA_PORT              1608598.128513171
+         ff 03 61 00 00 05 01 00  61 df                    |..a.....a.|
+Sending: GET_READER_OPTIONAL_PARAMS    1608598.128660983
+         ff 02 6a 01 0c 2e 42                              |..j...B|
+Received:GET_READER_OPTIONAL_PARAMS    1608598.130614928
+         ff 03 6a 00 00 01 0c 01  32 45                    |..j.....2E|
+Sending: GET_READER_OPTIONAL_PARAMS    1608598.130747717
+         ff 02 6a 01 0d 2e 43                              |..j...C|
+Received:GET_READER_OPTIONAL_PARAMS    1608598.133116871
+         ff 06 6a 00 00 01 0d 00  00 00 00 15 43           |..j.........C|
+Sending: SET_REGION                    1608598.133294161
+         ff 01 97 0d 4b b0                                 |....K.|
+Received:SET_REGION                    1608598.135127143
+         ff 00 97 00 00 77 9e                              |.....w.|
+Sending: SET_READ_TX_POWER             1608598.135314487
+         ff 02 92 08 98 49 c1                              |.....I.|
+Received:SET_READ_TX_POWER             1608598.137182683
+         ff 00 92 00 00 27 3b                              |.....';|
+Sending: SET_WRITE_TX_POWER            1608598.137317673
+         ff 02 94 08 98 29 07                              |.....).|
+Received:SET_WRITE_TX_POWER            1608598.139181408
+         ff 00 94 00 00 47 fd                              |.....G.|
+Sending: SET_ANTENNA_PORT              1608598.139334656
+         ff 02 91 01 01 70 3b                              |.....p;|
+Received:SET_ANTENNA_PORT              1608598.141248843
+         ff 00 91 00 00 17 58                              |......X|
+Sending: SET_READER_OPTIONAL_PARAMS    1608598.141391398
+         ff 03 9a 01 06 01 a9 5c                           |.......\|
+Received:SET_READER_OPTIONAL_PARAMS    1608598.143471456
+         ff 00 9a 00 00 a6 33                              |......3|
+Sending: GET_READER_STATS              1608598.143757271
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1608598.146075706
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1608598.146245646
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1608598.147965998
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1608598.148106117
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1608598.150175988
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1608598.150440445
+         ff 10 22 03 00 13 03 e8  00 00 00 00 00 00 00 00  |..".............|
+         10 00 00 86 a3                                    |.....|
+Received:READ_TAG_ID_MULTIPLE          1608599.160809727
+         ff 07 22 00 00 03 00 13  00 00 00 01 65 8a        |..".........e.|
+Sending: GET_TAG_ID_BUFFER             1608599.161120138
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1608599.166592092
+         ff 26 29 00 00 01 ff 00  01 14 d1 11 0e 13 e8 00  |.&).............|
+         00 03 29 00 ab 05 00 00  00 00 80 30 00 e2 00 51  |..)........0...Q|
+         86 01 07 01 87 07 70 c4  c1 ba 1e 92 d7           |......p......|
+Sending: WRITE_TAG_DATA                1608599.170450637
+         ff 23 24 03 e8 01 00 00  00 00 03 00 00 00 00 60  |.#$............`|
+         e2 00 51 86 01 07 01 87  07 70 c4 c1 49 20 61 6d  |..Q......p..I am|
+         20 47 72 6f 6f 74 a6 6a                           | Groot.j|
+Received:WRITE_TAG_DATA                1608599.246089019
+         ff 00 24 00 00 e0 26                              |..$...&|
+Sending: GET_READER_STATS              1608599.246448176
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1608599.248747520
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1608599.248930668
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1608599.250666122
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1608599.250844006
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1608599.252846522
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1608599.253118475
+         ff 11 22 00 00 17 03 e8  01 09 28 07 d0 00 03 00  |..".......(.....|
+         00 00 00 20 49 70                                 |... Ip|
+Received:READ_TAG_ID_MULTIPLE          1608600.265874100
+         ff 4d 22 00 00 00 00 17  00 00 00 01 01 28 00 16  |.M"..........(..|
+         00 00 49 20 61 6d 20 47  72 6f 6f 74 00 00 00 00  |..I am Groot....|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 90 9a                                       |....|
+Sending: GET_TAG_ID_BUFFER             1608600.266777939
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1608600.278056115
+         ff 66 29 00 00 01 ff 00  01 16 d4 11 0e 03 80 00  |.f).............|
+         00 01 a0 00 ae 05 02 00  49 20 61 6d 20 47 72 6f  |........I am Gro|
+         6f 74 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |ot..............|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 80 34 00 e2 00 51  |...........4...Q|
+         86 01 07 01 87 07 70 c4  c1 47 bb 9a c1           |......p..G...|
diff --git a/tests/writeEpc.result b/tests/writeEpc.result
new file mode 100644
--- /dev/null
+++ b/tests/writeEpc.result
@@ -0,0 +1,6 @@
+Right 1
+Right (TagReadData {trTag = TagData {tdEpc = "\226\NULQ\134\SOH\a\SOH\135\ap\196\193", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 47646, tdGen2 = Just (GEN2_TagData {g2Pc = "0\NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 174, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 31, trRssi = -47, trFrequency = 922600, trTimestamp = 0, trData = "", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right ""
+Right 1
+Right (TagReadData {trTag = TagData {tdEpc = "\SOH#Eg\137\171\205\239", tdProtocol = TAG_PROTOCOL_GEN2, tdCrc = 36510, tdGen2 = Just (GEN2_TagData {g2Pc = " \NUL"})}, trMetadataFlags = [METADATA_FLAG_READCOUNT,METADATA_FLAG_RSSI,METADATA_FLAG_ANTENNAID,METADATA_FLAG_FREQUENCY,METADATA_FLAG_TIMESTAMP,METADATA_FLAG_PHASE,METADATA_FLAG_PROTOCOL,METADATA_FLAG_DATA,METADATA_FLAG_GPIO_STATUS], trPhase = 171, trAntenna = 1, trGpio = [GpioPin {gpId = 1, gpHigh = False, gpOutput = False},GpioPin {gpId = 2, gpHigh = False, gpOutput = False},GpioPin {gpId = 3, gpHigh = False, gpOutput = False},GpioPin {gpId = 4, gpHigh = False, gpOutput = False}], trReadCount = 22, trRssi = -45, trFrequency = 918400, trTimestamp = 0, trData = "\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL", trEpcMemData = "", trTidMemData = "", trUserMemData = "", trReservedMemData = ""})
+Right ""
diff --git a/tests/writeEpc.transport b/tests/writeEpc.transport
new file mode 100644
--- /dev/null
+++ b/tests/writeEpc.transport
@@ -0,0 +1,124 @@
+Sending: VERSION                       1783113.335963260
+         ff 00 03 1d 0c                                    |.....|
+Received:VERSION                       1783113.340546799
+         ff 14 03 00 00 14 12 08  00 30 00 00 02 20 16 12  |.........0... ..|
+         13 01 07 01 02 00 00 00  10 1b 05                 |...........|
+Sending: GET_CURRENT_PROGRAM           1783113.341025567
+         ff 00 0c 1d 03                                    |.....|
+Received:GET_CURRENT_PROGRAM           1783113.342675574
+         ff 01 0c 00 00 52 63 03                           |.....Rc.|
+Sending: GET_POWER_MODE                1783113.342832512
+         ff 00 68 1d 67                                    |..h.g|
+Received:GET_POWER_MODE                1783113.344719334
+         ff 01 68 00 00 00 a4 bf                           |..h.....|
+Sending: GET_READER_OPTIONAL_PARAMS    1783113.344877962
+         ff 02 6a 01 0e 2e 40                              |..j...@|
+Received:GET_READER_OPTIONAL_PARAMS    1783113.347044658
+         ff 03 6a 00 00 01 0e 00  30 44                    |..j.....0D|
+Sending: GET_READER_OPTIONAL_PARAMS    1783113.354181389
+         ff 02 6a 01 12 2e 5c                              |..j...\|
+Received:GET_READER_OPTIONAL_PARAMS    1783113.356482817
+         ff 04 6a 00 00 01 12 00  00 69 af                 |..j......i.|
+Sending: GET_TAG_PROTOCOL              1783113.356679203
+         ff 00 63 1d 6c                                    |..c.l|
+Received:GET_TAG_PROTOCOL              1783113.358546212
+         ff 02 63 00 00 00 05 21  46                       |..c....!F|
+Sending: GET_ANTENNA_PORT              1783113.358712824
+         ff 01 61 05 bd b8                                 |..a...|
+Received:GET_ANTENNA_PORT              1783113.360832578
+         ff 03 61 00 00 05 01 00  61 df                    |..a.....a.|
+Sending: GET_READER_OPTIONAL_PARAMS    1783113.361047512
+         ff 02 6a 01 0c 2e 42                              |..j...B|
+Received:GET_READER_OPTIONAL_PARAMS    1783113.363254874
+         ff 03 6a 00 00 01 0c 01  32 45                    |..j.....2E|
+Sending: GET_READER_OPTIONAL_PARAMS    1783113.363464915
+         ff 02 6a 01 0d 2e 43                              |..j...C|
+Received:GET_READER_OPTIONAL_PARAMS    1783113.365915536
+         ff 06 6a 00 00 01 0d 00  00 00 00 15 43           |..j.........C|
+Sending: SET_REGION                    1783113.366099275
+         ff 01 97 0d 4b b0                                 |....K.|
+Received:SET_REGION                    1783113.367851295
+         ff 00 97 00 00 77 9e                              |.....w.|
+Sending: SET_READ_TX_POWER             1783113.368065458
+         ff 02 92 08 98 49 c1                              |.....I.|
+Received:SET_READ_TX_POWER             1783113.369971357
+         ff 00 92 00 00 27 3b                              |.....';|
+Sending: SET_WRITE_TX_POWER            1783113.370116064
+         ff 02 94 08 98 29 07                              |.....).|
+Received:SET_WRITE_TX_POWER            1783113.371990494
+         ff 00 94 00 00 47 fd                              |.....G.|
+Sending: SET_ANTENNA_PORT              1783113.372144979
+         ff 02 91 01 01 70 3b                              |.....p;|
+Received:SET_ANTENNA_PORT              1783113.374086488
+         ff 00 91 00 00 17 58                              |......X|
+Sending: SET_READER_OPTIONAL_PARAMS    1783113.374223675
+         ff 03 9a 01 06 01 a9 5c                           |.......\|
+Received:SET_READER_OPTIONAL_PARAMS    1783113.376213620
+         ff 00 9a 00 00 a6 33                              |......3|
+Sending: GET_READER_STATS              1783113.376365163
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1783113.378504811
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1783113.378674249
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1783113.380379708
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1783113.380525173
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1783113.382539190
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1783113.382687791
+         ff 10 22 03 00 13 03 e8  00 00 00 00 00 00 00 00  |..".............|
+         10 00 00 86 a3                                    |.....|
+Received:READ_TAG_ID_MULTIPLE          1783114.389189850
+         ff 07 22 00 00 03 00 13  00 00 00 01 65 8a        |..".........e.|
+Sending: GET_TAG_ID_BUFFER             1783114.389440192
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1783114.394987785
+         ff 26 29 00 00 01 ff 00  01 1f d1 11 0e 13 e8 00  |.&).............|
+         00 03 23 00 ae 05 00 00  00 00 80 30 00 e2 00 51  |..#........0...Q|
+         86 01 07 01 87 07 70 c4  c1 ba 1e f3 0f           |......p......|
+Sending: WRITE_TAG_ID                  1783114.395787548
+         ff 1c 23 03 e8 01 00 00  00 00 60 e2 00 51 86 01  |..#.......`..Q..|
+         07 01 87 07 70 c4 c1 01  23 45 67 89 ab cd ef 5b  |....p...#Eg....[|
+         20                                                | |
+Received:WRITE_TAG_ID                  1783114.473001670
+         ff 00 23 00 00 90 c1                              |..#....|
+Sending: GET_READER_STATS              1783114.473210471
+         ff 03 6c 01 9f 41 89 7b                           |..l..A.{|
+Received:GET_READER_STATS              1783114.475568734
+         ff 03 6c 00 00 01 9f 41  86 9c                    |..l....A..|
+Sending: CLEAR_TAG_ID_BUFFER           1783114.475730903
+         ff 00 2a 1d 25                                    |..*.%|
+Received:CLEAR_TAG_ID_BUFFER           1783114.477455041
+         ff 00 2a 00 00 01 e8                              |..*....|
+Sending: SET_ANTENNA_PORT              1783114.477668332
+         ff 03 91 02 01 01 42 c5                           |......B.|
+Received:SET_ANTENNA_PORT              1783114.479714545
+         ff 00 91 00 00 17 58                              |......X|
+Sending: READ_TAG_ID_MULTIPLE          1783114.479888386
+         ff 11 22 00 00 17 03 e8  01 09 28 07 d0 00 03 00  |..".......(.....|
+         00 00 00 20 49 70                                 |... Ip|
+Received:READ_TAG_ID_MULTIPLE          1783115.497038299
+         ff 4d 22 00 00 00 00 17  00 00 00 01 01 28 00 16  |.M"..........(..|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 e4 bf                                       |....|
+Sending: GET_TAG_ID_BUFFER             1783115.498013194
+         ff 03 29 01 ff 00 1b 03                           |..).....|
+Received:GET_TAG_ID_BUFFER             1783115.508879879
+         ff 62 29 00 00 01 ff 00  01 16 d3 11 0e 03 80 00  |.b).............|
+         00 01 9d 00 ab 05 02 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+         00 00 00 00 00 00 00 00  00 00 60 20 00 01 23 45  |..........` ..#E|
+         67 89 ab cd ef 8e 9e 37  23                       |g......7#|
+Sending: WRITE_TAG_ID                  1783115.510126246
+         ff 1c 23 03 e8 01 00 00  00 00 40 01 23 45 67 89  |..#.......@.#Eg.|
+         ab cd ef e2 00 51 86 01  07 01 87 07 70 c4 c1 72  |.....Q......p..r|
+         c4                                                |.|
+Received:WRITE_TAG_ID                  1783115.619815239
+         ff 00 23 00 00 90 c1                              |..#....|
