2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-22 08:11:44 +00:00

add 20_FRM_LCD.pm, update Device::Firmata

git-svn-id: https://svn.fhem.de/fhem/trunk@2871 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
ntruchsess 2013-03-08 17:59:23 +00:00
parent ad56fdf5cd
commit 52f3f7a15e
7 changed files with 721 additions and 49 deletions

View File

@ -28,7 +28,7 @@ sub FRM_Initialize($) {
require "$main::attr{global}{modpath}/FHEM/DevIo.pm";
# Provider
$hash->{Clients} = ":FRM_IN:FRM_OUT:FRM_AD:FRM_PWM:FRM_I2C:FRM_SERVO:OWX:";
$hash->{Clients} = ":FRM_IN:FRM_OUT:FRM_AD:FRM_PWM:FRM_I2C:FRM_SERVO:OWX:FRM_LCD:";
$hash->{ReadyFn} = "FRM_Ready";
$hash->{ReadFn} = "FRM_Read";
@ -159,7 +159,6 @@ sub FRM_Ready($) {
my ($hash) = @_;
my $name = $hash->{NAME};
print "ready: $name\n";
if ($name=~/^^FRM:.+:\d+$/) { # this is a closed tcp-connection, remove it
TcpServer_Close($hash);
delete $main::defs{$hash->{SNAME}}{FirmataDevice} if (defined $hash->{SNAME} && defined $main::defs{$hash->{SNAME}}{FirmataDevice});

246
fhem/FHEM/20_FRM_LCD.pm Executable file
View File

@ -0,0 +1,246 @@
#############################################
package main;
use strict;
use warnings;
use Device::Firmata;
use Device::Firmata::Constants qw/ :all /;
#####################################
my %sets = (
"text" => "",
"home" => "",
"clear" => "",
"display" => "on,off",
"cursor" => "",
"scroll" => "left,right",
);
my %gets = (
);
sub
FRM_LCD_Initialize($)
{
my ($hash) = @_;
$hash->{DefFn} = "FRM_Client_Define";
$hash->{InitFn} = "FRM_LCD_Init";
$hash->{SetFn} = "FRM_LCD_Set";
$hash->{UndefFn} = "FRM_LCD_Undef";
$hash->{AttrFn} = "FRM_LCD_Attr";
$hash->{AttrList} = "IODev model backLight:on,off blink:on,off autoClear:on,off autoBreak:on,off loglevel:0,1,2,3,4,5 $main::readingFnAttributes";
# autoScroll:on,off direction:leftToRight,rightToLeft do not work reliably
}
sub
FRM_LCD_Init($)
{
my ($hash,$args) = @_;
my $u = "wrong syntax: define <name> FRM_LCD <type> <size-x> <size-y> [<address>]";
return $u if(int(@$args) < 3);
$hash->{type} = shift @$args;
$hash->{sizex} = shift @$args;
$hash->{sizey} = shift @$args;
$hash->{address} = shift @$args if (@$args);
return "no IODev set" unless defined $hash->{IODev};
return "no FirmataDevice assigned to ".$hash->{IODev}->{NAME} unless defined $hash->{IODev}->{FirmataDevice};
if (($hash->{type} eq "i2c") and defined $hash->{address}) {
require LiquidCrystal_I2C;
my $lcd = LiquidCrystal_I2C->new($hash->{address},$hash->{sizex},$hash->{sizey});
$lcd->attach($hash->{IODev}->{FirmataDevice});
$lcd->init();
$hash->{lcd} = $lcd;
my $name = $hash->{NAME};
# FRM_LCD_Apply_Attribute($name,"backlight");
# FRM_LCD_Apply_Attribute($name,"autoscroll");
# FRM_LCD_Apply_Attribute($name,"direction");
# FRM_LCD_Apply_Attribute($name,"blink");
if (! (defined AttrVal($name,"stateFormat",undef))) {
$main::attr{$name}{"stateFormat"} = "text";
}
}
return undef;
}
sub FRM_LCD_Attr(@) {
my ($command,$name,$attribute,$value) = @_;
my $hash = $main::defs{$name};
if ($command eq "set") {
$main::attr{$name}{$attribute}=$value;
FRM_LCD_Apply_Attribute($name,$attribute);
}
}
sub FRM_LCD_Apply_Attribute {
my ($name,$attribute) = @_;
my $lcd = $main::defs{$name}{lcd};
if (defined $lcd) {
ATTRIBUTE_HANDLER: {
$attribute eq "backLight" and do {
if (AttrVal($name,"backLight","on") eq "on") {
$lcd->backlight();
} else {
$lcd->noBacklight();
}
last;
};
$attribute eq "autoScroll" and do {
if (AttrVal($name,"autoScroll","on") eq "on") {
$lcd->autoscroll();
} else {
$lcd->noAutoscroll();
}
last;
};
$attribute eq "direction" and do {
if (AttrVal($name,"direction","leftToRight") eq "leftToRight") {
$lcd->leftToRight();
} else {
$lcd->rightToLeft();
}
last;
};
$attribute eq "blink" and do {
if (AttrVal($name,"blink","off") eq "on") {
$lcd->blink();
} else {
$lcd->noBlink();
}
last;
};
}
} else {
main::Log (3, "no lcd found");
}
}
sub FRM_LCD_Set(@) {
my ($hash, @a) = @_;
return "Need at least one parameters" if(@a < 2);
my $command = $a[1];
my $value = $a[2];
return "Unknown argument $a[1], choose one of " . join(" ", sort keys %sets)
if(!defined($sets{$command}));
my $lcd = $hash->{lcd};
COMMAND_HANDLER: {
$command eq "text" and do {
if (AttrVal($hash->{NAME},"autoClear","on") eq "on") {
$lcd->clear();
}
if (AttrVal($hash->{NAME},"autoBreak","on") eq "on") {
my $sizex = $hash->{sizex};
my $sizey = $hash->{sizey};
my $start = 0;
my $len = length $value;
for (my $line = 0;$line<$sizey;$line++) {
$lcd->setCursor(0,$line);
if ($start<$len) {
$lcd->print(substr $value, $start, $sizex);
} else {
last;
}
$start+=$sizex;
}
} else {
$lcd->print($value);
}
main::readingsSingleUpdate($hash,"text",$value,1);
last;
};
$command eq "home" and do {
$lcd->home();
last;
};
$command eq "clear" and do {
$lcd->clear();
main::readingsSingleUpdate($hash,"text","",1);
last;
};
$command eq "display" and do {
if ($value ne "off") {
$lcd->display();
} else {
$lcd->noDisplay();
}
last;
};
$command eq "cursor" and do {
my ($x,$y) = split ",",$value;
$lcd->setCursor($x,$y);
last;
};
$command eq "scroll" and do {
if ($value eq "left") {
$lcd->scrollDisplayLeft();
} else {
$lcd->scrollDisplayRight();
}
last;
};
}
}
sub
FRM_LCD_Undef($$)
{
my ($hash, $name) = @_;
}
1;
=pod
=begin html
<a name="FRM_I2C"></a>
<h3>FRM_I2C</h3>
<ul>
represents an integrated curcuit connected to the i2c-pins of an <a href="http://www.arduino.cc">Arduino</a>
running <a href="http://www.firmata.org">Firmata</a><br>
Requires a defined <a href="#FRM">FRM</a>-device to work.<br>
this FRM-device has to be configures for i2c by setting attr 'i2c-config' on the FRM-device<br>
it reads out the ic-internal storage in intervals of 'sampling-interval' as set on the FRM-device<br><br>
<a name="FRM_I2Cdefine"></a>
<b>Define</b>
<ul>
<code>define &lt;name&gt; FRM_I2C &lt;i2c-address&gt; &lt;register&gt; &lt;bytes-to-read&gt;</code> <br>
Specifies the FRM_I2C device.<br>
<li>i2c-address is the (device-specific) address of the ic on the i2c-bus</li>
<li>register is the (device-internal) address to start reading bytes from.</li>
<li>bytes-to-read is the number of bytes read from the ic</li>
</ul>
<br>
<a name="FRM_I2Cset"></a>
<b>Set</b><br>
<ul>
N/A<br>
</ul>
<a name="FRM_I2Cget"></a>
<b>Get</b><br>
<ul>
N/A<br>
</ul><br>
<a name="FRM_I2Cattr"></a>
<b>Attributes</b><br>
<ul>
<li><a href="#IODev">IODev</a><br>
Specify which <a href="#FRM">FRM</a> to use. (Optional, only required if there is more
than one FRM-device defined.)
</li>
<li><a href="#eventMap">eventMap</a><br></li>
<li><a href="#readingFnAttributes">readingFnAttributes</a><br></li>
</ul>
</ul>
<br>
=end html
=cut

View File

@ -60,7 +60,7 @@ sub open {
# We're going to try and create the device connection first...
my $package = "Device::Firmata::Platform";
eval "require $package";
my $device = $package->open($serial_port,$opts);
my $device = $package->open($serial_port,$opts) or die "Could not connect to Firmata Server";
# Figure out what platform we're running on
$device->probe;

View File

@ -28,6 +28,7 @@ use constant (
PIN_SHIFT => 5,
PIN_I2C => 6,
PIN_ONEWIRE => 7,
PIN_STEPPER => 8,
PIN_LOW => 0,
PIN_HIGH => 1,

View File

@ -351,11 +351,12 @@ sub sysex_handle {
=head2 probe
Request the version of the protocol that the
target device is using. Sometimes, we'll have to
wait a couple of seconds for the response so we'll
try for 2 seconds and rapidly fire requests if
we don't get a response quickly enough ;)
On device boot time we wait 3 seconds for firmware name
that the target device is using.
If not received the starting message, then we wait for
response another 2 seconds and fire requests for version.
If the response received, then we store protocol version
and analog mapping and capability.
=cut
@ -364,46 +365,33 @@ sub probe {
# --------------------------------------------------
my ($self) = @_;
my $proto = $self->{protocol};
my $io = $self->{io};
$self->{metadata}{firmware} = '';
$self->{metadata}{firmware_version} = '';
# Wait for 10 seconds only
my $end_tics = time + 10;
# Query every .5 seconds
my $query_tics = time;
# Wait for 5 seconds only
my $end_tics = time + 5;
$self->firmware_version_query();
while ( $end_tics >= time ) {
if ( $query_tics <= time ) {
# Query the device for information on the firmata firmware_version
$self->firmware_version_query();
select (undef,undef,undef,0.1);
# Try to get a response
$self->poll;
if ( $self->{metadata}{firmware}
&& $self->{metadata}{firmware_version} )
{
$self->{protocol}->{protocol_version} = $self->{metadata}{firmware_version};
$self->analog_mapping_query();
$self->capability_query();
while ($end_tics >= time) {
if (($self->{metadata}{analog_mappings}) and ($self->{metadata}{capabilities})) {
return 1;
}
$self->poll();
select( undef, undef, undef, 0.2 ); # wait for response
if ( $self->poll && $self->{metadata}{firmware} && $self->{metadata}{firmware_version} ) {
$self->{protocol}->{protocol_version} = $self->{metadata}{firmware_version};
if ( $self->{metadata}{capabilities} ) {
if ( $self->{metadata}{analog_mappings} ) {
return 1;
}
else {
$self->analog_mapping_query();
}
return 1;
}
$query_tics = time + 0.5;
else {
$self->capability_query();
}
}
else {
$self->firmware_version_query() unless $end_tics - 2 >= time; # version query on last 2 sec only
}
select (undef,undef,undef,0.1);
}
return undef;
return;
}
=head2 pin_mode
@ -436,10 +424,7 @@ sub pin_mode {
last;
};
( $mode == PIN_PWM || $mode == PIN_I2C || $mode == PIN_ONEWIRE || $mode == PIN_SERVO ) and do {
$self->{io}->data_write($self->{protocol}->message_prepare( SET_PIN_MODE => 0, $pin, $mode ));
last;
};
$self->{io}->data_write($self->{protocol}->message_prepare( SET_PIN_MODE => 0, $pin, $mode ));
};
$self->{pin_modes}->{$pin} = $mode;
return 1;
@ -786,7 +771,7 @@ sub poll {
# --------------------------------------------------
my $self = shift;
my $buf = $self->{io}->data_read(100) or return;
my $buf = $self->{io}->data_read(512) or return;
my $messages = $self->{protocol}->message_data_receive($buf);
$self->messages_handle($messages);
return $messages;
@ -833,8 +818,7 @@ sub observe_i2c {
sub observe_onewire {
my ( $self, $pin, $observer, $context ) = @_;
return undef unless ($self->is_supported_mode($pin,PIN_INPUT));
return undef unless ($self->is_supported_mode($pin,PIN_OUTPUT));
return undef unless ($self->is_supported_mode($pin,PIN_ONEWIRE));
$self->{onewire_observer}[$pin] = {
method => $observer,
context => $context,

View File

@ -305,7 +305,11 @@ sub sysex_parse {
$return_data = $self->handle_scheduler_response($sysex_data);
last;
};
$command == $protocol_commands->{RESERVED_COMMAND} and do {
$return_data = $sysex_data;
last;
};
}
return {
@ -313,6 +317,11 @@ sub sysex_parse {
command_str => $command_str,
data => $return_data
};
} else {
return {
command => $command,
data => $sysex_data
}
}
}
return undef;

View File

@ -0,0 +1,433 @@
# www.DFRobot.com
# last updated on 21/12/2011
# Tim Starling Fix the reset bug (Thanks Tim)
# wiki doc http://www.dfrobot.com/wiki/index.php?title=I2C/TWI_LCD1602_Module_(SKU:_DFR0063)
# Support Forum: http://www.dfrobot.com/forum/
# Compatible with the Arduino IDE 1.0
# Library version:1.1
# When the display powers up, it is configured as follows:
#
# 1. Display clear
# 2. Function set:
# DL = 1; 8-bit interface data
# N = 0; 1-line display
# F = 0; 5x8 dot character font
# 3. Display on/off control:
# D = 0; Display off
# C = 0; Cursor off
# B = 0; Blinking off
# 4. Entry mode set:
# I/D = 1; Increment by 1
# S = 0; No shift
#
# Note, however, that resetting the Arduino doesn't reset the LCD, so we
# can't assume that its in that state when a sketch starts (and the
# LiquidCrystal constructor is called).
package LiquidCrystal_I2C;
use warnings;
use strict;
#Basic commands and constants
use constant LCD_CLEARDISPLAY => 0x01;
use constant LCD_RETURNHOME => 0x02;
use constant LCD_ENTRYMODESET => 0x04;
use constant LCD_DISPLAYCONTROL => 0x08;
use constant LCD_CURSORSHIFT => 0x10;
use constant LCD_FUNCTIONSET => 0x20;
use constant LCD_SETCGRAMADDR => 0x40;
use constant LCD_SETDDRAMADDR => 0x80;
# flags for display entry mode
use constant LCD_ENTRYRIGHT => 0x00;
use constant LCD_ENTRYLEFT => 0x02;
use constant LCD_ENTRYSHIFTINCREMENT => 0x01;
use constant LCD_ENTRYSHIFTDECREMENT => 0x00;
# flags for display on/off control
use constant LCD_DISPLAYON => 0x04;
use constant LCD_DISPLAYOFF => 0x00;
use constant LCD_CURSORON => 0x02;
use constant LCD_CURSOROFF => 0x00;
use constant LCD_BLINKON => 0x01;
use constant LCD_BLINKOFF => 0x00;
# flags for display/cursor shift
use constant LCD_DISPLAYMOVE => 0x08;
use constant LCD_CURSORMOVE => 0x00;
use constant LCD_MOVERIGHT => 0x04;
use constant LCD_MOVELEFT => 0x00;
# flags for function set
use constant LCD_8BITMODE => 0x10;
use constant LCD_4BITMODE => 0x00;
use constant LCD_2LINE => 0x08;
use constant LCD_1LINE => 0x00;
use constant LCD_5x10DOTS => 0x04;
use constant LCD_5x8DOTS => 0x00;
# flags for backlight control
use constant LCD_BACKLIGHT => 0x08;
use constant LCD_NOBACKLIGHT => 0x00;
use constant En => 0b00000100; # Enable bit
use constant Rw => 0b00000010; # Read / Write bit
use constant Rs => 0b00000001; # Register select bit
sub print($$) {
my ($self,$c) = @_;
my @buf = unpack "c*",$c;
foreach my $s (@buf) {
$self->write($s);
}
};
sub write($$) {
my ( $self, $value ) = @_;
$self->send( $value, Rs );
return 0;
}
sub new($$$$) {
my ( $class, $lcd_Addr, $lcd_cols, $lcd_rows ) = @_;
return bless {
Addr => $lcd_Addr,
cols => $lcd_cols,
rows => $lcd_rows,
backlightval => LCD_NOBACKLIGHT,
}, $class;
}
sub init($) {
my $self = shift;
$self->init_priv();
}
sub attach($$) {
my ($self,$dev) = @_;
$self->{FirmataDevice} = $dev;
}
sub init_priv($) {
my $self = shift;
$self->{displayfunction} =
LCD_4BITMODE | LCD_1LINE |
LCD_5x8DOTS;
$self->begin( $self->{cols}, $self->{rows} );
}
sub begin($$$$) {
my ( $self, $cols, $lines, $dotsize ) = @_;
if ( $lines > 1 ) {
$self->{displayfunction} |= LCD_2LINE;
}
$self->{numlines} = $lines;
# for some 1 line displays you can select a 10 pixel high font
if ( (defined $dotsize) && ($dotsize != 0) && ( $lines == 1 ) ) {
$self->{displayfunction} |= LCD_5x10DOTS;
}
# SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
# according to datasheet, we need at least 40ms after power rises above 2.7V
# before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
select( undef, undef, undef, 0.050 );
# Now we pull both RS and R/W low to begin commands
$self->expanderWrite( $self->{backlightval} )
; # reset expanderand turn backlight off (Bit 8 =1)
select( undef, undef, undef, 1 );
#put the LCD into 4 bit mode
# this is according to the hitachi HD44780 datasheet
# figure 24, pg 46
# we start in 8bit mode, try to set 4 bit mode
$self->write4bits( 0x03 << 4 );
select( undef, undef, undef, 0.0045 ); # wait min 4.1ms
# second try
$self->write4bits( 0x03 << 4 );
select( undef, undef, undef, 0.0045 ); # wait min 4.1ms
# third go!
$self->write4bits( 0x03 << 4 );
select( undef, undef, undef, 0.00015 );
# finally, set to 4-bit interface
$self->write4bits( 0x02 << 4 );
# set # lines, font size, etc.
$self->command(
LCD_FUNCTIONSET | $self->{displayfunction} );
# turn the display on with no cursor or blinking default
$self->{displaycontrol} =
LCD_DISPLAYON | LCD_CURSOROFF |
LCD_BLINKOFF;
$self->display();
# clear it off
$self->clear();
# Initialize to default text direction (for roman languages)
$self->{displaymode} =
LCD_ENTRYLEFT |
LCD_ENTRYSHIFTDECREMENT;
# set the entry mode
$self->command(
LCD_ENTRYMODESET | $self->{displaymode} );
$self->home();
}
#********** high level commands, for the user!
sub clear($) {
my $self = shift;
$self->command(LCD_CLEARDISPLAY)
; # clear display, set cursor position to zero
select( undef, undef, undef, 0.002 ); # this command takes a long time!
}
sub home($) {
my $self = shift;
$self->command(LCD_RETURNHOME)
; # set cursor position to zero
select( undef, undef, undef, 0.002 ); # this command takes a long time!
}
sub setCursor($$$) {
my ( $self, $col, $row ) = @_;
my @row_offsets = ( 0x00, 0x40, 0x14, 0x54 );
if ( $row > $self->{numlines} ) {
$row = $self->{numlines} - 1; # we count rows starting w/0
}
$self->command(
LCD_SETDDRAMADDR | ( $col + $row_offsets[$row] ) );
}
# Turn the display on/off (quickly)
sub noDisplay($) {
my $self = shift;
$self->{displaycontrol} &=
~LCD_DISPLAYON; #TODO validate '~'
$self->command(
LCD_DISPLAYCONTROL | $self->{displaycontrol} );
}
sub display($) {
my $self = shift;
$self->{displaycontrol} |= LCD_DISPLAYON;
$self->command(
LCD_DISPLAYCONTROL | $self->{displaycontrol} );
}
# Turns the underline cursor on/off
sub noCursor($) {
my $self = shift;
$self->{displaycontrol} &=
~LCD_CURSORON; #TODO validate '~'
$self->command(
LCD_DISPLAYCONTROL | $self->{displaycontrol} );
}
sub cursor($) {
my $self = shift;
$self->{displaycontrol} |= LCD_CURSORON;
$self->command(
LCD_DISPLAYCONTROL | $self->{displaycontrol} );
}
# Turn on and off the blinking cursor
sub noBlink($) {
my $self = shift;
$self->{displaycontrol} &=
~LCD_BLINKON; #TODO validate '~'
$self->command(
LCD_DISPLAYCONTROL | $self->{displaycontrol} );
}
sub blink($) {
my $self = shift;
$self->{displaycontrol} |= LCD_BLINKON;
$self->command(
LCD_DISPLAYCONTROL | $self->{displaycontrol} );
}
# These commands scroll the display without changing the RAM
sub scrollDisplayLeft($) {
my $self = shift;
$self->command( LCD_CURSORSHIFT |
LCD_DISPLAYMOVE |
LCD_MOVELEFT );
}
sub scrollDisplayRight($) {
my $self = shift;
$self->command( LCD_CURSORSHIFT |
LCD_DISPLAYMOVE |
LCD_MOVERIGHT );
}
# This is for text that flows Left to Right
sub leftToRight($) {
my $self = shift;
$self->{displaymode} |= LCD_ENTRYLEFT;
$self->command(
LCD_ENTRYMODESET | $self->{displaymode} );
}
# This is for text that flows Right to Left
sub rightToLeft($) {
my $self = shift;
$self->{displaymode} &=
~LCD_ENTRYLEFT; #TODO validate '~'
$self->command(
LCD_ENTRYMODESET | $self->{displaymode} );
}
# This will 'right justify' text from the cursor
sub autoscroll($) {
my $self = shift;
$self->{displaymode} |= LCD_ENTRYSHIFTINCREMENT;
$self->command(
LCD_ENTRYMODESET | $self->{displaymode} );
}
# This will 'left justify' text from the cursor
sub noAutoscroll($) {
my $self = shift;
$self->{displaymode} &=
~LCD_ENTRYSHIFTINCREMENT; #TODO validate '~'
$self->command(
LCD_ENTRYMODESET | $self->{displaymode} );
}
# Allows us to fill the first 8 CGRAM locations
# with custom characters
sub createChar($$$) {
my ( $self, $location, $charmap ) = @_;
$location &= 0x7; # we only have 8 locations 0-7
$self->command( LCD_SETCGRAMADDR | ( $location << 3 ) );
for ( my $i = 0 ; $i < 8 ; $i++ ) {
$self->write( @$charmap[$i] );
}
}
# Turn the (optional) backlight off/on
sub noBacklight($) {
my $self = shift;
$self->{backlightval} = LCD_NOBACKLIGHT;
$self->expanderWrite(0);
}
sub backlight($) {
my $self = shift;
$self->{backlightval} = LCD_BACKLIGHT;
$self->expanderWrite(0);
}
#*********** mid level commands, for sending data/cmds
sub command($$) {
my ( $self, $value ) = @_;
$self->send( $value, 0 );
}
#************ low level data pushing commands **********
# write either command or data
sub send($$$) {
my ( $self, $value, $mode ) = @_;
my $highnib = $value & 0xf0;
my $lownib = ( $value << 4 ) & 0xf0;
$self->write4bits( ($highnib) | $mode );
$self->write4bits( ($lownib) | $mode );
}
sub write4bits($$) {
my ( $self, $value ) = @_;
$self->expanderWrite($value);
$self->pulseEnable($value);
}
sub expanderWrite($$) {
my ( $self, $data ) = @_;
$self->{FirmataDevice}->i2c_write($self->{Addr},($data) | $self->{backlightval});
}
sub pulseEnable($$) {
my ( $self, $data ) = @_;
$self->expanderWrite( $data | En ); # En high
select( undef, undef, undef, 0.000001 ); # enable pulse must be >450ns
$self->expanderWrite( $data & ~En )
; # En low TODO: validate '~'
select( undef, undef, undef, 0.000050 ); # commands need > 37us to settle
}
# Alias functions
sub cursor_on($) {
my $self = shift;
$self->cursor();
}
sub cursor_off($) {
my $self = shift;
$self->noCursor();
}
sub blink_on($) {
my $self = shift;
$self->blink();
}
sub blink_off($) {
my $self = shift;
$self->noBlink();
}
sub load_custom_character($$$) {
my ( $self, $char_num, $rows ) = @_;
$self->createChar( $char_num, $rows );
}
sub setBacklight($$) {
my ( $self, $new_val ) = @_;
if ($new_val) {
$self->backlight(); # turn backlight on
}
else {
$self->noBacklight(); # turn backlight off
}
}
# unsupported API functions
sub off($) { }
sub on($) { }
sub setDelay ($$$) { }
sub status($) {
return 0;
}
sub keypad ($) {
return 0;
}
sub init_bargraph($$) {
return 0;
}
sub draw_horizontal_graph($$$$$) { }
sub draw_vertical_graph($$$$$) { }
sub setContrast($$) { }
1;