GCC Code Coverage Report


Directory: ./
File: channeloutput/SPInRF24L01.cpp
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 25 119 21.0%
Functions: 6 30 20.0%
Branches: 13 98 13.3%

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 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23
24 #include "../log.h"
25 #include "../settings.h"
26
27 #include "SPInRF24L01.h"
28 #include "ChannelOutputSetup.h"
29
30 #ifdef USENRF
31 #include "RF24.h"
32 #else
33 #include "stdint.h"
34
35 #define rf24_datarate_e int
36 #define RF24_250KBPS 0
37 #define RF24_1MBPS 1
38 #define RF24_2MBPS 7
39 #define RPI_V2_GPIO_P1_15 2
40 #define RPI_V2_GPIO_P1_24 3
41 #define RPI_V2_GPIO_P1_26 7
42 #define BCM2835_SPI_SPEED_8MHZ 4
43 #define RF24_CRC_16 5
44 #define RF24_PA_MAX 6
45
46 class RF24 {
47 public:
48 ✗ RF24(int, int, int) {}
49 ✗ ~RF24() {}
50 ✗ void begin() {}
51 ✗ void setDataRate(int) {}
52 ✗ int getDataRate(void) { return RF24_250KBPS; }
53 ✗ void setRetries(int, int) {}
54 ✗ void setPayloadSize(int) {}
55 ✗ void setAutoAck(int) {}
56 ✗ void setChannel(int&) {}
57 ✗ void setCRCLength(int) {}
58 ✗ void openWritingPipe(const uint64_t&) {}
59 ✗ void openReadingPipe(int, const uint64_t&) {}
60 ✗ void setPALevel(int) {}
61 ✗ void flush_tx() {}
62 ✗ void powerUp() {}
63 ✗ void printDetails() {}
64 ✗ void write(char*, int) {}
65 };
66
67 #endif
68
69 //TODO: Check max channels
70 #define SPINRF24L01_MAX_CHANNELS 512
71 const uint64_t pipes[2] = {
72 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL
73 };
74
75 #include "Plugin.h"
76 class SPInRF24L01Plugin : public FPPPlugins::Plugin, public FPPPlugins::ChannelOutputPlugin {
77 public:
78 1 SPInRF24L01Plugin() :
79
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
3 FPPPlugins::Plugin("SPInRF24L01") {
80 1 }
81 1 virtual ChannelOutput* createChannelOutput(unsigned int startChannel, unsigned int channelCount) override {
82
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 SPInRF24L01Output(startChannel, channelCount);
83 }
84 };
85
86 extern "C" {
87 1 FPPPlugins::Plugin* createPlugin() {
88
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 SPInRF24L01Plugin();
89 }
90 }
91
92 /////////////////////////////////////////////////////////////////////////////
93
94 class SPInRF24L01PrivData {
95 public:
96 ✗ SPInRF24L01PrivData() :
97 ✗ radio(nullptr),
98 ✗ speed(RF24_250KBPS),
99 ✗ channel(0) {}
100 RF24* radio;
101 rf24_datarate_e speed;
102 int channel;
103 };
104
105 /////////////////////////////////////////////////////////////////////////////
106
107 1 SPInRF24L01Output::SPInRF24L01Output(unsigned int startChannel, unsigned int channelCount) :
108 ChannelOutput(startChannel, channelCount),
109 1 data(nullptr) {
110 1 }
111 4 SPInRF24L01Output::~SPInRF24L01Output() {
112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
2 if (data) {
113 ✗ delete data;
114 }
115 4 }
116
117 1 int SPInRF24L01Output::Init(Json::Value config) {
118 // Deprecated in FPP 10, scheduled for removal in FPP 11 (GitHub #2937)
119 1 LogWarn(VB_CHANNELOUT, "SPI-nRF24L01 output is deprecated and will be removed in FPP 11\n");
120
121 1 int chanNum = -1;
122 1 rf24_datarate_e ss = RF24_250KBPS;
123
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (config.isMember("speed")) {
124 1 int i = config["speed"].asInt();
125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (i == 0) {
126 ✗ ss = RF24_250KBPS;
127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 } else if (i == 1) {
128 ✗ ss = RF24_1MBPS;
129
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 } else if (i == 2) {
130 ✗ ss = RF24_2MBPS;
131 } else {
132 1 LogErr(VB_CHANNELOUT, "Invalid speed %d from config\n", i);
133
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 AddOutputConfigWarning(40, "nRF24 radio output: invalid speed in configuration");
134 1 return 0;
135 }
136 }
137 ✗ if (config.isMember("channel")) {
138 ✗ chanNum = config["channel"].asInt();
139 }
140
141 ✗ if (chanNum > 83 && chanNum < 101) {
142 ✗ LogWarn(VB_CHANNELOUT, "FCC RESTRICTED FREQUENCY RANGE OF %dMHz\n", 2400 + chanNum);
143 }
144
145 ✗ if (chanNum < 0 || chanNum > 125) {
146 ✗ LogErr(VB_CHANNELOUT, "Invalid channel '%d'\n", chanNum);
147 ✗ AddOutputConfigWarning(40, "nRF24 radio output: invalid channel " + std::to_string(chanNum) + " (must be 0-125)");
148 ✗ return 0;
149 }
150
151 ✗ RF24* radio = new RF24(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_26, BCM2835_SPI_SPEED_8MHZ);
152 ✗ if (!radio) {
153 ✗ LogErr(VB_CHANNELOUT, "Failed to create our radio instance, unable to continue!\n");
154 ✗ AddOutputConfigWarning(40, "nRF24 radio output: could not create radio instance");
155 ✗ return 0;
156 }
157 ✗ data = new SPInRF24L01PrivData();
158 ✗ data->channel = chanNum;
159 ✗ data->speed = ss;
160
161 // This section of code was basically lifted from the initialization in
162 // Komby's RF1 library. This was tested on a Pi using a similar version
163 // of the RF24 library and works, so no further investigation to whether
164 // or not all of these are required was done.
165 ✗ radio->begin();
166
167 // Attempt to detect whether or not the radio is present:
168 ✗ radio->setDataRate(RF24_250KBPS);
169 ✗ if (radio->getDataRate() != RF24_250KBPS) {
170 ✗ LogErr(VB_CHANNELOUT, "Failed to detect nRF Radio by setting speed to 250k!\n");
171 ✗ AddOutputConfigWarning(40, "nRF24 radio output: radio not detected (check wiring/SPI)");
172 ✗ delete radio;
173 ✗ delete data;
174 ✗ data = nullptr;
175 ✗ return 0;
176 }
177
178 ✗ radio->setDataRate(data->speed);
179 ✗ radio->setRetries(0, 0);
180 ✗ radio->setPayloadSize(32);
181 ✗ radio->setAutoAck(0);
182 ✗ radio->setChannel(data->channel);
183 ✗ radio->setCRCLength(RF24_CRC_16);
184
185 ✗ radio->openWritingPipe(pipes[0]);
186 ✗ radio->openReadingPipe(1, pipes[1]);
187 ✗ radio->setPALevel(RF24_PA_MAX);
188
189 ✗ radio->flush_tx();
190 ✗ radio->powerUp();
191
192 ✗ data->radio = radio;
193
194 ✗ if (WillLog(LOG_DEBUG, VB_CHANNELOUT)) {
195 ✗ data->radio->printDetails();
196 }
197
198 ✗ return ChannelOutput::Init(config);
199 }
200
201 ✗ int SPInRF24L01Output::Close(void) {
202 ✗ LogDebug(VB_CHANNELOUT, "SPInRF24L01Output::Close\n");
203
204 ✗ delete data->radio;
205 ✗ data->radio = NULL;
206 ✗ return ChannelOutput::Close();
207 }
208
209 ✗ int SPInRF24L01Output::SendData(unsigned char* channelData) {
210 char packet[32];
211 ✗ int i = 0;
212 ✗ RF24* radio = data->radio;
213
214 ✗ for (i = 0; i * 30 < m_channelCount; i++) {
215 ✗ LogDebug(VB_CHANNELOUT,
216 "Shipping off packet %d (offset: %d/%d, size: %d)\n",
217 i, i * 30, m_channelCount,
218 ((i * 30) + 30 > m_channelCount ? m_channelCount - i * 30 : 30));
219
220 ✗ bzero(packet, sizeof(packet));
221
222 ✗ memcpy(packet, channelData + (i * 30), ((i * 30) + 30 > m_channelCount ? m_channelCount - i * 30 : 30));
223 ✗ packet[30] = i;
224
225 ✗ radio->write(packet, 32);
226 }
227 ✗ return m_channelCount;
228 }
229
230 ✗ void SPInRF24L01Output::DumpConfig(void) {
231 ✗ ChannelOutput::DumpConfig();
232 ✗ if (data) {
233 ✗ if (data->speed == RF24_2MBPS)
234 ✗ LogDebug(VB_CHANNELOUT, " speed : 2MBPS\n");
235 ✗ else if (data->speed == RF24_1MBPS)
236 ✗ LogDebug(VB_CHANNELOUT, " speed : 1MBPS\n");
237 ✗ else if (data->speed == RF24_250KBPS)
238 ✗ LogDebug(VB_CHANNELOUT, " speed : 250KBPS\n");
239 ✗ LogDebug(VB_CHANNELOUT, " channel : %d\n", data->channel);
240 }
241 ✗ }
242
243 ✗ void SPInRF24L01Output::GetRequiredChannelRanges(const std::function<void(int, int)>& addRange) {
244 ✗ addRange(m_startChannel, m_startChannel + m_channelCount - 1);
245 ✗ }
246