mirror of
https://github.com/nasa/fprime.git
synced 2025-12-10 00:44:37 -06:00
183 lines
6.2 KiB
C++
183 lines
6.2 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. Any commercial use must be negotiated with the Office
|
|
// of Technology Transfer at the California Institute of Technology.
|
|
//
|
|
// This software may be subject to U.S. export control laws and
|
|
// regulations. By accepting this document, the user agrees to comply
|
|
// with all U.S. export laws and regulations. User has the
|
|
// responsibility to obtain export licenses, or other export authority
|
|
// as may be required before exporting such information to foreign
|
|
// countries or providing access to foreign persons.
|
|
// ======================================================================
|
|
|
|
#include <Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.hpp>
|
|
#include "Fw/Types/BasicTypes.hpp"
|
|
#include <Fw/Types/Assert.hpp>
|
|
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <linux/types.h>
|
|
#include <linux/spi/spidev.h>
|
|
#include <errno.h>
|
|
|
|
//#define DEBUG_PRINT(x,...) printf(x,##__VA_ARGS__); fflush(stdout)
|
|
#define DEBUG_PRINT(x,...)
|
|
|
|
namespace Drv {
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Handler implementations for user-defined typed input ports
|
|
// ----------------------------------------------------------------------
|
|
|
|
void LinuxSpiDriverComponentImpl::SpiReadWrite_handler(
|
|
const NATIVE_INT_TYPE portNum, Fw::Buffer &writeBuffer,
|
|
Fw::Buffer &readBuffer) {
|
|
|
|
if (this->m_fd == -1) {
|
|
return;
|
|
}
|
|
|
|
DEBUG_PRINT("Writing %d bytes to SPI\n",writeBuffer.getsize());
|
|
|
|
spi_ioc_transfer tr;
|
|
// Zero for unused fields:
|
|
memset(&tr, 0, sizeof(tr));
|
|
tr.tx_buf = writeBuffer.getdata();
|
|
tr.rx_buf = 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
|
|
*/
|
|
|
|
NATIVE_INT_TYPE 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);
|
|
return;
|
|
|
|
}
|
|
|
|
bool LinuxSpiDriverComponentImpl::open(NATIVE_INT_TYPE device,
|
|
NATIVE_INT_TYPE select,
|
|
SpiFrequency clock) {
|
|
|
|
this->m_device = device;
|
|
this->m_select = select;
|
|
NATIVE_INT_TYPE fd;
|
|
NATIVE_INT_TYPE ret;
|
|
|
|
// Open:
|
|
char devName[256];
|
|
snprintf(devName,sizeof(devName),"/dev/spidev%d.%d",device,select);
|
|
// null terminate
|
|
devName[sizeof(devName)-1] = 0;
|
|
DEBUG_PRINT("Opening SPI device %s\n",devName);
|
|
|
|
fd = ::open(devName, O_RDWR);
|
|
if (fd == -1) {
|
|
DEBUG_PRINT("open SPI device %d.%d failed. %d\n",device,select,errno);
|
|
this->log_WARNING_HI_SPI_OpenError(device,select,fd);
|
|
return false;
|
|
} else {
|
|
DEBUG_PRINT("Successfully opened SPI device %s fd %d\n",devName,fd);
|
|
}
|
|
|
|
this->m_fd = fd;
|
|
|
|
// Configure:
|
|
/*
|
|
* SPI Mode 0
|
|
*/
|
|
U8 mode = SPI_MODE_0; // Mode 0 (CPOL = 0, CPHA = 0)
|
|
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
|
|
if (ret == -1) {
|
|
DEBUG_PRINT("ioctl SPI_IOC_WR_MODE fd %d failed. %d\n",fd,errno);
|
|
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
|
|
return false;
|
|
} else {
|
|
DEBUG_PRINT("SPI fd %d WR mode successfully configured to %d\n",fd,mode);
|
|
}
|
|
|
|
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
|
|
if (ret == -1) {
|
|
DEBUG_PRINT("ioctl SPI_IOC_RD_MODE fd %d failed. %d\n",fd,errno);
|
|
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
|
|
return false;
|
|
} else {
|
|
DEBUG_PRINT("SPI fd %d RD mode successfully configured to %d\n",fd,mode);
|
|
}
|
|
|
|
/*
|
|
* 8 bits per word
|
|
*/
|
|
U8 bits = 8;
|
|
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
|
|
if (ret == -1) {
|
|
DEBUG_PRINT("ioctl SPI_IOC_WR_BITS_PER_WORD fd %d failed. %d\n",fd,errno);
|
|
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
|
|
return false;
|
|
} else {
|
|
DEBUG_PRINT("SPI fd %d WR bits per word successfully configured to %d\n",fd,bits);
|
|
}
|
|
|
|
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
|
|
if (ret == -1) {
|
|
DEBUG_PRINT("ioctl SPI_IOC_RD_BITS_PER_WORD fd %d failed. %d\n",fd,errno);
|
|
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
|
|
return false;
|
|
} else {
|
|
DEBUG_PRINT("SPI fd %d RD bits per word successfully configured to %d\n",fd,bits);
|
|
}
|
|
|
|
/*
|
|
* Max speed in Hz
|
|
*/
|
|
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &clock);
|
|
if (ret == -1) {
|
|
DEBUG_PRINT("ioctl SPI_IOC_WR_MAX_SPEED_HZ fd %d failed. %d\n",fd,errno);
|
|
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
|
|
return false;
|
|
} else {
|
|
DEBUG_PRINT("SPI fd %d WR freq successfully configured to %d\n",fd,clock);
|
|
}
|
|
|
|
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &clock);
|
|
if (ret == -1) {
|
|
DEBUG_PRINT("ioctl SPI_IOC_RD_MAX_SPEED_HZ fd %d failed. %d\n",fd,errno);
|
|
this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
|
|
return false;
|
|
} else {
|
|
DEBUG_PRINT("SPI fd %d RD freq successfully configured to %d\n",fd,clock);
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
LinuxSpiDriverComponentImpl::~LinuxSpiDriverComponentImpl(void) {
|
|
DEBUG_PRINT("Closing SPI device %d\n",this->m_fd);
|
|
(void) close(this->m_fd);
|
|
}
|
|
|
|
} // end namespace Drv
|