F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
Loading...
Searching...
No Matches
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
30namespace 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;
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 log_WARNING_HI_SPI_ConfigError(I32 device, I32 select, I32 error) const
void log_WARNING_HI_SPI_OpenError(I32 device, I32 select, I32 error) const
void tlmWrite_SPI_Bytes(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
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)