bcd_clock


#!/usr/bin/perl -w
#
# bcd_clock -- BCD clock
# for a hardware implementation:
# http://www.thinkgeek.com/homeoffice/lights/59e0/
#
use strict;
use Term::ReadKey;
use Term::ANSIScreen qw/:color :constants :cursor :screen/;
use integer;

#
# signal handlers
#
$SIG{INT}  = \&sighndl;
$SIG{TERM} = \&sighndl;
$SIG{CHLD} = 'IGNORE';

my $key;             # key pressed
my $sigtermed;       # signal terminated
my @digit_in_col;    # digit to be encoded in screen column
my @led;             # three-d array of boolean on/off for each LED
my $hr;              # current hour
my $min;             # current minute
my $sec;             # current second
my $row;             # screen row coordinate
my $col;             # screen column coordinate
my $prev;            # index of previous LED map
my $curr;            # index of current LED map
my $n;               # temporary variable
my $on;              # current LED on?

$| = 1;
screeninit();

ReadMode 4;          # raw

$curr = 0;

#
# avoiding uninitialized value warnings...
#
for ( $col = 2; $col <= 22; $col += 4 ) {
    for ( $row = 7; $row >= 1; $row -= 2 ) {
        $led[$curr][$row][$col] = 0;
    }
}

while ( !$sigtermed ) {

    #
    # switch frames
    #
    $curr = 1 - $curr;
    $prev = 1 - $curr;

    ( $sec, $min, $hr ) = localtime();

    #
    # We could get fancy with all sorts of mappings
    # between time values and LED screen locations. Let's not.
    #
    $digit_in_col[2]  = $hr / 10;
    $digit_in_col[6]  = $hr % 10;
    $digit_in_col[10] = $min / 10;
    $digit_in_col[14] = $min % 10;
    $digit_in_col[18] = $sec / 10;
    $digit_in_col[22] = $sec % 10;

    for ( $col = 2; $col <= 22; $col += 4 ) {
        locate( 9, $col );
        $n = $digit_in_col[$col];
        print $n;
        for ( $row = 7; $row >= 1; $row -= 2 ) {
            $led[$curr][$row][$col] = $on = ( $n & 1 );
            if ( $on != $led[$prev][$row][$col] ) {
                locate( $row, $col );
                print $on ? BLACK ON_RED " " : " ";
            }
            $n >>= 1;
        }
    }
    locate( 1, 1 );

    if ( defined( $key = ReadKey(-1) ) ) {    # keypress!
        last if ( $key eq "Q" || $key eq "q" );
    }
    sleep 1;
}
locate( 1, 1 );
cls;
ReadMode 0;
exit(0);

sub sighndl {
    my ($sig) = @_;
    $sigtermed = $sig;
}

sub screeninit {
    $Term::ANSIScreen::AUTORESET = 1;
    cls;
    locate( 1, 1 );
    print "    ( )     ( )     ( )";
    locate( 3, 1 );
    print "    ( ) ( ) ( ) ( ) ( )";
    locate( 5, 1 );
    print "( ) ( ) ( ) ( ) ( ) ( )";
    locate( 7, 1 );
    print "( ) ( ) ( ) ( ) ( ) ( )";
    locate( 9, 1 );
    print "       :       :       ";
}