#include "archinc.h"
#include "cli.h"
#include "timer0.h"
#include "eventq.h"
#include "zarlink.h"
#include "zl_bus.h"
#include "zl_event.h"
#include "zlregs.h"
#include "nvstore.h"
#include "zl_lhb.h"
#include "zl_trunk.h"
#include "zl_mii.h"
#include "board.h"
#include "sfp.h"
#include "portmgr.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef CONFIG_INCLUDE_ZARLINK

#define LHB_FAIL_TOLERANCE_NVSTORE_NAME "failtol"
#define PORTMGR_DEFAULT_LINK_FAIL_TOLERANCE (200)

#define LHB_FAIL_COUNT_AGE_NVSTORE_NAME "lhbage"
#define PORTMGR_DEFAULT_LHB_FAIL_COUNT_AGE (36000) // this is 1 hr in 100ms (timer0) ticks

static const char * const portStatusTags[6] =    {"unknown ", "   up   ", "  down  ", " failed ", NULL, NULL};
static const char * const phyStatusTags[6] =     {"unknown ", " normal ", "pwr save", NULL, NULL, NULL};
static const char * const opticalStatusTags[6] = {"unknown ", " no SFP ", " normal ", "TX disab", "pwr off ", "   ---  "};
static const char * const lhbStatusTags[6] =     {"unknown ", "enabled ", "disabled", NULL, NULL, NULL};
static const char * const portEventTags[6] =     {"no event", " LHB OK ", "LHB FAIL", "port up ", "port dn ", NULL};

typedef struct {
  unsigned int portStatus;
  unsigned int phyStatus;
  unsigned int opticalStatus;
  unsigned int lhbStatus;
  unsigned int lastEvent;
  unsigned int numLinkFailures;
  } portStatus_t;

static unsigned short lhbReceived[NUM_ALL_PORTS];
static unsigned int linkFailTolerance;
static unsigned int linkFailAgeTime;

static unsigned char portConfig[NUM_ALL_PORTS];
static volatile portStatus_t ports[NUM_ALL_PORTS];

static int portsHandler(int argc, char * argv[], int flags);
static int portcfgHandler(int argc, char * argv[], int flags);
static int failtolHandler(int argc, char * argv[], int flags);
static int lhbageHandler(int argc, char * argv[], int flags);

/* 
 * port number sanity checking routines
 */

static int verifyPort(int portNum)
{
  if ((portNum >= 0) && (portNum < NUM_ALL_PORTS))
    return 0;
  else
    return -1;
}

static int verifyOpticalPort(int portNum)
{
  if ((portNum >= 0) && (portNum < NUM_OPTICAL_PORTS))
    return 0;
  else
    return -1;
}

/*
 * Low-level (switch register operations) per-port ops used internally 
 */

static int resetPort(int portNum)
{
  int i;
  volatile unsigned long dummy;

  zarlinkIndexedWrite(ECR4P_ADDR(portNum), 0x98);

  // read an RTC register for some delay
  for(i=0;i<100;i++)
    dummy = CTIME0;

  zarlinkIndexedWrite(ECR4P_ADDR(portNum), 0x18);

  return 0;
}

static int enablePort(int portNum)
{
  int retVal = 0;

  if (portNum < NUM_OPTICAL_PORTS) {
    // optical ports -- force up at 100BaseT/full duplex
    zarlinkIndexedWrite(ECR1P_ADDR(portNum), 0xd8);
    }
  else {
    // copper ports -- 4=SideARM, 5=Auto-negotiate (not SideARM)
    if (portNum == 5) {
      // use autonegotiation
      zarlinkIndexedWrite(ECR1P_ADDR(portNum), 0xc0);
      }
    else if (portNum == 4) {
      // SideARM: force up at 10MBit/s half-duplex because it can't autoneg!
      zarlinkIndexedWrite(ECR1P_ADDR(portNum), 0xde);
      }
    else {
      retVal = -1;
      }
    }

  return 0;
}

static int disablePort(int portNum)
{
  int retVal = 0;

  if (portNum < NUM_OPTICAL_PORTS) {
    // optical ports -- no autoneg
    zarlinkIndexedWrite(ECR1P_ADDR(portNum), 0xd0);
    }

  return retVal;
}

/*
 * Non-volatile configuration store/retrieve support
 */

#ifdef CONFIG_INCLUDE_NVSTORE

static char nvItemName[8];

static int checkPortConfig(int portNum)
{
  if (verifyPort(portNum) == -1) {
    return -1;
    }

  // write data structure to nvram
  sprintf(nvItemName, "port%d\x0", portNum);
  return nvstoreLookup(nvItemName);
}

static int savePortConfig(int portNum)
{
  if (verifyPort(portNum) == -1) {
    return -1;
    }

  // write data structure to nvram
  sprintf(nvItemName, "port%d\x0", portNum);
  return nvstoreWrite(nvItemName, &(portConfig[portNum]), sizeof(unsigned char));
}

static int loadPortConfig(int portNum)
{
  int retVal;
  unsigned char bytesRead;

  if (verifyPort(portNum) == -1) {
    return -1;
    }

  sprintf(nvItemName, "port%d\x0", portNum);
  retVal = nvstoreRead(nvItemName, (unsigned char *)&(portConfig[portNum]), &bytesRead);

  if (retVal == -1) {
    return -1;
    }
  else if (((size_t)bytesRead) != sizeof(unsigned char)) {
    return -1;
    }
  else {
    return 0;
    }
}

#endif /* CONFIG_INCLUDE_NVSTORE */

/*
 * Routine to age Link Hearbeat counts over timer as
 * suggested by Wayne as the best way of a true indic-
 * ation of a link failure and not fail on sporadic
 * single failures over a long time.
 */

static void ageLhbFailureCount(void)
{
  int i;
  int bufLen;
  char * pOutBuf;
  int retVal;

  pOutBuf = clicharGetOutputBuffer(&bufLen);
  pOutBuf[0] = '\0'; // zero out the buffer the lazy way

  sprintf(pOutBuf, "ageLhbFailureCount: zeroing LHB counts\r\n");
  clicharSendOutputBuffer(pOutBuf, bufLen);

  for(i=0;i<NUM_ALL_PORTS;i++) {
    if (ports[i].lhbStatus == LHB_STATUS_ENABLED) {
      ports[i].numLinkFailures = (unsigned int)0;
      }
    }
}

/*
 * public routines
 */

/*
 * Used by any code to notify port manager of _external_ events
 * like link heartbeat failures, and port up/down events from
 * CTRL1 interrupts
 */

int portmgrPortEventNotify(int portNum, int event)
{
  int retVal = -1;

  if (verifyPort(portNum) == -1)
    return retVal;

  switch(event) {
    case PORT_EVENT_LHB_TMOUT:
      ports[portNum].numLinkFailures++;
      if (ports[portNum].numLinkFailures > linkFailTolerance) {
        retVal = portmgrPortStatusRequest(portNum, PORT_STATUS_FAILED);
        }
      break;
    case PORT_EVENT_LHB_DETECT:
      if (ports[portNum].portStatus != PORT_STATUS_UP) {
        retVal = portmgrPortStatusRequest(portNum, PORT_STATUS_UP);
        }
      lhbReceived[portNum] += 1;
    case PORT_EVENT_PORT_UP:
      ports[portNum].portStatus = PORT_STATUS_UP;
      break;
    case PORT_EVENT_PORT_DOWN:
      ports[portNum].portStatus = PORT_STATUS_DOWN;
      break;
    default:
      break;
    }

  ports[portNum].lastEvent = event;

  return retVal;
}

int portmgrPortStatusGet(int portNum, int *pStatus)
{
  int retVal = -1;

  if ((verifyPort(portNum) == -1) || (pStatus == NULL))
    return retVal;

  *pStatus = ports[portNum].portStatus;
  return 0;
}

static char * statusTags[] = {
"PORT_STATUS_UNKNOWN", 
"PORT_STATUS_UP",
"PORT_STATUS_DOWN",
"PORT_STATUS_FAILED",
NULL
};

int portmgrPortStatusRequest(int portNum, int newStatus)
{
  int retVal = -1;
  int i;
  volatile unsigned long dummy;
  int bufLen;
  char * pOutBuf;

  pOutBuf = clicharGetOutputBuffer(&bufLen);
  sprintf(pOutBuf, "PortStatusRequest: port[%d]  state[%s]  \r\n\x0", 
           portNum, statusTags[newStatus]);
  clicharSendOutputBuffer(pOutBuf, bufLen);

  if (verifyPort(portNum) == -1)
    return retVal;

  switch(newStatus) {
    case PORT_STATUS_UNKNOWN:
      ports[portNum].portStatus = PORT_STATUS_UNKNOWN;
      break;
    case PORT_STATUS_UP:

      // If an optical port, then power it

      if (portNum < NUM_OPTICAL_PORTS) {
        portmgrOpticalStatusRequest(portNum, OPTICAL_STATUS_POWERUP);

        // TODO: may need substantial delay here
        // read an RTC register for some delay
        for(i=0;i<100;i++) {
          dummy = CTIME0;
          }

        // Restore (power up) PHY only if it has been put into power save mode
        portmgrPhyStatusRequest(portNum, PHY_STATUS_POWERUP);
 
        // TODO: may need substantial delay here
        // read an RTC register for some delay
        for(i=0;i<100;i++) {
          dummy = CTIME0;
          }

        resetPort(portNum);
        enablePort(portNum);
        }

      ports[portNum].numLinkFailures = 0;
      retVal = 0;
      ports[portNum].portStatus = PORT_STATUS_UP;
      break;
    case PORT_STATUS_DOWN:
      if (portNum < NUM_OPTICAL_PORTS) {
        portmgrOpticalStatusRequest(portNum, OPTICAL_STATUS_POWERDOWN);
        disablePort(portNum);
        portmgrPhyStatusRequest(portNum, PHY_STATUS_POWERDOWN);
        }
      retVal = 0;
      ports[portNum].portStatus = PORT_STATUS_DOWN;
      break;
    case PORT_STATUS_FAILED:
      // disable LHB on this port -- not elegant way to do it
      portmgrLhbStatusRequest(portNum, LHB_STATUS_DISABLED);

      // power down SFP module (if optical) and power down PHY
      if (portNum < NUM_OPTICAL_PORTS) {
        portmgrOpticalStatusRequest(portNum, OPTICAL_STATUS_POWERDOWN);
        portmgrPhyStatusRequest(portNum, PHY_STATUS_POWERDOWN);
        }
      ports[portNum].portStatus = PORT_STATUS_FAILED;
      // port has failed -- commence failover!
#ifdef CONFIG_INCLUDE_FAILOVER
      retVal = zarlinkTrunkFailover(portNum);
#endif
      break;
    }

  return retVal;
}

char * opticalStateTags[] = {
"OPTICAL_STATUS_UNKNOWN",
"OPTICAL_STATUS_NO_SFP",
"OPTICAL_STATUS_NORMAL",
"OPTICAL_STATUS_TXDISABL",
"OPTICAL_STATUS_POWERDOWN",
"OPTICAL_STATUS_NOT_OPTIC",
"OPTICAL_STATUS_POWERUP",
NULL
};

int portmgrOpticalStatusRequest(int portNum, int newStatus)
{
  int bufLen;
  char * pOutBuf;

  pOutBuf = clicharGetOutputBuffer(&bufLen);
  sprintf(pOutBuf, "OpticalStatusRequest: port[%d]  status[%s]  \r\n\x0", 
           portNum, opticalStateTags[newStatus]);
  clicharSendOutputBuffer(pOutBuf, bufLen);

  if (verifyOpticalPort(portNum) == -1)
    return -1;

  switch(newStatus) {
    case OPTICAL_STATUS_NORMAL:
      break;
    case OPTICAL_STATUS_POWERUP:
      medusaSfpPowerStateSet(portNum, true);
      ports[portNum].opticalStatus = OPTICAL_STATUS_NORMAL;
      break;
    case OPTICAL_STATUS_NO_SFP:
      // no SFP there
      medusaSfpPowerStateSet(portNum, false);
      ports[portNum].opticalStatus = OPTICAL_STATUS_POWERDOWN;
      break;
    case OPTICAL_STATUS_POWERDOWN:
      // unconditional powerdown
      medusaSfpPowerStateSet(portNum, false);
      ports[portNum].opticalStatus = OPTICAL_STATUS_POWERDOWN;
      break;
      }

  return 0;
}

static char * phyStateTags[] = {
"PHY_STATUS_UNKNOWN",
"PHY_STATUS_NORMAL",
"PHY_STATUS_POWERDOWN",
"PHY_STATUS_POWERUP",
NULL
};

int portmgrPhyStatusRequest(int portNum, int newStatus)
{
  int retVal = -1;
  int bufLen;
  char * pOutBuf;

  pOutBuf = clicharGetOutputBuffer(&bufLen);
  sprintf(pOutBuf, "PhyStatusRequest: port[%d]  status[%s]  \r\n\x0", 
           portNum, phyStateTags[newStatus]);
  clicharSendOutputBuffer(pOutBuf, bufLen);

  if (verifyPort(portNum) == -1)
    return retVal;

  switch(newStatus) {
    case PHY_STATUS_UNKNOWN:
      break;
    case PHY_STATUS_NORMAL:
      ports[portNum].phyStatus = PHY_STATUS_NORMAL;
      retVal = 0;
      break;
    case PHY_STATUS_POWERDOWN:
      zarlinkMiiPowerSave(MII_PORT_TO_PHY(portNum));
      ports[portNum].phyStatus = PHY_STATUS_POWERDOWN;
      retVal = 0;
      break;
    case PHY_STATUS_POWERUP:
      zarlinkMiiCtrlRestore(MII_PORT_TO_PHY(portNum));
      ports[portNum].phyStatus = PHY_STATUS_NORMAL;
      retVal = 0;
      break;
    default:
      break;
    }

  return retVal;
}

static char * lhbStateTags[] = {
"LHB_STATUS_UNKNOWN",
"LHB_STATUS_ENABLED",
"LHB_STATUS_DISABLED",
NULL
};

int portmgrLhbStatusRequest(int portNum, int newStatus)
{
  int retVal = -1;
  int bufLen;
  char * pOutBuf;

  pOutBuf = clicharGetOutputBuffer(&bufLen);
  sprintf(pOutBuf, "LhbStatusRequest: port[%d]  status[%s]  \r\n\x0", 
           portNum, lhbStateTags[newStatus]);
  clicharSendOutputBuffer(pOutBuf, bufLen);

  if (verifyPort(portNum) == -1)
    return retVal;

  switch(newStatus) {
    case LHB_STATUS_UNKNOWN:
      break;
    case LHB_STATUS_ENABLED:
      retVal = zarlinkLhbSetup(portNum, true);
      break;
    case LHB_STATUS_DISABLED:
      retVal = zarlinkLhbSetup(portNum, false);
      break;
    default:
      break;
    }

  ports[portNum].lhbStatus = newStatus;

  return retVal;
}

/* always enable the copper ports */
int portmgrPortEnableCopper(void)
{
  resetPort(4);
  enablePort(4);
  resetPort(5);
  enablePort(5);

  return 0;
}

int portmgrPortEnableFiberConfig(void)
{
  int i;
  int retVal = -1;
  int bufLen;
  char * pOutBuf;

  pOutBuf = clicharGetOutputBuffer(&bufLen);

  for(i=FIRST_OPTICAL_PORT; i<=LAST_OPTICAL_PORT;i++) {
    if (checkPortConfig(i) == 0) {
      if (loadPortConfig(i) == 0) {
         sprintf(pOutBuf, "PortEnableFiberConfig: port[%d] config[%02x] stored\r\n\x0", 
                 i, portConfig[i]);
         clicharSendOutputBuffer(pOutBuf, bufLen);
       if ((portConfig[i] & PORT_CONFIG_UPDOWN_MASK) == PORT_CONFIG_UP) {
          portmgrPortStatusRequest(i, PORT_STATUS_UP);
	  }
        else {
          portmgrPortStatusRequest(i, PORT_STATUS_DOWN);
          }
        }
      }

    }

  return 0;
}

int portmgrPhyPowerSave(void)
{
  int i;

  // power down the PHYs on all channels that have no SFP modules
  for(i=FIRST_OPTICAL_PORT; i<=LAST_OPTICAL_PORT; i++) {
    if ((ports[i].opticalStatus == OPTICAL_STATUS_NO_SFP) ||
        (ports[i].opticalStatus == OPTICAL_STATUS_POWERDOWN)) {
      portmgrPhyStatusRequest(i, PHY_STATUS_POWERDOWN);
      }
    }

  return 0;
}

int portmgrInit(void)
{
  int i;
  int retVal;
  unsigned int cfgFailTolerance;
  unsigned int cfgFailAgeTime;
  unsigned char bytesRead;

  // init status
  for(i=0;i<NUM_ALL_PORTS;i++) {
    ports[i].portStatus = PORT_STATUS_UNKNOWN;
    ports[i].phyStatus  = PHY_STATUS_NORMAL;
    if (i < NUM_OPTICAL_PORTS) {
      ports[i].opticalStatus = OPTICAL_STATUS_UNKNOWN;
      }
    else {
      ports[i].opticalStatus = OPTICAL_STATUS_NOT_OPTIC;
      }
    ports[i].lhbStatus  = LHB_STATUS_UNKNOWN;
    ports[i].lastEvent = 0;
    ports[i].numLinkFailures = 0;
    }

  // init LHB received counters
  for(i=0;i<NUM_ALL_PORTS;i++) {
    lhbReceived[i] = (unsigned short)0;
    }

  // init config
  for(i=0;i<NUM_OPTICAL_PORTS;i++) {
    portConfig[i] = (unsigned char)PORT_CONFIG_FO_POWER_AUTO;
    }

  /*
   * Lookup link fail tolerance or set to hardcoded default
   */
  if (nvstoreLookup(LHB_FAIL_TOLERANCE_NVSTORE_NAME) != 0) {
    linkFailTolerance = PORTMGR_DEFAULT_LINK_FAIL_TOLERANCE;
    }
  else {
    retVal = nvstoreRead(LHB_FAIL_TOLERANCE_NVSTORE_NAME, ((unsigned char *)&cfgFailTolerance), &bytesRead);
    if ( (retVal == -1) || 
        (((size_t)bytesRead) != sizeof(unsigned int)) || 
        (cfgFailTolerance == (unsigned int)0) ) {
      linkFailTolerance = PORTMGR_DEFAULT_LINK_FAIL_TOLERANCE;
      }
    else {
      linkFailTolerance = cfgFailTolerance;
      }
    }

  /*
   * Lookup link fail age time or set to hardcoded default
   */

  if (nvstoreLookup(LHB_FAIL_COUNT_AGE_NVSTORE_NAME) != 0) {
    linkFailAgeTime = PORTMGR_DEFAULT_LHB_FAIL_COUNT_AGE;
    }
  else {
    retVal = nvstoreRead(LHB_FAIL_COUNT_AGE_NVSTORE_NAME, ((unsigned char *)&cfgFailAgeTime), &bytesRead);
    if ( (retVal == -1) || 
         (((size_t)bytesRead) != sizeof(unsigned int)) || 
         (cfgFailAgeTime == (unsigned int)0)) {
      linkFailAgeTime = PORTMGR_DEFAULT_LHB_FAIL_COUNT_AGE;
      }
    else {
      linkFailAgeTime = cfgFailAgeTime;
      }
    }

  // TODO: read saved port configs from nvstore here

  cliRegisterCommand("ports", portsHandler, "ports - show switch port status");
  cliRegisterCommand("port",  portsHandler, "port - show switch port status");

  cliRegisterCommand("failtol", failtolHandler, "failtol - failtol [n] tolerate n LHB failures");
  cliRegisterCommand("lhbage", lhbageHandler, "lhbage - lhbage [seconds] age the LHB fail count ");

  // register to receive the periodic event to age the LHB failure count(s)
  eventqRegisterHandler(PERIODIC_EVENT, ageLhbFailureCount);

  // enable the periodic event with timer0
  timer0PeriodicEventEnable(linkFailAgeTime);

  return 0;
}  

static int portsHandler(int argc, char * argv[], int flags)
{
  int i;
  int portNum;
  int bufLen;
  char * pOutBuf;
  int retVal;

  pOutBuf = clicharGetOutputBuffer(&bufLen);
  pOutBuf[0] = '\0'; // zero out the buffer the lazy way

  if (argc == 1) { 
    sprintf(pOutBuf, "%s  %s  %s  %s  %s  %s  %s  %s\r\n\x0", 
      "Port", " Status ", "PHY Stat", "Optical ", 
      "LHB Stat", "Last Evt", "Fail", "LHB OK");
    clicharSendOutputBuffer(pOutBuf, bufLen);

    for(i=0;i<NUM_ALL_PORTS;i++) {
      sprintf(pOutBuf, "%c %2d  %s  %s  %s  %s  %s  %4d  %4d\r\n\x0", 
        ((i<NUM_OPTICAL_PORTS) ? 'F' : 'C'), i, 
        portStatusTags[ports[i].portStatus], 
        phyStatusTags[ports[i].phyStatus], 
        opticalStatusTags[ports[i].opticalStatus], 
        lhbStatusTags[ports[i].lhbStatus], 
        portEventTags[ports[i].lastEvent],
        ports[i].numLinkFailures, 
        lhbReceived[i]);
      clicharSendOutputBuffer(pOutBuf, bufLen);
      }
    retVal = 0;
    }
  else if (argc == 3) {
    portNum = atoi(argv[2]);

    if (verifyPort(portNum) != 0)
      return -1;

    switch(*argv[1]) {
      case 'u':
      case 'U':
        retVal = portmgrPortStatusRequest(portNum, PORT_STATUS_UP);
        sprintf(pOutBuf, "%s: port [%d] now UP\r\n", argv[0], portNum);
        portConfig[portNum] |= PORT_CONFIG_UP;
        break;
      case 'd':
      case 'D':
	retVal = portmgrPortStatusRequest(portNum, PORT_STATUS_DOWN);
        sprintf(pOutBuf, "%s: port [%d] now DOWN\r\n", argv[0], portNum);
        portConfig[portNum] &= ~PORT_CONFIG_UP;
        break;
      default:
        retVal = -1;
        break;
      } // switch()

    if (retVal != -1) {
      clicharSendOutputBuffer(pOutBuf, bufLen);
      retVal = savePortConfig(portNum);
      }

    } // if (argc == 3)
  else {
    retVal = -1;
    }

  return retVal;
}

static int failtolHandler(int argc, char * argv[], int flags)
{
  unsigned int setFailTolerance;
  boolean updateFailTolerance;
  int bufLen;
  char * pOutBuf;
  int retVal;

  pOutBuf = clicharGetOutputBuffer(&bufLen);
  pOutBuf[0] = '\0'; // zero out the buffer the lazy way

  if (argc == 1) {
    updateFailTolerance = false;
    retVal = 0;
    }
  else if (argc == 2) {
    setFailTolerance = (unsigned int)atoi(argv[1]);

    if (setFailTolerance < 1) {
      // issue warning
      updateFailTolerance = false;
      retVal = -1;
      }
    else {
      linkFailTolerance = setFailTolerance;
      updateFailTolerance = true;
      }
    }
  else {
    return -1;
    }

    sprintf(pOutBuf, "%s: LHB link fail tolerance is [%u]\r\n\x0", 
      argv[0], linkFailTolerance);
    clicharSendOutputBuffer(pOutBuf, bufLen);

#ifdef CONFIG_INCLUDE_NVSTORE
  if (updateFailTolerance == true) {
    retVal = nvstoreWrite(LHB_FAIL_TOLERANCE_NVSTORE_NAME, 
                          (unsigned char *)&(linkFailTolerance), 
                          sizeof(unsigned int));
    }
#endif 

  return retVal;
}

static int lhbageHandler(int argc, char * argv[], int flags)
{
  unsigned int setAgeTimeSeconds;
  boolean updateAgeTime;
  int bufLen;
  char * pOutBuf;
  int retVal;

  pOutBuf = clicharGetOutputBuffer(&bufLen);
  pOutBuf[0] = '\0'; // zero out the buffer the lazy way

  if (argc == 1) {
    updateAgeTime = false;
    retVal = 0;
    }
  else if (argc == 2) {
    setAgeTimeSeconds = (unsigned int)atoi(argv[1]);
    if (setAgeTimeSeconds < 1) {
      // issue warning
      retVal = -1;
      updateAgeTime = false;
      }
    else {
      linkFailAgeTime = (setAgeTimeSeconds * 10);
      updateAgeTime = true;
      }
    }
  else {
    return -1;
    }

  sprintf(pOutBuf, "%s: LHB failure count age time is [%u] seconds\r\n\x0", 
          argv[0], (linkFailAgeTime/10));
  clicharSendOutputBuffer(pOutBuf, bufLen);

#ifdef CONFIG_INCLUDE_NVSTORE
  if (updateAgeTime == true) {
    retVal = nvstoreWrite(LHB_FAIL_COUNT_AGE_NVSTORE_NAME, 
                          (unsigned char *)&(linkFailAgeTime), 
                          sizeof(unsigned int));
    }
#endif

  return retVal;
}

#endif /* CONFIG_INCLUDE_ZARLINK */

