309 lines
7.0 KiB
C++
309 lines
7.0 KiB
C++
/*
|
|
* OpenBTS provides an open source alternative to legacy telco protocols and
|
|
* traditionally complex, proprietary hardware systems.
|
|
*
|
|
* Copyright 2014 Range Networks, Inc.
|
|
*
|
|
* This software is distributed under the terms of the GNU General Public
|
|
* License version 3. See the COPYING and NOTICE files in the current
|
|
* directory for licensing information.
|
|
*
|
|
* This use of this software may be subject to additional restrictions.
|
|
* See the LEGAL file in the main directory for details.
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include "rnrad1.h"
|
|
|
|
using namespace ad9862;
|
|
|
|
rnrad1Rx::rnrad1Rx (int whichBoard,
|
|
unsigned int wDecimRate,
|
|
const std::string fpgaFilename = "",
|
|
const std::string firmwareFilename = "")
|
|
: rnrad1Core(whichBoard,RAD1_RX_INTERFACE,RAD1_RX_ALTINTERFACE,fpgaFilename,firmwareFilename,false)
|
|
{
|
|
|
|
mDevHandle = 0;
|
|
mEndptHandle = 0;
|
|
mBytesSeen = 0;
|
|
mEnabled = false;
|
|
mDecimRate = wDecimRate;
|
|
|
|
// initialize rx specific registers
|
|
// initialize registers that are common to rx and tx
|
|
bool result=true;
|
|
result &= write9862(REG_RX_PWR_DN,0);
|
|
result &= write9862(REG_RX_A,0); // minimum gain = 0x00 (max gain = 0x14)
|
|
result &= write9862(REG_RX_B,0); // minimum gain = 0x00 (max gain = 0x14)
|
|
result &= write9862(REG_RX_MISC,RX_MISC_HS_DUTY_CYCLE | RX_MISC_CLK_DUTY);
|
|
result &= write9862(REG_RX_IF,RX_IF_USE_CLKOUT1 | RX_IF_2S_COMP);
|
|
result &= write9862(REG_RX_DIGITAL,RX_DIGITAL_2_CHAN);
|
|
if (!result) {
|
|
LOG(ERR) << "Failed to init AD9862 RX regs";
|
|
exit(1);
|
|
}
|
|
|
|
// Reset the rx path and leave it disabled.
|
|
enable (false);
|
|
|
|
sendRqst(VRQ_FPGA_SET_RX_RESET, 1);
|
|
usleep(10);
|
|
sendRqst(VRQ_FPGA_SET_RX_RESET, 0);
|
|
|
|
setSampleRateDivisor (2); // usually correct
|
|
|
|
setDcOffsetClEnable(0xf, 0xf); // enable DC offset removal control loops
|
|
|
|
// check fusb buffering parameters
|
|
int blockSize = 4096; //fusb::default_block_size();
|
|
int numBlocks = 4*128; //std::max (1, fusb::default_buffer_size() / blockSize);
|
|
|
|
mDevHandle = fusb::make_devhandle (getHandle(), getContext());
|
|
mEndptHandle = mDevHandle->make_ephandle (RAD1_RX_ENDPOINT, true,
|
|
blockSize, numBlocks);
|
|
|
|
writeFpgaReg(FR_ATR_MASK_1,0);
|
|
writeFpgaReg(FR_ATR_TXVAL_1,0);
|
|
writeFpgaReg(FR_ATR_RXVAL_1,0);
|
|
writeFpgaReg(FR_ATR_MASK_3,0);
|
|
writeFpgaReg(FR_ATR_TXVAL_3,0);
|
|
writeFpgaReg(FR_ATR_RXVAL_3,0);
|
|
|
|
mSwMux = 0;
|
|
mHwMux = 0;
|
|
|
|
writeFpgaReg(FR_RX_FORMAT,0x00000300);
|
|
writeHwMuxReg();
|
|
setDecimRate(mDecimRate);
|
|
unsigned int mux = 0x00000010;
|
|
setMux(mux);
|
|
writeFpgaReg(FR_MODE, 0);
|
|
setRxFreq(0);
|
|
}
|
|
|
|
|
|
rnrad1Rx::~rnrad1Rx()
|
|
{
|
|
enable (false);
|
|
|
|
delete mEndptHandle;
|
|
delete mDevHandle;
|
|
|
|
// initialize registers that are common to rx and tx
|
|
bool result= write9862(REG_RX_PWR_DN,0x1);
|
|
|
|
}
|
|
|
|
|
|
bool rnrad1Rx::writeHwMuxReg()
|
|
{
|
|
bool s = disable();
|
|
bool ok = writeFpgaReg (FR_RX_MUX, mHwMux | 1);
|
|
restore (s);
|
|
return ok;
|
|
}
|
|
|
|
bool rnrad1Rx::setRxFreq (double freq)
|
|
{
|
|
int v = (int) rint (freq / (double) adcRate() * pow (2.0, 32.0));
|
|
mRxFreq = v * (double) adcRate() / pow (2.0, 32.0);
|
|
return writeFpgaReg (FR_RX_FREQ_0, v);
|
|
}
|
|
|
|
rnrad1Rx *rnrad1Rx::make(int whichBoard,
|
|
unsigned int wDecimRate,
|
|
const std::string fpgaFilename = "",
|
|
const std::string firmwareFilename = "")
|
|
{
|
|
try {
|
|
rnrad1Rx *u = new rnrad1Rx(whichBoard,
|
|
wDecimRate,
|
|
fpgaFilename,
|
|
firmwareFilename);
|
|
return u;
|
|
}
|
|
catch (...) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
bool rnrad1Rx::setDecimRate (unsigned int rate)
|
|
{
|
|
if ((rate & 0x1) || rate < 4 || rate > 256){
|
|
LOG(ERR) << "decimation rate must be EVEN and in [4, 256]";
|
|
return false;
|
|
}
|
|
|
|
mDecimRate = rate;
|
|
setUsbDataRate ((adcRate()/rate) * (2 * sizeof (short)));
|
|
|
|
bool s = disable ();
|
|
int v = mDecimRate/2 - 1;
|
|
bool ok = writeFpgaReg (FR_DECIM_RATE, v);
|
|
restore (s);
|
|
return ok;
|
|
}
|
|
|
|
bool rnrad1Rx::setMux (int mux)
|
|
{
|
|
int mHwMux = 0;
|
|
for (int i = 0; i < 8; i++){
|
|
int t = (mux >> (4 * i)) & 0x3;
|
|
mHwMux |= t << (2 * i + 4);
|
|
}
|
|
mSwMux = mux;
|
|
return writeHwMuxReg ();
|
|
}
|
|
|
|
|
|
bool rnrad1Rx::start()
|
|
{
|
|
if (!rnrad1Core::start ()) // invoke parent's method
|
|
return false;
|
|
|
|
// fire off reads before asserting rx_enable
|
|
|
|
if (!mEndptHandle->start ()){
|
|
LOG(ERR) << "Can't start USB RX stream";
|
|
return false;
|
|
}
|
|
|
|
if (!enable (true)){
|
|
LOG(ERR) << "Can't enable RX";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool rnrad1Rx::setSampleRateDivisor (unsigned int div)
|
|
{
|
|
return writeFpgaReg (FR_RX_SAMPLE_RATE_DIV, div - 1);
|
|
}
|
|
|
|
int rnrad1Rx::read (void *buf, int len, bool *overrun)
|
|
{
|
|
int r;
|
|
|
|
if (overrun) *overrun = false;
|
|
|
|
if (len < 0 || (len % 512) != 0){
|
|
LOG(ERR) << "read: invalid length = " << len;
|
|
return -1;
|
|
}
|
|
|
|
r = mEndptHandle->read (buf, len);
|
|
if (r > 0) mBytesSeen += r;
|
|
|
|
if (overrun != 0 && mBytesSeen >= mBytesPerPoll){
|
|
mBytesSeen = 0;
|
|
*overrun = true;
|
|
unsigned char status;
|
|
if (checkOverrun(&status) != 1)
|
|
LOG(ERR) << "Overrun check failed";
|
|
*overrun = status;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
bool rnrad1Rx::enable (bool on)
|
|
{
|
|
mEnabled = on;
|
|
return (sendRqst(VRQ_FPGA_SET_RX_ENABLE, on) == 0);
|
|
}
|
|
|
|
// conditional disable, return prev state
|
|
bool rnrad1Rx::disable ()
|
|
{
|
|
bool enabled = enable ();
|
|
if (enabled) enable (false);
|
|
return enabled;
|
|
}
|
|
|
|
// conditional set
|
|
void rnrad1Rx::restore (bool on)
|
|
{
|
|
if (on != enable ()) enable (on);
|
|
}
|
|
|
|
bool rnrad1Rx::setPga (int amp, double gain)
|
|
{
|
|
if (amp < 0 || amp > 1)
|
|
return false;
|
|
|
|
gain = std::min(pgaMax(), std::max(pgaMin(), gain));
|
|
int intGain = (int) rint((gain - pgaMin()) / pgaDbPerStep());
|
|
int reg = (amp & 1 == 0) ? REG_RX_A : REG_RX_B;
|
|
// read current value to get input buffer bypass flag.
|
|
unsigned char curRx;
|
|
if (!read9862(reg, &curRx))
|
|
return false;
|
|
|
|
curRx = (curRx & RX_X_BYPASS_INPUT_BUFFER) | (intGain & 0x7f);
|
|
return write9862(reg, curRx);
|
|
|
|
}
|
|
|
|
double rnrad1Rx::pga (int amp) const
|
|
{
|
|
if (amp < 0 || amp > 1) return READ_FAILED;
|
|
int reg = (amp & 1 == 0) ? REG_RX_A : REG_RX_B;
|
|
unsigned char v;
|
|
if (!read9862 (reg, &v)) return READ_FAILED;
|
|
return (pgaDbPerStep() * (v & 0x1f)) + pgaMin();
|
|
}
|
|
|
|
bool rnrad1Rx::writeOE (int value, int mask)
|
|
{
|
|
return writeFpgaReg(FR_OE_1, (mask << 16) | (value & 0xffff));
|
|
}
|
|
|
|
bool rnrad1Rx::writeIO (int value, int mask)
|
|
{
|
|
return writeFpgaReg(FR_IO_1, (mask << 16) | (value & 0xffff));
|
|
}
|
|
|
|
bool rnrad1Rx::readIO (int *value)
|
|
{
|
|
int t;
|
|
int reg = 0 + 1; // FIXME, *very* magic number (fix in serial_io.v)
|
|
if (!readFpgaReg(reg, &t)) return false;
|
|
*value = (t >> 16) & 0xffff; // FIXME, more magic
|
|
return true;
|
|
}
|
|
|
|
int rnrad1Rx::readIO (void)
|
|
{
|
|
int value;
|
|
if (!readIO(&value)) return READ_FAILED;
|
|
return value;
|
|
}
|
|
|
|
bool rnrad1Rx::writeRefClk(int value)
|
|
{
|
|
return writeFpgaReg(FR_RX_A_REFCLK, value);
|
|
}
|
|
|
|
bool rnrad1Rx::writeAuxDac (int dac, int value)
|
|
{
|
|
return rnrad1Core::writeAuxDac(dac, value);
|
|
}
|
|
|
|
bool rnrad1Rx::readAuxAdc (int adc, int *value)
|
|
{
|
|
return rnrad1Core::readAuxAdc(false, adc, value);
|
|
}
|
|
|
|
int rnrad1Rx::readAuxAdc (int adc)
|
|
{
|
|
int retVal;
|
|
rnrad1Rx::readAuxAdc(adc, &retVal);
|
|
return retVal;
|
|
}
|
|
|
|
int rnrad1Rx::blockSize() const { return mEndptHandle->block_size(); }
|
|
|
|
|