GCC Code Coverage Report


Directory: ./
File: Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.cpp
Date: 2026-09-23 21:11:01
Exec Total Coverage
Lines: 0 101 0.0%
Functions: 0 4 0.0%
Branches: 0 79 0.0%

Line Branch Exec Source
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
13 #include <fcntl.h>
14 #include <linux/spi/spidev.h>
15 #include <linux/types.h>
16 #include <sys/ioctl.h>
17 #include <unistd.h>
18 #include <Drv/LinuxSpiDriver/LinuxSpiDriverComponentImpl.hpp>
19 #include <Fw/FPrimeBasicTypes.hpp>
20 #include <Fw/Types/Assert.hpp>
21 #include <Fw/Types/FileNameString.hpp>
22 #include <Fw/Types/String.hpp>
23 #include <cerrno>
24 #include <cstdint>
25 #include <cstdio>
26 #include <cstdlib>
27 #include <cstring>
28
29 namespace Drv {
30
31 // ----------------------------------------------------------------------
32 // Handler implementations for user-defined typed input ports
33 // ----------------------------------------------------------------------
34
35 // @ DEPRECATED: Use SpiWriteRead port instead (same operation with a return value)
36 ✗ void LinuxSpiDriverComponentImpl::SpiReadWrite_handler(const FwIndexType portNum,
37 Fw::Buffer& writeBuffer,
38 Fw::Buffer& readBuffer) {
39 ✗ FW_ASSERT(portNum >= 0, static_cast<FwAssertArgType>(portNum));
40 ✗ FW_ASSERT(writeBuffer.isValid());
41 ✗ FW_ASSERT(readBuffer.isValid());
42 ✗ (void)SpiWriteRead_handler(portNum, writeBuffer, readBuffer);
43 ✗ }
44
45 ✗ SpiStatus LinuxSpiDriverComponentImpl::SpiWriteRead_handler(const FwIndexType portNum,
46 Fw::Buffer& writeBuffer,
47 Fw::Buffer& readBuffer) {
48 ✗ FW_ASSERT(portNum >= 0, static_cast<FwAssertArgType>(portNum));
49 ✗ FW_ASSERT(writeBuffer.isValid());
50 ✗ FW_ASSERT(readBuffer.isValid());
51 ✗ FW_ASSERT(writeBuffer.getSize() == readBuffer.getSize());
52
53 ✗ if (this->m_fd == -1) {
54 ✗ return SpiStatus::SPI_OPEN_ERR;
55 }
56
57 ✗ spi_ioc_transfer tr;
58 // Zero for unused fields:
59 ✗ (void)memset(&tr, 0, sizeof(tr));
60 ✗ tr.tx_buf = reinterpret_cast<__u64>(writeBuffer.getData());
61 ✗ tr.rx_buf = reinterpret_cast<__u64>(readBuffer.getData());
62 ✗ FW_ASSERT_NO_OVERFLOW(writeBuffer.getSize(), __u32);
63 ✗ tr.len = static_cast<__u32>(writeBuffer.getSize());
64 /*
65 .speed_hz = 0,
66 .delay_usecs = 0,
67 .bits_per_word = 0,
68 .cs_change = 0,
69 .tx_nbits = 0, // on more-recent kernel versions;
70 .rx_nbits = 0, // on more-recent kernel versions;
71 .pad = 0
72 */
73
74 ✗ int stat = ioctl(this->m_fd, SPI_IOC_MESSAGE(1), &tr);
75
76 ✗ if (stat < 1) {
77 ✗ this->log_WARNING_HI_SPI_WriteError(this->m_device, this->m_select, stat);
78 ✗ return SpiStatus::SPI_OTHER_ERR;
79 }
80 ✗ this->m_bytes += readBuffer.getSize();
81 ✗ this->tlmWrite_SPI_Bytes(this->m_bytes);
82
83 ✗ return SpiStatus::SPI_OK;
84 }
85
86 ✗ bool LinuxSpiDriverComponentImpl::open(FwIndexType device, FwIndexType select, SpiFrequency clock, SpiMode spiMode) {
87 ✗ FW_ASSERT(device >= 0, static_cast<FwAssertArgType>(device));
88 ✗ FW_ASSERT(select >= 0, static_cast<FwAssertArgType>(select));
89
90 ✗ this->m_device = device;
91 ✗ this->m_select = select;
92 int fd;
93 int ret;
94
95 // Open:
96 ✗ Fw::FileNameString devString;
97 Fw::FormatStatus formatStatus =
98 ✗ devString.format("/dev/spidev%" PRI_FwIndexType ".%" PRI_FwIndexType, device, select);
99 ✗ FW_ASSERT(formatStatus == Fw::FormatStatus::SUCCESS);
100
101 ✗ fd = ::open(devString.toChar(), O_RDWR);
102 ✗ if (fd == -1) {
103 ✗ this->log_WARNING_HI_SPI_OpenError(device, select, fd);
104 ✗ return false;
105 }
106
107 // Configure:
108 /*
109 * SPI Mode 0, 1, 2, 3
110 */
111
112 ✗ U8 mode; // Mode Select (CPOL = 0/1, CPHA = 0/1)
113 ✗ switch (spiMode) {
114 ✗ case SpiMode::SPI_MODE_CPOL_LOW_CPHA_LOW:
115 ✗ mode = SPI_MODE_0;
116 ✗ break;
117 ✗ case SpiMode::SPI_MODE_CPOL_LOW_CPHA_HIGH:
118 ✗ mode = SPI_MODE_1;
119 ✗ break;
120 ✗ case SpiMode::SPI_MODE_CPOL_HIGH_CPHA_LOW:
121 ✗ mode = SPI_MODE_2;
122 ✗ break;
123 ✗ case SpiMode::SPI_MODE_CPOL_HIGH_CPHA_HIGH:
124 ✗ mode = SPI_MODE_3;
125 ✗ break;
126 ✗ default:
127 // Assert if the device SPI Mode is not in the correct range
128 ✗ FW_ASSERT(false, spiMode);
129 ✗ break;
130 }
131
132 ✗ ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
133 ✗ if (ret == -1) {
134 ✗ this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
135 ✗ (void)::close(fd);
136 ✗ return false;
137 }
138
139 ✗ U8 read_mode = 0;
140 ✗ ret = ioctl(fd, SPI_IOC_RD_MODE, &read_mode);
141 ✗ if (ret == -1) {
142 ✗ this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
143 ✗ (void)::close(fd);
144 ✗ return false;
145 }
146
147 ✗ if (mode != read_mode) {
148 ✗ this->log_WARNING_LO_SPI_ConfigMismatch(device, select, Fw::String("MODE"), mode, read_mode);
149 }
150
151 /*
152 * 8 bits per word
153 */
154 ✗ U8 bits = 8;
155 ✗ ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
156 ✗ if (ret == -1) {
157 ✗ this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
158 ✗ (void)::close(fd);
159 ✗ return false;
160 }
161
162 ✗ U8 read_bits = 0;
163 ✗ ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &read_bits);
164 ✗ if (ret == -1) {
165 ✗ this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
166 ✗ (void)::close(fd);
167 ✗ return false;
168 }
169
170 ✗ if (bits != read_bits) {
171 ✗ this->log_WARNING_LO_SPI_ConfigMismatch(device, select, Fw::String("BITS_PER_WORD"), bits, read_bits);
172 }
173
174 /*
175 * Max speed in Hz
176 */
177 ✗ ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &clock);
178 ✗ if (ret == -1) {
179 ✗ this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
180 ✗ (void)::close(fd);
181 ✗ return false;
182 }
183
184 ✗ SpiFrequency read_clock;
185 ✗ ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &read_clock);
186 ✗ if (ret == -1) {
187 ✗ this->log_WARNING_HI_SPI_ConfigError(device, select, ret);
188 ✗ (void)::close(fd);
189 ✗ return false;
190 }
191
192 ✗ if (clock != read_clock) {
193 ✗ this->log_WARNING_LO_SPI_ConfigMismatch(device, select, Fw::String("MAX_SPEED_HZ"), clock, read_clock);
194 }
195
196 // The device is only published once it is fully configured, so that a failed configuration
197 // leaves the driver closed rather than pointing at a misconfigured device
198 ✗ this->m_fd = fd;
199
200 ✗ return true;
201 ✗ }
202
203 ✗ LinuxSpiDriverComponentImpl::~LinuxSpiDriverComponentImpl() {
204 ✗ (void)close(this->m_fd);
205 ✗ }
206
207 } // end namespace Drv
208