#include "archinc.h"
#include "cli.h"
#include "strutil.h"
#include "timer0.h"
#include "eventq.h"
#include "zarlink.h"
#include "zl_event.h"
#include "zl_rmon.h"
#include "zl_lhb.h"
#include "zl_bus.h"
#include "zlregs.h"
#include "portmgr.h"

#ifdef CONFIG_INCLUDE_ZARLINK

#include <stdio.h>
#include <stdlib.h>

static void handleCtrl1RxEvent(void);

static unsigned short ctrl1Data16[20];

static int decodeIntFrame(unsigned char *pFrameData)
{
  unsigned char intPort, intTrunk;
  unsigned long rmonOverflowBits;
  unsigned char u8temp;

  union {
    unsigned char u8[4];
    unsigned long u32;
  } u;

  // TODO: loop until all ctrl1 buffers retrieved and
  // processed before re-enabling interrupts

  if (pFrameData == NULL)
    return -1;

  // ensure it's an interrupt frame
  if ((pFrameData[0] != 0x70) || (pFrameData[1] != 0x00)) 
    return -1;

  if ((pFrameData[6] & 0x10) == 0) {
    intPort = (pFrameData[6] & 0x0f);
    intTrunk = -1;
    }
  else {
    intTrunk = (pFrameData[6] & 0x07);
    intPort = -1;
    }

  u.u8[0] = pFrameData[8];
  u.u8[1] = pFrameData[9];
  u.u8[2] = pFrameData[10];
  u.u8[3] = pFrameData[11];
  rmonOverflowBits = u.u32;

  if (rmonOverflowBits != 0) {
    zarlinkRmonCounterOverflow(intPort, rmonOverflowBits);
    }

  if ((pFrameData[11] & 0x40) != 0) {
    // Link status change

    if ((pFrameData[11] & 0x80) != 0) {
      // link is now down
      portmgrPortEventNotify((int)intPort, PORT_EVENT_PORT_DOWN);
      }
    else {
      // link is now up
      portmgrPortEventNotify((int)intPort, PORT_EVENT_PORT_UP);
      }
    }

  if ((pFrameData[12] & 0x04) != 0) {
    // LHB status change

    if ((pFrameData[12] & 0x08) != 0) {
      // LHB frame detected
      zarlinkLhbRxDetect((int)intPort);
      }   

    if ((pFrameData[12] & 0x10) != 0) {
      // LHB timeout
      zarlinkLhbRxTimeout((int)intPort);
      }
    }

  return 0;
}

int zarlinkCtrlRetrieveCtrl1(unsigned short *pCtrl1Buffer)
{
  int i;

  for(i=0;i<40/2;i++) {
    pCtrl1Buffer[i] = zarlinkCtrlBuffer1Read();
    }
  zarlinkCommandWrite(0x02);

  return 0;
}

static void handleCtrl1RxEvent(void)
{
  zarlinkCtrlRetrieveCtrl1(ctrl1Data16);
  zarlinkEventUnmaskIrq(INT_CONTROL_FRAME1);
  decodeIntFrame((unsigned char *)ctrl1Data16);
}

int zarlinkCtrl1Init(void)
{
  // register event handler for CTRL1 events
  eventqRegisterHandler(SWITCH_CTRL1_RX, handleCtrl1RxEvent);
  
  return 0;
}

#endif

