fprime/Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.cpp
M Starch 0659f0940b
Refactored type organization (#3422)
* Refactored type organization

* Creating better configuration/types header hierarchy

* Replace FpConfig type aliases with FPP generated aliases

* Add the aliases to the FPP model

* Config + Type Aliases builds

* Renamed Fw/Types.h,hpp to Fw/FPrimeBasicTypes.h,hpp

* Updating to FPP-a7

* Adding newline

* sp

* Fixing minor nit from review

* Spurious ;

---------

Co-authored-by: Andrei Tumbar <andrei.tumbar@jpl.nasa.gov>
2025-04-03 12:11:36 -07:00

170 lines
5.3 KiB
C++

// ======================================================================
// \title LinuxSpiDriverImpl.cpp
// \author tcanham
// \brief cpp file for LinuxSpiDriver component implementation class
//
// \copyright
// Copyright 2009-2015, by the California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship
// acknowledged.
//
// ======================================================================
#include <Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.hpp>
#include <Fw/FPrimeBasicTypes.hpp>
#include <Fw/Types/Assert.hpp>
#include <Fw/Types/FileNameString.hpp>
#include <cstdint>
#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <cerrno>
static_assert(FW_USE_PRINTF_FAMILY_FUNCTIONS_IN_STRING_FORMATTING, "Cannot use SPI driver without full string formatting");
namespace Drv {
// ----------------------------------------------------------------------
// Handler implementations for user-defined typed input ports
// ----------------------------------------------------------------------
void LinuxSpiDriverComponentImpl::SpiReadWrite_handler(
const FwIndexType portNum, Fw::Buffer &writeBuffer,
Fw::Buffer &readBuffer) {
if (this->m_fd == -1) {
return;
}
spi_ioc_transfer tr;
// Zero for unused fields:
memset(&tr, 0, sizeof(tr));
tr.tx_buf = reinterpret_cast<__u64>(writeBuffer.getData());
tr.rx_buf = reinterpret_cast<__u64>(readBuffer.getData());
tr.len = writeBuffer.getSize();
/*
.speed_hz = 0,
.delay_usecs = 0,
.bits_per_word = 0,
.cs_change = 0,
.tx_nbits = 0, // on more-recent kernel versions;
.rx_nbits = 0, // on more-recent kernel versions;
.pad = 0
*/
PlatformIntType stat = ioctl(this->m_fd, SPI_IOC_MESSAGE(1), &tr);
if (stat < 1) {
this->log_WARNING_HI_SPI_WriteError(this->m_device,this->m_select,stat);
}
this->m_bytes += readBuffer.getSize();
this->tlmWrite_SPI_Bytes(this->m_bytes);
}
bool LinuxSpiDriverComponentImpl::open(FwIndexType device,
FwIndexType select,
SpiFrequency clock,
SpiMode spiMode) {
FW_ASSERT(device >= 0, static_cast<FwAssertArgType>(device));
FW_ASSERT(select >= 0, static_cast<FwAssertArgType>(select));
this->m_device = device;
this->m_select = select;
PlatformIntType fd;
PlatformIntType ret;
// Open:
Fw::FileNameString devString;
Fw::FormatStatus formatStatus = devString.format("/dev/spidev%" PRI_FwIndexType ".%" PRI_FwIndexType, device, select);
FW_ASSERT(formatStatus == Fw::FormatStatus::SUCCESS);
fd = ::open(devString.toChar(), O_RDWR);
if (fd == -1) {
this->log_WARNING_HI_SPI_OpenError(device,select,fd);
return false;
}
this->m_fd = fd;
// Configure:
/*
* SPI Mode 0, 1, 2, 3
*/
U8 mode; // Mode Select (CPOL = 0/1, CPHA = 0/1)
switch(spiMode) {
case SpiMode::SPI_MODE_CPOL_LOW_CPHA_LOW:
mode = SPI_MODE_0;
break;
case SpiMode::SPI_MODE_CPOL_LOW_CPHA_HIGH:
mode = SPI_MODE_1;
break;
case SpiMode::SPI_MODE_CPOL_HIGH_CPHA_LOW:
mode = SPI_MODE_2;
break;
case SpiMode::SPI_MODE_CPOL_HIGH_CPHA_HIGH:
mode = SPI_MODE_3;
break;
default:
//Assert if the device SPI Mode is not in the correct range
FW_ASSERT(0, spiMode);
break;
}
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
return false;
}
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
return false;
}
/*
* 8 bits per word
*/
U8 bits = 8;
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
return false;
}
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
return false;
}
/*
* Max speed in Hz
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &clock);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
return false;
}
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &clock);
if (ret == -1) {
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
return false;
}
return true;
}
LinuxSpiDriverComponentImpl::~LinuxSpiDriverComponentImpl() {
(void) close(this->m_fd);
}
} // end namespace Drv