/************************************************************************/
/* Copyright 2010 MBARI													*/
/************************************************************************/
/* Summary	: Remote serial and power ports for Respiromters			*/
/* Filename : usrRemoteCmds.c											*/
/* Author	: Robert Herlien (rah)										*/
/* Project	: Benthic/Midwater Respirometers (BRS/MRS)					*/
/* Revision: 1.0														*/
/* Created	: 05/06/2010												*/
/*																			*/
/* 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:												*/
/* 06may2010 rah - split off from remote.c								*/
/************************************************************************/

#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 <drvr.h>						/* OASIS driver functions		*/
#include <parse.h>						/* Generic parser declarations	*/
#include <variable.h>					/* Variable definitions			*/
#include <utils.h>						/* OASIS Utility routines		*/
#include <modbus.h>						/* Modbus protocol library		*/
#include <remote.h>						/* Remote I/O library			*/
#include <usrRemoteCmds.h>				/* User funcs for Remote I/O	*/
#include <debug.h>

#include <cfxpico.h>					/* Persistor PicoDOS definitions*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


/********************************/
/*		External Data			*/
/*		(from remote.c)			*/
/********************************/

Extern RemSerPort		serPorts[];
Extern RemIOPort		pwrPorts[];
Extern RemIOPort		outPorts[];


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

MLocal char		*coilErrStr = "ERROR Reading Coil";
MLocal char		*onStr = "ON";
MLocal char		*offStr = "OFF";


/************************************************************************/
/* Function	   : coilStateStr											*/
/* Purpose	   : Return literal string "ON" or "OFF"					*/
/* Inputs	   : ModBus bus, slave, coil number							*/
/* Outputs	   : "ON", "OFF", "BUS OFF", or "ERROR"						*/
/************************************************************************/
MLocal char *coilStateStr(Nat16 bus, Nat16 slave, Nat16 coil)
{
	ModBusHandle		mh;
	Errno				rtn;
	Byte				state;

	if (!modBusIsPowered(bus))
		return("BUS OFF");

	if ((mh = modBusOpen(bus)) == NULL)
		return(coilErrStr);

	rtn = readCoils(mh, slave, coil, 1, &state);
	modBusClose(mh);

	if (rtn != OK)
		return(coilErrStr);

	return((state & 1) ? onStr : offStr);
}


/************************************************************************/
/* Function	   : showRemote												*/
/* Purpose	   : Show status of remote/virtual ports					*/
/* Inputs	   : None													*/
/* Outputs	   : OK														*/
/************************************************************************/
CmdRtn showRemote(void)
{
	Nat16		i;
	RemSerPort	*rp;

	for (i = 0, rp = serPorts; i < VIRT_SER_PORTS; i++, rp++)
		if (rp->assigned || (rp->sem.sem_owner != NULL))
		{
			xprintf("Serial %hd ", i+PHYS_SER_PORTS);
			if (rp->name[0] != '\0')
				xprintf("[%s] ", rp->name);
			if (rp->assigned)
				xprintf("is assigned, ");
			if (rp->sem.sem_owner != NULL)
				xprintf("opened by %s ", ((TaskDesc *)(rp->sem.sem_owner))->td_name);
			xprintf("on Modbus %hd slave %hd port %hd\n",
					rp->bus, rp->slave, rp->port);
		}

	for (i = 0; i < VIRT_PWR_PORTS; i++)
		if (pwrPorts[i].assigned)
		{
			xprintf("Power bit %2hd ", i+PHYS_PWR_PORTS);
			if (pwrPorts[i].name[0] != '\0')
				xprintf("[%s] ", pwrPorts[i].name);
			xprintf(" is assigned to Modbus %hd slave %hd coil %hd mult %.2f surge %lu ms [%s]\n",
					pwrPorts[i].bus, pwrPorts[i].slave, pwrPorts[i].coil,
					pwrPorts[i].multiplier, pwrPorts[i].surgeDelayMs,
					coilStateStr(pwrPorts[i].bus, pwrPorts[i].slave, PowerBit(pwrPorts[i].coil)));

		}
	for (i = 0; i < VIRT_OUT_PORTS; i++)
		if (outPorts[i].assigned)
		{
			xprintf("Output bit %2hd ", i);
			if (outPorts[i].name[0] != '\0')
				xprintf("[%s] ", outPorts[i].name);
			xprintf(" is assigned to Modbus %hd slave %hd coil %hd mult %.2f surge %lu ms [%s]\n",
					outPorts[i].bus, outPorts[i].slave, outPorts[i].coil,
					outPorts[i].multiplier, outPorts[i].surgeDelayMs,
					coilStateStr(outPorts[i].bus, outPorts[i].slave, OutputBit(outPorts[i].coil)));
		}

	return(OK);

} /* showRemote() */


/************************************************************************/
/* Function	   : onOff													*/
/* Purpose	   : Look for "ON", "OFF", "1", or "0"						*/
/* Inputs	   : String													*/
/* Outputs	   : TRUE for ON, FALSE for OFF								*/
/************************************************************************/
MLocal MBool onOff(char *s)
{
	if (strcasecmp(s, "ON") == 0)
		return(TRUE);
	if (atoi(s) == 1)
		return(TRUE);
	return(FALSE);
}


/************************************************************************/
/* Function	   : usrRemPower											*/
/* Purpose	   : User I/F function to turn on/off a (remote) power bit	*/
/* Inputs	   : pmask, Power bit, bool for on/off						*/
/* Outputs	   : OK or ERROR											*/
/************************************************************************/
Int16 usrRemPower(Nat16 pmask, char *bitStr, char *onOffStr)
{
	Int16		bitNum;
	
	if (((pmask & 3) != 3) || 
		((bitNum = findRemPwrPort(bitStr)) == ERROR))
	{
		xprintf("Usage: remPower <bitNum> <On|Off>\n");
		return(ERROR);
	}

	return(onOff(onOffStr) ? pwrBitOn(bitNum) : pwrBitOff(bitNum));

} /* usrRemPower() */


/************************************************************************/
/* Function	   : usrRemOutput											*/
/* Purpose	   : User I/F function to turn on/off a remote output bit	*/
/* Inputs	   : pmask, Output bit, bool for on/off						*/
/* Outputs	   : OK or ERROR											*/
/************************************************************************/
Int16 usrRemOutput(Nat16 pmask, char *bitStr, char *onOffStr)
{
	Int16		bitNum;
	
	if (((pmask & 3) != 3) || 
		((bitNum = findRemOutputPort(bitStr)) == ERROR))
	{
		xprintf("Usage: remOutput <bitNum> <On|Off>\n");
		return(ERROR);
	}

	return(remOutput(bitNum, onOff(onOffStr)));

} /* usrRemOutput() */


/************************************************************************/
/* Function	   : usrRemOutPulse											*/
/* Purpose	   : User I/F function to pulse a remote output bit			*/
/* Inputs	   : pmask, Output bit, time in ms							*/
/* Outputs	   : OK or ERROR											*/
/************************************************************************/
Int16 usrRemOutPulse(Nat16 pmask, char *bitStr, char *timeStr)
{
	Int16		bitNum;
	Flt32		fltSecs;

	if (((pmask & 3) != 3) || 
		((bitNum = findRemOutputPort(bitStr)) == ERROR) ||
		!getFltVal(timeStr, &fltSecs))
	{
		xprintf("Usage: remPulse <bitNum> <seconds>\n");
		return(ERROR);
	}

	xprintf("Pulsing remote output bit %d for %.2f secs\n", bitNum, fltSecs);

	return(remOutPulseOn(bitNum, fltSecs));

} /* usrRemOutPulse() */


/************************************************************************/
/* Function	   : usrAssignSerial										*/
/* Purpose	   : User I/F function to assign a virtual serial port		*/
/* Inputs	   : pmask, virt serport number, bus, slave, port			*/
/* Outputs	   : OK or ERROR											*/
/************************************************************************/
Int16 usrAssignSerial(Nat16 pmask, Parm_t virtPort, Parm_t bus, Parm_t slave, Parm_t port)
{
	if ((pmask & 0xf) != 0xf)
	{
		xprintf("Usage: assignSerial <virtSerNum> <modBusNum> <slave> <port>\n");
		return(ERROR);
	}

	if (assignVirtSerial(NULL, virtPort, bus, slave, port) != OK)
	{
		xprintf("Bad port number reference or port already assigned\n");
		return(ERROR);
	}

	xprintf("Bus %ld slave %ld port %ld assigned to virtual serial port %ld\n",
			bus, slave, port, virtPort);
	return(OK);

} /* usrAssignSerial() */


/************************************************************************/
/* Function	   : usrAssignPower											*/
/* Purpose	   : User I/F function to assign a virtual power port		*/
/* Inputs	   : pmask, virt power number, bus, slave, port				*/
/* Outputs	   : OK or ERROR											*/
/************************************************************************/
Int16 usrAssignPower(Nat16 pmask, Parm_t virtPort, Parm_t bus, Parm_t slave, Parm_t port)
{
	if ((pmask & 0xf) != 0xf)
	{
		xprintf("Usage: assignPower <virtPwrNum> <modBusNum> <slave> <port>\n");
		return(ERROR);
	}

	if (assignVirtPwr(NULL, virtPort, bus, slave, port, 1.0, 0.0) != OK)
	{
		xprintf("Bad port number reference or port already assigned\n");
		return(ERROR);
	}

	xprintf("Bus %ld slave %ld port %ld assigned to virtual power port %ld\n",
			bus, slave, port, virtPort);
	return(OK);

} /* usrAssignPower() */


/************************************************************************/
/* Function	   : usrAssignOutput										*/
/* Purpose	   : User I/F function to assign a virtual output port		*/
/* Inputs	   : pmask, virt output number, bus, slave, port			*/
/* Outputs	   : OK or ERROR											*/
/************************************************************************/
Int16 usrAssignOutput(Nat16 pmask, Parm_t virtPort, Parm_t bus, Parm_t slave, Parm_t port)
{
	if ((pmask & 0xf) != 0xf)
	{
		xprintf("Usage: assignOutput <virtOutputNum> <modBusNum> <slave> <port>\n");
		return(ERROR);
	}

	if (assignVirtOutput(NULL, virtPort, bus, slave, port, 1.0, 0.0) != OK)
	{
		xprintf("Bad port number reference or port already assigned\n");
		return(ERROR);
	}

	xprintf("Bus %ld slave %ld port %ld assigned to virtual output port %ld\n",
			bus, slave, port, virtPort);
	return(OK);

} /* usrAssignOutput() */
