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 <cerrno>
23 #include <cstdint>
24 #include <cstdio>
25 #include <cstdlib>
26 
28  "Cannot use SPI driver without full string formatting");
29 
30 namespace Drv {
31 
32 // ----------------------------------------------------------------------
33 // Handler implementations for user-defined typed input ports
34 // ----------------------------------------------------------------------
35 
36 void LinuxSpiDriverComponentImpl::SpiReadWrite_handler(const FwIndexType portNum,
37  Fw::Buffer& writeBuffer,
38  Fw::Buffer& readBuffer) {
39  if (this->m_fd == -1) {
40  return;
41  }
42 
43  spi_ioc_transfer tr;
44  // Zero for unused fields:
45  memset(&tr, 0, sizeof(tr));
46  tr.tx_buf = reinterpret_cast<__u64>(writeBuffer.getData());
47  tr.rx_buf = reinterpret_cast<__u64>(readBuffer.getData());
48  FW_ASSERT_NO_OVERFLOW(writeBuffer.getSize(), __u32);
49  tr.len = static_cast<__u32>(writeBuffer.getSize());
50  /*
51  .speed_hz = 0,
52  .delay_usecs = 0,
53  .bits_per_word = 0,
54  .cs_change = 0,
55  .tx_nbits = 0, // on more-recent kernel versions;
56  .rx_nbits = 0, // on more-recent kernel versions;
57  .pad = 0
58  */
59 
60  int stat = ioctl(this->m_fd, SPI_IOC_MESSAGE(1), &tr);
61 
62  if (stat < 1) {
63  this->log_WARNING_HI_SPI_WriteError(this->m_device, this->m_select, stat);
64  }
65  this->m_bytes += readBuffer.getSize();
66  this->tlmWrite_SPI_Bytes(this->m_bytes);
67 }
68 
70  FW_ASSERT(device >= 0, static_cast<FwAssertArgType>(device));
71  FW_ASSERT(select >= 0, static_cast<FwAssertArgType>(select));
72 
73  this->m_device = device;
74  this->m_select = select;
75  int fd;
76  int ret;
77 
78  // Open:
79  Fw::FileNameString devString;
80  Fw::FormatStatus formatStatus =
81  devString.format("/dev/spidev%" PRI_FwIndexType ".%" PRI_FwIndexType, device, select);
82  FW_ASSERT(formatStatus == Fw::FormatStatus::SUCCESS);
83 
84  fd = ::open(devString.toChar(), O_RDWR);
85  if (fd == -1) {
86  this->log_WARNING_HI_SPI_OpenError(device, select, fd);
87  return false;
88  }
89 
90  this->m_fd = fd;
91 
92  // Configure:
93  /*
94  * SPI Mode 0, 1, 2, 3
95  */
96 
97  U8 mode; // Mode Select (CPOL = 0/1, CPHA = 0/1)
98  switch (spiMode) {
100  mode = SPI_MODE_0;
101  break;
103  mode = SPI_MODE_1;
104  break;
106  mode = SPI_MODE_2;
107  break;
109  mode = SPI_MODE_3;
110  break;
111  default:
112  // Assert if the device SPI Mode is not in the correct range
113  FW_ASSERT(0, spiMode);
114  break;
115  }
116 
117  ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
118  if (ret == -1) {
119  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
120  return false;
121  }
122 
123  ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
124  if (ret == -1) {
125  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
126  return false;
127  }
128 
129  /*
130  * 8 bits per word
131  */
132  U8 bits = 8;
133  ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
134  if (ret == -1) {
135  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
136  return false;
137  }
138 
139  ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
140  if (ret == -1) {
141  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
142  return false;
143  }
144 
145  /*
146  * Max speed in Hz
147  */
148  ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &clock);
149  if (ret == -1) {
150  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
151  return false;
152  }
153 
154  ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &clock);
155  if (ret == -1) {
156  this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
157  return false;
158  }
159 
160  return true;
161 }
162 
164  (void)close(this->m_fd);
165 }
166 
167 } // 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
#define FW_USE_PRINTF_FAMILY_FUNCTIONS_IN_STRING_FORMATTING
Definition: FpConfig.h:80
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