F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
LinuxSpiDriverComponentImpl.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title LinuxSpiDriverImpl.cpp
3 // \author tcanham
4 // \brief cpp file for LinuxSpiDriver component implementation class
5 //
6 // \copyright
7 // Copyright 2009-2015, by the California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 //
11 // ======================================================================
12 
13 #include <fcntl.h>
14 #include <linux/spi/spidev.h>
15 #include <linux/types.h>
16 #include <sys/ioctl.h>
17 #include <unistd.h>
19 #include <Fw/FPrimeBasicTypes.hpp>
20 #include <Fw/Types/Assert.hpp>
22 #include <Fw/Types/String.hpp>
23 #include <cerrno>
24 #include <cstdint>
25 #include <cstdio>
26 #include <cstdlib>
27 
29  "Cannot use SPI driver without full string formatting");
30 
31 namespace Drv {
32 
33 // ----------------------------------------------------------------------
34 // Handler implementations for user-defined typed input ports
35 // ----------------------------------------------------------------------
36 
37 void LinuxSpiDriverComponentImpl::SpiReadWrite_handler(const FwIndexType portNum,
38  Fw::Buffer& writeBuffer,
39  Fw::Buffer& readBuffer) {
40  FW_ASSERT(writeBuffer.getSize() == readBuffer.getSize());
41 
42  if (this->m_fd == -1) {
43  return;
44  }
45 
46  spi_ioc_transfer tr;
47  // Zero for unused fields:
48  memset(&tr, 0, sizeof(tr));
49  tr.tx_buf = reinterpret_cast<__u64>(writeBuffer.getData());
50  tr.rx_buf = reinterpret_cast<__u64>(readBuffer.getData());
51  FW_ASSERT_NO_OVERFLOW(writeBuffer.getSize(), __u32);
52  tr.len = static_cast<__u32>(writeBuffer.getSize());
53  /*
54  .speed_hz = 0,
55  .delay_usecs = 0,
56  .bits_per_word = 0,
57  .cs_change = 0,
58  .tx_nbits = 0, // on more-recent kernel versions;
59  .rx_nbits = 0, // on more-recent kernel versions;
60  .pad = 0
61  */
62 
63  int stat = ioctl(this->m_fd, SPI_IOC_MESSAGE(1), &tr);
64 
65  if (stat < 1) {
66  this->log_WARNING_HI_SPI_WriteError(this->m_device, this->m_select, stat);
67  }
68  this->m_bytes += readBuffer.getSize();
69  this->tlmWrite_SPI_Bytes(this->m_bytes);
70 }
71 
73  FW_ASSERT(device >= 0, static_cast<FwAssertArgType>(device));
74  FW_ASSERT(select >= 0, static_cast<FwAssertArgType>(select));
75 
76  this->m_device = device;
77  this->m_select = select;
78  int fd;
79  int ret;
80 
81  // Open:
82  Fw::FileNameString devString;
83  Fw::FormatStatus formatStatus =
84  devString.format("/dev/spidev%" PRI_FwIndexType ".%" PRI_FwIndexType, device, select);
85  FW_ASSERT(formatStatus == Fw::FormatStatus::SUCCESS);
86 
87  fd = ::open(devString.toChar(), O_RDWR);
88  if (fd == -1) {
89  this->log_WARNING_HI_SPI_OpenError(device, select, fd);
90  return false;
91  }
92 
93  this->m_fd = fd;
94 
95  // Configure:
96  /*
97  * SPI Mode 0, 1, 2, 3
98  */
99 
100  U8 mode; // Mode Select (CPOL = 0/1, CPHA = 0/1)
101  switch (spiMode) {
103  mode = SPI_MODE_0;
104  break;
106  mode = SPI_MODE_1;
107  break;
109  mode = SPI_MODE_2;
110  break;
112  mode = SPI_MODE_3;
113  break;
114  default:
115  // Assert if the device SPI Mode is not in the correct range
116  FW_ASSERT(0, spiMode);
117  break;
118  }
119 
120  ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
121  if (ret == -1) {
122  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
123  return false;
124  }
125 
126  U8 read_mode = 0;
127  ret = ioctl(fd, SPI_IOC_RD_MODE, &read_mode);
128  if (ret == -1) {
129  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
130  return false;
131  }
132 
133  if (mode != read_mode) {
134  this->log_WARNING_LO_SPI_ConfigMismatch(device, select, Fw::String("MODE"), mode, read_mode);
135  }
136 
137  /*
138  * 8 bits per word
139  */
140  U8 bits = 8;
141  ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
142  if (ret == -1) {
143  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
144  return false;
145  }
146 
147  U8 read_bits = 0;
148  ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &read_bits);
149  if (ret == -1) {
150  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
151  return false;
152  }
153 
154  if (bits != read_bits) {
155  this->log_WARNING_LO_SPI_ConfigMismatch(device, select, Fw::String("BITS_PER_WORD"), bits, read_bits);
156  }
157 
158  /*
159  * Max speed in Hz
160  */
161  ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &clock);
162  if (ret == -1) {
163  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
164  return false;
165  }
166 
167  SpiFrequency read_clock;
168  ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &read_clock);
169  if (ret == -1) {
170  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
171  return false;
172  }
173 
174  if (clock != read_clock) {
175  this->log_WARNING_LO_SPI_ConfigMismatch(device, select, Fw::String("MAX_SPEED_HZ"), clock, read_clock);
176  }
177 
178  return true;
179 }
180 
182  (void)close(this->m_fd);
183 }
184 
185 } // end namespace Drv
bool open(FwIndexType device, FwIndexType select, SpiFrequency clock, SpiMode spiMode=SpiMode::SPI_MODE_CPOL_LOW_CPHA_LOW)
Open device.
void log_WARNING_HI_SPI_ConfigError(I32 device, I32 select, I32 error) const
void log_WARNING_HI_SPI_WriteError(I32 device, I32 select, I32 error)
U8 * getData() const
Definition: Buffer.cpp:56
void log_WARNING_LO_SPI_ConfigMismatch(I32 device, I32 select, const Fw::StringBase &parameter, U32 write_value, U32 read_value) const
#define FW_USE_PRINTF_FAMILY_FUNCTIONS_IN_STRING_FORMATTING
Definition: FpConfig.h:79
void tlmWrite_SPI_Bytes(FwSizeType arg, Fw::Time _tlmTime=Fw::Time()) const
const char * toChar() const
#define PRI_FwIndexType
FormatStatus format(const CHAR *formatString,...)
write formatted string to buffer
Definition: StringBase.cpp:55
void log_WARNING_HI_SPI_OpenError(I32 device, I32 select, I32 error) const
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:53
FwSizeType getSize() const
Definition: Buffer.cpp:60
PlatformIndexType FwIndexType
#define FW_ASSERT_NO_OVERFLOW(value, T)
Definition: Assert.hpp:49
#define FW_ASSERT(...)
Definition: Assert.hpp:14
FormatStatus
status of string format calls
Definition: format.hpp:18