-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathfrontend_monitor.cpp
More file actions
207 lines (161 loc) · 6.17 KB
/
Copy pathfrontend_monitor.cpp
File metadata and controls
207 lines (161 loc) · 6.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*
* File role: DVBv5 frontend property reader.
*
* Reads FE_GET_PROPERTY tuning parameters and statistics one property at a
* time so older drivers can return partial DVBv5 data without hiding all fields.
*/
#include "frontend_monitor.h"
#include <linux/dvb/frontend.h>
#include <string.h>
#include <sys/ioctl.h>
// Thin wrapper around FE_GET_PROPERTY for one batch of DVBv5 properties.
static int get_frontend_properties(int fd, struct dtv_property *properties, unsigned int property_count) {
struct dtv_properties props;
memset(&props, 0, sizeof(props));
props.num = property_count;
props.props = properties;
return ioctl(fd, FE_GET_PROPERTY, &props);
}
// A statistic is useful only when the driver returned at least one scaled value.
static bool property_has_stat(const struct dtv_property *property) {
return property->u.st.len > 0 &&
property->u.st.stat[0].scale != FE_SCALE_NOT_AVAILABLE;
}
// The monitor currently displays the first stat entry returned by the driver.
static struct dtv_stats property_first_stat(const struct dtv_property *property) {
return property->u.st.stat[0];
}
// Read one DVBv5 scalar property without letting unsupported commands poison
// the rest of the frontend snapshot on older drivers.
static bool read_frontend_property_data(int fd, unsigned int command, uint32_t *value) {
struct dtv_property property;
memset(&property, 0, sizeof(property));
property.cmd = command;
if (get_frontend_properties(fd, &property, 1) < 0)
return false;
*value = property.u.data;
return true;
}
// Read one DVBv5 statistic property and keep only scaled values.
static bool read_frontend_property_stat(int fd, unsigned int command, struct dtv_stats *stat) {
struct dtv_property property;
memset(&property, 0, sizeof(property));
property.cmd = command;
if (get_frontend_properties(fd, &property, 1) < 0)
return false;
if (!property_has_stat(&property))
return false;
*stat = property_first_stat(&property);
return true;
}
// Read basic tuning parameters independently so one unsupported property does
// not hide all other PARAMS fields.
static bool read_frontend_v5_params(int fd, struct frontend_v5_snapshot *snapshot) {
bool has_data = false;
uint32_t value;
if (read_frontend_property_data(fd, DTV_DELIVERY_SYSTEM, &value)) {
snapshot->has_delivery_system = true;
snapshot->delivery_system = (fe_delivery_system_t)value;
has_data = true;
}
if (read_frontend_property_data(fd, DTV_FREQUENCY, &value)) {
snapshot->has_frequency = true;
snapshot->frequency = value;
has_data = true;
}
if (read_frontend_property_data(fd, DTV_MODULATION, &value)) {
snapshot->has_modulation = true;
snapshot->modulation = (fe_modulation_t)value;
has_data = true;
}
if (read_frontend_property_data(fd, DTV_BANDWIDTH_HZ, &value)) {
snapshot->has_bandwidth_hz = true;
snapshot->bandwidth_hz = value;
has_data = true;
}
if (read_frontend_property_data(fd, DTV_SYMBOL_RATE, &value)) {
snapshot->has_symbol_rate = true;
snapshot->symbol_rate = value;
has_data = true;
}
if (read_frontend_property_data(fd, DTV_INNER_FEC, &value)) {
snapshot->has_inner_fec = true;
snapshot->inner_fec = (fe_code_rate_t)value;
has_data = true;
}
if (read_frontend_property_data(fd, DTV_CODE_RATE_HP, &value)) {
snapshot->has_code_rate_hp = true;
snapshot->code_rate_hp = (fe_code_rate_t)value;
has_data = true;
}
if (read_frontend_property_data(fd, DTV_CODE_RATE_LP, &value)) {
snapshot->has_code_rate_lp = true;
snapshot->code_rate_lp = (fe_code_rate_t)value;
has_data = true;
}
if (read_frontend_property_data(fd, DTV_GUARD_INTERVAL, &value)) {
snapshot->has_guard_interval = true;
snapshot->guard_interval = (fe_guard_interval_t)value;
has_data = true;
}
if (read_frontend_property_data(fd, DTV_TRANSMISSION_MODE, &value)) {
snapshot->has_transmission_mode = true;
snapshot->transmission_mode = (fe_transmit_mode_t)value;
has_data = true;
}
if (read_frontend_property_data(fd, DTV_HIERARCHY, &value)) {
snapshot->has_hierarchy = true;
snapshot->hierarchy = (fe_hierarchy_t)value;
has_data = true;
}
return has_data;
}
// Read optional DVBv5 statistics independently; failure leaves PARAMS intact.
static bool read_frontend_v5_stats(int fd, struct frontend_v5_snapshot *snapshot) {
bool has_data = false;
if (read_frontend_property_stat(fd, DTV_STAT_SIGNAL_STRENGTH, &snapshot->signal_strength)) {
snapshot->has_signal_strength = true;
has_data = true;
}
if (read_frontend_property_stat(fd, DTV_STAT_CNR, &snapshot->cnr)) {
snapshot->has_cnr = true;
has_data = true;
}
if (read_frontend_property_stat(fd, DTV_STAT_PRE_ERROR_BIT_COUNT, &snapshot->pre_error_bit_count)) {
snapshot->has_pre_error_bit_count = true;
has_data = true;
}
if (read_frontend_property_stat(fd, DTV_STAT_PRE_TOTAL_BIT_COUNT, &snapshot->pre_total_bit_count)) {
snapshot->has_pre_total_bit_count = true;
has_data = true;
}
if (read_frontend_property_stat(fd, DTV_STAT_POST_ERROR_BIT_COUNT, &snapshot->post_error_bit_count)) {
snapshot->has_post_error_bit_count = true;
has_data = true;
}
if (read_frontend_property_stat(fd, DTV_STAT_POST_TOTAL_BIT_COUNT, &snapshot->post_total_bit_count)) {
snapshot->has_post_total_bit_count = true;
has_data = true;
}
if (read_frontend_property_stat(fd, DTV_STAT_ERROR_BLOCK_COUNT, &snapshot->error_block_count)) {
snapshot->has_error_block_count = true;
has_data = true;
}
if (read_frontend_property_stat(fd, DTV_STAT_TOTAL_BLOCK_COUNT, &snapshot->total_block_count)) {
snapshot->has_total_block_count = true;
has_data = true;
}
return has_data;
}
// Read DVBv5 frontend data. Each property is isolated because older drivers may
// reject newer commands while supporting other DVBv5 values.
int read_frontend_v5_snapshot(int fd, struct frontend_v5_snapshot *snapshot) {
if (fd < 0 || snapshot == NULL)
return -1;
memset(snapshot, 0, sizeof(*snapshot));
bool has_params = read_frontend_v5_params(fd, snapshot);
bool has_stats = read_frontend_v5_stats(fd, snapshot);
if (!has_params && !has_stats)
return -1;
return 0;
}