// // Copyright 2017 Ettus Research, a National Instruments Company // // SPDX-License-Identifier: GPL-3.0-or-later // #include "adi/common.h" #include #include #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) { mpm::types::log_level_t mpm_log_level; if (level & ADIHAL_LOG_ERROR) { mpm_log_level = mpm::types::log_level_t::ERROR; } else if (level & ADIHAL_LOG_WARNING) { mpm_log_level = mpm::types::log_level_t::WARNING; } else { mpm_log_level = mpm::types::log_level_t::TRACE; } // FIXME: This caused segfault with the async pattern call to c++ from boost python // mpm::types::log_buf::make_singleton()->post( // mpm_log_level, // "AD937X", // str(boost::format("[Device ID %d] [Error code: %d] %s") // % int(deviceIndex) % 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; }