#!/usr/bin/perl -w
#
# parse/convert lirc config for NEC protocol for use w/ IRMP
#
# $Id: lirc2irmp.pl 245 2013-06-25 12:54:15Z schwenke $

use strict;
use IO::File;

if (@ARGV) {
    while (my $file = shift @ARGV) {
        my $fh = new IO::File $file, "r";
        process($fh);
    }
} else {
    my $fh = new IO::File "-";
    process($fh);
}

exit 0;


sub process
{
    my $fh = shift;
    while (my $line = <$fh>) {
        if ($line =~ /begin remote/o) {
            my $is_nec = 1;
            my $name;
            my $syscode;
            my %keycodes = ();
            while (my $line = <$fh>) {
                last if ($line =~ /end remote/o);
                next if ($line =~ /^#/o);
                next if ($line =~ /^\s*$/o);

                #scan the block of key codes
                if ($line =~ /begin codes/) {
                    while (my $line = <$fh>) {
                        last if ($line =~ /end codes/o);
                        chomp $line;
                        $line =~ s/^\s*//; #snip leading whitespace
                        $line =~ s/\s*$//; #snip trailing whitespace
                        $line =~ tr/\t /  /s; #compress whitespace
                        my ($key, $val) = split " ", $line, 2;
                        $keycodes{$key} = bitreverse(hex $val) & 0xff;
                    }
                }

                chomp $line;
                $line =~ s/^\s*//; #snip leading whitespace
                $line =~ s/\s*$//; #snip trailing whitespace
                $line =~ tr/\t /  /s; #compress whitespace
                my ($key, $val) = split " ", $line, 2;
                if ($key eq "name") {
                    $name = $val;
                }
                elsif ($key eq "bits") {
                    if ($val ne "16") {
                        warn "probably not NEC : '$line'";
                        $is_nec = 0;
                    }
                }
                elsif ($key eq "flags") {
                    if ($val ne "SPACE_ENC|CONST_LENGTH") {
                        warn "probably not NEC : '$line'";
                        $is_nec = 0;
                    }
                }
                elsif ($key eq "header") {
                    my ($a, $b) = split " ", $val;
                    unless (approx($a, 9000) && approx($b, 4500)) {
                        warn "probably not NEC : '$line'";
                        $is_nec = 0;
                    }
                }
                elsif ($key eq "one") {
                    my ($a, $b) = split " ", $val;
                    unless (approx($a, 560) && approx($b, 1690)) {
                        warn "probably not NEC : '$line'";
                        $is_nec = 0;
                    }
                }
                elsif ($key eq "zero") {
                    my ($a, $b) = split " ", $val;
                    unless (approx($a, 560) && approx($b, 565)) {
                        warn "probably not NEC : '$line'";
                        $is_nec = 0;
                    }
                }
                elsif ($key eq "repeat") {
                    my ($a, $b) = split " ", $val;
                    unless (approx($a, 9000) && approx($b, 2250)) {
                        warn "probably not NEC : '$line'";
                        $is_nec = 0;
                    }
                }
                elsif ($key eq "ptrail") {
                    unless (approx($val, 560)) {
                        warn "probably not NEC : '$line'";
                        $is_nec = 0;
                    }
                }
                elsif ($key eq "gap") {
                    unless (approx($val, 108000)) {
                        warn "probably not NEC : '$line'";
                        $is_nec = 0;
                    }
                }
                elsif ($key eq "toggle_bit") {
                    if ($val ne "0") {
                        warn "probably not NEC : '$line'";
                        $is_nec = 0;
                    }
                }
                elsif ($key eq "pre_data_bits") {
                    if ($val ne "16") {
                        warn "probably not NEC : '$line'";
                        $is_nec = 0;
                    }
                }
                elsif ($key eq "pre_data") {
                    $syscode = bitreverse(hex $val);
                }
            }

            if ($is_nec && defined $syscode && scalar %keycodes) {
                if (defined $name) {
                    printf "/* codes for remote control '%s' */\n", $name;
                }
                printf "#define MY_REMOTE_ID\t0x%04x\n", $syscode;
                for my $k (sort keys %keycodes) {
                    printf "#define KEY_%s\t0x%02x\n", $k, $keycodes{$k};
                }
            }
        }
    }
}

#
# reverse bits in a 16 bit integer
#
sub bitreverse
{
    my $in = shift;
    my $out = 0;
    for my $i (1..16) {
        $out *= 2;
        if ($in & 1) { $out += 1; }
        $in /= 2;
    }
    return $out;
}

#
# test if a value is within +/-20% of nominal
#
sub approx
{
    my $val = shift;
    my $target = shift;
    return ($val >= $target*0.8 && $val <= $target*1.2 ? 1 : 0);
}


