packages feed

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

/**
 *  @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;
}