#!/usr/bin/perl

# simple read operation against waterkotte with control 'resümat cd4 (8126)'
# (c) 2009 alexander.philipp.lintenhofer
#

use strict;
use Device::SerialPort;
use POSIX qw(floor);

#####################################################################################################
if ($#ARGV != 0) { die "Usage: $0 <attribute>\n"; }
my $attr = $ARGV[0];

use constant TYPE_UNDEF     => 0;
use constant TYPE_DATE      => 1;
use constant TYPE_TIME      => 2;
use constant TYPE_DATETIME  => 3;
use constant TYPE_DEC       => 4;
use constant TYPE_FLOAT1    => 5;
use constant TYPE_FLOAT3    => 6;
use constant TYPE_BIN       => 7;
use constant TYPE_BOOL      => 8;
use constant TYPE_SPECI     => 9;

use constant DLE         => 0x10;
use constant STX         => 0x02;
use constant ETX         => 0x03;

my  @frame;
our %wp_memory;

require('WPmemaddr.inc.pl');
require('WPhelperfunctions.inc.pl');

#####################################################################################################
#####################################################################################################
# main
#

@frame = buildFrame($attr);

for (my $attempt=0; $attempt<5;$attempt++)
{
    if ((scalar(@frame) > 10)&&(my $serial = Device::SerialPort->new("/dev/ttyr00",0,'/tmp/wp_op.lock')))
    {
        $serial->baudrate(9600);
        $serial->parity("none");
        $serial->databits(8);
        $serial->stopbits(1);
        $serial->write_settings || undef $serial;

        # frame contains bytes, but for serial->write we need a string
        if (($serial->write(pack("C*",@frame)))==scalar(@frame))
        {
            my @comdump;

            sleep 1;
            my ($count,$retVal) = $serial->read(16);

            if ($count > 10)
            {
                for(my $i=0; $i < length($retVal); $i++) { $comdump[$i] = ord(substr($retVal,$i,1)); }
                print interpretData(@comdump)."\n";
            }
            else { print STDERR "Read operation failed\n"; exit 1; }
        }
        else { print STDERR ("Error writing to rs232\n"); exit 1; }

        $serial->close() || print STDERR ("Close failed\n");
        exit 0;
    }
    sleep 2;
}
print STDERR ("Open failed\n"); exit 1;

#####################################################################################################
#####################################################################################################
# functions
#

#####################################################################################################
#####################################################################################################
# buildFrame()
# - builds command-frame according to selected attribute
#

sub buildFrame
{
    my $changeAttr = $_[0];

    if (defined($wp_memory{$changeAttr}))
    {
        ###########################################################################################
        # 1.) frame header, delimiter, start text
        @frame = (0xff,DLE,STX);

        ###########################################################################################
        # 2.) <cmdcode>
        push(@frame,(0x01,0x15));

        ###########################################################################################
        # 3.) <addr>
        push(my @bytes,(hex2bytearray($wp_memory{$attr}{addr},2)));

        ###########################################################################################
        # 4.) <length>
        push(@bytes,(hex2bytearray($wp_memory{$attr}{bytes},2)));

        # byte stuffing...
        my @stuffedBytes;
        for (my $i=0, my $j=0; $i<scalar(@bytes); $i++,$j++)
        {
            if ($bytes[$i]==16) { $stuffedBytes[$j]=16; $stuffedBytes[++$j]=16; }
            else { $stuffedBytes[$j]=$bytes[$i]; }
        }

        push(@frame,@stuffedBytes);

        ###########################################################################################
        # 5.) delimiter, end text
        push(@frame,(DLE,ETX));

        ###########################################################################################
        # 6.) CRC
        push(@frame,(0,0,0xff));
        my @crc = hex2bytearray(GetCRC16(@frame),2);
        @frame[(scalar(@frame)-3)] = $crc[0];
        @frame[(scalar(@frame)-2)] = $crc[1];

        return @frame;
    }
    else { print STDERR "Attribute not defined or not writeable\n"; return 0 }
}

#####################################################################################################
# interpretData():
# - interprets data bytes of frame
# - returns single result
#

sub interpretData
{
    my @comdump = @_;
    my @data = fetchFrameData(@comdump);
    my $type = $wp_memory{$attr}{type};
    my $currVal;

    if ($wp_memory{$attr}{bytes} == scalar(@data))
    {
        for(my $i=0;$i<$wp_memory{$attr}{bytes};$i++)
        {
            $currVal .= sprintf("%02x",$data[$i]);
        }

        if    ($type == TYPE_DEC)        { $currVal = hex($currVal); }
        elsif ($type == TYPE_FLOAT1)     { $currVal = hex2float1($currVal); }
        elsif ($type == TYPE_FLOAT3)     { $currVal = hex2float3($currVal); }
        elsif ($type == TYPE_DATE)       { $currVal = sprintf("%02d.%02d.%02d",hex(substr($currVal,0,2)),hex(substr($currVal,2,2)),hex(substr($currVal,4,2))); }
        elsif ($type == TYPE_TIME)       { $currVal = sprintf("%02d:%02d:%02d",hex(substr($currVal,4,2)),hex(substr($currVal,2,2)),hex(substr($currVal,0,2))); }
        elsif ($type == TYPE_DATETIME)   { $currVal = sprintf("%02d.%02d.%02d,%02d:%02d:%02d",hex(substr($currVal,6,2)),hex(substr($currVal,8,2)),hex(substr($currVal,10,2)),hex(substr($currVal,4,2)),hex(substr($currVal,2,2)),hex(substr($currVal,0,2))); }
        elsif ($type == TYPE_BIN)        { $currVal = sprintf("%08b",hex($currVal)); }
        elsif ($type == TYPE_BOOL)       { $currVal = (hex($currVal)==1)?1:0; }
        elsif ($type == TYPE_SPECI)
        {
            if ($wp_memory{$attr}{menu}=='00.02')   { $currVal = '3.2.3.1'; }
        }

        return $currVal;
    }
    else
    {
        print STDERR (localtime().": frame data size (".scalar(@data).") not equal to size of datatype (".$wp_memory{$attr}{bytes}.")\n");
        foreach (@comdump) { print STDERR $_.' '; }
        print STDERR "\n";
        return 0;
    }
}
