|
@@ -0,0 +1,554 @@
|
|
|
+#!/usr/bin/perl
|
|
|
+# Ezkey.pm
|
|
|
+# Interface to the Alpha Sign Communications Protocol, EZ KEY II
|
|
|
+# See http://www.ams-i.com/Pages/97088061.htm
|
|
|
+#
|
|
|
+# The purpose of this interface is to objectify and simplify communication
|
|
|
+# with LED signs like the BetaBrite: http://betabrite.com/
|
|
|
+#
|
|
|
+# @author Matt Sparks
|
|
|
+package Ezkey;
|
|
|
+
|
|
|
+use strict;
|
|
|
+use Data::Dumper;
|
|
|
+use IO::Handle;
|
|
|
+use Date::Format;
|
|
|
+use POSIX qw/floor/;
|
|
|
+
|
|
|
+require Exporter;
|
|
|
+our @ISA = qw/Exporter/;
|
|
|
+our @EXPORT = qw/%modes %graphics %positions/;
|
|
|
+
|
|
|
+# Display Modes (p89)
|
|
|
+our %modes = (
|
|
|
+ "rotate" => "a",
|
|
|
+ "hold" => "b",
|
|
|
+ "flash" => "c",
|
|
|
+ "roll_up" => "e",
|
|
|
+ "roll_down" => "f",
|
|
|
+ "roll_left" => "g",
|
|
|
+ "roll_right" => "h",
|
|
|
+ "wipe_up" => "i",
|
|
|
+ "wipe_down" => "j",
|
|
|
+ "wipe_left" => "k",
|
|
|
+ "wipe_right" => "l",
|
|
|
+ "scroll" => "m",
|
|
|
+ "automode" => "o",
|
|
|
+ "roll_in" => "p",
|
|
|
+ "roll_out" => "q",
|
|
|
+ "wipe_in" => "r",
|
|
|
+ "wipe_out" => "s",
|
|
|
+ "compressed_rotate" => "t", # only available on certain sign models
|
|
|
+ "explode" => "u", # alpha 3.0 protocol
|
|
|
+ "clock" => "v", # alpha 3.0 protocol
|
|
|
+ # Special Modes
|
|
|
+ "twinkle" => "n0",
|
|
|
+ "sparkle" => "n1",
|
|
|
+ "snow" => "n2",
|
|
|
+ "interlock" => "n3",
|
|
|
+ "switch" => "n4",
|
|
|
+ "slide" => "n5", # only Betabrite 1036 (same as CYCLE_COLORS?)
|
|
|
+ "spray" => "n6",
|
|
|
+ "starburst" => "n7",
|
|
|
+ "welcome" => "n8",
|
|
|
+ "slot_machine" => "n9",
|
|
|
+ "news_flash" => "nA", # only Betabrite 1036
|
|
|
+ "trumpet_animation" => "nb", # only betabrite 1036
|
|
|
+ "cycle_colors" => "nC", # only AlphaEclipse 3600
|
|
|
+ # Special Graphics (these display before the message)
|
|
|
+ "thank_you" => "nS",
|
|
|
+ "no_smoking" => "nU",
|
|
|
+ "dont_drive_drink" => "nV",
|
|
|
+ "running_animal" => "nW",
|
|
|
+ "fish_animation" => "nW",
|
|
|
+ "fireworks" => "nX",
|
|
|
+ "turbo_car" => "nY",
|
|
|
+ "balloon_animation" => "nY",
|
|
|
+ "cherry_bomb" => "nZ",
|
|
|
+);
|
|
|
+
|
|
|
+# Display Positions
|
|
|
+our %positions = (
|
|
|
+ "middle_line" => "\x20",
|
|
|
+ "top_line" => "\x22",
|
|
|
+ "bottom_line" => "\x26",
|
|
|
+ "fill" => "\x30",
|
|
|
+ "left" => "\x31",
|
|
|
+ "right" => "\x32",
|
|
|
+);
|
|
|
+
|
|
|
+# Character Sets
|
|
|
+our %charsets = (
|
|
|
+ "five_high_std" => "1",
|
|
|
+ "five_stroke" => "2",
|
|
|
+ "seven_high_std" => "3",
|
|
|
+ "seven_stroke" => "4",
|
|
|
+ "seven_high_fancy" => "5",
|
|
|
+ "ten_high_std" => "6",
|
|
|
+ "seven_shadow" => "7",
|
|
|
+ "full_height_fancy" => "8",
|
|
|
+ "full_height_std" => "9",
|
|
|
+ "seven_shadow_fancy"=> ":",
|
|
|
+ "five_wide" => ";",
|
|
|
+ "seven_wide" => "<",
|
|
|
+ "seven_fancy_wide" => "=",
|
|
|
+ "wide_stroke_five" => ">",
|
|
|
+ # The following four only work on Alpha 2.0 and Alpha 3.0 protocols
|
|
|
+ "five_high_cust" => "W",
|
|
|
+ "seven_high_cust" => "X",
|
|
|
+ "ten_high_cust" => "Y",
|
|
|
+ "fifteen_high_cust" => "Z",
|
|
|
+);
|
|
|
+
|
|
|
+# Extended characters
|
|
|
+our %extchars = (
|
|
|
+ "up_arrow" => "\x64",
|
|
|
+ "down_arrow" => "\x65",
|
|
|
+ "left_arrow" => "\x66",
|
|
|
+ "right_arrow" => "\x67",
|
|
|
+ "pacman" => "\x68",
|
|
|
+ "sail_boat" => "\x69",
|
|
|
+ "ball" => "\x6A",
|
|
|
+ "telephone" => "\x6B",
|
|
|
+ "heart" => "\x6C",
|
|
|
+ "car" => "\x6D",
|
|
|
+ "handicap" => "\x6E",
|
|
|
+ "rhino" => "\x6F",
|
|
|
+ "mug" => "\x70",
|
|
|
+ "satellite_dish" => "\x71",
|
|
|
+ "copyright_symbol" => "\x72",
|
|
|
+ "male_symbol" => "\x73",
|
|
|
+ "female_symbol" => "\x74",
|
|
|
+ "bottle" => "\x75",
|
|
|
+ "diskette" => "\x76",
|
|
|
+ "printer" => "\x77",
|
|
|
+ "musical_note" => "\x78",
|
|
|
+ "infinity_symbol" => "\x79",
|
|
|
+);
|
|
|
+
|
|
|
+# Counters
|
|
|
+# We have 5 of them.
|
|
|
+our %counters = (
|
|
|
+ 1 => "z",
|
|
|
+ 2 => "{",
|
|
|
+ 3 => "|",
|
|
|
+ 4 => "}",
|
|
|
+ 5 => "-",
|
|
|
+);
|
|
|
+
|
|
|
+# Colors
|
|
|
+our %colors = (
|
|
|
+ "red" => "1",
|
|
|
+ "green" => "2",
|
|
|
+ "amber" => "3",
|
|
|
+ "dim_red" => "4",
|
|
|
+ "dim_green" => "5",
|
|
|
+ "brown" => "6",
|
|
|
+ "orange" => "7",
|
|
|
+ "yellow" => "8",
|
|
|
+ "rainbow_1" => "9",
|
|
|
+ "rainbow_2" => "A",
|
|
|
+ "color_mix" => "B",
|
|
|
+ "autocolor" => "C",
|
|
|
+);
|
|
|
+
|
|
|
+# Command Codes
|
|
|
+use constant {
|
|
|
+ WRITE_TEXT => "A", # Write TEXT file (p18)
|
|
|
+ READ_TEXT => "B", # Read TEXT file (p19)
|
|
|
+ WRITE_SPECIAL => "E", # Write SPECIAL FUNCTION commands (p21)
|
|
|
+ READ_SPECIAL => "F", # Read SPECIAL FUNCTION commands (p29)
|
|
|
+ WRITE_STRING => "G", # Write STRING (p37)
|
|
|
+ READ_STRING => "H", # Read STRING (p38)
|
|
|
+ WRITE_SMALL_DOTS => "I", # Write SMALL DOTS PICTURE file (p39)
|
|
|
+ READ_SMALL_DOTS => "J", # Read SMALL DOTS PICTURE file (p41)
|
|
|
+ WRITE_RGB_DOTS => "K", # Write RGB DOTS PICTURE file (p44)
|
|
|
+ READ_RGB_DOTS => "L", # Read RGB DOTS PICTURE file (p46)
|
|
|
+ WRITE_LARGE_DOTS => "M", # Write LARGE DOTS PICTURE file (p42)
|
|
|
+ READ_LARGE_DOTS => "N", # Read LARGE DOTS PICTURE file (p43)
|
|
|
+ WRITE_ALPHAVISION => "O", # Write ALPHAVISION BULLETIN (p48)
|
|
|
+ SET_TIMEOUT => "T", # Set Timeout Message (p118) (Alpha 2.0/3.0)
|
|
|
+};
|
|
|
+
|
|
|
+# Constants used in transmission packets
|
|
|
+use constant {
|
|
|
+ NUL => "\x00", # NULL
|
|
|
+ SOH => "\x01", # Start of Header
|
|
|
+ STX => "\x02", # Start of TeXt (precedes a command code)
|
|
|
+ ETX => "\x03", # End of TeXt
|
|
|
+ EOT => "\x04", # End Of Transmission
|
|
|
+# ENQ => "\x05", # Enquiry
|
|
|
+# ACK => "\x06", # Acknowledge
|
|
|
+ BEL => "\x07", # Bell
|
|
|
+ BS => "\x08", # Backspace
|
|
|
+ HT => "\x09", # Horizontal tab
|
|
|
+ LF => "\x0A", # Line Feed
|
|
|
+ NL => "\x0A", # New Line
|
|
|
+ VT => "\x0B", # Vertical Tab
|
|
|
+# FF => "\x0C", # Form Feed
|
|
|
+# NP => "\x0C", # New Page
|
|
|
+ CR => "\x0D", # Carriage Return
|
|
|
+ CAN => "\x18", # Cancel
|
|
|
+ SUB => "\x1A", # Substitute (select charset)
|
|
|
+ ESC => "\x1B", # Escape character
|
|
|
+};
|
|
|
+
|
|
|
+# Constructor
|
|
|
+# - device: device of the LED sign
|
|
|
+sub new {
|
|
|
+ my($class,$device)=@_;
|
|
|
+
|
|
|
+ my $self={
|
|
|
+ "device" => $device,
|
|
|
+ "type" => "Z", # Type Code, see protocol
|
|
|
+ "address" => "00", # Sign Address, see protocol
|
|
|
+ "mode" => "rotate", # Default display mode
|
|
|
+ "position" => "middle_line", # Approrpriate for one-line signs
|
|
|
+ "debug" => 0, # debugging
|
|
|
+ };
|
|
|
+
|
|
|
+ return bless $self,$class;
|
|
|
+}
|
|
|
+
|
|
|
+# Connect to the sign (open the serial device)
|
|
|
+# If no device is known, the default /dev/ttyS0 is selected
|
|
|
+sub connect {
|
|
|
+ my($this,$device)=@_;
|
|
|
+ $device ||= $this->{device};
|
|
|
+ if (!$device) {
|
|
|
+ warn "No device specified. Defaulting to /dev/ttyS0.\n";
|
|
|
+ $device = "/dev/ttyS0";
|
|
|
+ }
|
|
|
+
|
|
|
+ # Open a connection to the sign
|
|
|
+ open(OUT,">",$device)
|
|
|
+ or die "Could not open $device for output: $!\n";
|
|
|
+ OUT->autoflush(1);
|
|
|
+
|
|
|
+ open(IN,"<",$device)
|
|
|
+ or die "Could not open $device for input: $!\n";
|
|
|
+ IN->autoflush(1);
|
|
|
+}
|
|
|
+
|
|
|
+# Disconnect from the sign (close the serial device)
|
|
|
+sub disconnect {
|
|
|
+ my($this)=@_;
|
|
|
+ close OUT;
|
|
|
+ close IN;
|
|
|
+}
|
|
|
+
|
|
|
+sub _packet {
|
|
|
+ my($this,$contents)=@_;
|
|
|
+ return ((NUL x 5) . SOH . $this->{type} . $this->{address} . STX
|
|
|
+ . $contents . EOT);
|
|
|
+}
|
|
|
+
|
|
|
+sub _write {
|
|
|
+ my($this,$packet)=@_;
|
|
|
+ die "Not connected to device. Use \$sign->connect().\n" if !OUT->opened;
|
|
|
+ if ($this->{debug}) {
|
|
|
+ # make human-readable packet for display
|
|
|
+ my $hr = $packet;
|
|
|
+ #for(0..27) {
|
|
|
+ # my $hex = hex $_;
|
|
|
+ # $hr =~ s/\x$hex/[$hex]/g;
|
|
|
+ #}
|
|
|
+ print "Writing packet: $hr\n";
|
|
|
+ }
|
|
|
+ print OUT $packet;
|
|
|
+}
|
|
|
+
|
|
|
+# Read from the sign
|
|
|
+# This does not seem to work correctly yet. All read_* functions therefore
|
|
|
+# do not work.
|
|
|
+sub _read {
|
|
|
+ my($this)=@_;
|
|
|
+ my $data;
|
|
|
+ sysread IN,$data,1024;
|
|
|
+ return $data;
|
|
|
+}
|
|
|
+
|
|
|
+sub dec2hex {
|
|
|
+ my($dec) = @_;
|
|
|
+ return sprintf("%lx ", $dec );
|
|
|
+}
|
|
|
+
|
|
|
+sub hex2dec {
|
|
|
+ return hex($_[0]);
|
|
|
+}
|
|
|
+
|
|
|
+# Set display mode
|
|
|
+# for $mode, use one of the Standard Mode constants exported
|
|
|
+# if $mode is SPECIAL, set $special_mode to one of the defined special modes
|
|
|
+sub set_mode {
|
|
|
+ my($this,$mode)=@_;
|
|
|
+
|
|
|
+ if ($modes{$mode}) {
|
|
|
+ $this->{mode} = $mode;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ warn "Warning: '$mode' is an invalid mode\n";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+# Get display mode
|
|
|
+sub get_mode {
|
|
|
+ my($this)=@_;
|
|
|
+ return $this->{mode};
|
|
|
+}
|
|
|
+
|
|
|
+# Set display position
|
|
|
+# This is mostly unimportant for one line signs.
|
|
|
+sub set_position {
|
|
|
+ my($this,$position)=@_;
|
|
|
+ if ($positions{$position}) {
|
|
|
+ $this->{position} = $position;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ warn "Warning: '$position' is an invalid position\n";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+# Get display position
|
|
|
+sub get_position {
|
|
|
+ my($this)=@_;
|
|
|
+ return $this->{position};
|
|
|
+}
|
|
|
+
|
|
|
+# Write TEXT to the sign
|
|
|
+sub write_text {
|
|
|
+ my($this,$msg,$label)=@_;
|
|
|
+ $label ||= "A";
|
|
|
+
|
|
|
+ # [WRITE_TEXT][File Label][ESC][Display Position][Mode Code]
|
|
|
+ # [Special Specifier][ASCII Message]
|
|
|
+ my $packet = $this->_packet(WRITE_TEXT . $label . ESC
|
|
|
+ . $positions{$this->{position}}
|
|
|
+ . $modes{$this->{mode}} . $msg);
|
|
|
+ $this->_write($packet);
|
|
|
+}
|
|
|
+
|
|
|
+# Read TEXT from the sign
|
|
|
+sub read_text {
|
|
|
+ my($this,$label)=@_;
|
|
|
+ $label ||= "A";
|
|
|
+ $this->_write($this->_packet(READ_TEXT . $label));
|
|
|
+ return $this->_read();
|
|
|
+}
|
|
|
+
|
|
|
+# Create a STRING
|
|
|
+# This is necessary to allocate memory for the STRING on the sign
|
|
|
+#
|
|
|
+# $string_label: label of the STRING to create
|
|
|
+# $string_size: size of the STRING to create, in bytes. 125 max.
|
|
|
+# Default is 32.
|
|
|
+sub create_string {
|
|
|
+ my($this,$string_label,$string_size)=@_;
|
|
|
+ $string_label ||= 1;
|
|
|
+ $string_size = 125 if $string_size > 125;
|
|
|
+ $string_size ||= 32;
|
|
|
+ my $size_hex = hex($string_size);
|
|
|
+ $size_hex = "0"x(4-length($size_hex)).$size_hex if length($size_hex) < 4;
|
|
|
+ my $packet = $this->_packet(WRITE_SPECIAL . "\$"
|
|
|
+ . "A" # call label.. why does this matter?
|
|
|
+ . "A" # text file type
|
|
|
+ . "U" # this TEXT file is unlocked
|
|
|
+ . "0100" # text file size in hex
|
|
|
+ . "FF" # text file's start time (FF = always)
|
|
|
+ . "00" # text file's stop time
|
|
|
+ . $string_label
|
|
|
+ . "B" # string file type
|
|
|
+ . "L" # this string file is locked
|
|
|
+ . $size_hex
|
|
|
+ . "0000" # padding
|
|
|
+ );
|
|
|
+ $this->_write($packet);
|
|
|
+}
|
|
|
+
|
|
|
+# Write a STRING
|
|
|
+sub write_string {
|
|
|
+ my($this,$data,$label)=@_;
|
|
|
+ $label ||= 1;
|
|
|
+ my $packet = $this->_packet(WRITE_STRING . $label . $data);
|
|
|
+ $this->_write($packet);
|
|
|
+}
|
|
|
+
|
|
|
+sub read_string {
|
|
|
+ my($this,$label)=@_;
|
|
|
+ $label ||= 1;
|
|
|
+ my $packet = $this->_packet(READ_STRING . $label);
|
|
|
+ $this->_write($packet);
|
|
|
+ return $this->_read();
|
|
|
+}
|
|
|
+
|
|
|
+# Call a STRING
|
|
|
+# Returns the control code of specified string label. This is for
|
|
|
+# inserting a STRING file into a TEXT file
|
|
|
+sub call_string {
|
|
|
+ my($this,$string_label)=@_;
|
|
|
+ $string_label ||= "1";
|
|
|
+ return "\x10" . $string_label;
|
|
|
+}
|
|
|
+
|
|
|
+# Call Date
|
|
|
+# Returns the control code for the date to be inserted in a TEXT
|
|
|
+# $format: integer from 0 to 9
|
|
|
+# 0 - MM/DD/YY
|
|
|
+# 1 - DD/MM/YY
|
|
|
+# 2 - MM-DD-YY
|
|
|
+# 3 - DD-MM-YY
|
|
|
+# 4 - MM.DD.YY
|
|
|
+# 5 - DD.MM.YY
|
|
|
+# 6 - MM DD YY
|
|
|
+# 7 - DD MM YY
|
|
|
+# 8 - MMM.DD, YYYY
|
|
|
+# 9 - Day of week
|
|
|
+# Format defaults to 0 if invalid or not specified
|
|
|
+sub call_date {
|
|
|
+ my($this,$format);
|
|
|
+ $format ||= 0;
|
|
|
+ $format = 0 if ($format < 0 || $format > 9);
|
|
|
+ return "\x0B" . $format;
|
|
|
+}
|
|
|
+
|
|
|
+# Call Time
|
|
|
+# Returns control code for the time.
|
|
|
+sub call_time {
|
|
|
+ my($this)=@_;
|
|
|
+ return "\x13";
|
|
|
+}
|
|
|
+
|
|
|
+# Clear sign's memory
|
|
|
+sub clear_memory {
|
|
|
+ my($this)=@_;
|
|
|
+ my $packet = $this->_packet(WRITE_SPECIAL . "\$");
|
|
|
+ $this->_write($packet);
|
|
|
+}
|
|
|
+
|
|
|
+# Generate a tone/beep
|
|
|
+# $frequency: frequency of tone to generate, in hex ("00" through "FE")
|
|
|
+# $duration: duration, in hex, of tone in 0.1s increments ("1" through "F")
|
|
|
+# $repeat: number of times, in hex, to repeat the tone ("0" through "F")
|
|
|
+sub beep {
|
|
|
+ my($this,$frequency,$duration,$repeat)=@_;
|
|
|
+ $frequency ||= "10";
|
|
|
+ $duration ||= "2";
|
|
|
+ $repeat ||= 0;
|
|
|
+
|
|
|
+ my $packet = $this->_packet(WRITE_SPECIAL . "(2" . $frequency . $duration
|
|
|
+ . $repeat);
|
|
|
+ $this->_write($packet);
|
|
|
+}
|
|
|
+
|
|
|
+# Perform a soft reset on the sign (does not clear memory; non-destructive)
|
|
|
+sub soft_reset {
|
|
|
+ my($this)=@_;
|
|
|
+ my $packet = $this->_packet(WRITE_SPECIAL . ",");
|
|
|
+ $this->_write($packet);
|
|
|
+}
|
|
|
+
|
|
|
+# Set the day of the week on the sign
|
|
|
+# $day must be an integer between 1 and 7.
|
|
|
+# 1 = Sunday, 2 = Monday, etc.
|
|
|
+# Omitting the $day parameter will cause today's day to be sent
|
|
|
+# Returns -1 if an invalid day is specified.
|
|
|
+sub set_day {
|
|
|
+ my($this,$day)=@_;
|
|
|
+ return -1 if ($day && ($day < 1 || $day > 7));
|
|
|
+ $day ||= time2str("%w",time)+1;
|
|
|
+
|
|
|
+ my $packet = $this->_packet(WRITE_SPECIAL . "&" . $day);
|
|
|
+ $this->_write($packet);
|
|
|
+}
|
|
|
+
|
|
|
+# Sets the date in the memory of the sign. This must be done each day to keep
|
|
|
+# the clock 'up to date', because the sign will not automatically advance the
|
|
|
+# day.
|
|
|
+#
|
|
|
+# NOTE: each of the parameters must be two characters long.
|
|
|
+#
|
|
|
+# If no date is specified, today's date will be used.
|
|
|
+sub set_date {
|
|
|
+ my($this,$year,$month,$day)=@_;
|
|
|
+ $year ||= time2str("%y",time);
|
|
|
+ $month ||= time2str("%m",time);
|
|
|
+ $day ||= time2str("%d",time);
|
|
|
+
|
|
|
+ my $packet = $this->_packet(WRITE_SPECIAL . ";" . $month . $day . $year);
|
|
|
+ $this->_write($packet);
|
|
|
+}
|
|
|
+
|
|
|
+# Sets the hour and minute of the internal clock on the sign
|
|
|
+# $h: hour in twenty-four hour format (18 instead of 6 for 6PM)
|
|
|
+# $m: minute
|
|
|
+# If no time (or an invalid time) is specified, the current system time will
|
|
|
+# be used
|
|
|
+sub set_time {
|
|
|
+ my($this,$h,$m)=@_;
|
|
|
+ $h = "" if ($h < 0 or $h > 23);
|
|
|
+ $m = "" if ($m < 0 or $m > 59);
|
|
|
+ $h ||= time2str("%H",time);
|
|
|
+ $m ||= time2str("%M",time);
|
|
|
+
|
|
|
+ my $packet = $this->_packet(WRITE_SPECIAL . "\x20" . $h . $m);
|
|
|
+ $this->_write($packet);
|
|
|
+}
|
|
|
+
|
|
|
+# Sets the time format on the sign
|
|
|
+# $format: 1 - 24-hour (military) time
|
|
|
+# 0 - 12-hour (standard am/pm) format
|
|
|
+# 12-hour is the default
|
|
|
+sub set_time_format {
|
|
|
+ my($this,$format)=@_;
|
|
|
+ $format ||= 0;
|
|
|
+ $format = 0 if ($format > 1 || $format < 0);
|
|
|
+ my $byte = ($format == 0) ? "S" : "M";
|
|
|
+
|
|
|
+ my $packet = $this->_packet(WRITE_SPECIAL . "\x27" . $byte);
|
|
|
+ $this->_write($packet);
|
|
|
+}
|
|
|
+
|
|
|
+# Returns color code for a specified color
|
|
|
+# If an invalid color is specified, autocolor will be used
|
|
|
+sub color {
|
|
|
+ my($this,$color)=@_;
|
|
|
+ $color = "autocolor" if !$colors{$color};
|
|
|
+ return "\x1C" . $colors{$color};
|
|
|
+}
|
|
|
+
|
|
|
+# Returns control code for a specified character set
|
|
|
+# Defaults to 'five_high_std', Five High Standard
|
|
|
+sub charset {
|
|
|
+ my($this,$charset)=@_;
|
|
|
+ $charset = "five_high_std" if !$charsets{$charset};
|
|
|
+ return "\x1A" . $charsets{$charset};
|
|
|
+}
|
|
|
+
|
|
|
+# Returns control code for a specified extended char
|
|
|
+# Defaults to 'left_arrow'
|
|
|
+sub extchar {
|
|
|
+ my($this,$extchar)=@_;
|
|
|
+ $extchar = "left_arrow" if !$extchars{$extchar};
|
|
|
+ return "\x08" . $extchars{$extchar};
|
|
|
+}
|
|
|
+
|
|
|
+# Returns control code to set the character spacing.
|
|
|
+# $option: if 0, set proportional characters (default)
|
|
|
+# 1, fixed width left justified characters
|
|
|
+sub spacing {
|
|
|
+ my($this,$option)=@_;
|
|
|
+ my $byte = ($option == 0) ? 0 : 1;
|
|
|
+ return "\x1E" . $byte;
|
|
|
+}
|
|
|
+
|
|
|
+# Set the speed
|
|
|
+# $speed: integer 1 (slowest) through 5 (fastest) inclusive.
|
|
|
+sub speed {
|
|
|
+ my($this,$speed)=@_;
|
|
|
+ $speed ||= 1;
|
|
|
+ $speed = 1 if ($speed < 1 || $speed > 5);
|
|
|
+ my $n = 20+$speed;
|
|
|
+ return chr($n);
|
|
|
+}
|
|
|
+
|
|
|
+1;
|