#!/usr/bin/perl -w
# $Id: mmset,v 1.6 2000/02/26 19:31:20 dick Exp $
#======================================================================#
# mmset - Convert DVB2000 general settings file to/from ASCII
#
# (c) 1999-2000, Dick Streefland
#======================================================================#

require "getopts.pl";

my $name = $0;
$name =~ s/.*\///;
$usage = "\
Usage: $name [<options>] <file>
Convert a DVB2000 general settings file to ASCII.
Options:
   -u   convert ASCII to back to binary
";
my $SIZE = 1264;

#======================================================================#
# parse command line
#======================================================================#
$opt_u = 0;
if	( ! &Getopts( "u" ) )
{
	print STDERR "$usage";
	exit;
}
if	( @ARGV > 0 )
{
	open( STDIN, $ARGV[0] ) || die "cannot open \"$ARGV[0]\"";
}

#======================================================================#
# read settings file layout
#======================================================================#
while	( <DATA> )
{
	chomp;
	($off, $type, $desc) = split /\s/, $_, 3;
	next if $type eq "-";
	$off = hex $off;
	$desc = "Color: " . $desc if $type eq "color";
	$type[$off] = $type;
	$desc[$off] = $desc;
}

#======================================================================#
# do it
#======================================================================#
if	( $opt_u )
{
	$line = 0;
	$set = "\x55" x $SIZE;
	while	( <STDIN> )
	{
		$line++;
		s/#.*//;
		($off, @x) = split /[:\s]+/;
		$off = hex $off;
		$type = shift @x;
		($size, $templ, $format) = &check_type( $type );
		foreach	( @x )
		{
			if	( $type eq "color" )
			{
				# printf STDERR "===> %s\t", $_;
				($T, $R, $G, $B, $code) =
					/(\d)\*(\d+)\/(\d+)\/(\d+)\[(\w+)\]/;
				$_ = hex $code;
				($To, $Ro, $Go, $Bo) = &decode_color( $_ );
				if	(  $T != $To
					|| $R != $Ro
					|| $G != $Go
					|| $B != $Bo
					)
				{
					$_ = &encode_color( $T, $R, $G, $B );
				}
				# printf STDERR "old %8x new %8x\n", $code, $_;
			}
			elsif	( $type !~ /^dec/ )
			{
				$_ = hex $_;
			}
			substr( $set, $off, $size ) = pack( $templ, $_ );
			$off += $size;
		}
	}
	print $set;
}
else
{
	$n = sysread( STDIN, $set, $SIZE + 1 );
	&error( "bad settings file" ) unless $n == $SIZE;

	for	( $off = 0; $off < $SIZE; )
	{
		$desc = $desc[$off];
		printf "%04x:", $off;
		if	( defined $type[$off] )
		{
			printf " %-6s ", $type[$off];
			($size, $templ, $format) = &check_type( $type[$off] );
			$val = unpack( $templ, substr( $set, $off, $size ) );
			if	( $type[$off] eq "color" )
			{
				($T, $R, $G, $B) = &decode_color( $val );
				printf( "%d*%03d/%03d/%03d", $T, $R, $G, $B );
				printf( "[%08x]", $val );
			}
			else
			{
				printf( $format, $val );
			}
			$off += $size;
		}
		else
		{
			printf " %-6s ", "hex1";
			while	( $off < $SIZE && ! defined $type[$off] )
			{
				printf " %02x", ord substr( $set, $off, 1 );
				$off++;
				last if ($off & 15) == 0;
			}
		}
		printf "\t# %s", $desc if $desc;
		printf "\n";
	}
}

sub	error ()
{
	printf STDERR @_;
	printf STDERR "\n";
	exit 1;
}

sub	check_type ()
{
	my ($type) = @_;
	my ($size, $templ, $format);

	if	( $type =~ /1$/ )
	{
		$size = 1;
		$templ = "C";
	}
	elsif	( $type =~ /2$/ )
	{
		$size = 2;
		$templ = "n";
	}
	else
	{
		$size = 4;
		$templ = "N";
	}
	if	( $type =~ /^dec/ )
	{
		$format = "%10d";
	}
	else
	{
		$format = "  %8x";
	}
	return ($size, $templ, $format);
}

sub	decode_color ()
{
	my ($code) = @_;
	my ($T, $R, $G, $B);
	my ($Y, $U, $V);

	if	( $code == 0 )
	{
		$T = $R = $G = $B = 0;
	}
	else
	{
		$T = (($code >> 6) & 3) + 1;
		$Y = ($code >> 16) & 0x3f;
		$U = ($code >>  8) & 0x3f;
		$V = ($code >>  0) & 0x3f;
		($R, $G, $B) = &yuv_to_rgb($Y, $U, $V);
	}
	return ($T, $R, $G, $B);
}

sub	encode_color ()
{
	my ($T, $R, $G, $B) = @_;
	my ($Y, $U, $V);
	my ($code);

	if	( $T == 0 )
	{
		$code = 0;
	}
	else
	{
		($Y, $U, $V) = &rgb_to_yuv($R, $G, $B);
		$code = ($T - 1) * 0x40404040;
		$code |= $Y << 24;
		$code |= $Y << 16;
		$code |= $U <<  8;
		$code |= $V;
	}
	return $code;
}

sub	rgb_to_yuv ()
{
	my ($R, $G, $B) = @_;
	my ($Y, $U, $V);

	# standard RGB to YUV transformation:
	$Y = 0.299 * $R + 0.587 * $G + 0.114 * $B;
	$U = 0.493 * ($B - $Y);
	$V = 0.877 * ($R - $Y);
	# correction:
	$Y = 236/256 * $Y + 12;
	$U = 272/256 * $U + 128;
	$V = 196/256 * $V + 128;
	# scale down to 6 bits resolution:
	$Y = int( $Y / 4 + 0.5 );
	$U = int( $U / 4 + 0.5 );
	$V = int( $V / 4 + 0.5 );

	return ($Y, $U, $V);
}

sub	yuv_to_rgb ()
{
	my ($Y, $U, $V) = @_;
	my ($R, $G, $B);

	$Y = (4 * $Y - 12)  / (236/256);
	$U = (4 * $U - 128) / (272/256);
	$V = (4 * $V - 128) / (196/256);

	$R = $Y + $V / 0.877;
	$G = $Y - $U * 0.394 - $V * 0.581;
	$B = $Y + $U / 0.493;

	$R = int( $R + 0.5 );
	$G = int( $G + 0.5 );
	$B = int( $B + 0.5 );

	$R = 0 if $R < 0;
	$G = 0 if $G < 0;
	$B = 0 if $B < 0;
	$R = 255 if $R > 255;
	$G = 255 if $G > 255;
	$B = 255 if $B > 255;

	return ($R, $G, $B);
}

#======================================================================#
# settings file layout
#======================================================================#
__END__
000	hex	"DVSO"
008	dec2	2 * channel delay
00e	hex1	Serial speed (19200=0x0c, 38400=0x0d)
012	dec1	Data Download: BIN/ASCII/HEX
013	dec1	Data Download - Mode: 0..6
017	dec1	Data Download: normal/test mode/single
018	dec	LNB 1 - LOF 1
01c	dec	LNB 1 - LOF 2
020	dec	LNB 1 - SWT
024	dec	LNB 4 - CBand LOF
028	dec	key delay
02c	dec	key repeat
032	dec4	Data Download - Buffer
036	hex1	SAT: off/auto
038	hex1	VCR: off/auto
03a	hex1	Priority: SAT/VCR
040	dec2	current TV channel (0-based)
042	dec2	current Radio channel (0-based)
044	dec1	volume left (0..128)
046	dec1	volume right (0..128)
047	dec1	LNB control (0=DiSEqC, 1=12v)
048	dec2	2 * volume delay
04b	dec1	TV key: normal/OFF
04e	dec2	2 * volume slider position
050	color	?
054	color	?
058	color	?
05c	color	?
060	color	?
064	color	?
068	color	?
06c	color	?
070	color	?
074	color	?
078	color	?
07c	color	?
080	color	?
084	color	?
088	color	?
08c	color	?
091	dec1	positioner: LNB 1..4 enable (bits 00..3)
092	dec2	positioner: type DiSEqC/VSEC
096	dec2	2 * mute picture position
098	hex1	CAM enable (00=off, ff=on)
09e	dec2	2 * channel position PAL
0a2	dec1	Channel font: big/small
0ae	dec1	RGB out: ON/KILL
0af	hex1	Nr. Browse: 00=off, ff=on
0b0	dec1	cinch menu - 12V: (0..4)
0b1	dec1	Mode dec/enc: PAL/NTSC (bit 0: dec, bit 1: enc)
0b2	dec1	LNB at +0.5V/+0.0V 
0b3	dec1	Scroll mode (0..2)
0b4	dec1	TT Character set (0..3)
0b5	dec1	TT subtitles enable (0..1)
0b7	dec1	LNB is off/normal
0bc	hex1	tracking: bit0=audio, bit1=signal
0be	dec1	CAM mode (0=normal, 1=SCT disable)
0c0	color	tv channel list foreground
0c4	color	tv channel list background
0c8	color	expert menu foreground
0cc	color	expert menu background
0d8	color	subtitle background
0dc	dec1	display dim normal	
0dd	dec1	display dim standby	
0de	dec1	cinch menu - 12V standby: Low/High
0df	dec1	cinch menu - 12V SAT: --/Low/High
0e0	dec2	video position - horizontal
0e2	hex1	positioner: DiSEqC address
0e3	dec1	SCART menu - pin 8 SAT: 12V/6V/0V
0e4	dec1	SCART menu - pin 8 VCR: 12V/6V/0V
0e5	dec1	SCART menu - pin 8 DIG: 12V/6V/0V
0e6	dec1	clock adjust
0e8	dec1	SCART menu - standby default: --/SAT/VCR
0e9	dec1	cinch menu - 12V VCR: --/Low/High
0ef	hex1	Encoder 71xx - Burst Ampl
0f4	hex1	DiSEqC Menu - DiSEqC Adr
0f7	dec1	LNB short warning: on/off
0f8	dec1	display: freq/names
0fe	dec1	channel/global mode
0ff	dec1	C-Band LNB: 1/2/3/4/-
100	dec	DiSEqC Menu - Bit 0: Low/High/Band
101	dec1	DiSEqC Menu - 22KHz: Band/High/Low
102	dec1	video output (0=RGB, 1=Cr/Y/Cb, 2=S-Video, 3=CVBS)
103	dec1	Encoder 71xx - Gain U
104	dec1	Encoder 71xx - Gain V
105	dec1	DiSEqC Menu - Burstmode off/on
106	dec1	DiSEqC Menu - Bit 1: Low/High/Pol.
109	dec1	intro mode (0=none, 1=default, 2=other)
10b	hex1	Powerup: bit0=auto/run bit1=mode1/mode2
10c	dec1	event info: none, current, current/next
116	dec1	LNB ext. OFF/ON
117	dec1	up/down swap
118	color	Volume slider background
11c	color	Volume slider border
120	color	Volume slider
124	color	EPG background
128	color	EPG header line
12c	color	EPG text
130	color	TT black
134	color	TT red
138	color	TT green
13c	color	TT yellow
140	color	TT blue
144	color	TT magenta
148	color	TT cyan
14c	color	TT white
150	color	?
154	color	radio channel list background
158	dec1	LNB 1 14/18v (0=Polar, 1=low, 2=high, 3=band)
15a	dec1	LNB 2 14/18v (0=Polar, 1=low, 2=high, 3=band)
15c	dec1	LNB 3 14/18v (0=Polar, 1=low, 2=high, 3=band)
15e	dec1	LNB 4 14/18v (0=Polar, 1=low, 2=high, 3=band)
3ee	dec2	clock tune
3f0	dec	menu position - horizontal
3f4	dec	menu/channel position - vertical
3f8	dec	channel position - horizontal
3fe	dec1	radio mode (0=mode1, 1=mode2)
3ff	dec1	tv/radio (0=tv, 1=radio)
400	color	menu background
404	color	title bar background
408	color	?
40c	color	?
410	color	menu left
414	color	menu title
418	color	?
41c	color	?
420	color	menu foreground
424	color	title foreground
428	color	?
42c	color	?
430	color	?
434	color	?
438	color	?
43c	color	signal bar
440	hex2	parental lock (hex)
444	dec	LNB 2 - LOF 1
448	dec	LNB 2 - LOF 2
44c	dec	LNB 3 - LOF 1
450	dec	LNB 3 - LOF 2
454	dec	LNB 2 - SWT
458	dec	LNB 3 - SWT
45e	dec2	2 * channel position NTSC
4ea	dec1	Status: Grafic/Text
4f0	end	end
