/****************************************************************************/
/* Copyright (c) 2000 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : PSA916Server.cc                                               */
/* Author   :                                                               */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 02/07/2000                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
#include <process.h>

#include <time.h>
#include "PSA916Server.h"
#include "FloatAttribute.h"
#include "AngleAttribute.h"

PSA916Server::PSA916Server(SerialParameters *serialParams,
			   const char *configFileName) 
  : RangeFinderIF_SK(),
    _attributes("psa916Server")
{
  _serialParams = serialParams;
  _input = new PSA916Input(SharedData::ReadWrite);
  _output = new PSA916Output(SharedData::ReadWrite);
  _output->data.deviceReady = False;
  _output->write();

  _attributes.add(new AngleAttribute("xzAngle", "x-z plane mounting angle",
				    &_xzAngle));

  _attributes.add(new FloatAttribute("maxRange", "Max measurable range",
				     &_maxRange, 99.));

  AttributeParser::parse(configFileName, &_attributes);

  enable();
}


PSA916Server::~PSA916Server()
{
  delete _input;
  delete _output;
}


void PSA916Server::name(DeviceIF::Name name)
{
  strcpy(name, "PSA916");
}


void PSA916Server::serialNumber(DeviceIF::Name number)
{
  strcpy(number, "XXX");
}


DeviceIF::Status PSA916Server::initialize()
{
  // Dummy implementation for now
  return DeviceIF::Ok;
}


DeviceIF::Status PSA916Server::powerOn()
{
  // Dummy implementation for now
  return DeviceIF::Ok;
}


DeviceIF::Status PSA916Server::powerOff()
{
  // Dummy implementation for now
  return DeviceIF::Ok;
}


DeviceIF::Status PSA916Server::status()
{
  // Dummy implementation for now
  return DeviceIF::Ok;
}


DeviceIF::Status PSA916Server::dataLoggingOn()
{
  // Dummy for now
  return DeviceIF::Ok;
}


DeviceIF::Status PSA916Server::dataLoggingOff()
{
  // Dummy for now
  return DeviceIF::Ok;
}


DeviceIF::Status PSA916Server::enable()
{
  _input->data.enabled = True;
  _input->write();

  return DeviceIF::Ok;
}


DeviceIF::Status PSA916Server::disable()
{
  _input->data.enabled = False;
  _input->write();

  return DeviceIF::Ok;
}


void PSA916Server::xzAngle(double *radians)
{
  *radians = _xzAngle;
}


void PSA916Server::maxRange(double *meters)
{
  *meters = _maxRange;
}


DeviceIF::Status PSA916Server::range(Boolean *echoReceived, 
				     double *value, 
				     TimeIF::TimeSpec *sampleTime)
{
  _output->read();
  if (!_output->data.deviceReady)
    return DeviceIF::Error;

  *value = _output->data.range;
  sampleTime->seconds = (long)_output->data.updateTime.tv_sec;
  sampleTime->nanoSeconds = (long)_output->data.updateTime.tv_nsec;

  if (*value > _maxRange) {
    /*
    Note that the PSA916 returns range of "99.99" when out-of-range, 
    even though no other indicator of a problem is returned. 
    So we do this check against maximum-measurable range too. (Note
    that _maxRange can be specified in config file.)
    */
    *echoReceived = False;
  }
  else
    *echoReceived = _output->data.echoReceived;


  return DeviceIF::Ok;
}


int PSA916Server::spawnAuxTasks()
{
  char *program = "psa916";
  char errorBuf[256];
  char buf[256];
 
  pid_t pid;
 
  switch ((pid = fork())) {
     
  case 0:
    // In child
    // Execute server program
    execlp(program, program, "-serial", _serialParams->string(), 0);

    sprintf(errorBuf, 
	    "Task::spawnServer() - execlp() of \"%s\" failed", program);

    perror(errorBuf);
 
    break;

  case -1:
    perror("Task::spawnServer() - fork() failed");
    return -1;
  }

  return 0;
}


