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