/*
 Rocrail - Model Railroad Software
 Copyright (c) 2002-2022 Robert Jan Versluis, Rocrail.net
 All rights reserved.
*/
#include "cbus.h"
#include "cbus_dfs.h"
#include "wiocan_dfs.h"
#include "trace.h"
#include "gen/revision.h"

//---------- CBus constructor.
CBus::CBus(byte ID, byte BoardType) {
  trace("CBUS ID=%d", ID);
  m_CANID     = ID;
  m_BoardType = BoardType;
}


int CBus::getCANBPS() {
  return 125;
}

byte CBus::getFilters(unsigned long* filters) {
  return 0;
}

void CBus::setID(byte id) {
  m_CANID = id;
}


bool CBus::evalFrame(iCANFrame frame, iCmdData cmd) {
  bool eval = false;
  cmd->cmd = 0;
  
  if( frame->ext == 0 && frame->dlc > 0 ) {
    // Query Node
    if( frame->data[0] == OPC_QNN ) {
      trace("query");
      cmd->cmd = CMD_QUERY;
      eval = true;
    }
    // Start of Day
    else if( frame->data[0] == OPC_ASRQ ) {
      trace("SoD");
      cmd->cmd = CMD_SOD;
      eval = true;
    }
    // Fast clock
    else if( frame->data[0] == OPC_FCLK ) {
      trace("Fast clock %02u%02u speed=%u temp=%d", frame->data[2], frame->data[1], frame->data[4], frame->data[6]);
    }
    // Request read of node variable
    else if( frame->data[0] == OPC_NVRD ) {
      trace("get cv %u", frame->data[3]);
      cmd->cmd   = CMD_GETCV;
      cmd->id    = frame->data[1] * 256 + frame->data[2];
      cmd->addr  = frame->data[3];
      cmd->thisid = (cmd->id == m_CANID) ? true:false;
      eval = true;
    }
    // Request read of node variable
    else if( frame->data[0] == OPC_NVSET ) {
      trace("set cv %u=%u", frame->data[3], frame->data[4]);
      cmd->cmd   = CMD_SETCV;
      cmd->id    = frame->data[1] * 256 + frame->data[2];
      cmd->addr  = frame->data[3];
      cmd->value = frame->data[4];
      cmd->thisid = (cmd->id == m_CANID) ? true:false;
      eval = true;
    }
    // General OPCs
    if( frame->data[0] == OPC_RTOF ) {
      trace("power off");
      cmd->cmd = EVT_POWER_OFF;
      eval = true;
    }
    
    else if( frame->data[0] == OPC_RTON ) {
      trace("power off");
      cmd->cmd = EVT_POWER_ON;
      eval = true;
    }
    
    // Accessory OPCs
    else if( frame->data[0] == OPC_ARON || frame->data[0] == OPC_ARSON || frame->data[0] == OPC_ACON || frame->data[0] == OPC_ASON ) {
      trace("output on");
      cmd->cmd  = CMD_OUTPUT_ON;
      cmd->id   = frame->data[1] * 256 + frame->data[2];
      cmd->addr = frame->data[3] * 256 + frame->data[4];
      cmd->thisid = (cmd->id == m_CANID) ? true:false;
      cmd->datacnt = frame->dlc - 5;
      memcpy( cmd->data, frame->data+5, 3);
      eval = true;
    }
    else if( frame->data[0] == OPC_AROF || frame->data[0] == OPC_ARSOF || frame->data[0] == OPC_ACOF || frame->data[0] == OPC_ASOF ) {
      trace("output off");
      cmd->cmd  = CMD_OUTPUT_OFF;
      cmd->id   = frame->data[1] * 256 + frame->data[2];
      cmd->addr = frame->data[3] * 256 + frame->data[4];
      cmd->thisid = (cmd->id == m_CANID) ? true:false;
      cmd->datacnt = frame->dlc - 5;
      memcpy( cmd->data, frame->data+5, 3);
      eval = true;
    }

  }

  // WIOCAN
  else if( frame->ext == 1 && frame->state == CAN_BUFFER_DATA && frame->dlc <= 8 ) {
    trace("ID=%04lX ext=%d dlc=%d %02X %02X %02X %02X - %02X %02X %02X %02X", frame->id, frame->ext, frame->dlc,
      frame->data[0], frame->data[1], frame->data[2], frame->data[3], frame->data[4], frame->data[5], frame->data[6], frame->data[7]);
    
  }

  return eval;
}


bool CBus::makeFrame(iCANFrame frame, iCmdData cmd) {
  bool didmake = false;
  if( cmd->cmd == CMD_GETCV ) {
    frame->id = m_CANID;
    frame->ext = 0;
    frame->dlc = 5;
    frame->data[0] = OPC_NVANS;
    frame->data[1] = 0;
    frame->data[2] = m_CANID;
    frame->data[3] = cmd->addr;
    frame->data[4] = cmd->value;
    didmake = true;
  }
  else if( cmd->cmd == CMD_PUBLISH ) {
    frame->id = m_CANID;
    frame->ext = 0;
    frame->dlc = 8;
    frame->data[0] = OPC_PNN;
    frame->data[1] = 0;
    frame->data[2] = m_CANID;
    frame->data[3] = MANU_ROCRAIL;
    frame->data[4] = m_BoardType;
    frame->data[5] = (CV::get(EE_CONFIG) + CFG_FLAT);
    frame->data[6] = RCAN_VERMAJ; //revisionnr / 256;
    frame->data[7] = RCAN_VERMIN; //revisionnr % 256;
    didmake = true;
  }
  else if( cmd->cmd == EVT_SENSOR) {
    frame->id  = m_CANID;
    frame->ext = 0;
    frame->dlc = 5;
    frame->data[0] = cmd->value ? OPC_ACON:OPC_ACOF;
    frame->data[1] = 0;
    frame->data[2] = m_CANID;
    frame->data[3] = 0;
    frame->data[4] = cmd->addr + 1;
    didmake = true;
  }
  else if( cmd->cmd == EVT_OUTPUT) {
    frame->id  = m_CANID;
    frame->ext = 0;
    frame->dlc = 5;
    frame->data[0] = cmd->value ? OPC_ARON:OPC_AROF;
    frame->data[1] = 0;
    frame->data[2] = m_CANID;
    frame->data[3] = 0;
    frame->data[4] = cmd->addr + 1;
    didmake = true;
  }
  
  
  return didmake;
}
