F´ Flight Software - C/C++ Documentation  devel
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>
16 
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 //#define DEBUG_PRINT(...) printf(##__VA_ARGS__); fflush(stdout)
28 #define DEBUG_PRINT(...)
29 
30 namespace Drv {
31 
32  // ----------------------------------------------------------------------
33  // Handler implementations for user-defined typed input ports
34  // ----------------------------------------------------------------------
35 
36  void LinuxSpiDriverComponentImpl::SpiReadWrite_handler(
37  const NATIVE_INT_TYPE portNum, Fw::Buffer &writeBuffer,
38  Fw::Buffer &readBuffer) {
39 
40  if (this->m_fd == -1) {
41  return;
42  }
43 
44  DEBUG_PRINT("Writing %d bytes to SPI\n",writeBuffer.getSize());
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  tr.len = writeBuffer.getSize();
52 /*
53  .speed_hz = 0,
54  .delay_usecs = 0,
55  .bits_per_word = 0,
56  .cs_change = 0,
57  .tx_nbits = 0, // on more-recent kernel versions;
58  .rx_nbits = 0, // on more-recent kernel versions;
59  .pad = 0
60 */
61 
62  NATIVE_INT_TYPE stat = ioctl(this->m_fd, SPI_IOC_MESSAGE(1), &tr);
63 
64  if (stat < 1) {
65  this->log_WARNING_HI_SPI_WriteError(this->m_device,this->m_select,stat);
66  }
67  this->m_bytes += readBuffer.getSize();
68  this->tlmWrite_SPI_Bytes(this->m_bytes);
69  }
70 
72  NATIVE_INT_TYPE select,
73  SpiFrequency clock,
74  SpiMode spiMode) {
75 
76  this->m_device = device;
77  this->m_select = select;
78  NATIVE_INT_TYPE fd;
79  NATIVE_INT_TYPE ret;
80 
81  // Open:
82  char devName[256];
83  snprintf(devName,sizeof(devName),"/dev/spidev%d.%d",device,select);
84  // null terminate
85  devName[sizeof(devName)-1] = 0;
86  DEBUG_PRINT("Opening SPI device %s\n",devName);
87 
88  fd = ::open(devName, O_RDWR);
89  if (fd == -1) {
90  DEBUG_PRINT("open SPI device %d.%d failed. %d\n",device,select,errno);
91  this->log_WARNING_HI_SPI_OpenError(device,select,fd);
92  return false;
93  } else {
94  DEBUG_PRINT("Successfully opened SPI device %s fd %d\n",devName,fd);
95  }
96 
97  this->m_fd = fd;
98 
99  // Configure:
100  /*
101  * SPI Mode 0, 1, 2, 3
102  */
103 
104  U8 mode; // Mode Select (CPOL = 0/1, CPHA = 0/1)
105  switch(spiMode) {
107  mode = SPI_MODE_0;
108  break;
110  mode = SPI_MODE_1;
111  break;
113  mode = SPI_MODE_2;
114  break;
116  mode = SPI_MODE_3;
117  break;
118  default:
119  //Assert if the device SPI Mode is not in the correct range
120  FW_ASSERT(0, spiMode);
121  break;
122  }
123 
124  ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
125  if (ret == -1) {
126  DEBUG_PRINT("ioctl SPI_IOC_WR_MODE fd %d failed. %d\n",fd,errno);
127  this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
128  return false;
129  } else {
130  DEBUG_PRINT("SPI fd %d WR mode successfully configured to %d\n",fd,mode);
131  }
132 
133  ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
134  if (ret == -1) {
135  DEBUG_PRINT("ioctl SPI_IOC_RD_MODE fd %d failed. %d\n",fd,errno);
136  this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
137  return false;
138  } else {
139  DEBUG_PRINT("SPI fd %d RD mode successfully configured to %d\n",fd,mode);
140  }
141 
142  /*
143  * 8 bits per word
144  */
145  U8 bits = 8;
146  ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
147  if (ret == -1) {
148  DEBUG_PRINT("ioctl SPI_IOC_WR_BITS_PER_WORD fd %d failed. %d\n",fd,errno);
149  this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
150  return false;
151  } else {
152  DEBUG_PRINT("SPI fd %d WR bits per word successfully configured to %d\n",fd,bits);
153  }
154 
155  ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
156  if (ret == -1) {
157  DEBUG_PRINT("ioctl SPI_IOC_RD_BITS_PER_WORD fd %d failed. %d\n",fd,errno);
158  this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
159  return false;
160  } else {
161  DEBUG_PRINT("SPI fd %d RD bits per word successfully configured to %d\n",fd,bits);
162  }
163 
164  /*
165  * Max speed in Hz
166  */
167  ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &clock);
168  if (ret == -1) {
169  DEBUG_PRINT("ioctl SPI_IOC_WR_MAX_SPEED_HZ fd %d failed. %d\n",fd,errno);
170  this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
171  return false;
172  } else {
173  DEBUG_PRINT("SPI fd %d WR freq successfully configured to %d\n",fd,clock);
174  }
175 
176  ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &clock);
177  if (ret == -1) {
178  DEBUG_PRINT("ioctl SPI_IOC_RD_MAX_SPEED_HZ fd %d failed. %d\n",fd,errno);
179  this->log_WARNING_HI_SPI_ConfigError(device,select,ret);
180  return false;
181  } else {
182  DEBUG_PRINT("SPI fd %d RD freq successfully configured to %d\n",fd,clock);
183  }
184 
185  return true;
186 
187  }
188 
190  DEBUG_PRINT("Closing SPI device %d\n",this->m_fd);
191  (void) close(this->m_fd);
192  }
193 
194 } // end namespace Drv
#define FW_ASSERT(...)
Definition: Assert.hpp:14
PlatformIntType NATIVE_INT_TYPE
Definition: BasicTypes.h:51
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:26
C++-compatible configuration header for fprime configuration.
#define DEBUG_PRINT(...)
void log_WARNING_HI_SPI_WriteError(I32 device, I32 select, I32 error)
void tlmWrite_SPI_Bytes(U32 arg, Fw::Time _tlmTime=Fw::Time())
void log_WARNING_HI_SPI_ConfigError(I32 device, I32 select, I32 error)
void log_WARNING_HI_SPI_OpenError(I32 device, I32 select, I32 error)
bool open(NATIVE_INT_TYPE device, NATIVE_INT_TYPE select, SpiFrequency clock, SpiMode spiMode=SpiMode::SPI_MODE_CPOL_LOW_CPHA_LOW)
Open device.
U8 * getData() const
Definition: Buffer.cpp:68
U32 getSize() const
Definition: Buffer.cpp:72
@ SPI_MODE_CPOL_HIGH_CPHA_LOW
(CPOL = 1, CPHA = 0)
@ SPI_MODE_CPOL_LOW_CPHA_HIGH
(CPOL = 0, CPHA = 1)
@ SPI_MODE_CPOL_HIGH_CPHA_HIGH
(CPOL = 1, CPHA = 1)
@ SPI_MODE_CPOL_LOW_CPHA_LOW
(CPOL = 0, CPHA = 0)