1 /*
2  *  libzvbi - Teletext packet decoder, packet 8/30
3  *
4  *  Copyright (C) 2003, 2004 Michael H. Schimek
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License version 2 as
8  *  published by the Free Software Foundation.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 /* $Id: packet-830.c,v 1.4 2013/07/10 11:37:18 mschimek Exp $ */
21 
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25 
26 #include <assert.h>
27 #include <errno.h>
28 #include "misc.h"
29 #include "bcd.h"		/* vbi_lbcd2bin() */
30 #include "hamm.h"		/* vbi_rev16p(), vbi_iham8() */
31 #include "packet-830.h"
32 
33 /**
34  * @addtogroup Packet830 Teletext Packet 8/30 Decoder
35  * @ingroup LowDec
36  * @brief Functions to decode Teletext packet 8/30 (ETS 300 706).
37  *
38  * Teletext pages are transmitted in packets numbered 0 to 31. Packet
39  * 0 to 25 contain the text of the page, packet 26 to 29 additional
40  * information like Fastext links. Packet 30 and 31 are reserved for
41  * data transmissions unrelated to any page. Since each packet
42  * contains a magazine number 1 to 8 (the first digit of the Teletext
43  * page number) 16 logical channels can be distinguished. Packet 30
44  * with magazine number 8 carries a Country and Network Identifier,
45  * and either a local time (format 1) or PDC label (format 2).
46  *
47  * These are low level functions. See test/decode.c for a usage
48  * example.
49  *
50  * The @a vbi_decoder module can decode a full Teletext signal and
51  * provide the information transmitted in packet 8/30 as @c
52  * VBI_EVENT_NETWORK, @c VBI_EVENT_NETWORK_ID, @c VBI_EVENT_LOCAL_TIME
53  * and @c VBI_EVENT_PROG_ID. See examples/network.c and
54  * examples/pdc1.c.
55  */
56 
57 /* Resources:
58    http://pdc.ro.nu/jd-code.html
59 */
60 
61 /**
62  * @param cni CNI of type VBI_CNI_TYPE_8301 will be stored here.
63  * @param buffer Teletext packet as defined for @c VBI_SLICED_TELETEXT_B,
64  *   i.e. 42 bytes without clock run-in and framing code.
65  *
66  * Decodes a Teletext packet 8/30 format 1 according to ETS 300 706
67  * section 9.8.1, returning the contained 16 bit Country and Network
68  * Identifier in @a *cni.
69  *
70  * @returns
71  * Always @c TRUE, no error checking possible. It may be prudent to
72  * wait for a second transmission of the received CNI to ensure
73  * correct reception.
74  *
75  * @since 0.2.34
76  */
77 vbi_bool
vbi_decode_teletext_8301_cni(unsigned int * cni,const uint8_t buffer[42])78 vbi_decode_teletext_8301_cni	(unsigned int *		cni,
79 				 const uint8_t		buffer[42])
80 {
81 	assert (NULL != cni);
82 	assert (NULL != buffer);
83 
84 	*cni = vbi_rev16p (buffer + 9);
85 
86 	return TRUE;
87 }
88 
89 /* Should use vbi_bcd2bin() but that function is limited to four BCD
90    digits in libzvbi 0.2 and cannot be changed for compatibility
91    reasons. */
92 static int
bcd2bin(int bcd)93 bcd2bin				(int			bcd)
94 {
95 	unsigned int f;
96 	int bin = 0;
97 
98 	for (f = 1; f < 100000; f = f * 10) {
99 		bin += (bcd & 15) * f;
100 		bcd >>= 4;
101 	}
102 
103 	return bin;
104 }
105 
106 /**
107  * @param time The current time in seconds since 1970-01-01 00:00 UTC
108  *   will be stored here.
109  * @param seconds_east The offset of the local time of the intended
110  *   audience of the program in seconds east of UTC will be stored here,
111  *   including a daylight-saving time offset if daylight-saving is
112  *   currently in effect in that time zone. To get the local time of the
113  *   intended audience add @a seconds_east to @a time.
114  * @param buffer Teletext packet as defined for @c VBI_SLICED_TELETEXT_B,
115  *   i.e. 42 bytes without clock run-in and framing code.
116  *
117  * Decodes a Teletext packet 8/30 format 1 according to ETS 300 706
118  * section 9.8.1, returning the current time in the UTC time zone and
119  * the time zone of the intended audience of the program.
120  *
121  * @returns
122  * On error the function returns @c FALSE:
123  * - The buffer contains uncorrectable errors or
124  * - The time is not representable as a time_t.
125  * In these cases @a *time and @a *seconds_east remain unchanged.
126  *
127  * @since 0.2.34
128  */
129 vbi_bool
vbi_decode_teletext_8301_local_time(time_t * time,int * seconds_east,const uint8_t buffer[42])130 vbi_decode_teletext_8301_local_time
131 				(time_t *		time,
132 				 int *			seconds_east,
133 				 const uint8_t		buffer[42])
134 {
135 	int64_t mjd;
136 	int64_t utc;
137 	int64_t t;
138 	int bcd;
139 	int field;
140 	int offset;
141 
142 	assert (NULL != time);
143 	assert (NULL != seconds_east);
144 	assert (NULL != buffer);
145 
146 	/* Modified Julian Date. */
147 
148 	bcd = (+ ((buffer[12] & 15) << 16)
149 	       +  (buffer[13] << 8)
150 	       +   buffer[14]
151 	       - 0x11111);
152 	if (unlikely (!vbi_is_bcd (bcd))) {
153 		errno = 0;
154 		return FALSE;
155 	}
156 
157 	mjd = bcd2bin (bcd);
158 
159 	/* UTC time. */
160 
161 	bcd = (+ (buffer[15] << 16)
162 	       + (buffer[16] << 8)
163 	       +  buffer[17]
164 	       - 0x111111);
165 	if (unlikely (!vbi_is_bcd (bcd))) {
166 		errno = 0;
167 		return FALSE;
168 	}
169 
170 	utc = (bcd & 15) + ((bcd >> 4) & 15) * 10;
171 	if (unlikely (utc > 60)) {
172 		errno = 0;
173 		return FALSE;
174 	}
175 
176 	field = ((bcd >> 8) & 15) + ((bcd >> 12) & 15) * 10;
177 	if (unlikely (field >= 60)) {
178 		errno = 0;
179 		return FALSE;
180 	}
181 	utc += field * 60;
182 
183 	field = ((bcd >> 16) & 15) + (bcd >> 20) * 10;
184 	if (unlikely (field >= 24)) {
185 		errno = 0;
186 		return FALSE;
187 	}
188 	utc += field * 3600;
189 
190 	/* Local time offset in seconds east of UTC. */
191 
192 	offset = (buffer[11] & 0x3E) * (15 * 60);
193 	if (buffer[11] & 0x40)
194 		offset = -offset;
195 
196 	t = (mjd - 40587) * 86400 + utc;
197 	if (t < TIME_MIN || t > TIME_MAX) {
198 		errno = EOVERFLOW;
199 		return FALSE;
200 	}
201 
202 
203 	*time = t;
204 
205 	*seconds_east = offset;
206 
207 	return TRUE;
208 }
209 
210 /**
211  * @param cni CNI of type VBI_CNI_TYPE_8302 will be stored here.
212  * @param buffer Teletext packet as defined for @c VBI_SLICED_TELETEXT_B,
213  *   i.e. 42 bytes without clock run-in and framing code.
214  *
215  * Decodes a Teletext packet 8/30 format 2 according to ETS 300 706
216  * section 9.8.2, returning the contained 16 bit Country and Network
217  * Identifier in @a *cni.
218  *
219  * @returns
220  * @c FALSE if the buffer contains uncorrectable errors. In this case
221  * @a *cni remains unchanged.
222  *
223  * @since 0.2.34
224  */
225 vbi_bool
vbi_decode_teletext_8302_cni(unsigned int * cni,const uint8_t buffer[42])226 vbi_decode_teletext_8302_cni	(unsigned int *		cni,
227 				 const uint8_t		buffer[42])
228 {
229 	int b[13];
230 
231 	assert (NULL != cni);
232 	assert (NULL != buffer);
233 
234 	b[ 7] = vbi_unham16p (buffer + 10);
235 	b[ 8] = vbi_unham16p (buffer + 12);
236 	b[10] = vbi_unham16p (buffer + 16);
237 	b[11] = vbi_unham16p (buffer + 18);
238 
239 	if (unlikely ((b[7] | b[8] | b[10] | b[11]) < 0))
240 		return FALSE;
241 
242 	b[ 7] = vbi_rev8 (b[ 7]);
243 	b[ 8] = vbi_rev8 (b[ 8]);
244 	b[10] = vbi_rev8 (b[10]);
245 	b[11] = vbi_rev8 (b[11]);
246 
247 	*cni = (+ ((b[ 7] & 0x0F) << 12)
248 		+ ((b[10] & 0x03) << 10)
249 		+ ((b[11] & 0xC0) << 2)
250 		+  (b[ 8] & 0xC0)
251 		+  (b[11] & 0x3F));
252 
253 	return TRUE;
254 }
255 
256 /**
257  * @param pid PDC program ID will be stored here.
258  * @param buffer Teletext packet as defined for @c VBI_SLICED_TELETEXT_B,
259  *   i.e. 42 bytes without clock run-in and framing code.
260  *
261  * Decodes a Teletext packet 8/30 format 2 according to ETS 300 231,
262  * and stores the contained PDC recording-control data in @a *pid.
263  *
264  * @returns
265  * @c FALSE if the buffer contains uncorrectable errors or invalid
266  * data. In this case @a *pid remains unchanged.
267  *
268  * @since 0.2.34
269  */
270 vbi_bool
vbi_decode_teletext_8302_pdc(vbi_program_id * pid,const uint8_t buffer[42])271 vbi_decode_teletext_8302_pdc	(vbi_program_id *	pid,
272 				 const uint8_t		buffer[42])
273 {
274 	uint8_t b[13];
275 	unsigned int i;
276 	int error;
277 
278 	assert (NULL != pid);
279 	assert (NULL != buffer);
280 
281 	error = vbi_unham8 (buffer[9]);
282 	b[ 6] = vbi_rev8 (error) >> 4;
283 
284 	for (i = 7; i <= 12; ++i) {
285 		int t;
286 
287 		t = vbi_unham16p (buffer + i * 2 - 4);
288 		error |= t;
289 		b[i] = vbi_rev8 (t);
290 	}
291 
292 	if (unlikely (error < 0))
293 		return FALSE;
294 
295 	CLEAR (*pid);
296 
297 	pid->channel	= VBI_PID_CHANNEL_LCI_0 + ((b[6] >> 2) & 3);
298 
299 	pid->cni_type	= VBI_CNI_TYPE_8302;
300 
301 	pid->cni	= (+ ((b[ 7] & 0x0F) << 12)
302 			   + ((b[10] & 0x03) << 10)
303 			   + ((b[11] & 0xC0) << 2)
304 			   +  (b[ 8] & 0xC0)
305 			   +  (b[11] & 0x3F));
306 
307 	pid->pil	= (+ ((b[ 8] & 0x3F) << 14)
308 			   +  (b[ 9]         << 6)
309 			   +  (b[10]         >> 2));
310 
311 	pid->luf	= (b[6] >> 1) & 1;
312 	pid->mi		= (b[7] >> 5) & 1;
313 	pid->prf	= (b[6] >> 0) & 1;
314 
315 	pid->pcs_audio	= (b[7] >> 6) & 3;
316 
317 	pid->pty	= b[12];
318 
319 	return TRUE;
320 }
321 
322 /*
323 Local variables:
324 c-set-style: K&R
325 c-basic-offset: 8
326 End:
327 */
328