/****************************************************************************/
/* Copyright 2014 - 2015 MBARI                                              */
/****************************************************************************/
/* Summary  : ModBus callback routines for Miscellaneous Registers          */
/* Filename : misc.c                                                        */
/* Author   : Robert Herlien (rah)                                          */
/* Project  : OASIS5 Controller                                             */
/* Revision : 1.0                                                           */
/* Created  : 11/02/2015                                                    */
/*                                                                          */
/* MBARI provides this documentation and code "as is", with no warranty,    */
/* express or implied, of its quality or consistency. It is provided without*/
/* support and without obligation on the part of the Monterey Bay Aquarium  */
/* Research Institute to assist in its use, correction, modification, or    */
/* enhancement. This information should not be published or distributed to  */
/* third parties without specific written permission from MBARI.            */
/*                                                                          */
/****************************************************************************/
/* Modification History:                                                    */
/* 2nov2015 rah - created from misc.c in FOCE Medium Voltage Converter      */
/****************************************************************************/

#include <stdio.h>
#include <xc.h>
#include <Generic.h>
#include <string.h>

#include "regs.h"
#include "misc.h"
#include "dig_io.h"
#include "inst_port.h"
#include "config.h"
#include "sys_timer.h"
#include "mb.h"
#include "mbport.h"


extern USHORT mbTimeout;


/********************************/
/*  Module Local Data           */
/********************************/

static BlinkyState blinkyDebug = BLINKY_DEBUG24;
static WORD     blinkyCount = 0;
static unsigned long lastBlinkyTick = 0, blinkyStartTick = 0;


/************************************************************************/
/* Function    : miscInit                                               */
/* Purpose     : Initialize this module                                 */
/* Inputs      : None                                                   */
/* Outputs     : None                                                   */
/************************************************************************/
void miscInit(void)
{
    blinkyDebug = BLINKY_DEBUG24;
    blinkyCount = 0;
    lastBlinkyTick = 0;
    blinkyStartTick = 0;
    digBlinkyOn();
}

/************************************************************************/
/* Function    : miscRegRead                                            */
/* Purpose     : Read Misc Modbus Holding Register                      */
/* Inputs      : Register address                                       */
/* Outputs     : Value                                                  */
/************************************************************************/
UINT miscRegRead(unsigned int address, ConfigData *configp)
{       
    switch(address)
    {

      case BOARD_TYPE_REG:
#ifdef O5_DB
          return(BOARD_TYPE_O5_DAUGHTER);
#else
          return(BOARD_TYPE_O5_EXPANDER);
#endif

      case NUM_SER_PORTS_REG:
          return(SER_PORT_TOTAL);

      case NUM_RELAYS_REG:
          return(PWR_PORT_TOTAL);

      case NUM_DIO_REG:
          return(0);

      case NUM_ANALOG_REG:
          return(0);

      case SER_SWITCH_REG:
          return(0);

      case CONTROL_REG:
          return(0);

      case BLINKY_REG:
          return(blinkyDebug);

      case SERIAL_NUM_REG:
          return(configp->serialNum);

      case SOFTWARE_REV_REG:
          return((SW_REV_HIGH << 8) | (SW_REV_LOW & 0xff));

      case MB_ID_REG:
          return(configp->id);

      case MB_BAUD_REG:
          return(configp->baud/100);

      case RELAY_STATE_REG:
          return(digPwrGet());

      case MB_TIMEOUT_REG:
          return(mbTimeout);

    }

    return(0);
}


/************************************************************************/
/* Function    : miscRegWrite                                           */
/* Purpose     : Write Misc Modbus Holding Register                     */
/* Inputs      : Register address, value                                */
/* Outputs     : Error Code                                             */
/************************************************************************/
eMBErrorCode    miscRegWrite(UINT address, UINT val, ConfigData *configp)
{
    switch(address)
    {
      case CONTROL_REG:
          break;                 /* Do this later                */

      case BLINKY_REG:
          setBlinkyDebug(val);
          break;

      case SERIAL_NUM_REG:
          configp->serialNum = val;
          break;

      case MB_ID_REG:
          if ((val <= 0) || (val > 247))
              return(MB_EINVAL);
          configp->id = val;
          break;
          
      case MB_BAUD_REG:
#ifdef O5_DB
	configp->baud = val * 100L;
	SPI1BRGL = (PBCLK/(200L*val)) - 1;
#else
          if ((val == 192) || (val == 384) || (val == 576) ||
              (val == 1152))
              configp->baud = 100L*val;
          else
              return(MB_EINVAL);
          break;
#endif
          
      case MB_TIMEOUT_REG:
          if (val < 35)
              return(MB_EINVAL);
          mbTimeout = val;
          xMBPortTimersInit(val);
          break;

      default:
          return(MB_EINVAL);
    }

    return(MB_ENOERR);
}


/************************************************************************/
/*     get/set/BlinkyDebug                                              */
/* Get or set the blinkyDebug variable                                  */
/************************************************************************/
void setBlinkyDebug(BlinkyState state)
{
    blinkyDebug = state;
    blinkyCount = 0;
    lastBlinkyTick = tmrGetTicks();
    blinkyStartTick = tmrGetTicks();

    if ((state == BLINKY_OFF) || (state == BLINKY_ERROR))
        digBlinkyOff();
    else
        digBlinkyOn();
}

BlinkyState getBlinkyDebug(void)
{
    return(blinkyDebug);
}


/************************************************************************/
/* Function    : blinkyTask                                             */
/* Purpose     : Run the blinky LED                                     */
/* Inputs      : Got modbus frame                                       */
/* Outputs     : None                                                   */
/************************************************************************/
void blinkyTask(BOOL gotModbus)
{
    unsigned long curTick = tmrGetTicks();

    switch(blinkyDebug)
    {
      case BLINKY_OFF:
          digBlinkyOff();
          return;

      case BLINKY_ON:
          digBlinkyOn();
          return;

      case BLINKY_DEBUG24:
          if ((curTick - blinkyStartTick) >= (24*3600L*TICKS_PER_SEC))
          {
              digBlinkyOff();
              return;
          }
          // Note fall through to BLINKY_DEBUG!!!

      case BLINKY_DEBUG:
          if (gotModbus)
          {
              if ((curTick - lastBlinkyTick) >= TICKS_PER_SEC/2)
              {
                  digToggleBlinky();
                  lastBlinkyTick = curTick;
              }
          }
          else
              digBlinkyOn();
          return;

      case BLINKY_ERROR:
          if (blinkyCount < 6)
          {
              if ((curTick - lastBlinkyTick) >= TICKS_PER_SEC/10)
              {
                  digToggleBlinky();
                  blinkyCount++;
                  lastBlinkyTick = curTick;
              }
          }
          else if (curTick - lastBlinkyTick >= 2*TICKS_PER_SEC)
          {
              digBlinkyOff();
              blinkyCount = 0;
              lastBlinkyTick = curTick;
          }
          
          return;

      case BLINKY50:
          if ((curTick - lastBlinkyTick) >= TICKS_PER_SEC/2)
          {
              digToggleBlinky();
              lastBlinkyTick = curTick;
          }

          return;
    }

}
