/*
 *  libzvbi - Video Programming System
 *
 *  Copyright (C) 2000-2004 Michael H. Schimek
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* $Id: vps.c,v 1.3 2006/05/31 03:50:02 mschimek Exp $ */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#include "misc.h"
#include "vps.h"

/**
 * @addtogroup VPS Video Programming System Decoder
 * @ingroup LowDec
 * @brief Functions to decode VPS packets (ETS 300 231).
 */

/**
 * @param cni CNI of type VBI_CNI_TYPE_VPS is stored here.
 * @param buffer VPS packet as defined for @c VBI_SLICED_VPS,
 *   i.e. 13 bytes without clock run-in and start code.
 *
 * Decodes a VPS packet according to ETS 300 231, returning the
 * 12 bit Country and Network Identifier in @a cni.
 *
 * The code 0xDC3 is translated according to TR 101 231: "As this
 * code is used for a time in two networks a distinction for automatic
 * tuning systems is given in data line 16 [VPS]: bit 3 of byte 5 = 1
 * for the ARD network / = 0 for the ZDF network."
 *
 * @returns
 * Always @c TRUE, no error checking possible. It may be prudent to
 * wait until two identical packets have been received.
 *
 * @since 0.2.20
 */
vbi_bool
vbi_decode_vps_cni		(unsigned int *		cni,
				 const uint8_t		buffer[13])
{
	unsigned int cni_value;

	assert (NULL != cni);
	assert (NULL != buffer);

	cni_value = (+ ((buffer[10] & 0x03) << 10)
		     + ((buffer[11] & 0xC0) << 2)
		     +  (buffer[ 8] & 0xC0)
		     +  (buffer[11] & 0x3F));

	if (0x0DC3 == cni_value)
		cni_value = (buffer[2] & 0x10) ?
			0x0DC2 /* ZDF */ : 0x0DC1 /* ARD */;

	*cni = cni_value;

	return TRUE;
}

#if 3 == VBI_VERSION_MINOR

/**
 * @param pid PDC data is stored here.
 * @param buffer VPS packet as defined for @c VBI_SLICED_VPS,
 *   i.e. 13 bytes without clock run-in and start code.
 * 
 * Decodes a VPS datagram according to ETS 300 231,
 * storing PDC recording-control data in @a pid.
 *
 * @returns
 * Always @c TRUE, no error checking possible.
 *
 * @since 9.9.9
 */
vbi_bool
vbi_decode_vps_pdc		(vbi_program_id *	pid,
				 const uint8_t		buffer[13])
{
	assert (NULL != pid);
	assert (NULL != buffer);

	pid->cni_type	= VBI_CNI_TYPE_VPS;

	pid->cni	= (+ ((buffer[10] & 0x03) << 10)
			   + ((buffer[11] & 0xC0) << 2)
			   +  (buffer[ 8] & 0xC0)
			   +  (buffer[11] & 0x3F));

	pid->channel	= VBI_PID_CHANNEL_VPS;

	pid->pil	= (+ ((buffer[ 8] & 0x3F) << 14)
			   +  (buffer[ 9] << 6)
			   +  (buffer[10] >> 2));

	pid->month	= VBI_PIL_MONTH (pid->pil) - 1; 
	pid->day	= VBI_PIL_DAY (pid->pil) - 1; 
	pid->hour	= VBI_PIL_HOUR (pid->pil); 
	pid->minute	= VBI_PIL_MINUTE (pid->pil); 

	pid->length	= 0; /* unknown */

	pid->luf	= FALSE; /* no update, just pil */
	pid->mi		= FALSE; /* label is not 30 s early */
	pid->prf	= FALSE; /* prepare to record unknown */

	pid->pcs_audio	= buffer[ 2] >> 6;
	pid->pty	= buffer[12];

	pid->tape_delayed = FALSE;

	return TRUE;
}

#endif /* 3 == VBI_VERSION_MINOR */

/**
 * @param buffer VPS packet as defined for @c VBI_SLICED_VPS,
 *   i.e. 13 bytes without clock run-in and start code.
 * @param cni CNI of type VBI_CNI_TYPE_VPS.
 *
 * Stores the 12 bit Country and Network Identifier @a cni in
 * a VPS packet according to ETS 300 231.
 *
 * @returns
 * @c FALSE if @a cni is invalid; in this case @a buffer remains
 * unmodified.
 *
 * @since 0.2.20
 */
vbi_bool
vbi_encode_vps_cni		(uint8_t		buffer[13],
				 unsigned int		cni)
{
	assert (NULL != buffer);

	if (unlikely (cni > 0x0FFF))
		return FALSE;

	buffer[8] = (buffer[8] & 0x3F) | (cni & 0xC0);
	buffer[10] = (buffer[10] & 0xFC) | (cni >> 10);
	buffer[11] = (cni & 0x3F) | ((cni >> 2) & 0xC0);

	return TRUE;
}

#if 3 == VBI_VERSION_MINOR

/**
 * @param buffer VPS packet as defined for @c VBI_SLICED_VPS,
 *   i.e. 13 bytes without clock run-in and start code.
 * @param pid PDC data.
 * 
 * Stores PDC recording-control data (CNI, PIL, PCS audio, PTY) in
 * a VPS datagram according to ETS 300 231. If non-zero the function
 * encodes @a pid->pil, otherwise it calculates the PIL from
 * @a pid->month, day, hour and minute.
 *
 * @returns
 * @c FALSE if any of the parameters to encode are invalid; in this
 * case @a buffer remains unmodified.
 *
 * @since 9.9.9
 */
vbi_bool
vbi_encode_vps_pdc		(uint8_t		buffer[13],
				 const vbi_program_id *pid)
{
	unsigned int month;
	unsigned int day;
	unsigned int hour;
	unsigned int minute;
	unsigned int pil;

	assert (NULL != buffer);
	assert (NULL != pid);

	if (unlikely ((unsigned int) pid->pty > 0xFF))
		return FALSE;

	if (unlikely ((unsigned int) pid->pcs_audio > 3))
		return FALSE;

	pil = pid->pil;

	switch (pil) {
	case VBI_PIL_TIMER_CONTROL:
	case VBI_PIL_INHIBIT_TERMINATE:
	case VBI_PIL_INTERRUPT:
	case VBI_PIL_CONTINUE:
		break;

	default:
		if (0 == pil) {
			month = pid->month;
			day = pid->day;
			hour = pid->hour;
			minute = pid->minute;

			pil = VBI_PIL (month, day, hour, minute);
		} else {
			month = VBI_PIL_MONTH (pil);
			day = VBI_PIL_DAY (pil);
			hour = VBI_PIL_HOUR (pil);
			minute = VBI_PIL_MINUTE (pil);
		}

		if (unlikely ((month - 1) > 11
			      || (day - 1) > 30
			      || hour > 23
			      || minute > 59))
			return FALSE;

		break;
	}

	if (!vbi_encode_vps_cni (buffer, pid->cni))
		return FALSE;

	buffer[2] = (buffer[2] & 0x3F) | (pid->pcs_audio << 6);
	buffer[8] = (buffer[8] & 0xC0) | ((pil >> 14) & 0x3F);
	buffer[9] = pil >> 6;
	buffer[10] = (buffer[10] & 0x03) | (pil << 2);
	buffer[12] = pid->pty;

	return TRUE;
}

#endif /* 3 == VBI_VERSION_MINOR */


syntax highlighted by Code2HTML, v. 0.9.1