#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include "et1000.h"
#include "wrs_smb.h"
#include "smartbits.h"
#include "tests_body.h"
#include "switch_config.h"

int force_stop;

int main()
{
  FILE *logfile;
  int test_no, result;
  int t_pass = 0, t_warn = 0, t_fail = 0;
	// Set Hub Slot Port location of the two cards in test
	//int iHub = 0;
	//int iSlot = 7;
#if BANK 
	int iPort1 = 2;
  int iPort2 = 3;
#else
	int iPort1 = 0;
  int iPort2 = 1;
#endif

	int iDataLength = 100;
	int iStreams = 1;

	linkToSmartBits();

	if (HTSlotReserve(HUB, SLOT) < 0) {
    fprintf(stderr, "Could not reserve the card\n");
    CHECKERROR(NSUnLink());
    return -1;
  }

  CHECKERROR( HTResetPort(RESET_FULL, HUB, SLOT, iPort1) );
  CHECKERROR( HTResetPort(RESET_FULL, HUB, SLOT, iPort2) );

  //reset_ports(SMB_PALL);
  //latency_meas(iPort1, iPort2);
  //basic_traffic(FRAME_SZ, iPort1, iPort2);
  //setup_stream(iPort1, iPort2, FRAME_SZ, 1000, 0.1, 5, -1, 1);
  
  //temp_run_test(iPort1, iPort2);

  logfile = open_logfile();
  if (!logfile) {
    fprintf(stderr, "Could not open the logfile\n");
    CHECKERROR(NSUnLink());
    return -1;
  }

  force_stop = 0;

  for(test_no=TEST_3_1_4; test_no<=TEST_3_3_2; ++test_no) {
  //for(test_no=TEST_3_1_1; test_no<TEST_3_3_2+1; ++test_no) {
  //for(test_no=TEST_3_1_4; test_no<TEST_3_1_4+1; ++test_no) {
    //test_no = TEST_2_2_2;
    result = run_and_analyze(test_no, logfile);
    switch (result) {
      case TEST_PASSED:
        ++t_pass;
        break;
      case TEST_WARNING:
        ++t_warn;
        break;
      case TEST_FAILED:
        ++t_fail;
        break;
    }
    if (force_stop) break;
    NSDelay(5);
  }

  //Greg
  //while(!detect_stop()) {
  //  show_allcntrs(SMB_PALL, NULL);
  //}
  run_traffic(SMB_PALL, TRAFFIC_STOP);

  printf("----------------------\n");
  printf("PASSED:   %d\n", t_pass);
  printf("WARNINGS: %d\n", t_warn);
  printf("FAILED:   %d\n", t_fail);

  fclose(logfile);

  NSDelay(1);
  CHECKERROR(NSUnLink());

	return 0;
}

/**********************************************************************/

void latency_meas(int p_tx, int p_rx)
{
  HTLatencyStructure lat_tx, lat_rx;
  GIGAutoFiberNegotiate aneg_tx, aneg_rx;
  HTCountStructure cnt_tx, cnt_rx;
  int i;

  //clear counters
  CHECKERROR( HTResetPort(RESET_FULL, HUB, SLOT, p_tx) );
  CHECKERROR( HTResetPort(RESET_FULL, HUB, SLOT, p_rx) );

  set_port_config(p_tx);
  set_port_config(p_rx);
  printf("Showing card info\n");
  show_card_info(p_tx);
  show_card_info(p_rx);

#if FIBER
//
//  HTGetStructure(GIG_STRUC_AUTO_FIBER_NEGOTIATE, 0, 0, 0, &aneg_tx, sizeof(GIGAutoFiberNegotiate), HUB, SLOT, p_tx);
//  HTSetStructure(GIG_STRUC_AUTO_FIBER_NEGOTIATE, 0, 0, 0, &aneg_rx, sizeof(GIGAutoFiberNegotiate), HUB, SLOT, p_rx);
#endif

  //get MAC
  //{ 
  //  int mac_tx[6], mac_rx[6];
  //  CHECKERROR( HTGetBuiltInAddress(mac_tx, HUB, SLOT, p_tx) );
  //  CHECKERROR( HTGetBuiltInAddress(mac_rx, HUB, SLOT, p_rx) );
  //  printf("MAC tx: ");
  //  for(int i=0; i<6; ++i)
  //    printf("%02x ", mac_tx[i]);
  //  printf("\n");

  //  printf("MAC rx: ");
  //  for(int i=0; i<6; ++i)
  //    printf("%02x ", mac_rx[i]);
  //  printf("\n");
  //}


  //clear the group
  //CHECKERROR( HGClearGroup() );

  //add ports to a group
  CHECKERROR( HGAddtoGroup(HUB, SLOT, p_tx) );
  CHECKERROR( HGAddtoGroup(HUB, SLOT, p_rx) );

  //set transmit mode on TX port
  CHECKERROR( HTTransmitMode(SINGLE_BURST_MODE, HUB, SLOT, p_tx) );
  CHECKERROR( HTBurstCount(1000, HUB, SLOT, p_tx) );
  CHECKERROR( HTGap(90, HUB, SLOT, p_tx) );
#if FIBER
#else
  //CHECKERROR( HTDuplexMode(FULLDUPLEX_MODE, HUB, SLOT, p_tx) );
#endif
	CHECKERROR( HTGapAndScale(90, NANO_SCALE, HUB, SLOT, p_tx) );

  //set lattency transmitter and receiver
  lat_tx.Range = 12;
  lat_tx.iData[6] = 0xff;
  lat_tx.iData[7] = 0xff;
  lat_tx.iData[8] = 0xff;
  lat_tx.iData[9] = 0xff;
  lat_tx.iData[10] = 0xff;
  lat_tx.iData[11] = 0xff;
  for (i=0; i<6; ++i)
    lat_tx.iData[i] = 0xa5;
  lat_tx.Offset = 0;
  lat_tx.ulLatency = 0;

  lat_rx.Range = 12;
  lat_rx.iData[6] = 0xff;
  lat_rx.iData[7] = 0xff;
  lat_rx.iData[8] = 0xff;
  lat_rx.iData[9] = 0xff;
  lat_rx.iData[10] = 0xff;
  lat_rx.iData[11] = 0xff;
  for (i=0; i<6; ++i)
    lat_rx.iData[i] = 0xa5;
  lat_rx.Offset = 0;
  lat_rx.ulLatency = 0;
  CHECKERROR( HTLatency(HT_LATENCY_RXTX, &lat_tx, HUB, SLOT, p_tx) );
  CHECKERROR( HTLatency(HT_LATENCY_RX, &lat_rx, HUB, SLOT, p_rx) );

  //Timestamp-Initialization Sequence
  CHECKERROR( HGSetGroupBehavior(ALLOW_LATENCY_COUNTER_RESET) );
  CHECKERROR( HGStop() );
  CHECKERROR( HGSetGroupBehavior(INHIBIT_LATENCY_COUNTER_RESET) );

  //start transmission
  //CHECKERROR( HGStart() );
  //CHECKERROR( HGRun(HTRUN) );
  CHECKERROR( HTRun(HTRUN, HUB, SLOT, p_tx) );
  NSDelay(2);
  // Now wait until transmission stops
  CHECKERROR( HTGetCounters(&cnt_tx, HUB, SLOT, p_tx) );
  while (cnt_tx.TmtPktRate != 0)
  {
	     CHECKERROR( HTGetCounters(&cnt_tx, HUB, SLOT, p_tx) );
	     CHECKERROR( HTGetCounters(&cnt_rx, HUB, SLOT, p_rx) );
       show_cntrs(&cnt_tx, p_tx);
       show_cntrs(&cnt_rx, p_rx);
       NSDelay(1);
  }
  NSDelay(1);
	CHECKERROR( HTGetCounters(&cnt_tx, HUB, SLOT, p_tx) );
	CHECKERROR( HTGetCounters(&cnt_rx, HUB, SLOT, p_rx) );
  show_cntrs(&cnt_tx, p_tx);
  show_cntrs(&cnt_rx, p_rx);


  //get latency info
  CHECKERROR( HTLatency(HT_LATENCY_REPORT, &lat_tx, HUB, SLOT, p_tx) );
  CHECKERROR( HTLatency(HT_LATENCY_REPORT, &lat_rx, HUB, SLOT, p_rx) );
  printf("Latency tx: %lu\n", lat_tx.ulLatency);
  printf("Latency rx: %lu\n", lat_rx.ulLatency);
  printf("Latency   : %lu\n", lat_rx.ulLatency - lat_tx.ulLatency);
  CHECKERROR( HTLatency(HT_LATENCY_OFF, &lat_tx, HUB, SLOT, p_tx) );
  CHECKERROR( HTLatency(HT_LATENCY_OFF, &lat_rx, HUB, SLOT, p_rx) );
  CHECKERROR( HGStop() );
}

/**********************************************************************/

int basic_traffic(int fsize, int p_tx, int p_rx)
{
  int pattern[1514];  //max frame size
  HTCountStructure cs1, cs2;
  HTVFDStructure vfd1, vfd2, vfd3;
  static int vfd1Data[6], vfd2Data[6], vfd3Data[2];
  int i;

  CHECKERROR( HTResetPort(RESET_FULL, HUB, SLOT, p_tx) );
  CHECKERROR( HTResetPort(RESET_FULL, HUB, SLOT, p_rx) );
  set_port_config(p_tx);
  set_port_config(p_rx);
  printf("Showing card info\n");
  show_card_info(p_tx);
  show_card_info(p_rx);

  CHECKERROR( HTDataLength(fsize, HUB, SLOT, p_tx) );
  for(i=0; i<fsize; ++i)
    pattern[i] = 0xaa;
  CHECKERROR( HTFillPattern(fsize, pattern, HUB, SLOT, p_tx) );
  //VFD1
  vfd1.Configuration = HVFD_STATIC;
  vfd1.Range = 6;
  vfd1.Offset = 0;
  vfd1Data[0] = 0x07;
  vfd1Data[1] = 0x06;
  vfd1Data[2] = 0x05;
  vfd1Data[3] = 0x04;
  vfd1Data[4] = 0x03;
  vfd1Data[5] = 0x02;
  printf("9\n"); fflush(stdout);
  vfd1.Data = vfd1Data;
  printf("10\n"); fflush(stdout);
  CHECKERROR( HTVFD(HVFD_1, &vfd1, HUB, SLOT, p_tx) );
  printf("11\n"); fflush(stdout);

  //VFD2
  vfd2.Configuration = HVFD_STATIC;
  vfd2.Range = 6;
  vfd2.Offset = 48;
  vfd2Data[0] = 0x06;
  vfd2Data[1] = 0x05;
  vfd2Data[2] = 0x04;
  vfd2Data[3] = 0x03;
  vfd2Data[4] = 0x02;
  vfd2Data[5] = 0x01;
  printf("9\n"); fflush(stdout);
  vfd2.Data = vfd2Data;
  printf("10\n"); fflush(stdout);
  CHECKERROR( HTVFD(HVFD_2, &vfd2, HUB, SLOT, p_tx) );
  printf("11\n"); fflush(stdout);

  //VFD3
  NSDelay(1);
  vfd3.Configuration = HVFD_ENABLED;
  vfd3.Range = 2;
  vfd3.Offset = 12*8;
  vfd3Data[0] = 0x88;
  vfd3Data[1] = 0xf7;
  vfd3.Data = vfd3Data;
  vfd3.DataCount = 2;
  CHECKERROR( HTVFD(HVFD_3, &vfd3, HUB, SLOT, p_tx) );
  NSDelay(1);

  CHECKERROR( HTTransmitMode(SINGLE_BURST_MODE, HUB, SLOT, p_tx) );
  //CHECKERROR( HTTransmitMode(CONTINUOUS_PACKET_MODE, HUB, SLOT, p_tx) );
  CHECKERROR( HTBurstCount(1000, HUB, SLOT, p_tx) );
	CHECKERROR( HTGapAndScale(96, NANO_SCALE, HUB, SLOT, p_tx) );
  clearCounters(HUB, SLOT, p_tx);
  clearCounters(HUB, SLOT, p_rx);
  CHECKERROR( HTRun(HTRUN, HUB, SLOT, p_tx) );
  NSDelay(1);
  CHECKERROR( HTRun(HTRUN, HUB, SLOT, p_tx) );
  CHECKERROR(HTGetCounters(&cs1, HUB, SLOT, p_tx));
  while (cs1.TmtPktRate != 0)
  {
    CHECKERROR(HTGetCounters(&cs1, HUB, SLOT, p_tx));
    CHECKERROR(HTGetCounters(&cs2, HUB, SLOT, p_rx));
    show_cntrs(&cs1, p_tx);
    show_cntrs(&cs2, p_rx);
    NSDelay(1);
  }
  NSDelay(5);

}

int setup_stream(int port, char *dmac, char *smac, int fsize, int fnum, float ratio, int v_pri, int vid, int idx)
{
  static StreamIP str[MAX_STREAMS];
  static int n_streams = 0;
  static StreamIPVLAN strv[MAX_STREAMS];
  NSPortTransmit tx_mode;
  static L3StreamExtension l3_ext[MAX_STREAMS];
  unsigned long eth_speed;
  char dip[4] = {192, 168, 1, 1};
  char sip[4] = {192, 168, 1, 3};
  /* procedure according to  page 332 of SmartLibrary Overview */

  //printf("stream: port %d, dmac %02x:%02x:%02x:%02x:%02x:%02x, smac %02x:%02x:%02x:%02x:%02x:%02x, size %d, fnum %d, ratio %f, pri %d, vid %d, idx %d\n",
  //    port, dmac[0]&0xff, dmac[1]&0xff, dmac[2]&0xff, dmac[3]&0xff, dmac[4]&0xff, dmac[5]&0xff,
  //    smac[0]&0xff, smac[1]&0xff, smac[2]&0xff, smac[3]&0xff, smac[4]&0xff, smac[5]&0xff, fsize, fnum, ratio, v_pri, vid, idx);
  //6
  if (vid < 0 && idx >=0 ) {
    //////// no VLAN ///////////
    //IP Stream
    bzero(&str[idx], sizeof(StreamIP));
    str[idx].ucActive = 1;
    str[idx].ucProtocolType = STREAM_PROTOCOL_IP;
    str[idx].uiFrameLength = fsize;

    str[idx].ucTagField = 1;
    memcpy(str[idx].DestinationMAC, dmac, 6);
    memcpy(str[idx].SourceMAC, smac, 6);
    str[idx].TimeToLive = 255;
    str[idx].InitialSequenceNumber = 0;
    bzero(str[idx].DestinationIP, 4);
    bzero(str[idx].SourceIP, 4);
    memcpy(str[idx].DestinationIP, dip, 4);
    memcpy(str[idx].SourceIP, sip, 4);
    str[idx].Protocol = 4;
    //str.uiActualSequenceNumber = 0xcafe;
    n_streams++;
  }
  else if (vid >= 0 && idx >= 0) {
    //////// VLANs ///////////
    bzero(&strv[idx], sizeof(StreamIP));
    strv[idx].ucActive = 1;
    strv[idx].ucProtocolType = STREAM_PROTOCOL_IP_VLAN;
    strv[idx].uiFrameLength = fsize;
    strv[idx].ucTagField = 0;
    memcpy(strv[idx].DestinationMAC, dmac, 6);
    memcpy(strv[idx].SourceMAC, smac, 6);
    strv[idx].TimeToLive = 255;
    strv[idx].InitialSequenceNumber = 0;
    bzero(strv[idx].DestinationIP, 4);
    bzero(strv[idx].SourceIP, 4);
    bzero(strv[idx].Netmask, 4);
    memcpy(strv[idx].DestinationIP, dip, 4);
    memcpy(strv[idx].SourceIP, sip, 4);
    bzero(strv[idx].Gateway, 4);
    strv[idx].Protocol = 4;
    strv[idx].VLAN_Pri = v_pri;
    strv[idx].VLAN_Cfi = VLAN_CFI_RIF_ABSENT;
    strv[idx].VLAN_Vid = vid;
    n_streams++;
  }
  else if(vid<0 && idx == -1) {
    CHECKERROR( HTSetStructure(L3_DEFINE_IP_STREAM, 0, 0, 0, str, n_streams*sizeof(StreamIP), HUB, SLOT, port) );
  }
  else if(vid>=0 && idx == -1)
    CHECKERROR( HTSetStructure(L3_DEFINE_IP_STREAM_VLAN, 0, 0, 0, strv, n_streams*sizeof(StreamIPVLAN), HUB, SLOT, port) );

  //7
  // Stream EXT
  //printf("Calculated %lu frames/sec for %f ratio\n", ratio_to_fps(fsize, ratio), ratio);
  if (idx >= 0) {
    bzero(&l3_ext[idx], sizeof(L3StreamExtension));
    //l3_ext[idx].ulFrameRate = ratio_to_fps(fsize, ratio);
    //l3_ext[idx].ulBurstCount = fnum;
    //l3_ext[idx].uiInitialSeqNumber = 0;
    //l3_ext[idx].ucIPHeaderChecksumError = 0;
    //if (fnum > 0)
    //  l3_ext[idx].ulTxMode = L3_SINGLE_BURST_MODE;
    //else
    //  l3_ext[idx].ulTxMode = L3_CONTINUOUS_MODE;
  }
  else {
    //printf("define L3 EXT for %d streams\n", n_streams);
    //printf("L3 EXT rate %lu count %lu\n", l3_ext[0].ulFrameRate, l3_ext[0].ulBurstCount);
    //CHECKERROR( HTSetStructure(L3_DEFINE_STREAM_EXTENSION, 0, 0, 0,
    //      l3_ext, n_streams*sizeof(L3StreamExtension), HUB, SLOT, port) );

    ///*verify frame rate*/
    //NSDelay(1);
    //bzero(l3_ext, MAX_STREAMS*sizeof(L3StreamExtension));
    //CHECKERROR( HTGetStructure(L3_READ_STREAM_EXTENSION, 1, 0, 0, l3_ext,
    //      sizeof(L3StreamExtension), HUB, SLOT, port) );
    //printf("L3 EXT read rate %lu %s %lu\n", l3_ext[0].ulFrameRate,
    //    l3_ext[0].ulTxMode==L3_CONTINUOUS_MODE?"cont":"sburst", l3_ext[0].ulBurstCount);

    bzero(&tx_mode, sizeof(NSPortTransmit));
    tx_mode.ulBurstCount  = n_streams*fnum;
    tx_mode.ucScheduleMode = SCHEDULE_MODE_GAP; //SCHEDULE_MODE_FRAME_RATE;
    //printf("calculated gap %ld\n", ratio_to_gap(fsize, ratio));
    tx_mode.ulInterFrameGap = ratio_to_gap(fsize, ratio);
    tx_mode.uiGapScale = NANO_SCALE;
    tx_mode.ucRandomGapEnable = 0;
    if (fnum > 0)
      tx_mode.ucTransmitMode = SINGLE_BURST_MODE;
    else
      tx_mode.ucTransmitMode = CONTINUOUS_PACKET_MODE;

    CHECKERROR( HTSetStructure(NS_PORT_TRANSMIT, 0, 0, 0, &tx_mode, sizeof(NSPortTransmit), HUB, SLOT, port) );
    n_streams = 0;
  }

  return 0;
}

int temp_run_test(int p_tx, int p_rx)
{
  int bidir = 1;
  HTCountStructure cs_tx, cs_rx;
  int tx_led, rx_led;
  char mac[SMB_PORTS][6] = {{0x3c, 0x47, 0x0e, 0x04, 0x05, 0x06},
                            {0x3c, 0x47, 0x0e, 0x14, 0x15, 0x16},
                            {0x3c, 0x47, 0x0e, 0x24, 0x25, 0x26},
                            {0x3c, 0x47, 0x0e, 0x34, 0x35, 0x36}};

  reset_ports(SMB_P0 | SMB_P1 | SMB_P2 | SMB_P3);

  //smb_learning(SMB_P0 | SMB_P1 | SMB_P2 | SMB_P3, mac, 3);

  setup_stream(p_tx, mac[1], mac[0], FRAME_SZ, 1000, 0.1, 5, -1, 0);
  setup_stream(p_rx, mac[0], mac[1], FRAME_SZ, 1234, 0.1, 5, -1, 0);
  
  //wait_linkup(SMB_P0 | SMB_P1);
  smb_set_trigger(mac[0], p_rx, 6, 6, HTTRIGGER_1);
  smb_set_trigger(mac[1], p_tx, 6, 6, HTTRIGGER_1);

  clear_allcntrs(SMB_PALL);

  ////wait for link up
  wait_linkup(SMB_P0 | SMB_P1);

  //generate traffic
  if(bidir)
    run_traffic(1<<p_tx | 1<<p_rx, 1);
  else
    run_traffic(1<<p_tx, 1);

  NSDelay(1);

  //Greg
  while(!detect_stop()) {
    show_allcntrs(NULL, SMB_PALL, NULL);
  }
  run_traffic(1<<p_tx | 1<<p_rx, 0);

  return 0;
}

FILE* open_logfile()
{
  time_t curtime;
  struct tm *t;
  char filename[30];
  FILE *f;

  curtime = time(NULL);
  t = localtime(&curtime);

  sprintf(filename, "%s-%d-%02d-%02d-%02d-%02d.log", LOG_FILE, t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min);
  printf("%s\n", filename);
  f = fopen(filename, "w");
  
  return f;
}
