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 #include <cstring>
28 
30  "Cannot use SPI driver without full string formatting");
31 
32 namespace Drv {
33 
34 // ----------------------------------------------------------------------
35 // Handler implementations for user-defined typed input ports
36 // ----------------------------------------------------------------------
37 
38 // @ DEPRECATED: Use SpiWriteRead port instead (same operation with a return value)
39 void LinuxSpiDriverComponentImpl::SpiReadWrite_handler(const FwIndexType portNum,
40  Fw::Buffer& writeBuffer,
41  Fw::Buffer& readBuffer) {
42  FW_ASSERT(portNum >= 0, static_cast<FwAssertArgType>(portNum));
43  FW_ASSERT(writeBuffer.isValid());
44  FW_ASSERT(readBuffer.isValid());
45  (void)SpiWriteRead_handler(portNum, writeBuffer, readBuffer);
46 }
47 
48 SpiStatus LinuxSpiDriverComponentImpl::SpiWriteRead_handler(const FwIndexType portNum,
49  Fw::Buffer& writeBuffer,
50  Fw::Buffer& readBuffer) {
51  FW_ASSERT(portNum >= 0, static_cast<FwAssertArgType>(portNum));
52  FW_ASSERT(writeBuffer.isValid());
53  FW_ASSERT(readBuffer.isValid());
54  FW_ASSERT(writeBuffer.getSize() == readBuffer.getSize());
55 
56  if (this->m_fd == -1) {
58  }
59 
60  spi_ioc_transfer tr;
61  // Zero for unused fields:
62  memset(&tr, 0, sizeof(tr));
63  tr.tx_buf = reinterpret_cast<__u64>(writeBuffer.getData());
64  tr.rx_buf = reinterpret_cast<__u64>(readBuffer.getData());
65  FW_ASSERT_NO_OVERFLOW(writeBuffer.getSize(), __u32);
66  tr.len = static_cast<__u32>(writeBuffer.getSize());
67  /*
68  .speed_hz = 0,
69  .delay_usecs = 0,
70  .bits_per_word = 0,
71  .cs_change = 0,
72  .tx_nbits = 0, // on more-recent kernel versions;
73  .rx_nbits = 0, // on more-recent kernel versions;
74  .pad = 0
75  */
76 
77  int stat = ioctl(this->m_fd, SPI_IOC_MESSAGE(1), &tr);
78 
79  if (stat < 1) {
80  this->log_WARNING_HI_SPI_WriteError(this->m_device, this->m_select, stat);
82  }
83  this->m_bytes += readBuffer.getSize();
84  this->tlmWrite_SPI_Bytes(this->m_bytes);
85 
86  return SpiStatus::SPI_OK;
87 }
88 
90  FW_ASSERT(device >= 0, static_cast<FwAssertArgType>(device));
91  FW_ASSERT(select >= 0, static_cast<FwAssertArgType>(select));
92 
93  this->m_device = device;
94  this->m_select = select;
95  int fd;
96  int ret;
97 
98  // Open:
99  Fw::FileNameString devString;
100  Fw::FormatStatus formatStatus =
101  devString.format("/dev/spidev%" PRI_FwIndexType ".%" PRI_FwIndexType, device, select);
102  FW_ASSERT(formatStatus == Fw::FormatStatus::SUCCESS);
103 
104  fd = ::open(devString.toChar(), O_RDWR);
105  if (fd == -1) {
106  this->log_WARNING_HI_SPI_OpenError(device, select, fd);
107  return false;
108  }
109 
110  this->m_fd = fd;
111 
112  // Configure:
113  /*
114  * SPI Mode 0, 1, 2, 3
115  */
116 
117  U8 mode; // Mode Select (CPOL = 0/1, CPHA = 0/1)
118  switch (spiMode) {
120  mode = SPI_MODE_0;
121  break;
123  mode = SPI_MODE_1;
124  break;
126  mode = SPI_MODE_2;
127  break;
129  mode = SPI_MODE_3;
130  break;
131  default:
132  // Assert if the device SPI Mode is not in the correct range
133  FW_ASSERT(0, spiMode);
134  break;
135  }
136 
137  ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
138  if (ret == -1) {
139  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
140  return false;
141  }
142 
143  U8 read_mode = 0;
144  ret = ioctl(fd, SPI_IOC_RD_MODE, &read_mode);
145  if (ret == -1) {
146  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
147  return false;
148  }
149 
150  if (mode != read_mode) {
151  this->log_WARNING_LO_SPI_ConfigMismatch(device, select, Fw::String("MODE"), mode, read_mode);
152  }
153 
154  /*
155  * 8 bits per word
156  */
157  U8 bits = 8;
158  ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
159  if (ret == -1) {
160  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
161  return false;
162  }
163 
164  U8 read_bits = 0;
165  ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &read_bits);
166  if (ret == -1) {
167  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
168  return false;
169  }
170 
171  if (bits != read_bits) {
172  this->log_WARNING_LO_SPI_ConfigMismatch(device, select, Fw::String("BITS_PER_WORD"), bits, read_bits);
173  }
174 
175  /*
176  * Max speed in Hz
177  */
178  ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &clock);
179  if (ret == -1) {
180  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
181  return false;
182  }
183 
184  SpiFrequency read_clock;
185  ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &read_clock);
186  if (ret == -1) {
187  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
188  return false;
189  }
190 
191  if (clock != read_clock) {
192  this->log_WARNING_LO_SPI_ConfigMismatch(device, select, Fw::String("MAX_SPEED_HZ"), clock, read_clock);
193  }
194 
195  return true;
196 }
197 
199  (void)close(this->m_fd);
200 }
201 
202 } // 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:65
void tlmWrite_SPI_Bytes(FwSizeType arg, Fw::Time _tlmTime=Fw::Time()) const
Other errors that do not fit.
const char * toChar() const
Convert to a C-style char*.
bool isValid() const
Definition: Buffer.cpp:52
#define PRI_FwIndexType
FormatStatus format(const CHAR *formatString,...)
write formatted string to buffer
Definition: StringBase.cpp:39
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
SPI driver failed to open device.
Transaction okay.
#define FW_ASSERT(...)
Definition: Assert.hpp:14
FormatStatus
status of string format calls
Definition: format.hpp:18