GCC Code Coverage Report


Directory: ./
File: channeloutput/GenericSPI.cpp
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 53 64 82.8%
Functions: 10 10 100.0%
Branches: 26 64 40.6%

Line Branch Exec Source
1 /*
2 * This file is part of the Falcon Player (FPP) and is Copyright (C)
3 * 2013-2022 by the Falcon Player Developers.
4 *
5 * The Falcon Player (FPP) is free software, and is covered under
6 * multiple Open Source licenses. Please see the included 'LICENSES'
7 * file for descriptions of what files are covered by each license.
8 *
9 * This source file is covered under the GPL v2 as described in the
10 * included LICENSE.GPL file.
11 */
12
13 #include "fpp-pch.h"
14
15 #include "fpp-json.h"
16
17 #include <errno.h>
18 #include <fcntl.h>
19
20 #include "../log.h"
21
22
23 #include "GenericSPI.h"
24
25 #define MAX_CHANNELS 16777215
26
27 #ifdef PLATFORM_PI
28 #define MIN_SPI_SPEED_HZ 32000
29 #define MAX_SPI_SPEED_HZ 125000000
30 #elif PLATFORM_BBB
31 //TODO need to confirm these
32 #define MIN_SPI_SPEED_HZ 1500
33 #define MAX_SPI_SPEED_HZ 48000000
34 #elif PLATFORM_BB64
35 //TODO need to confirm these
36 #define MIN_SPI_SPEED_HZ 32000
37 #define MAX_SPI_SPEED_HZ 125000000
38 #elif PLATFORM_ARMBIAN
39 #define MIN_SPI_SPEED_HZ 50000
40 #define MAX_SPI_SPEED_HZ 2500000
41 #else
42 //not sure what other platforms could be used, using safe values here
43 #define MIN_SPI_SPEED_HZ 50000
44 #define MAX_SPI_SPEED_HZ 100000
45 #endif
46
47 #include "Plugin.h"
48 class GenericSPIPlugin : public FPPPlugins::Plugin, public FPPPlugins::ChannelOutputPlugin {
49 public:
50 1 GenericSPIPlugin() :
51
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
3 FPPPlugins::Plugin("GenericSPI") {
52 1 }
53 1 virtual ChannelOutput* createChannelOutput(unsigned int startChannel, unsigned int channelCount) override {
54
2/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
2 return new GenericSPIOutput(startChannel, channelCount);
55 }
56 };
57
58 extern "C" {
59 1 FPPPlugins::Plugin* createPlugin() {
60
2/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
2 return new GenericSPIPlugin();
61 }
62 }
63
64 /////////////////////////////////////////////////////////////////////////////
65
66 /*
67 *
68 */
69 1 GenericSPIOutput::GenericSPIOutput(unsigned int startChannel, unsigned int channelCount) :
70 ThreadedChannelOutput(startChannel, channelCount),
71 1 m_port(-1),
72 1 m_speed_hz(0),
73 1 m_spi(nullptr) {
74
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 LogDebug(VB_CHANNELOUT, "GenericSPIOutput::GenericSPIOutput(%u, %u)\n",
75 startChannel, channelCount);
76 1 }
77
78 /*
79 *
80 */
81 4 GenericSPIOutput::~GenericSPIOutput() {
82 2 LogDebug(VB_CHANNELOUT, "GenericSPIOutput::~GenericSPIOutput()\n");
83
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 if (m_spi) {
84
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 delete m_spi;
85 }
86 4 }
87
88 /*
89 *
90 */
91
92 1 int GenericSPIOutput::Init(Json::Value config) {
93 1 LogDebug(VB_CHANNELOUT, "GenericSPIOutput::Init()\n");
94
95
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (config.isMember("device")) {
96
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 std::string device = config["device"].asString();
97
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (device == "spidev0.0")
98 1 m_port = 0;
99 ✗ else if (device == "spidev0.1")
100 ✗ m_port = 1;
101 1 }
102
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (config.isMember("speed")) {
103 //input page ask for speed in khz
104
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 std::string speedStr = config["speed"].asString();
105 1 int config_speed = 1000 * std::atoi(speedStr.c_str());
106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (config_speed < MIN_SPI_SPEED_HZ)
107 ✗ m_speed_hz = MIN_SPI_SPEED_HZ;
108
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (config_speed > MAX_SPI_SPEED_HZ)
109 1 m_speed_hz = MAX_SPI_SPEED_HZ;
110 else
111 ✗ m_speed_hz = config_speed;
112 1 }
113
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (m_port == -1) {
115 ✗ LogErr(VB_CHANNELOUT, "Invalid Config for SPI. Invalid port.\n");
116 ✗ return 0;
117 }
118
119 1 LogDebug(VB_CHANNELOUT, "Using SPI Port %d\n", m_port);
120
121
2/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 m_spi = new SPIUtils(m_port, m_speed_hz);
122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!m_spi->isOk()) {
123 ✗ LogErr(VB_CHANNELOUT, "Unable to open SPI device\n");
124 ✗ delete m_spi;
125 ✗ m_spi = nullptr;
126 ✗ return 0;
127 }
128
129
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 return ThreadedChannelOutput::Init(config);
130 }
131
132 /*
133 *
134 */
135 1 int GenericSPIOutput::Close(void) {
136 1 LogDebug(VB_CHANNELOUT, "GenericSPIOutput::Close()\n");
137
138 1 return ThreadedChannelOutput::Close();
139 }
140 2 void GenericSPIOutput::GetRequiredChannelRanges(const std::function<void(int, int)>& addRange) {
141 2 addRange(m_startChannel, m_startChannel + m_channelCount - 1);
142 2 }
143
144 /*
145 *
146 */
147 18 int GenericSPIOutput::RawSendData(unsigned char* channelData) {
148 18 LogDebug(VB_CHANNELOUT, "GenericSPIOutput::RawSendData(%p)\n", channelData);
149
150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!m_spi) {
151 ✗ return 0;
152 }
153
154 18 m_spi->xfer(channelData, nullptr, m_channelCount);
155
156 18 return m_channelCount;
157 }
158
159 /*
160 *
161 */
162 2 void GenericSPIOutput::DumpConfig(void) {
163 2 LogDebug(VB_CHANNELOUT, "GenericSPIOutput::DumpConfig()\n");
164
165 2 LogDebug(VB_CHANNELOUT, " port : %d\n", m_port);
166
167 2 ThreadedChannelOutput::DumpConfig();
168 2 }
169