F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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:55
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:30
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)