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 <FpConfig.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 NATIVE_INT_TYPE 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  NATIVE_INT_TYPE 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  NATIVE_INT_TYPE select,
70  SpiFrequency clock,
71  SpiMode spiMode) {
72 
73  this->m_device = device;
74  this->m_select = select;
75  NATIVE_INT_TYPE fd;
76  NATIVE_INT_TYPE ret;
77 
78  // Open:
79  Fw::FileNameString devString;
80  Fw::FormatStatus formatStatus = devString.format("/dev/spidev%d.%d", device, select);
81  FW_ASSERT(formatStatus == Fw::FormatStatus::SUCCESS);
82 
83  fd = ::open(devString.toChar(), O_RDWR);
84  if (fd == -1) {
85  this->log_WARNING_HI_SPI_OpenError(device,select,fd);
86  return false;
87  }
88 
89  this->m_fd = fd;
90 
91  // Configure:
92  /*
93  * SPI Mode 0, 1, 2, 3
94  */
95 
96  U8 mode; // Mode Select (CPOL = 0/1, CPHA = 0/1)
97  switch(spiMode) {
99  mode = SPI_MODE_0;
100  break;
102  mode = SPI_MODE_1;
103  break;
105  mode = SPI_MODE_2;
106  break;
108  mode = SPI_MODE_3;
109  break;
110  default:
111  //Assert if the device SPI Mode is not in the correct range
112  FW_ASSERT(0, spiMode);
113  break;
114  }
115 
116  ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
117  if (ret == -1) {
118  this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
119  return false;
120  }
121 
122  ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
123  if (ret == -1) {
124  this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
125  return false;
126  }
127 
128  /*
129  * 8 bits per word
130  */
131  U8 bits = 8;
132  ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
133  if (ret == -1) {
134  this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
135  return false;
136  }
137 
138  ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
139  if (ret == -1) {
140  this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
141  return false;
142  }
143 
144  /*
145  * Max speed in Hz
146  */
147  ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &clock);
148  if (ret == -1) {
149  this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
150  return false;
151  }
152 
153  ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &clock);
154  if (ret == -1) {
155  this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
156  return false;
157  }
158 
159  return true;
160 
161  }
162 
164  (void) close(this->m_fd);
165  }
166 
167 } // end namespace Drv
void log_WARNING_HI_SPI_ConfigError(I32 device, I32 select, I32 error) const
PlatformIntType NATIVE_INT_TYPE
Definition: BasicTypes.h:55
void log_WARNING_HI_SPI_WriteError(I32 device, I32 select, I32 error)
U8 * getData() const
Definition: Buffer.cpp:68
U32 getSize() const
Definition: Buffer.cpp:72
void tlmWrite_SPI_Bytes(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
const char * toChar() const
#define FW_USE_PRINTF_FAMILY_FUNCTIONS_IN_STRING_FORMATTING
Definition: FpConfig.h:192
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
C++-compatible configuration header for fprime configuration.
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:30
bool open(NATIVE_INT_TYPE device, NATIVE_INT_TYPE select, SpiFrequency clock, SpiMode spiMode=SpiMode::SPI_MODE_CPOL_LOW_CPHA_LOW)
Open device.
#define FW_ASSERT(...)
Definition: Assert.hpp:14
FormatStatus
status of string format calls
Definition: format.hpp:18