#include "ECUBoard.h"
#include "vxUtils.h"
#include "DmErrno.h"

ECUBoard::ECUBoard(const char *systemName,
		   const char *appName,
		   const char *deviceName,
                   Word channelNo,
                   IbcApp *app)
    : SerialDevice(systemName, appName, deviceName, channelNo)
{
  _name = strdup(deviceName);
  _mainApp = app;
  _maxChannels = 24;

  _initialized = FALSE;  
  char dmPrefix[MaxDmNameLen];
  sprintf(dmPrefix, "%s.%s.%s.", systemName, appName, name);
  _dmPrefix = strdup(dmPrefix);

  char system = (char)systemName;
  char applicName = (char)appName;
  char device = (char)deviceName; 
  _ecuSerialChan = channelNo;

  ECU_OutputState[0] = 0;
  ECU_OutputState[1] = 0;
  ECU_OutputState[2] = 0;
  ECU_OutputState[3] = 0;
}


ECUBoard::~ECUBoard()
{
  free((void *)_name);
  free((void *)_dmPrefix);
}

///////////////////////////////////////////////////////////////////
// Initialize DM items and micro
STATUS ECUBoard::handleResetEvent()
{
  return(OK);
};
  
///////////////////////////////////////////////////////////////////
// Add DM items to monitored group 
// [input] dmMonitor: DmMonitor which monitors component
STATUS ECUBoard::startMonitoring(DmMonitor *dmMonitor)
{
  for (int i = 0; i < _outputs.size(); i++)
  {
    DigitalOutput *output;
    
    _outputs.get(i, (void **)&output);
    dmMonitor->addMonitoredItem(output->dmItem);
  }
  return OK;
};

///////////////////////////////////////////////////////////////////
// Process changes to DM items
STATUS ECUBoard::processDmChanges(DmGroup *dmGroup)
{
  STATUS status;

  for (int i = 0; i < _outputs.size(); i++)
  {
    DigitalOutput *output;
    _outputs.get(i, (void **)&output);
    
    if (output->switchMethod() != SwitchedByFramework)
      continue;
  
    if (dmGroup->itemChanged(output->dmItem))
    {
//      logMsg("ECUBoard::processDmChanges() - "
//      	      "output %s (chan #%d) changed\n", 
//        	      output->name(), output->channelNo());

      Errno err;
      MBool value;
      DM_Time t;
    
      if ((err = dm_read(output->dmItem, &value, sizeof(MBool), &t)) 
	  != SUCCESS)
      {
	char errorBuf[errorMsgSize];
	sprintDmError(err, "ECUBoard::processDmChanges()", errorBuf);
	logMsg(errorBuf);
	status = ERROR;
      }
      else
      {
      
          status = setECUDigitalOutputs(output->channelNo(), 
                                    value ? ON : OFF);
      
//	  logMsg("ECUBoard::processDmChanges() - "
//		"value=%d, status=%d\n",(char *) value, status);

	if (status == ERROR)
	{
	  logMsg("ECUBoard::processDmChanges() - card %s, output %s "
		 "ERROR status from setECUDigitalOutputs()\n", 
		 name(), output->name());
	}
      }
    }
  }  
   return(status);
};

///////////////////////////////////////////////////////////////////
// Start providers for sampling
STATUS ECUBoard::startSampling()
{
return(OK);
}

///////////////////////////////////////////////////////////////////
// Read micro and update DM items
STATUS ECUBoard::sampleMicro()
{
return(OK);
};

///////////////////////////////////////////////////////////////////
// Call after receiving SRQ
MBool ECUBoard::handleSrq(Word requestCode, Byte *packet)
{
return(OK);
};

///////////////////////////////////////////////////////////////////
// Call after receiving reset SRQ
STATUS ECUBoard::handleResetSrq()
{
return(OK);
};

///////////////////////////////////////////////////////////////////
// Add Digital Output to ECU Card
DigitalOutput *ECUBoard::addOutput(const char *name, 
                                   SwitchMethod switchMethod )
{ 
  if (_outputs.size()  >= _maxChannels)
  {
//    setError("ECUBoard::addOutput() - "
//	     "Exceeded maximum number of channels");

    return NULL;
  }
  DigitalOutput *output =
    new DigitalOutput(_systemName, _appName, name, 
		      _outputs.size() + 1, 
                      switchMethod);

  _outputs.add((void **)&output);

  return(output);
};
  

STATUS ECUBoard::initECUDigitalOutputs()
{
  STATUS status;
  Byte buffer[9];
  Int16 i, nBytes = 9;
  Byte checksum;

  ECU_OutputState[0] = 0;
  ECU_OutputState[1] = 0;
  ECU_OutputState[2] = 0;
  ECU_OutputState[3] = 0;

  if (Quad_Serial_Open( _mainApp->device->channel(), 
                             QUAD_SERIAL_0_ADDR, 
                             _ecuSerialChan ) == ERROR)
     return(status);

  if (Quad_Serial_SetLineParm( _mainApp->device->channel(), 
                             QUAD_SERIAL_0_ADDR, 
                             _ecuSerialChan,
                             (Nat16) ECU_BAUD, 
                             (Nat16) ECU_DATA, 
                             (Nat16) ECU_STOP, 
                             (Nat16) ECU_PAR, 
                             ECU_HANDSHAKE, 
                             ECU_PROTO) == ERROR)
     return(status);          


  buffer[0] = START_BYTE;
  buffer[1] = ALL_BOARDS;
  buffer[2] = DIG_OUT_FUNC;
  buffer[3] = 0x00;//ALL OFF
  buffer[4] = 0x00;
  buffer[5] = 0x00;
  buffer[6] = 0x00;

  checksum = CHECKSUM_BASE;

  for(i=0; i<7; i++)
      checksum = checksum + buffer[i];
  
  buffer[7] = checksum;
  buffer[8] = END_BYTE;  

  return Quad_Serial_Write( _mainApp->device->channel(), 
                             QUAD_SERIAL_0_ADDR, 
                             _ecuSerialChan,
                             buffer, nBytes );
}

STATUS ECUBoard::setECUDigitalOutputs(int chan, MBool outputValue )
{
  STATUS status;
  Byte buffer[9];
  Int16 i, nBytes = 9;
  Byte checksum;
  Byte channelNo;
  Byte ECU_Board_Num;
  Int16 module;

  channelNo = (Byte)chan;

  Word serialChan = 3;
  
  if (channelNo <= 8)
  {
      ECU_Board_Num = BOARD_0;
      module        = MOTHER_BOARD;      
  }
  else if(channelNo <= 16)
  {
      channelNo = channelNo - 8;
      ECU_Board_Num = BOARD_0;
      module        = EXPANSION_1;      
  }
  else if(channelNo <= 24)
  {
      channelNo = channelNo - 16;
      ECU_Board_Num = BOARD_0;
      module        = EXPANSION_2;      
  }
  else if(channelNo <= 32)
  {
      channelNo = channelNo - 24;
      ECU_Board_Num = BOARD_0;
      module        = EXPANSION_3;      
  }


  switch (channelNo)
  {
    case 0:
      if (outputValue == ON)
      ECU_OutputState[module] |= CHANNEL_0;
      else if(outputValue == OFF)
      ECU_OutputState[module] &= ~CHANNEL_0;
      break;

    case 1:
      if (outputValue == ON)
      ECU_OutputState[module] |= CHANNEL_1;
      else if(outputValue == OFF)
      ECU_OutputState[module] &= ~CHANNEL_1;
      break;

    case 2:
      if (outputValue == ON)
      ECU_OutputState[module] |= CHANNEL_2;
      else if(outputValue == OFF)
      ECU_OutputState[module] &= ~CHANNEL_2;
      break;

    case 3:
      if (outputValue == ON)
      ECU_OutputState[module] |= CHANNEL_3;
      else if(outputValue == OFF)
      ECU_OutputState[module] &= ~CHANNEL_3;
      break;

    case 4:
      if (outputValue == ON)
      ECU_OutputState[module] |= CHANNEL_4;
      else if(outputValue == OFF)
      ECU_OutputState[module] &= ~CHANNEL_4;
      break;

    case 5:
      if (outputValue == ON)
      ECU_OutputState[module] |= CHANNEL_5;
      else if(outputValue == OFF)
      ECU_OutputState[module] &= ~CHANNEL_5;
      break;

    case 6:
      if (outputValue == ON)
      ECU_OutputState[module] |= CHANNEL_6;
      else if(outputValue == OFF)
      ECU_OutputState[module] &= ~CHANNEL_6;
      break;

    case 7:
      if (outputValue == ON)
      ECU_OutputState[module] |= CHANNEL_7;
      else if(outputValue == OFF)
      ECU_OutputState[module] &= ~CHANNEL_7;
      break;

    case 8:
      if (outputValue == ON)
      ECU_OutputState[module] |= CHANNEL_8;
      else if(outputValue == OFF)
      ECU_OutputState[module] &= ~CHANNEL_8;
      break;

  }
  
  buffer[0] = START_BYTE;
  buffer[1] = ECU_Board_Num;
  buffer[2] = DIG_OUT_FUNC;
  buffer[3] = ECU_OutputState[MOTHER_BOARD];
  buffer[4] = ECU_OutputState[EXPANSION_1];
  buffer[5] = ECU_OutputState[EXPANSION_2];
  buffer[6] = ECU_OutputState[EXPANSION_3];

  checksum = CHECKSUM_BASE;

  for(i=0; i<7; i++)
      checksum = checksum + buffer[i];
  
  buffer[7] = checksum;
  buffer[8] = END_BYTE;  
     
  status =  Quad_Serial_Write( _mainApp->device->channel(), 
                             QUAD_SERIAL_0_ADDR, 
                             _ecuSerialChan,
                             buffer, nBytes );

  status = Quad_Serial_Read( _mainApp->device->channel(), 
                             QUAD_SERIAL_0_ADDR, 
                             _ecuSerialChan,
                             buffer, nBytes ); 

  return(status);

}























