//
// Copyright 2017 Ettus Research (National Instruments)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
#include "adi/common.h"
#include
#include
#include
#include
#include
#include
ad9371_spiSettings_t::ad9371_spiSettings_t(
mpm::types::regs_iface* spi_iface_
) :
spi_iface(spi_iface_)
{
spi_settings.chipSelectIndex = 0; // set later
spi_settings.writeBitPolarity = 1; // unused
spi_settings.longInstructionWord = 1;
spi_settings.MSBFirst = 1;
spi_settings.CPHA = 0;
spi_settings.CPOL = 0;
spi_settings.enSpiStreaming = 0; // unused
spi_settings.autoIncAddrUp = 0; // unused
spi_settings.fourWireMode = 1; // unused
spi_settings.spiClkFreq_Hz = 250000000; // currently unused
}
// TODO: change // not implemented to meaningful errors
// close hardware pointers
commonErr_t CMB_closeHardware(void)
{
// not implemented
return COMMONERR_FAILED;
}
// GPIO function
commonErr_t CMB_setGPIO(uint32_t GPIO)
{
// not implemented
return COMMONERR_FAILED;
}
// hardware reset function
commonErr_t CMB_hardReset(uint8_t spiChipSelectIndex)
{
// TODO: implement
return COMMONERR_OK;
}
//
// SPI read/write functions
//
// allows the platform HAL to work with devices with various SPI settings
commonErr_t CMB_setSPIOptions(spiSettings_t *spiSettings)
{
// not implemented
return COMMONERR_OK;
}
// value of 0 deasserts all chip selects
commonErr_t CMB_setSPIChannel(uint16_t chipSelectIndex)
{
// not implemented
return COMMONERR_OK;
}
// single SPI byte write function
commonErr_t CMB_SPIWriteByte(spiSettings_t *spiSettings, uint16_t addr, uint8_t data)
{
if (spiSettings == nullptr || spiSettings->MSBFirst == 0) {
return COMMONERR_FAILED;
}
ad9371_spiSettings_t *spi = ad9371_spiSettings_t::make(spiSettings);
try {
spi->spi_iface->poke8(addr, data);
return COMMONERR_OK;
} catch (const std::exception &e) {
// TODO: spit out a reasonable error here (that will survive the C API transition)
std::stringstream ss;
ss << "Error in CMB_SPIWriteByte: " << e.what();
CMB_writeToLog(
ADIHAL_LOG_ERROR,
spiSettings->chipSelectIndex,
ad9371_spi_errors_t::SPI_WRITE_ERROR,
ss.str().c_str());
}
return COMMONERR_FAILED;
}
// multi SPI byte write function (address, data pairs)
commonErr_t CMB_SPIWriteBytes(spiSettings_t *spiSettings, uint16_t *addr, uint8_t *data, uint32_t count)
{
if (spiSettings == nullptr ||
addr == nullptr ||
data == nullptr ||
spiSettings->MSBFirst == 0)
{
return COMMONERR_FAILED;
}
ad9371_spiSettings_t *spi = ad9371_spiSettings_t::make(spiSettings);
try {
for (size_t i = 0; i < count; ++i)
{
uint32_t data_word = (0) | (addr[i] << 8) | (data[i]);
spi->spi_iface->poke8(addr[i], data[i]);
}
return COMMONERR_OK;
} catch (const std::exception &e) {
// TODO: spit out a reasonable error here (that will survive the C API transition)
std::stringstream ss;
ss << "Error in CMB_SPIWriteBytes: " << e.what();
CMB_writeToLog(
ADIHAL_LOG_ERROR,
spiSettings->chipSelectIndex,
ad9371_spi_errors_t::SPI_WRITE_ERROR,
ss.str().c_str());
}
return COMMONERR_FAILED;
}
// single SPI byte read function
commonErr_t CMB_SPIReadByte (spiSettings_t *spiSettings, uint16_t addr, uint8_t *readdata)
{
if (spiSettings == nullptr ||
readdata == nullptr ||
spiSettings->MSBFirst == 0)
{
return COMMONERR_FAILED;
}
ad9371_spiSettings_t *spi = ad9371_spiSettings_t::make(spiSettings);
try {
*readdata = spi->spi_iface->peek8(addr);
return COMMONERR_OK;
} catch (const std::exception &e) {
// TODO: spit out a reasonable error here (that will survive the C API transition)
std::stringstream ss;
ss << "Error in CMB_SPIReadByte: " << e.what();
CMB_writeToLog(
ADIHAL_LOG_ERROR,
spiSettings->chipSelectIndex,
ad9371_spi_errors_t::SPI_READ_ERROR,
ss.str().c_str());
}
return COMMONERR_FAILED;
}
// write a field in a single register
commonErr_t CMB_SPIWriteField(
spiSettings_t *spiSettings,
uint16_t addr, uint8_t field_val,
uint8_t mask, uint8_t start_bit
) {
ad9371_spiSettings_t *spi = ad9371_spiSettings_t::make(spiSettings);
try {
uint8_t current_value = spi->spi_iface->peek8(addr);
uint8_t new_value = ((current_value & ~mask) | (field_val << start_bit));
spi->spi_iface->poke8(addr, new_value);
return COMMONERR_OK;
} catch (const std::exception &e) {
// TODO: spit out a reasonable error here (that will survive the C API transition)
std::stringstream ss;
ss << "Error in CMB_SPIWriteField: " << e.what();
CMB_writeToLog(
ADIHAL_LOG_ERROR,
spiSettings->chipSelectIndex,
ad9371_spi_errors_t::SPI_WRITE_ERROR,
ss.str().c_str());
}
return COMMONERR_FAILED;
}
// read a field in a single register
commonErr_t CMB_SPIReadField(
spiSettings_t *spiSettings,
uint16_t addr, uint8_t *field_val,
uint8_t mask, uint8_t start_bit
) {
ad9371_spiSettings_t *spi = ad9371_spiSettings_t::make(spiSettings);
try {
uint8_t value = spi->spi_iface->peek8(addr);
*field_val = static_cast((value & mask) >> start_bit);
return COMMONERR_OK;
} catch (const std::exception &e) {
// TODO: spit out a reasonable error here (that will survive the C API transition)
std::stringstream ss;
ss << "Error in CMB_SPIReadField: " << e.what();
CMB_writeToLog(
ADIHAL_LOG_ERROR,
spiSettings->chipSelectIndex,
ad9371_spi_errors_t::SPI_READ_ERROR,
ss.str().c_str());
}
return COMMONERR_FAILED;
}
// platform timer functions
commonErr_t CMB_wait_ms(uint32_t time_ms)
{
std::this_thread::sleep_for(std::chrono::milliseconds(time_ms));
return COMMONERR_OK;
}
commonErr_t CMB_wait_us(uint32_t time_us)
{
std::this_thread::sleep_for(std::chrono::microseconds(time_us));
return COMMONERR_OK;
}
commonErr_t CMB_setTimeout_ms(spiSettings_t *spiSettings, uint32_t timeOut_ms)
{
ad9371_spiSettings_t *mpm_spi = ad9371_spiSettings_t::make(spiSettings);
mpm_spi->timeout_start = std::chrono::steady_clock::now();
mpm_spi->timeout_duration = std::chrono::milliseconds(timeOut_ms);
return COMMONERR_OK;
}
commonErr_t CMB_setTimeout_us(spiSettings_t *spiSettings, uint32_t timeOut_us)
{
ad9371_spiSettings_t *mpm_spi = ad9371_spiSettings_t::make(spiSettings);
mpm_spi->timeout_start = std::chrono::steady_clock::now();
mpm_spi->timeout_duration = std::chrono::microseconds(timeOut_us);
return COMMONERR_OK;
}
commonErr_t CMB_hasTimeoutExpired(spiSettings_t *spiSettings)
{
ad9371_spiSettings_t *mpm_spi = ad9371_spiSettings_t::make(spiSettings);
auto current_time = std::chrono::steady_clock::now();
if ((std::chrono::steady_clock::now() - mpm_spi->timeout_start) > mpm_spi->timeout_duration)
{
return COMMONERR_FAILED;
}
else {
return COMMONERR_OK;
}
}
// platform logging functions
commonErr_t CMB_openLog(const char *filename)
{
// not implemented
return COMMONERR_FAILED;
}
commonErr_t CMB_closeLog(void)
{
// not implemented
return COMMONERR_FAILED;
}
commonErr_t CMB_writeToLog(ADI_LOGLEVEL level, uint8_t deviceIndex, uint32_t errorCode, const char *comment)
{
// TODO: send to logging API
// TODO: filter log messages based on level
std::cout << "[CMB_writeToLog] level==" << level << " errorCode==" << errorCode << " " << comment;
return COMMONERR_OK;
}
commonErr_t CMB_flushLog(void)
{
// not implemented
return COMMONERR_FAILED;
}
/* platform FPGA AXI register read/write functions */
commonErr_t CMB_regRead(uint32_t offset, uint32_t *data)
{
// not implemented
return COMMONERR_FAILED;
}
commonErr_t CMB_regWrite(uint32_t offset, uint32_t data)
{
// not implemented
return COMMONERR_FAILED;
}
/* platform DDR3 memory read/write functions */
commonErr_t CMB_memRead(uint32_t offset, uint32_t *data, uint32_t len)
{
// not implemented
return COMMONERR_FAILED;
}
commonErr_t CMB_memWrite(uint32_t offset, uint32_t *data, uint32_t len)
{
// not implemented
return COMMONERR_FAILED;
}