/** \file
 *
 *  Contains the AnalogToDigital class implementation.
 *
 *  Copyright (c) 2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 *
 */

#include "AnalogToDigital.h"

#include <cstdlib>
#include <ctype.h>

#include "data/Slate.h"
#include "units/Units.h"

AnalogToDigital::AnalogToDigital( const ConfigURI& adCfg, const ConfigURI& vrefCfg,
                                  const ConfigURI& resCfg, bool useHardware, Logger& logger )
    : useHardware_( useHardware ),
      io_( adCfg, useHardware, logger ),
      vrefPerBit_( ReadVRefPerBit( vrefCfg, resCfg, logger ) ),
      timeout_( Timespan::ZERO_TIMESPAN ),
      started_( false ),
      startTime_( Timestamp::NOT_SET_TIME ),
      logger_( logger )
{}

AnalogToDigital::AnalogToDigital( const ConfigURI& adCfg, const ConfigURI& vrefCfg,
                                  const ConfigURI& resCfg, const ConfigURI& timeoutCfg, bool useHardware, Logger& logger )
    : useHardware_( useHardware ),
      io_( adCfg, useHardware, logger ),
      vrefPerBit_( ReadVRefPerBit( vrefCfg, resCfg, logger ) ),
      timeout_( ReadTimeout( timeoutCfg, logger ) ),
      started_( false ),
      startTime_( Timestamp::NOT_SET_TIME ),
      logger_( logger )
{}

AnalogToDigital::~AnalogToDigital() {}

void AnalogToDigital::startRead()
{
    if( io_.isWritable() )
    {
        startTime_ = Timestamp::Now();
        started_ = true;
        io_.write( "\n", 1 );
    }
    else
    {
        started_ = false;
    }
}

float AnalogToDigital::readCounts()
{
    Timespan elapsed;
    if( !started_ || startTime_.elapsed() >= timeout_ )
    {
        startTime_ = Timestamp::Now();
    }
    started_ = false;
    char buffer[12] = "           ";
    int tries = 0;
    while( io_.isReadable() )
    {
        unsigned int bytesRead = io_.read( buffer, 11 ).bytesRead();
        if( bytesRead > 0
                && 0 != *buffer
                && ( isdigit( *buffer ) || *buffer == '-' ) )
        {
            return atof( buffer );
        }
        ++tries;
        elapsed = startTime_.elapsed();
        if( elapsed > timeout_ )
        {
            break;
        }
        Timespan( 0.004 ).sleepFor();
    }
    logger_.syslog( Str( "A/D timeout, " ) + tries + " tries over " + ( int )elapsed.asMillis() +  " ms\n", Syslog::INFO );
    return nanf( "" );
}

double AnalogToDigital::ReadTimeout( const ConfigURI& timeoutUri, Logger& logger )
{
    double timeout( 0.0 );
    Slate::ReadOnce( timeoutUri, Units::SECOND, timeout, logger );
    return timeout;
}

float AnalogToDigital::ReadVRefPerBit( const ConfigURI& vrefCfg, const ConfigURI& resCfg, Logger& logger )
{
    int bits( 12 );
    Slate::ReadOnce( resCfg, Units::BIT, bits, logger );
    double vref( 3.30 );
    Slate::ReadOnce( vrefCfg, Units::VOLT, vref, logger );
    return vref / ( 1 << bits );
}
