GCC Code Coverage Report


Directory: ./
File: channeloutput/GenericSerial.cpp
Date: 2026-10-29 08:11:58
Exec Total Coverage
Lines: 62 66 93.9%
Functions: 10 10 100.0%
Branches: 26 54 48.1%

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 <fcntl.h>
18 #include <termios.h>
19 #include <unistd.h>
20
21 #include "../common.h"
22 #include "../log.h"
23
24 #include "GenericSerial.h"
25 #include "serialutil.h"
26
27 /////////////////////////////////////////////////////////////////////////////
28 #include "Plugin.h"
29 class GenericSerialPlugin : public FPPPlugins::Plugin, public FPPPlugins::ChannelOutputPlugin {
30 public:
31 7 GenericSerialPlugin() :
32
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
21 FPPPlugins::Plugin("GenericSerial") {
33 7 }
34 13 virtual ChannelOutput* createChannelOutput(unsigned int startChannel, unsigned int channelCount) override {
35
2/6
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
26 return new GenericSerialOutput(startChannel, channelCount);
36 }
37 };
38
39 extern "C" {
40 7 FPPPlugins::Plugin* createPlugin() {
41
2/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
14 return new GenericSerialPlugin();
42 }
43 }
44 /*
45 *
46 */
47 13 GenericSerialOutput::GenericSerialOutput(unsigned int startChannel, unsigned int channelCount) :
48
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 ThreadedChannelOutput(startChannel, channelCount), SerialChannelOutput(), m_speed(9600), m_headerSize(0), m_footerSize(0), m_packetSize(0), m_data(NULL) {
49
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 LogDebug(VB_CHANNELOUT, "GenericSerialOutput::GenericSerialOutput(%u, %u)\n",
50 startChannel, channelCount);
51
52 13 m_useDoubleBuffer = 1;
53 13 }
54
55 /*
56 *
57 */
58 52 GenericSerialOutput::~GenericSerialOutput() {
59 26 LogDebug(VB_CHANNELOUT, "GenericSerialOutput::~GenericSerialOutput()\n");
60 // An output whose Init() failed is deleted without Close() ever running --
61 // the packet buffer is allocated before the serial port opens, so it must
62 // be released here too.
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
26 delete[] m_data;
64 52 }
65
66 13 int GenericSerialOutput::Init(Json::Value config) {
67 13 LogDebug(VB_CHANNELOUT, "GenericSerialOutput::Init()\n");
68
69
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 if (config.isMember("speed")) {
70 13 m_speed = config["speed"].asInt();
71 }
72
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 if (config.isMember("footer")) {
73
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 m_footer = config["footer"].asString();
74 13 m_footerSize = m_footer.length();
75 }
76
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 if (config.isMember("header")) {
77
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 m_header = config["header"].asString();
78 13 m_headerSize = m_header.length();
79 }
80 13 m_packetSize = m_headerSize + m_channelCount + m_footerSize;
81
82 13 m_data = new char[m_packetSize + 1];
83
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (!m_data) {
84 ✗ LogErr(VB_CHANNELOUT, "Could not allocate channel data buffer\n");
85 ✗ return 0;
86 }
87
88
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2 times.
13 if (m_headerSize)
89 11 memcpy(m_data, m_header.c_str(), m_headerSize);
90
91
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (m_footerSize)
92 3 memcpy(m_data + m_headerSize + m_channelCount,
93 3 m_footer.c_str(), m_footerSize);
94
95
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (!setupSerialPort(config, m_speed, "8N1")) {
96 ✗ return 0;
97 }
98
99
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 return ThreadedChannelOutput::Init(config);
100 }
101
102 25 void GenericSerialOutput::GetRequiredChannelRanges(const std::function<void(int, int)>& addRange) {
103 25 addRange(m_startChannel, m_startChannel + m_channelCount - 1);
104 25 }
105
106 /*
107 *
108 */
109 13 int GenericSerialOutput::Close(void) {
110 13 LogDebug(VB_CHANNELOUT, "GenericSerialOutput::Close()\n");
111 13 closeSerialPort();
112
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 delete[] m_data;
113 13 m_data = nullptr;
114 13 return ThreadedChannelOutput::Close();
115 }
116
117 /*
118 *
119 */
120 324 int GenericSerialOutput::RawSendData(unsigned char* channelData) {
121 324 LogExcess(VB_CHANNELOUT, "GenericSerialOutput::RawSendData(%p)\n", channelData);
122
123 324 memcpy(m_data + m_headerSize, channelData, m_channelCount);
124
125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 324 times.
324 if (WillLog(LOG_EXCESSIVE, VB_CHANNELDATA))
126 ✗ HexDump("Generic Serial", m_data, std::min(m_headerSize + 16, m_packetSize), VB_CHANNELDATA);
127
128 // whole packets only: a truncated one desyncs the receiver
129 324 SerialWriteAll(m_fd, m_data, m_packetSize, 500);
130
131 324 return m_channelCount;
132 }
133
134 /*
135 *
136 */
137 26 void GenericSerialOutput::DumpConfig(void) {
138 26 LogDebug(VB_CHANNELOUT, "GenericSerialOutput::DumpConfig()\n");
139 26 dumpSerialConfig();
140 26 LogDebug(VB_CHANNELOUT, " Port Speed : %d\n", m_speed);
141 26 LogDebug(VB_CHANNELOUT, " Header Size: %d\n", m_headerSize);
142 26 LogDebug(VB_CHANNELOUT, " Header : '%s'\n", m_header.c_str());
143 26 LogDebug(VB_CHANNELOUT, " Footer Size: %d\n", m_footerSize);
144 26 LogDebug(VB_CHANNELOUT, " Footer : '%s'\n", m_footer.c_str());
145 26 LogDebug(VB_CHANNELOUT, " Packet Size: %d\n", m_packetSize);
146
147 26 ThreadedChannelOutput::DumpConfig();
148 26 }
149