/****************************************************************************/
/* Copyright 2003-2009 MBARI												*/
/****************************************************************************/
/* Summary	: Main Routine for OASIS kernel for Respirometer System			*/
/* Filename : oasis.c														*/
/* Author	: Robert Herlien (rah)											*/
/* Project	: Benthic/Midwater Respiromters (BRS/MRS)						*/
/* Revision : 1.0															*/
/* Created	: 10/14/2002													*/
/*																			*/
/* 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:													*/
/* 23dec2008 rah - created from Oasis3 oasis.c								*/
/* 10oct2002 rah - created from OASIS oasis.c								*/
/* $Log: oasis.c,v $
/* Revision 1.1	 2011/10/25 22:39:22  bobh
/* Initial oasis4 revision
/*
/* Revision 1.8	 2010/10/25 16:42:50  bobh
/* Changes to support scripting
/*
/* Revision 1.7	 2010/05/17 18:48:45  bobh
/* Added cfgsave, more, ren commands
/*
/* Revision 1.6	 2010/03/17 15:23:49  mrisi
/* added CVS tag
/*
/* Revision 1.5	 2010/01/22 16:22:59  bobh
/* Minor change to line 238
/*
/* Revision 1.4	 2009/11/19 19:05:58  bobh
/* Changes to support con to remote ports and fixes to file I/O due to testing
/*
/* Revision 1.3	 2009/04/27 22:49:43  bobh
/* First working version of remote serial ports
/*
/* Revision 1.2	 2009/04/17 18:05:04  bobh
/* Changes leading up to CDR
/*
/* Revision 1.1	 2009/03/25 20:34:41  bobh
/* Initial checkin
/*
 */
/****************************************************************************/

#include <mbariTypes.h>					/* MBARI type definitions			*/
#include <mbariConst.h>					/* MBARI constants					*/
#include <oasis.h>						/* OASIS controller definitions		*/
#include <custom.h>						/* Custom def's for deployment		*/
#include <io.h>							/* OASIS I/O definitions			*/
#include <list.h>						/* OASIS Linked List library		*/
#include <sem.h>						/* OASIS Semaphore library			*/
#include <task.h>						/* OASIS task dispatcher			*/
#include <malloc.h>						/* OASIS malloc routines			*/
#include <log.h>						/* OASIS data logging definitions	*/
#include <syslog.h>						/* Respirometer system logger		*/
#include <file.h>						/* OASIS File I/O Routines			*/
#include <drvr.h>						/* OASIS driver functions			*/
#include <clock.h>						/* OASIS clock routines				*/
#include <userif.h>						/* OASIS User Interface routines	*/
#include <usrcmds.h>					/* User Command function definitions*/
#include <utils.h>						/* OASIS Utility routines			*/
#include <serial.h>						/* OASIS serial I/O definitions		*/
#include <modbus.h>						/* Modbus protocol library			*/
#include <parm.h>						/* Parameter table definitions		*/
#include <remote.h>						/* Remote I/O library			*/
#include <diag.h>						/* OASIS diagnostic routines		*/
#include <debug.h>

#include <cfxpico.h>					/* Persistor PicoDOS definitions	*/
#include <stdio.h>						/* Standard I/O library				*/
#include <stdlib.h>						/* Standard C library				*/
#include <string.h>						/* Standard string library			*/


/********************************/
/*		External Data			*/
/********************************/

Extern Parm_t			radio_tmout;	/* Timeout for radio reset			*/
Extern Parm_t			logStatus;		/* Log on power up/down				*/
Extern MBool			diagnosticMode; /* Go into diagnostic mode			*/
Extern MBool			syncAtMidnight;
Extern MBool			wakeOnConsoleChar;
Extern MBool			blinky;			/* Blink LED?						*/


/********************************/
/*		Global Data				*/
/********************************/

Global TimeOfDay		radio_time;		/* Last time user connected on radio*/
Global Word				error;			/* Error vector						*/
Global MBool			running = FALSE;

const char * const		signon = "OASIS3 Kernel for Respirometers $Revision: 1.1 $";
const char * const		cvs_tag = "CVS tag $Name:  $";


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

#ifdef WATCHDOG
// This definition is the key to using the WDT on the Persistor CF2
short	CustomSYPCR = WDT6_5s | HaltMonEnable | BusMonEnable | BMT32;
#endif


/************************************************************************/
/* Function	   : oasis_init												*/
/* Purpose	   : Initialize OASIS controller							*/
/* Inputs	   : None													*/
/* Outputs	   : OK or ERROR											*/
/************************************************************************/
		MLocal Errno
oasis_init( Void )
{
#ifdef CORE_DUMP_ON_INIT
  file_coredump();
#endif	
  error = RESTART_ERR;					/* Init error vector			*/
  semLibInit();							/* Initialize semaphore lib		*/
  io_init();							/* Init I/O system, starts watchdog*/
  ser_init();							/* Init serial I/O system		*/
  task_init();							/* Initialize task module		*/
  initRemoteLib();						/* Init remote serial/IO lib	*/
  radio_time = clk_read();				/* Init read RTC, init radio tmout*/

  if (file_init() != OK)				/* Initialize file system		*/
	return(ERROR);
  if (sysLogInit() != OK)				/* Initialize syslogger			*/
	  return(ERROR);
  if (log_init() != OK)					/* Initialize log memory		*/
	return(ERROR);
  initModBus();							/* Init ModBus library			*/
  user_init();							/* Initialize user I/F			*/
  pwrpermFunc();						/* Set pwrperm bits (incl remote)*/
  drvr_init();							/* Init drvr module				*/

  return(OK);

} /* oasis_init() */


/************************************************************************/
/* Function	   : main													*/
/* Purpose	   : Main entry point										*/
/* Inputs	   : argc, argv												*/
/* Outputs	   : None													*/
/* Comments	   : Never returns											*/
/************************************************************************/
		int
main( int argc, char *argv[] )
{
  Nat32			next_alarm, task_alarm; /* Seconds 'til next alarm		*/
  Nat16			loopCntr;				/* Loop counter					*/
  Driver		*usrdp;					/* Driver ptr for user i/f		*/
  MBool			heartbeat = OFF;		/* Blink Light State			*/
  WhatWokeUs	wakeup = WakeNone;		/* How we woke up				*/
  MBool			ext_wake = TRUE;		/* User pressed wake button		*/
  TimeOfDay		tod;					/* Current time					*/
  Errno			rtn;
  int			signcnt=0;

  running = FALSE;
		// Identify the progam and build
  printf("\%s: %s %s \n", __FILE__, __DATE__, __TIME__);
		// Identify the device and its firmware
  printf("Persistor CF%d SN:%ld	  BIOS:%d.%d   PicoDOS:%d.%d\n", CFX,
		 BIOSGVT.CFxSerNum, BIOSGVT.BIOSVersion, BIOSGVT.BIOSRelease, 
		 BIOSGVT.PICOVersion, BIOSGVT.PICORelease);

  if ((100 * BIOSGVT.PICOVersion + BIOSGVT.PICORelease) < MIN_PICO_VER)
  {
	printf("Must use PicoDOS %d.%02d or later.	Exiting\n\n",
		   MIN_PICO_VER/100, MIN_PICO_VER % 100);
	return(1);
  }

  rtn = oasis_init();					/* Initialize					   */

  if (diagnosticMode ||
	  ((argc > 1) && (cmp_ulc(argv[1], "diagnosticMode") != NULL)))
	o3Diagnostic(0xffff);				/* If diagnostic mode set, just run*/
										/* the diagnostic (ends with reset)*/
  else if (rtn != OK)					/* If init was bad, abort		   */
  {
	printf("Error in OASIS Initialization!	Aborting\n\n");
	BIOSResetToPicoDOS();
  }

  usrdp = drvr_find("UserIF");
  xprintf("%s\n", signon);
  xprintf("%s\n\n", cvs_tag);
  running = TRUE;

  FOREVER
  {
	io_pwrup();
	tod = clk_read();
	drvr_pwrup();
	log_pwrup();

	if ( logStatus & LOG_PWRUP )		/* Log power up event if enabled   */
//		logOasisStatus( 1 );
	  logOasisStatus( 0x100 | wakeup );

	if (syncAtMidnight)
	  drvMidnightSync();				/* If need to sync @ midnight, check*/

	if (wakeup != WakeTmout)
	  ext_wake = TRUE;					/* If woke via usr button, run usrif*/

	/* Tickle Oasis3 hardware watchdog first time thru */
	ioPingWatchdog();
	/* and then init the loop counter */				
	loopCntr = 0;
	
#ifdef DEBUG_DRVR_TIMES
	clk_printtime(tod);
	dprintf("OASIS awake, wake type = %d\n", wakeup);
#endif

	do									/* Main loop - until drivers done  */
	{									/* Loop executes at 10 Hz		   */
		loopCntr++;
		if ((loopCntr % 5) == 0)
		{
			tod = clk_read();			/* Get current time twice per second*/
				   
			if (blinky && !diagnosticMode)
			{
				ioSetHeartbeat(heartbeat);		/* Blink heartbeat LED			   */
				heartbeat = !heartbeat;
			}

			serCheckXoffStatus();				/* See if XOFFs have timed out	   */

			if ( radio_tmout && (tod > (radio_time + (radio_tmout * 3600L))) )
				BIOSReset();			/* If no radio for 24 hrs, reset   */
		} 

		if (loopCntr >= O3_WATCHDOG_RATE)
		{
			ioPingWatchdog();			/* Tickle O3 hardware watchdog	   */
			loopCntr = 0;
		}
#ifdef WATCHDOG
		TickleSWSR();					/* Tickle 68332 watchdog		   */
#endif
		if (PinRead(IRQ5) == 0)
			ext_wake = TRUE;			/* If user pressing wake button	  */
										/*	 run user I/F				  */

		if (wakeOnConsoleChar && (usrdp != NULL) && (usrdp->drv_td == NULLTID) && 
			(serRxCount(usrdp->drv_parms[SER_PORT]) > 0))
			ext_wake = TRUE;

		if (ext_wake && (usrdp != DRV_NULL))
			usrdp->drv_wakeup = tod;
	  
		ext_wake = FALSE;

		task_delay(TICKS_PER_SECOND/10); /* Wait to see if drvrs running   */

		next_alarm = drvr_sample();		/* Start any drvr tasks not running*/
										/*	and get time to next wakeup	   */
		task_alarm = taskGetMinDelay();
#if 0
		if (next_alarm || task_alarm)
			dprintf("drvr_sample() returns %lu, taskGetMinDelay() returns %lu\n",
					next_alarm, task_alarm);
#endif
		if (task_alarm < next_alarm)
			next_alarm = task_alarm;

	} while (next_alarm < MIN_SLEEP_TIME); /* Repeat until all drivers done*/


	if (error)							/* If any generic errors,		   */
	{									/*	 log them					   */
		logError( error | ERR_LOG_BIT );
		error = 0;
	}
	
	if ( logStatus & LOG_PWRDOWN )		/* Log power down event if enabled */
		logOasisStatus( 0 );

	log_pwrdown();						/* DONE.  Power down the system	   */
#ifdef DEBUG_DRVR_TIMES
	clk_printtime(tod);
	dprintf("OASIS sleeping, wakeup secs = %lu\n", next_alarm);
#endif
	wakeup = io_pwrdown(next_alarm - SLEEP_WAKE_TIME);
  }

} /* _main() */
