###################################################################### # Cajun display manager/audio player # Copyright (c) 1999 Paul Bournival Jr. under the GNU Public License # # CajunSGX120L.pm 11 Jan 00 hm Rev 3.0 origination ###################################################################### package CajunSGX120L; require Exporter; use POSIX qw(:termios_h); use IPC::Open2; use Symbol; @ISA=qw(Exporter); @EXPORT=qw(); @EXPORT_OK=qw(); $esc=sprintf("%c",0xfe); $spaces=" " x 80; sub new { my $self={}; bless $self,"CajunSGX120L"; my($junk); ($junk,$cajun)=@_; # param not used $self->{cajun}=$cajun; # for later reference.. $self->{width}=20; $self->{height}=4; $self->{line1}=$self->{line2}=$self->{line3}=$self->{line4}=""; $self->{readh}=Symbol::gensym(); $self->{writeh}=Symbol::gensym(); open($self->{writeh},"+>$cajun->{config}{dispport}") or die "failed to open serial port"; $self->{readh}=$self->{writeh}; $fd_disp=fileno($self->{writeh}); $termios = POSIX::Termios->new(); $termios->getattr($fd_disp); $termios->setispeed(B9600); $termios->setospeed(B9600); $c_cflag = $termios->getcflag(); $c_lflag = $termios->getlflag(); $c_oflag = $termios->getoflag(); $c_iflag = $termios->getiflag(); # set raw ####################################################################### $c_iflag &= ~(BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF); $c_iflag &= ~(IUCLC|IXANY|IMAXBEL); $c_iflag |= IGNBRK; $c_oflag &= ~(OPOST|OLCUC|OCRNL|ONLCR|ONOCR|ONLRET|OFILL|OFDEL); $c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN|ECHOE|ECHOK|NOFLSH|XCASE); $c_lflag &= ~(TOSTOP|ECHOPRT|ECHOCTL|ECHOKE); $c_cflag &= ~(CSIZE|PARENB|PARODD|HUPCL|CSTOPB|CRTSCTS); $c_cflag |= CS8|CLOCAL|IXON|IXANY|CREAD; ####################################################################### $termios->setcflag($c_cflag); $termios->setlflag($c_lflag); $termios->setoflag($c_oflag); $termios->setiflag($c_iflag); $termios->setattr($fd_disp,TCSANOW); binmode $self->{writeh}; select($self->{writeh}); $|=1; select(STDOUT); my($writeh)=$self->{writeh}; print $writeh sprintf( "%c", 12 ); # clear & home cursor # print $writeh sprintf( "%c", 4 ); # hide cursor # print $writeh sprintf( "%c", 14 ); # backlight ON $self->backlight_on; $self; } sub backlight_on { my($self)=@_; my($writeh)=($self->{writeh}); print $writeh sprintf("%c", 14 ); } # The SGX120L does not handle automatic backlight off. We need to # provide this. We should start a background process which select()s # stdin (started w/ fork(), inherits $self->{writeh}), write ON on # refresh, restarts counter, timeout backlight off. sub backlight_off { my($self)=@_; my($writeh)=($self->{writeh}); print $writeh sprintf("%c", 15 ); } sub display_scroll { my($self,@lines)=@_; $self->line(1,$lines[0]); $self->line(2,$lines[1]); $self->line(3,$lines[2]); $self->line(4,$lines[3]); $self->refresh; } sub display_welcome { my($self)=@_; my($writeh)=$self->{writeh}; if ( 1 == 0 ) { # create custom characters for spelling big "CAJUN" on welcome screen. print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c", # 128 0x00,0x00,0x00,0x03,0x07,0x07,0x0e,0x0e,0x0e); print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c", # 129 0x01,0x00,0x00,0x1f,0x1f,0x1f,0x00,0x00); print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c", # 130 0x02,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e); print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c", # 131 0x03,0x0e,0x0e,0x07,0x07,0x03,0x00,0x00); print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c", # 132 0x04,0x0e,0x0e,0x1c,0x1c,0x18,0x00,0x00); print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c", # 133 0x05,0x00,0x00,0x18,0x1c,0x1c,0x0e,0x0e,0x0e); print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c", # 134 0x06,0x0e,0x0e,0x0e,0x0e,0x0e,0x00,0x00,0x00); print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c", # 135 0x07,0x00,0x00,0x0e,0x0e,0x0e,0x0e,0x0e,0x0e); $self->line(1, sprintf( "%c%c%c %c%c%c %c %c %c %c%c%c", 128, 129, 133, 128, 129, 133, 135, 135, 135, 128, 133, 135 )); $self->line(2, sprintf( "%c %c%c%c %c %c %c %c%c%c", 130, 130, 129, 130, 130, 130, 130, 130, 130, 130 )); $self->line(3, sprintf( "%c%c%c %c %c %c%c%c %c%c%c %c%c%c", 131, 129, 132, 134, 134, 131, 129, 132, 131, 129, 132, 134, 131, 132 )); $self->line(4,"Car Audio Jukebox v3.0"); $self->refresh; } else { $self->line(1,$self->center("Cajun v3.0")); $self->line(2,$self->center("Car Audio Jukebox")); $self->line(3,$self->center("(c) 1999")); $self->refresh; } } sub display_shuffle { my($self,$shoutcast)=@_; my($shoutcaststr)=($shoutcast ? "7) URL" : " "); $self->line(1,"1) All 5) Jazz"); $self->line(2,"2) Playlist 6) Slow"); $self->line(3,"3) Rock $shoutcaststr"); $self->line(4,"4) Pop"); $self->refresh; } sub display_play { my($self,$cajun)=@_; if ($cajun->{audiodev}->{state}==1) { # stopped... yuk! $self->line(1,$self->center("--Stopped--")); map { $self->line($_," " x $self->{width}); } (2..4); $self->refresh; } else { my($art,$title,$song,$off,$clock,$percent,$triple,$cur,$ttl); # ML: If the song name contains a newline, it must be a stream. if ($cajun->{playlist}[$cajun->{playsong}] =~ /\n/) { ($ip,$description,$bitrate,$listeners,$avlisten,$uptime) = split("\n",$cajun->{playlist}[$cajun->{playsong}]); $file="http://" . $ip; $art=$ip; $title=$description; $song=" Bitrate:" . $bitrate . " Listeners:" . $listeners . " Av. listen time:" . $avlisten . " Uptime:" . $uptime; } else { ($file,$triple)=split("\0",$cajun->{playlist}[$cajun->{playsong}]); ($art,$title,$song)=split("/",$triple); $art=Cajun::file2song($art); # remove leading numbers $title=Cajun::file2song($title); # remove leading numbers $song=Cajun::file2song($song); # remove leading numbers } $cur=$cajun->{playsong}+1; $ttl=scalar(@{ $cajun->{playlist} }); if ($cajun->{state_clock} eq "00:00:00") { $song_scroll = sprintf("%s ", $song); } # increment the counters if necessary. if ($cajun->{config}{scrollinterval}) { $cajun->{scrollcounter1}++; $cajun->{scrollcounter1}=0 if $cajun->{scrollcounter1}>length($art)-$self->{width}; $cajun->{scrollcounter2}++; $cajun->{scrollcounter2}=0 if $cajun->{scrollcounter2}>length($title)-$self->{width}; # $cajun->{scrollcounter3}++; # $cajun->{scrollcounter3}=0 if $cajun->{scrollcounter3}>length($song_scroll)-$self->{width}; $art=substr($art,$cajun->{scrollcounter1}); $title=substr($title,$cajun->{scrollcounter2}); $song_scroll=sprintf("%s%s", substr($song_scroll, 1,length($song_scroll)), substr($song_scroll, 0, 1)); # substr($song_scroll,$cajun->{scrollcounter3}); } $clock=$cajun->{state_clock} ne "" ? $cajun->{state_clock} : "00:00:00"; $clock=substr($clock,3); # chop the hours from the display if ($cajun->{state_range}>0) { $percent=int($cajun->{state_offset}/$cajun->{state_range}*100); } else { $percent=0; } $self->line(1,$self->center(sprintf("$clock %02d%% %d/%d",$percent, $cur,$ttl))); $self->line(2,$self->center($art)); $self->line(3,$self->center($title)); $self->line(4,$self->center($song_scroll)); $self->refresh; } } sub display_menu { my($self,$fmcard,$cdplayer)=@_; my($fmstr)=($fmcard ? "8) Radio" : " "); my($cdstr)=($cdplayer ? "5) CDAudio" : " "); $self->line(1,"1) Play $cdstr"); $self->line(2,"2) Utils 6) Playlst"); $self->line(3,"3) Shuffle *) SongUtl"); $self->line(4,"4) HotList $fmstr"); $self->refresh; } sub display_util { my($self)=@_; $self->line(1,"1) Stats 5) EQ "); $self->line(2,"2) Mount Media "); $self->line(3,"3) Password "); $self->line(4,"4) Contrast "); $self->refresh; } sub display_contrast { my($self)=@_; $self->line(1,$self->center("Use 1/3 to change")); $self->line(2,$self->center("Current setting:")); $self->line(3,$self->center($self->{cajun}->{config}{contrast})); $self->line(4,""); $self->refresh; } sub display_password { my($self)=@_; } sub display_cdaudio { my($self,$msg)=@_; my ($s1,$s2)=$self->{cajun}->{cdplayer}->status(); $self->line(1,""); $self->line(2,$self->center($s1)); $self->line(3,$self->center($s2)); $self->line(4,""); $self->refresh; } sub display_eq { my($self,$b,$v,$t)=@_; my($writeh)=($self->{writeh}); if ( $self->{cajun}->{config}{mixer} eq "braindead" ) { $self->line(1," Volume:"); $self->line(2," "); $self->line(3," "); $self->line(4," "); $self->refresh; print $writeh sprintf( "%c%c%c%c%c%c%c", 18, 0, 60, 9, 19, $v/2, 0 ); } else { $self->line(1," Treble:"); $self->line(2," Volume: "); $self->line(3," Bass:"); $self->line(4," "); $self->refresh; print $writeh sprintf( "%c%c%c%c%c%c%c", 18, 0, 60, 9, 19, $t/2, 0 ); print $writeh sprintf( "%c%c%c%c%c%c%c", 18, 1, 60, 9, 19, $v/2, 1 ); print $writeh sprintf( "%c%c%c%c%c%c%c", 18, 2, 60, 9, 19, $b/2, 2 ); } } sub display_mount { my($self,@mounts)=@_; my(@list); for $mount (@mounts) { ($part,$name,$stat)=split(":",$mount); push(@list,"$stat $name"); } $self->line(1,"1) Statistics "); $self->line(2,"2) Removable Media "); $self->line(3," "); $self->line(4," "); $self->refresh; } sub display_shutdown { my($self)=@_; $self->line(1,$self->center("Press '#' to shutdown,")); $self->line(2,$self->center("Any other to return")); $self->line(3,$self->center("to the main menu")); $self->line(4,""); $self->refresh; } # ML: I will also work on displaying CD's/Tracks per partition sub display_statistics { my($self,$partition_data)=@_; ($partition,$name)=split(":",$partition_data); open(DF,"df -h $partition|"); @lines=; close(DF); $stats=($lines[1]); ($df_filesystem,$df_size,$df_used,$df_available,$df_capacity,$df_mountpoint)=split(/\s+/,$stats); $self->line(1,"$name"); $self->line(2,"Size:$df_size Used:$df_used"); $self->line(3,"Free:$df_available $df_capacity full"); $self->line(4,"Press '0' to continue..."); $self->refresh; } sub display_stream { my ($self)=@_; $self->line(1,"1) Choose genre"); $self->line(2,"2) Choose station"); $self->line(3,""); $self->line(4,""); $self->refresh; } sub display_radio { my($self,$msg)=@_; my($writeh)=$self->{writeh}; # print $writeh sprintf( "%c", 25 ) . sprintf("%c%c%c%c%c%c%c%c%c", # 0x00,0x01,0x02,0x04,0x02, # 0x14,0x18,0x1c); my ($freq)=$self->{cajun}->{radiodev}->currfreq; my ($station)=$self->{cajun}->{radiodev}->getstation; my ($scanmode)=$self->{cajun}->{radiodev}->readmode; my ($seek_flag)=$self->{cajun}->{radiodev}->seekflag; if ($seek_flag eq "SK") { $seek_flag = "\0"; } $self->line(1,"FM $seek_flag"); $self->line(2,"Freq: $freq Mhz M-$station"); $self->line(3,"Mode: $scanmode"); $self->line(4,""); $self->refresh; } sub display_radioda { my($self,$msg)=@_; my ($freq)=$self->{cajun}->{radiodev}->{dafreq}; my ($scanmode)=$self->{cajun}->{radiodev}->readmode; my ($seek_flag)=$self->{cajun}->{radiodev}->seekflag; $self->line(1,"FM $seek_flag"); $self->line(2,"Freq: $freq Mhz M-$station"); $self->line(3,"Mode: $scanmode"); $self->line(4,$self->center("Enter Frequency")); $self->refresh; } # # message: if sleeptime==0, the previous screen won't be restored. # sub message { my($self,$message,$sleeptime)=@_; my($word,@words,$cc,$cl); my(@sv)=($self->{line1},$self->{line2},$self->{line3},$self->{line4}); ($self->{line1},$self->{line2},$self->{line3},$self->{line4})=("","","",""); $cc=0; $cl=1; for $word (split(" ",$message)) { if ($cc+length($word) > $self->{width}) { $cc=0; $cl++; } $self->{"line$cl"} .= $word . " "; $cc+=length($word)+1; } $self->refresh; sleep($sleeptime); # if time to sleep is 0, assume user wants to leave msg on screen. if ($sleeptime>0) { ($self->{line1},$self->{line2},$self->{line3},$self->{line4})=@sv; $self->refresh; } } sub line { my($self,$lineno,$msg)=@_; $msg=substr($msg . (" " x ($self->{width}+1)),0,$self->{width}); $self->{"line$lineno"}="$msg"; } sub refresh { my($self)=@_; my($str); my($writeh)=$self->{writeh}; print $writeh sprintf( "%c", 0x01 ); # home cursor for $row (1..4) { if ($self->{"line$row"} ne $self->{"cline$row"}) { $self->{"cline$row"}=$self->{"line$row"}; # Ctrl-P, pos, SPC, Text print $writeh sprintf( "%c%s ", 0x10, ($row - 1) * $self->{width}) . substr( $self->{"cline$row"} . $spaces,0,$self->{width} ); } } } sub center { my($self,$str)=@_; $str =~ s/ *$//; $str =~ s/^ *//; my($left)=($self->{width}-length($str)); my($extra)=" " x (int($left/2)); substr($extra . $str . $extra . " ",0,$self->{width}); } sub DESTROY { close($self->{writeh}); } 1;