1 /*
2 * Copyright (c) 2013 - Mauro Carvalho Chehab <mchehab@kernel.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation version 2.1 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
17 *
18 * Based on ETSI EN 300 468 V1.11.1 (2010-04)
19 */
20
21 #include <libdvbv5/desc_extension.h>
22 #include <libdvbv5/desc_t2_delivery.h>
23 #include <libdvbv5/dvb-fe.h>
24
25 #if __GNUC__ >= 9
26 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
27 #endif
28
dvb_desc_t2_delivery_init(struct dvb_v5_fe_parms * parms,const uint8_t * buf,struct dvb_extension_descriptor * ext,void * desc)29 int dvb_desc_t2_delivery_init(struct dvb_v5_fe_parms *parms,
30 const uint8_t *buf,
31 struct dvb_extension_descriptor *ext,
32 void *desc)
33 {
34 struct dvb_desc_t2_delivery *d = desc;
35 unsigned char *p = (unsigned char *) buf;
36 size_t desc_len = ext->length - 1, len, len2;
37 int i, pos = 0;
38
39 len = offsetof(struct dvb_desc_t2_delivery, bitfield);
40 len2 = offsetof(struct dvb_desc_t2_delivery, centre_frequency);
41
42 if (desc_len < len) {
43 dvb_logwarn("T2 delivery descriptor is too small");
44 return -1;
45 }
46 if (desc_len < len2) {
47 memcpy(d, buf, len);
48 bswap16(d->system_id);
49
50 /* It is valid to have length == 4 */
51 if (desc_len == len)
52 return 0;
53
54 dvb_logwarn("T2 delivery descriptor is truncated");
55 return -2;
56 }
57 memcpy(d, buf, len2);
58 bswap16(d->system_id);
59 bswap16(d->bitfield);
60 p += len2;
61
62 while (desc_len - (p - buf)) {
63 if (desc_len - (p - buf) < sizeof(uint16_t)) {
64 dvb_logwarn("T2 delivery descriptor is truncated");
65 return -2;
66 }
67
68 d->cell = realloc(d->cell, (d->num_cell + 1) * sizeof(*d->cell));
69 if (!d->cell) {
70 dvb_logerr("%s: out of memory", __func__);
71 return -3;
72 }
73
74 d->cell[d->num_cell].cell_id = *(uint16_t *)p;
75 bswap16(d->cell[d->num_cell].cell_id);
76 p += sizeof(uint16_t);
77
78 if (d->tfs_flag) {
79 d->cell[d->num_cell].num_freqs = *p;
80 p++;
81 }
82 else
83 d->cell[d->num_cell].num_freqs = 1;
84
85 d->frequency_loop_length += d->cell[d->num_cell].num_freqs;
86 d->centre_frequency = realloc(d->centre_frequency,
87 d->frequency_loop_length * sizeof(*d->centre_frequency));
88 if (!d->centre_frequency) {
89 dvb_logerr("%s: out of memory", __func__);
90 return -3;
91 }
92
93 d->cell[d->num_cell].centre_frequency = &d->centre_frequency[pos];
94
95 memcpy(&d->centre_frequency[pos], p, sizeof(*d->centre_frequency) * d->cell[d->num_cell].num_freqs);
96 p += sizeof(*d->centre_frequency) * d->cell[d->num_cell].num_freqs;
97
98 for (i = 0; i < d->cell[d->num_cell].num_freqs; i++) {
99 bswap32(d->centre_frequency[pos]);
100 pos++;
101 }
102
103 /* Handle subcel frequency table */
104 d->cell[d->num_cell].subcel_length = *p;
105 d->cell[d->num_cell].subcel = NULL;
106
107 p++;
108
109 if (d->cell[d->num_cell].subcel_length) {
110 d->cell[d->num_cell].subcel = calloc(d->cell[d->num_cell].subcel_length,
111 sizeof (*d->cell[d->num_cell].subcel));
112
113 if (!d->cell[d->num_cell].subcel) {
114 dvb_logerr("%s: out of memory", __func__);
115 return -3;
116 }
117 }
118
119 for (i = 0; i < d->cell[d->num_cell].subcel_length; i++) {
120 if (desc_len - (p - buf) < sizeof(uint8_t) + sizeof(uint32_t)) {
121 dvb_logwarn("T2 delivery descriptor is truncated");
122 return -2;
123 }
124 d->cell[d->num_cell].subcel[i].cell_id_extension = *p;
125 p++;
126
127 // Add transposer_frequency at centre_frequency table
128 d->frequency_loop_length++;
129 d->centre_frequency = realloc(d->centre_frequency,
130 d->frequency_loop_length * sizeof(*d->centre_frequency));
131 memcpy(&d->centre_frequency[pos], p, sizeof(*d->centre_frequency));
132 bswap32(d->centre_frequency[pos]);
133 d->cell[d->num_cell].subcel[i].transposer_frequency = d->centre_frequency[pos];
134 pos++;
135
136 p += sizeof(*d->centre_frequency);
137 }
138 d->num_cell++;
139 }
140
141 return 0;
142 }
143
dvb_desc_t2_delivery_print(struct dvb_v5_fe_parms * parms,const struct dvb_extension_descriptor * ext,const void * desc)144 void dvb_desc_t2_delivery_print(struct dvb_v5_fe_parms *parms,
145 const struct dvb_extension_descriptor *ext,
146 const void *desc)
147 {
148 const struct dvb_desc_t2_delivery *d = desc;
149 int i, j, k;
150
151 dvb_loginfo("| plp_id 0x%04x", d->plp_id);
152 dvb_loginfo("| system_id 0x%04x", d->system_id);
153
154 if (ext->length - 1 <= 4)
155 return;
156
157 dvb_loginfo("| tfs_flag %d", d->tfs_flag);
158 dvb_loginfo("| other_frequency_flag %d", d->other_frequency_flag);
159 dvb_loginfo("| transmission_mode %s (%d)",
160 fe_transmission_mode_name[dvbt2_transmission_mode[d->transmission_mode]], d->transmission_mode);
161 dvb_loginfo("| guard_interval %s (%d)",
162 fe_guard_interval_name[dvbt2_interval[d->guard_interval]], d->guard_interval );
163 dvb_loginfo("| reserved %d", d->reserved);
164 dvb_loginfo("| bandwidth %.2f MHz (%d)",
165 dvbt2_bw[d->bandwidth]/ 1000000., d->bandwidth);
166 dvb_loginfo("| SISO/MISO mode %s", siso_miso[d->SISO_MISO]);
167
168 /*
169 * All frequencies are also at the per-cell data. Yet, as the flat
170 * frequency table is what's used to add new transponders for DVB-T2
171 * scan, let's display the flat table too
172 */
173 for (i = 0; i < d->frequency_loop_length; i++)
174 dvb_loginfo("| frequency[%d] %.5f MHz", i, d->centre_frequency[i] / 100000.);
175
176
177 for (i = 0; i < d->num_cell; i++) {
178 struct dvb_desc_t2_delivery_cell *cell = &d->cell[i];
179 dvb_loginfo("| Cell ID 0x%04x", cell->cell_id);
180 for (j = 0; j < cell->num_freqs; j++) {
181 dvb_loginfo("| centre frequency[%d] %.5f MHz", j, cell->centre_frequency[j] / 100000.);
182
183 for (k = 0; k < cell->subcel_length; k++) {
184 struct dvb_desc_t2_delivery_subcell *subcel = &cell->subcel[k];
185 dvb_loginfo("| |- subcell %d", subcel->cell_id_extension);
186 dvb_loginfo("| |- transposer %.5f MHz", subcel->transposer_frequency / 100000.);
187 }
188 }
189 }
190 }
191
dvb_desc_t2_delivery_free(const void * desc)192 void dvb_desc_t2_delivery_free(const void *desc)
193 {
194 const struct dvb_desc_t2_delivery *d = desc;
195 int i;
196
197 if (d->centre_frequency)
198 free(d->centre_frequency);
199
200 if (d->cell) {
201 for (i = 0; i < d->num_cell; i++)
202 if (d->cell[i].subcel)
203 free(d->cell[i].subcel);
204 free (d->cell);
205 }
206
207 // No need to free d->subcell, as it is always NULL
208 }
209
210 const unsigned dvbt2_bw[] = {
211 [0] = 8000000,
212 [1] = 7000000,
213 [2] = 6000000,
214 [3] = 5000000,
215 [4] = 10000000,
216 [5] = 1712000,
217 [6 ...15] = 0, /* Reserved */
218 };
219 const uint32_t dvbt2_interval[] = {
220 [0] = GUARD_INTERVAL_1_32,
221 [1] = GUARD_INTERVAL_1_16,
222 [2] = GUARD_INTERVAL_1_8,
223 [3] = GUARD_INTERVAL_1_4,
224 [4] = GUARD_INTERVAL_1_128,
225 [5] = GUARD_INTERVAL_19_128,
226 [6] = GUARD_INTERVAL_19_256,
227 [7 ...15] = GUARD_INTERVAL_AUTO /* Reserved */
228 };
229 const unsigned dvbt2_transmission_mode[] = {
230 [0] = TRANSMISSION_MODE_2K,
231 [1] = TRANSMISSION_MODE_8K,
232 [2] = TRANSMISSION_MODE_4K,
233 [3] = TRANSMISSION_MODE_1K,
234 [4] = TRANSMISSION_MODE_16K,
235 [5] = TRANSMISSION_MODE_32K,
236 [6 ...7] = TRANSMISSION_MODE_AUTO, /* Reserved */
237 };
238 const char *siso_miso[4] = {
239 [0] = "Single Input, Single Output (SISO)",
240 [1] = "Multiple Input, Single Output (MISO)",
241 [2 ...3] = "reserved",
242 };
243