/***************************************************************
 * PrEncoderIntf.cpp
 *
 * This is an implementation of the interface
 * for derived encoder classes.
 *
 ****************************************************************/

/*
 * modification history
 *----------------------
 *
 * 10/26/97: K.C. Chang: created.
 */

#include "PrEncoderIntf.h"
#include <assert.h>

//2 bits=minimum number of bits to detect overflow
// assuming polling is being done fast enough
// highBitCount_= 2 
// highBitValue_= 11b = 3

PrEncoderIntf::PrEncoderIntf(int channelCount, int bitCount)
: PrDriverIntf(channelCount,bitCount),highBitCount_(2),highBitValue_(3)
{
    wrapCount_ = new int[channelCount];
    lastHighBitValue_ = new int[channelCount];
    for(int i=0;i<channelCount;i++)
      wrapCount_[i] = lastHighBitValue_[i] = 0;
}

PrEncoderIntf::~PrEncoderIntf()
{
    delete[] wrapCount_;
    delete[] lastHighBitValue_;
}

// read a channel value to 'num': calls channelValue()
inline int PrEncoderIntf::value(int channel,Float &num)
{
    assert(channel>=0 && channel < channelCount());

    num = channelValue(channel);

    return PR_DRIVER_OK;
}

// Merge the encoder counter bits with the software counter to produce 
// 32 bit signed integer value.
// returns the merged 32 bit signed integer value
int PrEncoderIntf::swCounterMerge(int channel,unsigned int bits)
{
    // get rid of other(overflow) bits
    bits &= bitMask();

    // get the value of the high bits
    int highBitValue = bits >> (bitCount()-highBitCount_);

    // check if a wrap occured: assuming polling is being done fast enough
    if ((highBitValue==0)&&(lastHighBitValue_[channel]==highBitValue_))
      wrapCount_[channel]++;
    else if ((highBitValue==highBitValue_)&&(lastHighBitValue_[channel]==0))
      wrapCount_[channel]--;
      
    // save the value of the high bits
    lastHighBitValue_[channel] = highBitValue;

    // merge the numbers
    return (wrapCount_[channel]*bitMask() + (int)bits);
}

// preset the 32 bit software encoder counter with value
// returns the counter bit ( < 32 bit) unsigned integer value
unsigned int PrEncoderIntf::swCounterPreset(int channel,int value)
{
    // find the number of wraps
    wrapCount_[channel] = value/bitMask();

    if (value>=0) 
      {
	  // find the offset
	  value = value%(bitMask()+1);
      }
    else
      {
	  // it needs to take care of the fact that the counter value is always positive
	  value = (-value)%(bitMask()+1);
	  wrapCount_[channel]--;
	  value = (bitMask()+1)-value;
      }
    // set the initial high bit value
    lastHighBitValue_[channel] = value >> (bitCount()-highBitCount_);
    return (unsigned int)value;
}

