#!/usr/bin/perl -w use FileHandle; use Time::HiRes; # Changes: # 2006-08-04 added arrow if displayed string is too long # 2006-08-11 improved line breaks and stream name removal system ("stty -F /dev/ttyS0 9600 -ocrnl -onlcr -onlret"); open (SERIAL, ">/dev/ttyS0") || die ("Could not open serial port: $!\n"); autoflush SERIAL 1; $oldpos = -2; $oldstatus = 23; $oldtitle = "Blubb"; while (1) { ($status, $time, $bitrate, $channels, $pos, $len, $title) = GetInfo (); if ($status == 2) { # stopped $title = ""; } if ($len > 0) { $pos = int ((51 / $len) * $pos); } else { $pos = -1; } if ($oldtitle ne $title) { LCDInit (1); LCDInit (2); LCDChars (1); LCDCmd (0x01, 1); LCDCmd (0x01, 2); LCDCmd (0x80 + 2, 1); if ($status != 2) { if ($len > 0) { while (length ($time) < 6) { $time = " $time"; } LCDSend ($time, 1); } else { LCDSend (" N/A "); } LCDSend (sprintf (" %3dk", $bitrate), 1); if ($channels == 1) { LCDSend (" MO ", 1); } else { LCDSend (" ST ", 1); } $message = $title; $message = strip ($message); if ($len < 0) { # remove stream name $closing = rindex ($message, ")"); $opening = rindex ($message, "(", $closing - 1); if (($opening > -1) and ($closing > -1)) { $closing_new = $closing; while (1) { $closing_new = rindex ($message, ")", $closing_new - 1); if ($closing_new > $opening) { $opening_new = rindex ($message, "(", $opening - 1); if ($opening_new > -1) { $opening = $opening_new; } else { last; } } else { last; } } substr ($message, $opening, $closing - $opening + 1) = ""; } } $message = strip ($message); LCDCmd (0xC0, 1); LCDSend (LCDLine (27, 1), 1); LCDCmd (0x80, 2); LCDSend (LCDLine (27, 1), 2); LCDCmd (0xC0, 2); LCDSend (LCDLine (27, 0), 2); if (length ($message) > 0) { LCDCmd (0xC0 + 25, 2); LCDChr (0x20, 2); LCDChr (0x7E, 2); } } $oldstatus = 23; $oldtitle = $title; $oldpos = -2; } if ($status != $oldstatus) { LCDCmd (0x80, 1); LCDChr ($status, 1); $oldstatus = $status; } if ($pos != $oldpos) { $newpos = $pos; LCDCmd (0x80 + 17, 1); if ($pos >= 0) { for ($num = 0; $num < 10; $num++) { if ($newpos >= 5) { LCDChr (255, 1); $newpos -= 5; } elsif ($newpos == 0) { LCDChr (32, 1); } else { LCDChr ($newpos + 2, 1); $newpos = 0; } } } else { LCDSend (" "); } $oldpos = $pos; } sleep (1); } # initialize the LCD sub LCDInit { my($ctrl, $val); ($ctrl) = @_; print (SERIAL chr (0x80 + 25)); # contrast $val = 0; if($ctrl == 2) { $val = 0x40; } print (SERIAL chr (0x03 | $val)); Time::HiRes::usleep (10*1000); print (SERIAL chr (0x03 | $val)); Time::HiRes::usleep (15*1000); print (SERIAL chr (0x03 | $val)); print (SERIAL chr (0x02 | $val)); LCDCmd (0x2A, $ctrl); LCDCmd (0x01, $ctrl); Time::HiRes::usleep (15*1000); LCDCmd (0x02, $ctrl); Time::HiRes::usleep (15*1000); LCDCmd (0x06, $ctrl); LCDCmd (0x0C, $ctrl); } # initialize custom characters sub LCDChars { my ($ctrl); ($ctrl) = @_; LCDCmd (0x40, $ctrl); LCDChr (0x10, $ctrl); # 0 = play LCDChr (0x18, $ctrl); LCDChr (0x1C, $ctrl); LCDChr (0x1E, $ctrl); LCDChr (0x1C, $ctrl); LCDChr (0x18, $ctrl); LCDChr (0x10, $ctrl); LCDChr (0x00, $ctrl); LCDChr (0x00, $ctrl); # 1 = pause LCDChr (0x1B, $ctrl); LCDChr (0x1B, $ctrl); LCDChr (0x1B, $ctrl); LCDChr (0x1B, $ctrl); LCDChr (0x1B, $ctrl); LCDChr (0x00, $ctrl); LCDChr (0x00, $ctrl); LCDChr (0x00, $ctrl); # 2 = stop LCDChr (0x1F, $ctrl); LCDChr (0x1F, $ctrl); LCDChr (0x1F, $ctrl); LCDChr (0x1F, $ctrl); LCDChr (0x1F, $ctrl); LCDChr (0x00, $ctrl); LCDChr (0x00, $ctrl); LCDChr (0x10, $ctrl); # 3 = progress block 1px LCDChr (0x10, $ctrl); LCDChr (0x10, $ctrl); LCDChr (0x10, $ctrl); LCDChr (0x10, $ctrl); LCDChr (0x10, $ctrl); LCDChr (0x10, $ctrl); LCDChr (0x10, $ctrl); LCDChr (0x18, $ctrl); # 4 = progress block 2px LCDChr (0x18, $ctrl); LCDChr (0x18, $ctrl); LCDChr (0x18, $ctrl); LCDChr (0x18, $ctrl); LCDChr (0x18, $ctrl); LCDChr (0x18, $ctrl); LCDChr (0x18, $ctrl); LCDChr (0x1C, $ctrl); # 5 = progress block 3px LCDChr (0x1C, $ctrl); LCDChr (0x1C, $ctrl); LCDChr (0x1C, $ctrl); LCDChr (0x1C, $ctrl); LCDChr (0x1C, $ctrl); LCDChr (0x1C, $ctrl); LCDChr (0x1C, $ctrl); LCDChr (0x1E, $ctrl); # 6 = progress block 4px LCDChr (0x1E, $ctrl); LCDChr (0x1E, $ctrl); LCDChr (0x1E, $ctrl); LCDChr (0x1E, $ctrl); LCDChr (0x1E, $ctrl); LCDChr (0x1E, $ctrl); LCDChr (0x1E, $ctrl); LCDCmd (0x80, $ctrl); } # send a line to the LCD sub LCDSend { my ($line, $ctrl, $len, $num, $char); ($line, $ctrl) = @_; $len = length($line); for ($num = 0; $num < $len; $num++) { $char = ord (substr ($line, $num, 1)); LCDChr ($char, $ctrl); } } # send a command to the LCD sub LCDCmd { my ($cmd, $ctrl, $cmd1, $cmd2); ($cmd, $ctrl) = @_; $cmd1 = $cmd / 16; $cmd2 = $cmd % 16; if ($ctrl == 2) { $cmd1 += 0x40; $cmd2 += 0x40; } print (SERIAL chr($cmd1), chr($cmd2)); } # send a character to the LCD sub LCDChr { my ($char, $ctrl, $cmd1, $cmd2); ($char, $ctrl) = @_; $cmd1 = $char / 16 + 0x10; $cmd2 = $char % 16 + 0x10; if ($ctrl == 2) { $cmd1 += 0x40; $cmd2 += 0x40; } print (SERIAL chr($cmd1), chr($cmd2)); } # return the first <= 27 chars of $message, splitting at spaces if possible sub LCDLine { my($end, $line, $len, $space); ($len, $space) = @_; if(length($message) <= $len) { $line = $message; $message = ""; } else { $end = rindex($message, " ", $len); if (($end > -1) and ($space != 0)) { $line = substr($message, 0, $end); $message = substr($message, $end + 1); } else { $line = substr($message, 0, $len); $message = substr($message, $len); } } return $line; } # return currently playing title from XMMS info file sub GetInfo { my (@info, $line, $title, $status, $pos, $len, $time, $channels, $bitrate); open (DATA, "/tmp/xmms-info") || return (2, "0:00", 128, 2, 0, -1, "Could not open /tmp/xmms-info: $!"); @info = ; close (DATA); $title = ""; $pos = 0; $len = -1; $time = "0:00"; $channels = 2; $bitrate = 128; foreach $line (@info) { chomp ($line); if ($line =~ /^Title: /) { $title = substr ($line, 7); $title =~ s/^Title: //; } elsif ($line =~ /^Status: /) { if ($line =~ /Playing/) { $status = 0; } elsif ($line =~ /Paused/) { $status = 1; } elsif ($line =~ /Stopped/) { $status = 2; } } elsif ($line =~ /^uSecPosition: /) { $pos = substr ($line, 14); } elsif ($line =~ /^uSecTime: /) { $len = substr ($line, 10); } elsif ($line =~ /^Time: /) { $time = substr ($line, 6); } elsif ($line =~ /^Current bitrate: /) { $bitrate = substr ($line, 17) / 1000; } elsif ($line =~ /^Channels: /) { $channels = substr ($line, 10); } } return ($status, $time, $bitrate, $channels, $pos, $len, $title); } # remove trailing \n and leading and trailing spaces sub strip { my ($text) = @_; chomp ($text); while ($text =~ s/^ //) { } while ($text =~ s/ $//) { } return ($text); }