#!/usr/bin/perl -w
#
#  libzvbi network identification example.
#
#  Copyright (C) 2006 Michael H. Schimek
#  Perl Port: Copyright (C) 2007 Tom Zoerner
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  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.
#

# Perl $Id: network.pl,v 1.1 2007/11/18 18:48:35 tom Exp tom $
# ZVBI #Id: network.c,v 1.2 2006/10/27 04:52:08 mschimek Exp #

# This example shows how to identify a network from data transmitted
# in XDS packets, Teletext packet 8/30 format 1 and 2, and VPS packets.

use blib;
use strict;
use Getopt::Long;
use Encode;
use Video::ZVBI qw(/^VBI_/);

my $cap;
my $dec;
my $quit;

my $option_vps = 0;
my $option_8301 = 0;
my $option_8302 = 0;
my $option_help = 0;
my $services;

sub handler {
        my($ev_type, $ev, $user_data) = @_;

	my $event_name;
	my $call_sign;
	my $network_name;

	# VBI_EVENT_NETWORK_ID is always sent when the decoder
	# receives a CNI. VBI_EVENT_NETWORK only if it can
	# determine a network name.

	if ($ev_type == VBI_EVENT_NETWORK) {
		$event_name = "VBI_EVENT_NETWORK";

	} elsif ($ev_type == VBI_EVENT_NETWORK_ID) {
		$event_name = "VBI_EVENT_NETWORK_ID";

        } else {
		die "Unexpected event type: $ev_type\n";
	}

	if (defined $ev->{name}) {
                # The network name is an ISO-8859-1 string (the API is
                # quite old...) so we convert it to locale encoding,
                # nowadays usually UTF-8.
                $network_name = decode("ISO-8859-1", $ev->{name});
        } else {
                $network_name = "unknown";
        }

	# ASCII.
	if (defined $ev->{call}) {
		$call_sign = $ev->{call};
        } else {
                $call_sign = "unknown";
        }

	printf  "%s: receiving: \"%s\" call sign: \"%s\" " .
	        "CNI VPS: 0x%x 8/30-1: 0x%x 8/30-2: 0x%x\n",
		$event_name,
		$network_name,
		$call_sign,
		$ev->{cni_vps},
		$ev->{cni_8301},
		$ev->{cni_8302};

        $quit = 1 if $ev->{cni_vps} != 0 && $option_vps;
        $quit = 1 if $ev->{cni_8301} != 0 && $option_8301;
        $quit = 1 if $ev->{cni_8302} != 0 && $option_8302;
}

sub mainloop {
	my $timeout;
	my $sliced_buffer;
	my $n_frames;

	# Don't wait more than two seconds for the driver to return data.
	$timeout = 2000;

	# Should receive a CNI within two seconds, call sign within ten seconds(?).
	if ($services & VBI_SLICED_CAPTION_525) {
		$n_frames = 11 * 30;
	} else {
		$n_frames = 3 * 25;
        }

	for (; $n_frames > 0; --$n_frames) {
		my $n_lines;
	        my $timestamp;
		my $r;

		$r = $cap->pull_sliced ( $sliced_buffer,
                                         $n_lines,
                                         $timestamp,
				         $timeout);
		if ($r == -1) {
			# Could be ignored, esp. EIO with some drivers.
			die "VBI read error: $!\n";

                } elsif ($r == 0) {
			die "VBI read timeout\n";

                } elsif ($r == 1) {
			# continue

                } else {
			die "Unexpected result code from pull_sliced: $r\n";
		}

		$dec->decode ( $sliced_buffer, $n_lines, $timestamp );

                return if defined $quit;
	}

	print "No network ID received or network unknown.\n";
}

sub usage {
        print STDERR "$0 - network identification test\n".
                     "Options:\n".
                     "\t--vps\tStop after receiving VPS\n".
                     "\t--8301\tStop after receiving packet 8/30/1\n".
                     "\t--8302\tStop after receiving packet 8/30/2\n".
                     "\t--help\tPrint this usage info\n";
        exit(1);
}

my %CmdOpts = (
        "vps" =>       \$option_vps,
        "8301" =>      \$option_8301,
        "8302" =>      \$option_8302,
);

sub main_func
{
	my $errstr;
	my $success;

        GetOptions(%CmdOpts) || usage();

        if (!$option_vps && !$option_8301 && !$option_8302) {
                $option_vps = $option_8301 = $option_8302 = 1;
        }

	$services = (VBI_SLICED_TELETEXT_B |
		     VBI_SLICED_VPS |
		     VBI_SLICED_CAPTION_525);

        # open VBI device (buffers:=5, strict:=0, verbose:=FALSE
	$cap = Video::ZVBI::capture::v4l2_new ("/dev/vbi0", 5, $services, 0, $errstr, 0);
        die "Cannot capture VBI data with V4L2 interface: $errstr\n" unless $cap;

	$dec = Video::ZVBI::vt::decoder_new ();
	die "Failed to create VT decoder\n" unless $dec;

	$success = $dec->event_handler_add ( (VBI_EVENT_NETWORK |
                                              VBI_EVENT_NETWORK_ID),
					     \&handler );
	die "Failed to install event handler\n" unless $success;

	mainloop ();
}

main_func();