mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-10 09:16:53 +00:00
Device::Firmata: removed from FHEM, use CPAN version (forum #114552)
git-svn-id: https://svn.fhem.de/fhem/trunk@23394 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
8af8e98c5d
commit
b7e37e6043
@ -1,5 +1,6 @@
|
|||||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
||||||
# Do not insert empty lines here, update check depends on it.
|
# Do not insert empty lines here, update check depends on it.
|
||||||
|
- change: Device::Firmata removed, use CPAN version (forum #114552)
|
||||||
- bugfix: 10_FRM: Device::Firmata check (forum #114552 msg #1112141)
|
- bugfix: 10_FRM: Device::Firmata check (forum #114552 msg #1112141)
|
||||||
- bugfix: 55_DWD_OpenData: forecast rotation (forum #83097 msg #1108423)
|
- bugfix: 55_DWD_OpenData: forecast rotation (forum #83097 msg #1108423)
|
||||||
- feature: 02_RSS: added readings to show filename and type of background
|
- feature: 02_RSS: added readings to show filename and type of background
|
||||||
|
@ -1,89 +0,0 @@
|
|||||||
package Device::Firmata;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
use Device::Firmata::Constants;
|
|
||||||
use Device::Firmata::Base
|
|
||||||
ISA => 'Device::Firmata::Base',
|
|
||||||
FIRMATA_ATTRIBS => {
|
|
||||||
};
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
Device::Firmata - Perl interface to Firmata for the arduino platform.
|
|
||||||
|
|
||||||
=head1 VERSION
|
|
||||||
|
|
||||||
Version 0.64
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
our $VERSION = '0.64';
|
|
||||||
our $DEBUG = 0;
|
|
||||||
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
use Device::Firmata::Constants qw/ :all /;
|
|
||||||
use Device::Firmata;
|
|
||||||
|
|
||||||
use Time::HiRes 'sleep';
|
|
||||||
|
|
||||||
$|++;
|
|
||||||
|
|
||||||
my $led_pin = 13;
|
|
||||||
|
|
||||||
my $device = Device::Firmata->open('/dev/ttyUSB0') or die "Could not connect to Firmata Server";
|
|
||||||
$device->pin_mode($led_pin=>PIN_OUTPUT);
|
|
||||||
my $iteration = 0;
|
|
||||||
while (1) {
|
|
||||||
my $strobe_state = $iteration++%2;
|
|
||||||
$device->digital_write($led_pin=>$strobe_state);
|
|
||||||
sleep 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head1 SUBROUTINES/METHODS
|
|
||||||
|
|
||||||
=head2 open
|
|
||||||
|
|
||||||
establish serial connection with an Arduino micro-controller. Single argument is the name of the device file mapped to the arduino. Typically '/dev/ttyUSB0' or 'COM9'
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub open {
|
|
||||||
# --------------------------------------------------
|
|
||||||
# Establish a connection to Arduino via the serial port
|
|
||||||
#
|
|
||||||
my ( $self, $serial_port, $opts ) = @_;
|
|
||||||
|
|
||||||
# We're going to try and create the device connection first...
|
|
||||||
my $package = "Device::Firmata::Platform";
|
|
||||||
eval "require $package";
|
|
||||||
my $serialio = "Device::Firmata::IO::SerialIO";
|
|
||||||
eval "require $serialio";
|
|
||||||
|
|
||||||
my $io = $serialio->open( $serial_port, $opts );
|
|
||||||
my $platform = $package->attach( $io, $opts ) or die "Could not connect to Firmata Server";
|
|
||||||
|
|
||||||
# Figure out what platform we're running on
|
|
||||||
$platform->probe;
|
|
||||||
return $platform;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub listen {
|
|
||||||
# --------------------------------------------------
|
|
||||||
# Listen on socket and wait for Arduino to establish a connection
|
|
||||||
#
|
|
||||||
my ( $pkg, $ip, $port, $opts ) = @_;
|
|
||||||
|
|
||||||
my $netio = "Device::Firmata::IO::NetIO";
|
|
||||||
eval "require $netio";
|
|
||||||
|
|
||||||
return $netio->listen( $ip, $port, $opts ) || die "Could not bind to socket";
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,386 +0,0 @@
|
|||||||
package Device::Firmata::Base;
|
|
||||||
|
|
||||||
use strict 'vars', 'subs';
|
|
||||||
use vars qw/
|
|
||||||
$AUTOLOAD
|
|
||||||
$FIRMATA_DEBUG_LEVEL
|
|
||||||
$FIRMATA_ERROR_CLASS
|
|
||||||
$FIRMATA_ERROR
|
|
||||||
$FIRMATA_ATTRIBS
|
|
||||||
$FIRMATA_DEBUGGING
|
|
||||||
$FIRMATA_LOCALE
|
|
||||||
$FIRMATA_LOCALE_PATH
|
|
||||||
$FIRMATA_LOCALE_MESSAGES
|
|
||||||
/;
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
Device::Firmata::Base -- Abstract baseclass for Device::Firmata modules
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
$FIRMATA_DEBUGGING = 1;
|
|
||||||
$FIRMATA_ATTRIBS = {};
|
|
||||||
$FIRMATA_LOCALE = 'en';
|
|
||||||
$FIRMATA_LOCALE_PATH = '.';
|
|
||||||
$FIRMATA_DEBUG_LEVEL = 0;
|
|
||||||
$FIRMATA_ERROR_CLASS = 'Device::Firmata::Error';
|
|
||||||
|
|
||||||
=head1 METHODS
|
|
||||||
|
|
||||||
=head2 import
|
|
||||||
|
|
||||||
Ease setting of configuration options
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub import {
|
|
||||||
my $self = shift;
|
|
||||||
my $pkg = caller;
|
|
||||||
my $config_opts = {
|
|
||||||
debugging => $FIRMATA_DEBUGGING,
|
|
||||||
};
|
|
||||||
|
|
||||||
if ( @_ ) {
|
|
||||||
my $opts = $self->parameters( @_ );
|
|
||||||
if ( my $attrs = $opts->{FIRMATA_ATTRIBS} ) {
|
|
||||||
*{$pkg.'::FIRMATA_ATTRIBS'} = \$attrs;
|
|
||||||
}
|
|
||||||
|
|
||||||
unless ( ref *{$pkg.'::ISA'} eq 'ARRAY' and @${$pkg.'::ISA'}) {
|
|
||||||
my @ISA = ref $opts->{ISA} ? @{$opts->{ISA}} :
|
|
||||||
$opts->{ISA} ? $opts->{ISA} :
|
|
||||||
__PACKAGE__;
|
|
||||||
*{$pkg.'::ISA'} = \@ISA;
|
|
||||||
}
|
|
||||||
use strict;
|
|
||||||
$self->SUPER::import( @_ );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 new
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub new {
|
|
||||||
my $pkg = shift;
|
|
||||||
my $basis = copy_struct( $pkg->init_class_attribs );
|
|
||||||
my $self = bless $basis, $pkg;
|
|
||||||
|
|
||||||
@_ = $self->pre_init( @_ ) if $self->{_biofunc_pre_init};
|
|
||||||
|
|
||||||
if ( $self->{_biofunc_init} ) {
|
|
||||||
$self->init( @_ );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$self->init_instance_attribs( @_ );
|
|
||||||
}
|
|
||||||
|
|
||||||
return $self->post_init if $self->{_biofunc_post_init};
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 create
|
|
||||||
|
|
||||||
A soft new as some objects will override new and
|
|
||||||
we don't want to cause problems but still want
|
|
||||||
to invoice our creation code
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub create {
|
|
||||||
my $self = shift;
|
|
||||||
my $basis = copy_struct( $self->init_class_attribs );
|
|
||||||
|
|
||||||
@$self{ keys %$basis } = values %$basis;
|
|
||||||
|
|
||||||
@_ = $self->pre_init( @_ ) if $self->{_biofunc_pre_init};
|
|
||||||
|
|
||||||
if ( $self->{_biofunc_init} ) {
|
|
||||||
$self->init( @_ );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$self->init_instance_attribs( @_ );
|
|
||||||
}
|
|
||||||
|
|
||||||
return $self->post_init if $self->{_biofunc_post_init};
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 init_instance_attribs
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub init_instance_attribs {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my $self = shift;
|
|
||||||
my $opts = $self->parameters( @_ );
|
|
||||||
|
|
||||||
foreach my $k ( keys %$self ) {
|
|
||||||
next unless exists $opts->{$k};
|
|
||||||
next if $k =~ /^_biofunc/;
|
|
||||||
$self->{$k} = $opts->{$k};
|
|
||||||
}
|
|
||||||
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 init_class_attribs
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub init_class_attribs {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my $class = ref $_[0] || shift;
|
|
||||||
my $track = { $class => 1, @_ ? %{$_[0]} : () };
|
|
||||||
|
|
||||||
return ${"${class}::ABSOLUTE_ATTRIBS"} if ${"${class}::ABSOLUTE_ATTRIBS"};
|
|
||||||
|
|
||||||
my $u = ${"${class}::FIRMATA_ATTRIBS"} || {};
|
|
||||||
|
|
||||||
for my $c ( @{"${class}::ISA"} ) {
|
|
||||||
next unless ${"${c}::FIRMATA_ATTRIBS"};
|
|
||||||
|
|
||||||
my $h;
|
|
||||||
if ( ${"${c}::ABSOLUTE_ATTRIBS"} ) {
|
|
||||||
$h = ${"${c}::ABSOLUTE_ATTRIBS"};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$c->fatal( "Cyclic dependancy!" ) if $track->{$c};
|
|
||||||
$h = $c->init_class_attribs( $c, $track );
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach my $k ( keys %$h ) {
|
|
||||||
next if exists $u->{$k};
|
|
||||||
$u->{$k} = copy_struct( $h->{$k} );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach my $f ( qw( pre_init init post_init ) ) {
|
|
||||||
$u->{"_biofunc_" . $f} = $class->can( $f ) ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
${"${class}::ABSOLUTE_ATTRIBS"} = $u;
|
|
||||||
|
|
||||||
return $u;
|
|
||||||
}
|
|
||||||
|
|
||||||
# logging/exception functions
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Utilty functions
|
|
||||||
|
|
||||||
=head2 parameters
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub parameters {
|
|
||||||
# --------------------------------------------------
|
|
||||||
return {} unless @_ > 1;
|
|
||||||
|
|
||||||
if ( @_ == 2 ) {
|
|
||||||
return $_[1] if ref $_[1];
|
|
||||||
return; # something wierd happened
|
|
||||||
}
|
|
||||||
|
|
||||||
@_ % 2 or $_[0]->warn( "Even number of elements were not passed to call.", join( " ", caller() ) );
|
|
||||||
|
|
||||||
shift;
|
|
||||||
|
|
||||||
return {@_};
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 copy_struct
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub copy_struct {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my $s = shift;
|
|
||||||
|
|
||||||
if ( ref $s ) {
|
|
||||||
if ( UNIVERSAL::isa( $s, 'HASH' ) ) {
|
|
||||||
return {
|
|
||||||
map { my $v = $s->{$_}; (
|
|
||||||
$_ => ref $v ? copy_struct( $v ) : $v
|
|
||||||
)} keys %$s
|
|
||||||
};
|
|
||||||
}
|
|
||||||
elsif ( UNIVERSAL::isa( $s, 'ARRAY' ) ) {
|
|
||||||
return [
|
|
||||||
map { ref $_ ? copy_struct($_) : $_ } @$s
|
|
||||||
];
|
|
||||||
}
|
|
||||||
die "Cannot copy struct! : ".ref($s);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $s;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 locale
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub locale {
|
|
||||||
# --------------------------------------------------
|
|
||||||
@_ >= 2 and shift;
|
|
||||||
$FIRMATA_LOCALE = shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 locale_path
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub locale_path {
|
|
||||||
# --------------------------------------------------
|
|
||||||
@_ >= 2 and shift;
|
|
||||||
$FIRMATA_LOCALE_PATH = shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 language
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub language {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my $self = shift;
|
|
||||||
require Device::Firmata::Language;
|
|
||||||
return Device::Firmata::Language->language(@_);
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 error
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub error {
|
|
||||||
# --------------------------------------------------
|
|
||||||
# Handle any error messages
|
|
||||||
#
|
|
||||||
my $self = shift;
|
|
||||||
if ( @_ ) {
|
|
||||||
my $err_msg = $self->init_error->error(@_);
|
|
||||||
$self->{error} = $err_msg;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $err_msg = $self->{error};
|
|
||||||
$self->{error} = '';
|
|
||||||
return $err_msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 init_error
|
|
||||||
|
|
||||||
Creates the global error object that will collect
|
|
||||||
all error messages generated on the system. This
|
|
||||||
function can be called as many times as desired.
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub init_error {
|
|
||||||
# --------------------------------------------------
|
|
||||||
#
|
|
||||||
$FIRMATA_ERROR and return $FIRMATA_ERROR;
|
|
||||||
|
|
||||||
if ( $FIRMATA_ERROR_CLASS eq 'Device::Firmata::Error' ) {
|
|
||||||
require Device::Firmata::Error;
|
|
||||||
return $FIRMATA_ERROR = $FIRMATA_ERROR_CLASS;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Try and load the file. Use default if fails
|
|
||||||
eval "require $FIRMATA_ERROR_CLASS";
|
|
||||||
$@ and return $FIRMATA_ERROR = $FIRMATA_ERROR_CLASS;
|
|
||||||
|
|
||||||
# Try and init the error object. Use default if fails
|
|
||||||
eval { $FIRMATA_ERROR = $FIRMATA_ERROR_CLASS->new(); };
|
|
||||||
$@ and return $FIRMATA_ERROR = $FIRMATA_ERROR_CLASS;
|
|
||||||
return $FIRMATA_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 fatal
|
|
||||||
|
|
||||||
Handle tragic and unrecoverable messages
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub fatal {
|
|
||||||
# --------------------------------------------------
|
|
||||||
#
|
|
||||||
my $self = shift;
|
|
||||||
return $self->error( -1, @_ );
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 warn
|
|
||||||
|
|
||||||
Handle tragic and unrecoverable messages
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub warn {
|
|
||||||
# --------------------------------------------------
|
|
||||||
#
|
|
||||||
my $self = shift;
|
|
||||||
return $self->error( 0, @_ );
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 debug
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub debug {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my ( $self, $debug ) = @_;
|
|
||||||
$FIRMATA_DEBUG_LEVEL = $debug;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 DESTROY
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub DESTROY {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my $self = shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 AUTOLOAD
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub AUTOLOAD {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my $self = shift;
|
|
||||||
my ($attrib) = $AUTOLOAD =~ /::([^:]+)$/;
|
|
||||||
|
|
||||||
if ( $self and UNIVERSAL::isa( $self, 'Device::Firmata::Base' ) ) {
|
|
||||||
$self->error( FIRMATA__unhandled => $attrib, join( " ", caller() ) );
|
|
||||||
die $self->error;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
die "Tried to call function '$attrib' via object '$self' @ ", join( " ", caller(1) ), "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
####################################################
|
|
||||||
# Object instantiation code
|
|
||||||
####################################################
|
|
||||||
|
|
||||||
=head2 object_load
|
|
||||||
|
|
||||||
Load the appropriate package and attempt to initialize
|
|
||||||
the object as well
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub object_load {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my $self = shift;
|
|
||||||
my $object_class = shift;
|
|
||||||
return unless $object_class =~ /^\w+(?:::\w+)*$/; # TODO ERROR MESSAGE
|
|
||||||
eval "require $object_class; 1" or die $@;
|
|
||||||
my $object = $object_class->new(@_);
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
1;
|
|
@ -1,62 +0,0 @@
|
|||||||
Revision history for Device-Firmata
|
|
||||||
|
|
||||||
0.64 2018.01.03 - Jens Beyer
|
|
||||||
support Firmata protocol version 2.5 feature PIN_PULLUP (Constants, Platform, Protocol)
|
|
||||||
|
|
||||||
0.63 2016.03.19 - Jens Beyer
|
|
||||||
supported protocol version detection modified (Protocol)
|
|
||||||
|
|
||||||
0.62 2016.02.22 - Jens Beyer
|
|
||||||
added software serial support (Platform, Protocol)
|
|
||||||
|
|
||||||
0.61 2016.01.09 - Jens Beyer
|
|
||||||
added serial pin support (Platform, Protocol, Constants)
|
|
||||||
added protocol version query (Platform)
|
|
||||||
fixed messages_handle: REPORT_VERSION returns protocol version (Platform)
|
|
||||||
added method get_max_compatible_protocol_version (Protocol)
|
|
||||||
|
|
||||||
0.60 2014.06.28 - Norbert Truchsess
|
|
||||||
Fixed formating of Firmata.pm as Windows line-endings break automatic install from CPAN
|
|
||||||
|
|
||||||
0.59 2014.06.26 - Norbert Truchsess
|
|
||||||
Fix a bug in the parser incorrectly skipping single 0x30 bytes
|
|
||||||
|
|
||||||
0.58 2014.06.26 - Yanick Champoux
|
|
||||||
cosmetic change to POD for CPAN
|
|
||||||
|
|
||||||
0.57 2014.06.12 - Norbert Truchsess
|
|
||||||
Fixed building dist for cpan
|
|
||||||
|
|
||||||
0.56 2014.06.04 - Norbert Truchsess
|
|
||||||
add generic method sysex_send to Platform.pl
|
|
||||||
|
|
||||||
0.55 2014.04.17 - Norbert Truchsess
|
|
||||||
fix digital-input message interference with output pins on same port
|
|
||||||
|
|
||||||
0.54 2014.03.04 - Norbert Truchsess
|
|
||||||
add stepper-motor protocol
|
|
||||||
|
|
||||||
0.53 2014.03.03 - Norbert Truchsess
|
|
||||||
add rotary-encoder protocol
|
|
||||||
|
|
||||||
0.52 2013.11.22 - Norbert Truchsess
|
|
||||||
add Firmata over Ethernet
|
|
||||||
|
|
||||||
0.51 2013.09.10/23:00 - Brett Carroll
|
|
||||||
Changed IO.pm to use Win32::SerialPort instead of Win32::Serialport on Windows platforms
|
|
||||||
Norbert Truchsess: fix handle onewire in capability-response
|
|
||||||
|
|
||||||
0.50 2012.12.13-2013.08.11 - Norbert Truchsess
|
|
||||||
adding all missing protocol-features (1-Wire, I2C, Servo ...)
|
|
||||||
adding observers for all suitable protocols
|
|
||||||
|
|
||||||
Valdas Kondrotas: various bugfixes and enhancements.
|
|
||||||
|
|
||||||
2011.03.23 - Chris Fedde
|
|
||||||
reorganizing as CPAN ready module
|
|
||||||
|
|
||||||
2011.02.16 Aki Mimoto
|
|
||||||
implementig all protocol basics and releasing Device::Firmata on Github
|
|
||||||
|
|
||||||
2010.08.31 Aki Mimoto
|
|
||||||
start of development
|
|
@ -1,396 +0,0 @@
|
|||||||
package Device::Firmata::Constants;
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
Device::Firmata::Constants - constants used in the Device::Firmata system
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use Exporter;
|
|
||||||
use vars qw/
|
|
||||||
@ISA @EXPORT_OK %EXPORT_TAGS
|
|
||||||
$BASE
|
|
||||||
$COMMANDS $COMMAND_NAMES
|
|
||||||
$COMMAND_LOOKUP
|
|
||||||
/;
|
|
||||||
@ISA = 'Exporter';
|
|
||||||
|
|
||||||
# Basic commands and constants
|
|
||||||
use constant (
|
|
||||||
$BASE = {
|
|
||||||
PIN_INPUT => 0,
|
|
||||||
PIN_OUTPUT => 1,
|
|
||||||
PIN_ANALOG => 2,
|
|
||||||
PIN_PWM => 3,
|
|
||||||
PIN_SERVO => 4,
|
|
||||||
PIN_SHIFT => 5,
|
|
||||||
PIN_I2C => 6,
|
|
||||||
PIN_ONEWIRE => 7,
|
|
||||||
PIN_STEPPER => 8,
|
|
||||||
PIN_ENCODER => 9,
|
|
||||||
PIN_SERIAL => 10,
|
|
||||||
PIN_PULLUP => 11,
|
|
||||||
PIN_LOW => 0,
|
|
||||||
PIN_HIGH => 1,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
# We need to apply all the available protocols
|
|
||||||
use constant (
|
|
||||||
$COMMANDS = {
|
|
||||||
|
|
||||||
V_2_01 => {
|
|
||||||
|
|
||||||
MAX_DATA_BYTES => 32, # max number of data bytes in non-Sysex messages
|
|
||||||
|
|
||||||
# message command bytes (128-255/0x80-0xFF)
|
|
||||||
DIGITAL_MESSAGE => 0x90, # send data for a digital pin
|
|
||||||
ANALOG_MESSAGE => 0xE0, # send data for an analog pin (or PWM)
|
|
||||||
REPORT_ANALOG => 0xC0, # enable analog input by pin #
|
|
||||||
REPORT_DIGITAL => 0xD0, # enable digital input by port pair
|
|
||||||
SET_PIN_MODE => 0xF4, # set a pin to INPUT/OUTPUT/PWM/etc
|
|
||||||
REPORT_VERSION => 0xF9, # report protocol version
|
|
||||||
SYSTEM_RESET => 0xFF, # reset from MIDI
|
|
||||||
START_SYSEX => 0xF0, # start a MIDI Sysex message
|
|
||||||
END_SYSEX => 0xF7, # end a MIDI Sysex message
|
|
||||||
|
|
||||||
# extended command set using sysex (0-127/0x00-0x7F)
|
|
||||||
SERVO_CONFIG => 0x70, # set max angle, minPulse, maxPulse, freq
|
|
||||||
STRING_DATA => 0x71, # a string message with 14-bits per char
|
|
||||||
SHIFT_DATA => 0x75, # a bitstream to/from a shift register
|
|
||||||
I2C_REQUEST => 0x76, # send an I2C read/write request
|
|
||||||
I2C_REPLY => 0x77, # a reply to an I2C read request
|
|
||||||
I2C_CONFIG => 0x78, # config I2C settings such as delay times and power pins
|
|
||||||
REPORT_FIRMWARE => 0x79, # report name and version of the firmware
|
|
||||||
SAMPLING_INTERVAL => 0x7A, # set the poll rate of the main loop
|
|
||||||
SYSEX_NON_REALTIME => 0x7E, # MIDI Reserved for non-realtime messages
|
|
||||||
SYSEX_REALTIME => 0x7F, # MIDI Reserved for realtime messages
|
|
||||||
|
|
||||||
# these are DEPRECATED to make the naming more consistent
|
|
||||||
FIRMATA_STRING => 0x71, # same as STRING_DATA
|
|
||||||
SYSEX_I2C_REQUEST => 0x76, # same as I2C_REQUEST
|
|
||||||
SYSEX_I2C_REPLY => 0x77, # same as I2C_REPLY
|
|
||||||
SYSEX_SAMPLING_INTERVAL => 0x7A, # same as SAMPLING_INTERVAL
|
|
||||||
|
|
||||||
# pin modes
|
|
||||||
INPUT => 0x00, # digital pin in digitalOut mode
|
|
||||||
OUTPUT => 0x01, # digital pin in digitalInput mode
|
|
||||||
ANALOG => 0x02, # analog pin in analogInput mode
|
|
||||||
PWM => 0x03, # digital pin in PWM output mode
|
|
||||||
SERVO => 0x04, # digital pin in Servo output mode
|
|
||||||
SHIFT => 0x05, # shiftIn/shiftOut mode
|
|
||||||
I2C => 0x06, # pin included in I2C setup
|
|
||||||
|
|
||||||
# Deprecated entries
|
|
||||||
deprecated => [
|
|
||||||
qw( FIRMATA_STRING SYSEX_I2C_REQUEST SYSEX_I2C_REPLY SYSEX_SAMPLING_INTERVAL )
|
|
||||||
],
|
|
||||||
}, # /Constants for Version 2.1
|
|
||||||
|
|
||||||
V_2_02 => {
|
|
||||||
|
|
||||||
MAX_DATA_BYTES => 32, # max number of data bytes in non-Sysex messages
|
|
||||||
|
|
||||||
# message command bytes (128-255/0x80-0xFF)
|
|
||||||
DIGITAL_MESSAGE => 0x90, # send data for a digital pin
|
|
||||||
ANALOG_MESSAGE => 0xE0, # send data for an analog pin (or PWM)
|
|
||||||
REPORT_ANALOG => 0xC0, # enable analog input by pin #
|
|
||||||
REPORT_DIGITAL => 0xD0, # enable digital input by port pair
|
|
||||||
SET_PIN_MODE => 0xF4, # set a pin to INPUT/OUTPUT/PWM/etc
|
|
||||||
REPORT_VERSION => 0xF9, # report protocol version
|
|
||||||
SYSTEM_RESET => 0xFF, # reset from MIDI
|
|
||||||
START_SYSEX => 0xF0, # start a MIDI Sysex message
|
|
||||||
END_SYSEX => 0xF7, # end a MIDI Sysex message
|
|
||||||
|
|
||||||
# extended command set using sysex (0-127/0x00-0x7F)
|
|
||||||
RESERVED_COMMAND => 0x00, # 2nd SysEx data byte is a chip-specific command (AVR, PIC, TI, etc).
|
|
||||||
ANALOG_MAPPING_QUERY => 0x69, # ask for mapping of analog to pin numbers
|
|
||||||
ANALOG_MAPPING_RESPONSE => 0x6A, # reply with mapping info
|
|
||||||
CAPABILITY_QUERY => 0x6B, # ask for supported modes and resolution of all pins
|
|
||||||
CAPABILITY_RESPONSE => 0x6C, # reply with supported modes and resolution
|
|
||||||
PIN_STATE_QUERY => 0x6D, # ask for a pin's current mode and value
|
|
||||||
PIN_STATE_RESPONSE => 0x6E, # reply with a pin's current mode and value
|
|
||||||
EXTENDED_ANALOG => 0x6F, # analog write (PWM, Servo, etc) to any pin
|
|
||||||
SERVO_CONFIG => 0x70, # set max angle, minPulse, maxPulse, freq
|
|
||||||
STRING_DATA => 0x71, # a string message with 14-bits per char
|
|
||||||
SHIFT_DATA => 0x75, # shiftOut config/data message (34 bits)
|
|
||||||
I2C_REQUEST => 0x76, # send an I2C read/write request
|
|
||||||
I2C_REPLY => 0x77, # a reply to an I2C read request
|
|
||||||
I2C_CONFIG => 0x78, # config I2C settings such as delay times and power pins
|
|
||||||
REPORT_FIRMWARE => 0x79, # report name and version of the firmware
|
|
||||||
SAMPLING_INTERVAL => 0x7A, # set the poll rate of the main loop
|
|
||||||
SYSEX_NON_REALTIME => 0x7E, # MIDI Reserved for non-realtime messages
|
|
||||||
SYSEX_REALTIME => 0x7F, # MIDI Reserved for realtime messages
|
|
||||||
|
|
||||||
# pin modes
|
|
||||||
INPUT => 0x00, # digital pin in digitalOut mode
|
|
||||||
OUTPUT => 0x01, # digital pin in digitalInput mode
|
|
||||||
ANALOG => 0x02, # analog pin in analogInput mode
|
|
||||||
PWM => 0x03, # digital pin in PWM output mode
|
|
||||||
SERVO => 0x04, # digital pin in Servo output mode
|
|
||||||
SHIFT => 0x05, # shiftIn/shiftOut mode
|
|
||||||
I2C => 0x06, # pin included in I2C setup
|
|
||||||
|
|
||||||
# Deprecated entries
|
|
||||||
deprecated => [
|
|
||||||
qw( FIRMATA_STRING SYSEX_I2C_REQUEST SYSEX_I2C_REPLY SYSEX_SAMPLING_INTERVAL )
|
|
||||||
],
|
|
||||||
|
|
||||||
}, # /Constants for Version 2.2
|
|
||||||
|
|
||||||
V_2_03 => {
|
|
||||||
|
|
||||||
MAX_DATA_BYTES => 32, # max number of data bytes in non-Sysex messages
|
|
||||||
|
|
||||||
# message command bytes (128-255/0x80-0xFF)
|
|
||||||
DIGITAL_MESSAGE => 0x90, # send data for a digital pin
|
|
||||||
ANALOG_MESSAGE => 0xE0, # send data for an analog pin (or PWM)
|
|
||||||
REPORT_ANALOG => 0xC0, # enable analog input by pin #
|
|
||||||
REPORT_DIGITAL => 0xD0, # enable digital input by port pair
|
|
||||||
SET_PIN_MODE => 0xF4, # set a pin to INPUT/OUTPUT/PWM/etc
|
|
||||||
REPORT_VERSION => 0xF9, # report protocol version
|
|
||||||
SYSTEM_RESET => 0xFF, # reset from MIDI
|
|
||||||
START_SYSEX => 0xF0, # start a MIDI Sysex message
|
|
||||||
END_SYSEX => 0xF7, # end a MIDI Sysex message
|
|
||||||
|
|
||||||
# extended command set using sysex (0-127/0x00-0x7F)
|
|
||||||
RESERVED_COMMAND => 0x00, # 2nd SysEx data byte is a chip-specific command (AVR, PIC, TI, etc).
|
|
||||||
ANALOG_MAPPING_QUERY => 0x69, # ask for mapping of analog to pin numbers
|
|
||||||
ANALOG_MAPPING_RESPONSE => 0x6A, # reply with mapping info
|
|
||||||
CAPABILITY_QUERY => 0x6B, # ask for supported modes and resolution of all pins
|
|
||||||
CAPABILITY_RESPONSE => 0x6C, # reply with supported modes and resolution
|
|
||||||
PIN_STATE_QUERY => 0x6D, # ask for a pin's current mode and value
|
|
||||||
PIN_STATE_RESPONSE => 0x6E, # reply with a pin's current mode and value
|
|
||||||
EXTENDED_ANALOG => 0x6F, # analog write (PWM, Servo, etc) to any pin
|
|
||||||
SERVO_CONFIG => 0x70, # set max angle, minPulse, maxPulse, freq
|
|
||||||
STRING_DATA => 0x71, # a string message with 14-bits per char
|
|
||||||
SHIFT_DATA => 0x75, # shiftOut config/data message (34 bits)
|
|
||||||
I2C_REQUEST => 0x76, # send an I2C read/write request
|
|
||||||
I2C_REPLY => 0x77, # a reply to an I2C read request
|
|
||||||
I2C_CONFIG => 0x78, # config I2C settings such as delay times and power pins
|
|
||||||
REPORT_FIRMWARE => 0x79, # report name and version of the firmware
|
|
||||||
SAMPLING_INTERVAL => 0x7A, # set the poll rate of the main loop
|
|
||||||
SYSEX_NON_REALTIME => 0x7E, # MIDI Reserved for non-realtime messages
|
|
||||||
SYSEX_REALTIME => 0x7F, # MIDI Reserved for realtime messages
|
|
||||||
|
|
||||||
# pin modes
|
|
||||||
INPUT => 0x00, # digital pin in digitalOut mode
|
|
||||||
OUTPUT => 0x01, # digital pin in digitalInput mode
|
|
||||||
ANALOG => 0x02, # analog pin in analogInput mode
|
|
||||||
PWM => 0x03, # digital pin in PWM output mode
|
|
||||||
SERVO => 0x04, # digital pin in Servo output mode
|
|
||||||
SHIFT => 0x05, # shiftIn/shiftOut mode
|
|
||||||
I2C => 0x06, # pin included in I2C setup
|
|
||||||
|
|
||||||
# Deprecated entries
|
|
||||||
deprecated => [
|
|
||||||
qw( FIRMATA_STRING SYSEX_I2C_REQUEST SYSEX_I2C_REPLY SYSEX_SAMPLING_INTERVAL )
|
|
||||||
],
|
|
||||||
|
|
||||||
}, # /Constants for Version 2.3 (same as V_2_02)
|
|
||||||
|
|
||||||
V_2_04 => {
|
|
||||||
|
|
||||||
MAX_DATA_BYTES => 64, # max number of data bytes in non-Sysex messages
|
|
||||||
|
|
||||||
# message command bytes (128-255/0x80-0xFF)
|
|
||||||
DIGITAL_MESSAGE => 0x90, # send data for a digital pin
|
|
||||||
ANALOG_MESSAGE => 0xE0, # send data for an analog pin (or PWM)
|
|
||||||
REPORT_ANALOG => 0xC0, # enable analog input by pin #
|
|
||||||
REPORT_DIGITAL => 0xD0, # enable digital input by port pair
|
|
||||||
SET_PIN_MODE => 0xF4, # set a pin to INPUT/OUTPUT/PWM/etc
|
|
||||||
REPORT_VERSION => 0xF9, # report protocol version
|
|
||||||
SYSTEM_RESET => 0xFF, # reset from MIDI
|
|
||||||
START_SYSEX => 0xF0, # start a MIDI Sysex message
|
|
||||||
END_SYSEX => 0xF7, # end a MIDI Sysex message
|
|
||||||
|
|
||||||
# extended command set using sysex (0-127/0x00-0x7F)
|
|
||||||
RESERVED_COMMAND => 0x00, # 2nd SysEx data byte is a chip-specific command (AVR, PIC, TI, etc).
|
|
||||||
ANALOG_MAPPING_QUERY => 0x69, # ask for mapping of analog to pin numbers
|
|
||||||
ANALOG_MAPPING_RESPONSE => 0x6A, # reply with mapping info
|
|
||||||
CAPABILITY_QUERY => 0x6B, # ask for supported modes and resolution of all pins
|
|
||||||
CAPABILITY_RESPONSE => 0x6C, # reply with supported modes and resolution
|
|
||||||
PIN_STATE_QUERY => 0x6D, # ask for a pin's current mode and value
|
|
||||||
PIN_STATE_RESPONSE => 0x6E, # reply with a pin's current mode and value
|
|
||||||
EXTENDED_ANALOG => 0x6F, # analog write (PWM, Servo, etc) to any pin
|
|
||||||
SERVO_CONFIG => 0x70, # set max angle, minPulse, maxPulse, freq
|
|
||||||
STRING_DATA => 0x71, # a string message with 14-bits per char
|
|
||||||
STEPPER_DATA => 0x72, # control a stepper motor
|
|
||||||
ONEWIRE_DATA => 0x73, # OneWire read/write/reset/select/skip/search request + read/search reply
|
|
||||||
SHIFT_DATA => 0x75, # shiftOut config/data message (34 bits)
|
|
||||||
I2C_REQUEST => 0x76, # send an I2C read/write request
|
|
||||||
I2C_REPLY => 0x77, # a reply to an I2C read request
|
|
||||||
I2C_CONFIG => 0x78, # config I2C settings such as delay times and power pins
|
|
||||||
REPORT_FIRMWARE => 0x79, # report name and version of the firmware
|
|
||||||
SAMPLING_INTERVAL => 0x7A, # set the poll rate of the main loop
|
|
||||||
SCHEDULER_DATA => 0x7B, # createtask/deletetask/addtotask/schedule/querytasks/querytask request and querytasks/querytask reply
|
|
||||||
SYSEX_NON_REALTIME => 0x7E, # MIDI Reserved for non-realtime messages
|
|
||||||
SYSEX_REALTIME => 0x7F, # MIDI Reserved for realtime messages
|
|
||||||
|
|
||||||
# pin modes
|
|
||||||
INPUT => 0x00, # digital pin in digitalOut mode
|
|
||||||
OUTPUT => 0x01, # digital pin in digitalInput mode
|
|
||||||
ANALOG => 0x02, # analog pin in analogInput mode
|
|
||||||
PWM => 0x03, # digital pin in PWM output mode
|
|
||||||
SERVO => 0x04, # digital pin in Servo output mode
|
|
||||||
SHIFT => 0x05, # shiftIn/shiftOut mode
|
|
||||||
I2C => 0x06, # pin included in I2C setup
|
|
||||||
ONEWIRE => 0x07, # pin configured for 1-Wire commuication
|
|
||||||
STEPPER => 0x08, # pin configured for stepper motor
|
|
||||||
|
|
||||||
# Deprecated entries
|
|
||||||
deprecated => [
|
|
||||||
qw( FIRMATA_STRING SYSEX_I2C_REQUEST SYSEX_I2C_REPLY SYSEX_SAMPLING_INTERVAL )
|
|
||||||
],
|
|
||||||
}, # /Constants for Version 2.4
|
|
||||||
|
|
||||||
V_2_05 => {
|
|
||||||
|
|
||||||
MAX_DATA_BYTES => 64, # max number of data bytes in non-Sysex messages
|
|
||||||
|
|
||||||
# message command bytes (128-255/0x80-0xFF)
|
|
||||||
DIGITAL_MESSAGE => 0x90, # send data for a digital pin
|
|
||||||
ANALOG_MESSAGE => 0xE0, # send data for an analog pin (or PWM)
|
|
||||||
REPORT_ANALOG => 0xC0, # enable analog input by pin #
|
|
||||||
REPORT_DIGITAL => 0xD0, # enable digital input by port pair
|
|
||||||
SET_PIN_MODE => 0xF4, # set a pin to INPUT/OUTPUT/PWM/etc
|
|
||||||
REPORT_VERSION => 0xF9, # report protocol version
|
|
||||||
SYSTEM_RESET => 0xFF, # reset from MIDI
|
|
||||||
START_SYSEX => 0xF0, # start a MIDI Sysex message
|
|
||||||
END_SYSEX => 0xF7, # end a MIDI Sysex message
|
|
||||||
|
|
||||||
# extended command set using sysex (0-127/0x00-0x7F)
|
|
||||||
RESERVED_COMMAND => 0x00, # 2nd SysEx data byte is a chip-specific command (AVR, PIC, TI, etc).
|
|
||||||
SERIAL_DATA => 0x60, # serial port config/write/read/close/flush/listen request and read reply
|
|
||||||
ENCODER_DATA => 0x61, # receive rotary-encoders current positions
|
|
||||||
ANALOG_MAPPING_QUERY => 0x69, # ask for mapping of analog to pin numbers
|
|
||||||
ANALOG_MAPPING_RESPONSE => 0x6A, # reply with mapping info
|
|
||||||
CAPABILITY_QUERY => 0x6B, # ask for supported modes and resolution of all pins
|
|
||||||
CAPABILITY_RESPONSE => 0x6C, # reply with supported modes and resolution
|
|
||||||
PIN_STATE_QUERY => 0x6D, # ask for a pin's current mode and value
|
|
||||||
PIN_STATE_RESPONSE => 0x6E, # reply with a pin's current mode and value
|
|
||||||
EXTENDED_ANALOG => 0x6F, # analog write (PWM, Servo, etc) to any pin
|
|
||||||
SERVO_CONFIG => 0x70, # set max angle, minPulse, maxPulse, freq
|
|
||||||
STRING_DATA => 0x71, # a string message with 14-bits per char
|
|
||||||
STEPPER_DATA => 0x72, # control a stepper motor
|
|
||||||
ONEWIRE_DATA => 0x73, # OneWire read/write/reset/select/skip/search request + read/search reply
|
|
||||||
SHIFT_DATA => 0x75, # shiftOut config/data message (34 bits)
|
|
||||||
I2C_REQUEST => 0x76, # send an I2C read/write request
|
|
||||||
I2C_REPLY => 0x77, # a reply to an I2C read request
|
|
||||||
I2C_CONFIG => 0x78, # config I2C settings such as delay times and power pins
|
|
||||||
REPORT_FIRMWARE => 0x79, # report name and version of the firmware
|
|
||||||
SAMPLING_INTERVAL => 0x7A, # set the poll rate of the main loop
|
|
||||||
SCHEDULER_DATA => 0x7B, # createtask/deletetask/addtotask/schedule/querytasks/querytask request and querytasks/querytask reply
|
|
||||||
SYSEX_NON_REALTIME => 0x7E, # MIDI Reserved for non-realtime messages
|
|
||||||
SYSEX_REALTIME => 0x7F, # MIDI Reserved for realtime messages
|
|
||||||
|
|
||||||
# pin modes
|
|
||||||
INPUT => 0x00, # digital pin in digitalOut mode
|
|
||||||
OUTPUT => 0x01, # digital pin in digitalInput mode
|
|
||||||
ANALOG => 0x02, # analog pin in analogInput mode
|
|
||||||
PWM => 0x03, # digital pin in PWM output mode
|
|
||||||
SERVO => 0x04, # digital pin in Servo output mode
|
|
||||||
SHIFT => 0x05, # shiftIn/shiftOut mode
|
|
||||||
I2C => 0x06, # pin included in I2C setup
|
|
||||||
ONEWIRE => 0x07, # pin configured for 1-Wire commuication
|
|
||||||
STEPPER => 0x08, # pin configured for stepper motor
|
|
||||||
SERIAL => 0x0A, # pin configured for serial port
|
|
||||||
PULLUP => 0x0B, # digital pin in digitalInput mode with pullup
|
|
||||||
|
|
||||||
# Deprecated entries
|
|
||||||
deprecated => [
|
|
||||||
qw( FIRMATA_STRING SYSEX_I2C_REQUEST SYSEX_I2C_REPLY SYSEX_SAMPLING_INTERVAL )
|
|
||||||
],
|
|
||||||
|
|
||||||
}, # /Constants for Version 2.5
|
|
||||||
|
|
||||||
V_2_06 => {
|
|
||||||
|
|
||||||
MAX_DATA_BYTES => 64, # max number of data bytes in non-Sysex messages
|
|
||||||
|
|
||||||
# message command bytes (128-255/0x80-0xFF)
|
|
||||||
DIGITAL_MESSAGE => 0x90, # send data for a digital pin
|
|
||||||
ANALOG_MESSAGE => 0xE0, # send data for an analog pin (or PWM)
|
|
||||||
REPORT_ANALOG => 0xC0, # enable analog input by pin #
|
|
||||||
REPORT_DIGITAL => 0xD0, # enable digital input by port pair
|
|
||||||
SET_PIN_MODE => 0xF4, # set a pin to INPUT/OUTPUT/PWM/etc
|
|
||||||
REPORT_VERSION => 0xF9, # report protocol version
|
|
||||||
SYSTEM_RESET => 0xFF, # reset from MIDI
|
|
||||||
START_SYSEX => 0xF0, # start a MIDI Sysex message
|
|
||||||
END_SYSEX => 0xF7, # end a MIDI Sysex message
|
|
||||||
|
|
||||||
# extended command set using sysex (0-127/0x00-0x7F)
|
|
||||||
RESERVED_COMMAND => 0x00, # 2nd SysEx data byte is a chip-specific command (AVR, PIC, TI, etc).
|
|
||||||
SERIAL_DATA => 0x60, # serial port config/write/read/close/flush/listen request and read reply
|
|
||||||
ENCODER_DATA => 0x61, # receive rotary-encoders current positions
|
|
||||||
ANALOG_MAPPING_QUERY => 0x69, # ask for mapping of analog to pin numbers
|
|
||||||
ANALOG_MAPPING_RESPONSE => 0x6A, # reply with mapping info
|
|
||||||
CAPABILITY_QUERY => 0x6B, # ask for supported modes and resolution of all pins
|
|
||||||
CAPABILITY_RESPONSE => 0x6C, # reply with supported modes and resolution
|
|
||||||
PIN_STATE_QUERY => 0x6D, # ask for a pin's current mode and value
|
|
||||||
PIN_STATE_RESPONSE => 0x6E, # reply with a pin's current mode and value
|
|
||||||
EXTENDED_ANALOG => 0x6F, # analog write (PWM, Servo, etc) to any pin
|
|
||||||
SERVO_CONFIG => 0x70, # set max angle, minPulse, maxPulse, freq
|
|
||||||
STRING_DATA => 0x71, # a string message with 14-bits per char
|
|
||||||
STEPPER_DATA => 0x72, # control a stepper motor
|
|
||||||
ONEWIRE_DATA => 0x73, # OneWire read/write/reset/select/skip/search request + read/search reply
|
|
||||||
SHIFT_DATA => 0x75, # shiftOut config/data message (34 bits)
|
|
||||||
I2C_REQUEST => 0x76, # send an I2C read/write request
|
|
||||||
I2C_REPLY => 0x77, # a reply to an I2C read request
|
|
||||||
I2C_CONFIG => 0x78, # config I2C settings such as delay times and power pins
|
|
||||||
REPORT_FIRMWARE => 0x79, # report name and version of the firmware
|
|
||||||
SAMPLING_INTERVAL => 0x7A, # set the poll rate of the main loop
|
|
||||||
SCHEDULER_DATA => 0x7B, # createtask/deletetask/addtotask/schedule/querytasks/querytask request and querytasks/querytask reply
|
|
||||||
SYSEX_NON_REALTIME => 0x7E, # MIDI Reserved for non-realtime messages
|
|
||||||
SYSEX_REALTIME => 0x7F, # MIDI Reserved for realtime messages
|
|
||||||
|
|
||||||
# pin modes
|
|
||||||
INPUT => 0x00, # digital pin in digitalOut mode
|
|
||||||
OUTPUT => 0x01, # digital pin in digitalInput mode
|
|
||||||
ANALOG => 0x02, # analog pin in analogInput mode
|
|
||||||
PWM => 0x03, # digital pin in PWM output mode
|
|
||||||
SERVO => 0x04, # digital pin in Servo output mode
|
|
||||||
SHIFT => 0x05, # shiftIn/shiftOut mode
|
|
||||||
I2C => 0x06, # pin included in I2C setup
|
|
||||||
ONEWIRE => 0x07, # pin configured for 1-Wire commuication
|
|
||||||
STEPPER => 0x08, # pin configured for stepper motor
|
|
||||||
ENCODER => 0x09, # pin configured for rotary-encoders
|
|
||||||
SERIAL => 0x0A, # pin configured for serial port
|
|
||||||
PULLUP => 0x0B, # digital pin in digitalInput mode with pullup
|
|
||||||
|
|
||||||
# Deprecated entries
|
|
||||||
deprecated => [
|
|
||||||
qw( FIRMATA_STRING SYSEX_I2C_REQUEST SYSEX_I2C_REPLY SYSEX_SAMPLING_INTERVAL )
|
|
||||||
],
|
|
||||||
|
|
||||||
}, # /Constants for Version 2.6
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
# Handle the reverse lookups of the protocol
|
|
||||||
$COMMAND_LOOKUP = {};
|
|
||||||
while ( my ( $protocol_version, $protocol_commands ) = each %$COMMANDS ) {
|
|
||||||
my $protocol_lookup = $COMMAND_LOOKUP->{$protocol_version} = {};
|
|
||||||
my $deprecated = $protocol_lookup->{deprecated} || [];
|
|
||||||
my $deprecated_lookup = { map { ( $_ => 1 ) } @$deprecated };
|
|
||||||
while ( my ( $protocol_command, $command_value ) = each %$protocol_commands ) {
|
|
||||||
next if $protocol_command eq 'deprecated';
|
|
||||||
next if $deprecated_lookup->{$protocol_command};
|
|
||||||
$protocol_lookup->{$command_value} = $protocol_command;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Now we consolidate all the string keynames into a single master list.
|
|
||||||
use constant ( $COMMAND_NAMES = { map { map { ( $_ => $_ ) } keys %$_ } values %$COMMANDS } );
|
|
||||||
use constant { COMMAND_NAMES => [ $COMMAND_NAMES = [ keys %$COMMAND_NAMES ] ] };
|
|
||||||
|
|
||||||
@EXPORT_OK = (
|
|
||||||
@$COMMAND_NAMES, keys %$BASE,
|
|
||||||
keys %$COMMANDS,
|
|
||||||
qw( $COMMANDS $COMMAND_NAMES $COMMAND_LOOKUP ),
|
|
||||||
);
|
|
||||||
|
|
||||||
%EXPORT_TAGS = ( all => \@EXPORT_OK );
|
|
||||||
|
|
||||||
1;
|
|
@ -1,92 +0,0 @@
|
|||||||
package Device::Firmata::Error;
|
|
||||||
# ==================================================================
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
Device::Firmata::Error - Error handlers
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use Exporter;
|
|
||||||
use vars qw/
|
|
||||||
@ISA
|
|
||||||
%ERRORS
|
|
||||||
@EXPORT
|
|
||||||
$FIRMATA_ERROR_DEFAULT
|
|
||||||
@ERROR_STACK
|
|
||||||
/;
|
|
||||||
use Device::Firmata::Base;
|
|
||||||
|
|
||||||
@ISA = 'Exporter';
|
|
||||||
|
|
||||||
@EXPORT = qw();
|
|
||||||
|
|
||||||
$FIRMATA_ERROR_DEFAULT = -1;
|
|
||||||
|
|
||||||
|
|
||||||
=head2 error
|
|
||||||
|
|
||||||
The base error reporting system. All errors will be
|
|
||||||
stored in this object until the error flush code is called.
|
|
||||||
This will allow the system to collect all errors that occur
|
|
||||||
in various parts of the system in one place. Very useful
|
|
||||||
for error reporting since it's a simple call to find
|
|
||||||
out the last error.
|
|
||||||
|
|
||||||
Invocation of this function
|
|
||||||
|
|
||||||
$err->error( [numerical error level], ErrorMessage, ... parameters ... );
|
|
||||||
|
|
||||||
ErrorMessage can be in the format "KEY" that will be referenced by
|
|
||||||
Device::Firmata::Base->language or "KEY:Message" where if ->language does
|
|
||||||
not map to anything, the error will default to Message
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub error {
|
|
||||||
# --------------------------------------------------
|
|
||||||
#
|
|
||||||
my $self = shift;
|
|
||||||
my $error_level = $_[0] =~ /^\-?\d+$/ ? shift : $FIRMATA_ERROR_DEFAULT;
|
|
||||||
my $message = shift;
|
|
||||||
my $error_code;
|
|
||||||
if ( $message =~ /^([A-Z0-9_]+)\s*:\s*/ ) {
|
|
||||||
$error_code = $1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$error_code = $message;
|
|
||||||
};
|
|
||||||
my $text = Device::Firmata::Base->language($message,@_);
|
|
||||||
push @ERROR_STACK, [ $text, $error_level, $text ];
|
|
||||||
|
|
||||||
if ( $error_level < 1 ) {
|
|
||||||
my $i = 1;
|
|
||||||
my ( $pkg, $fn, $line );
|
|
||||||
|
|
||||||
# Proceed up the call stack until we find out where the error likely occured (ie. Not in Device::Firmata::Base)
|
|
||||||
do { ( $pkg, $fn, $line ) = caller($i); $i++; } while ( $pkg eq 'Device::Firmata::Base' );
|
|
||||||
|
|
||||||
$error_level < 0 ? die "\@$fn:$pkg:$line". ' : ' . $text . "\n"
|
|
||||||
: warn "\@$fn:$pkg:$line". ' : ' . $text . "\n";
|
|
||||||
};
|
|
||||||
|
|
||||||
# warn "Error called with args: @_ from " . join( " ", caller() ) . "\n";
|
|
||||||
# require Carp;
|
|
||||||
# Carp::cluck();
|
|
||||||
|
|
||||||
return $text;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
=head2 errors_flush
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub errors_flush {
|
|
||||||
# --------------------------------------------------
|
|
||||||
@ERROR_STACK = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
1;
|
|
@ -1,203 +0,0 @@
|
|||||||
package Device::Firmata::IO::NetIO;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
use IO::Socket::INET;
|
|
||||||
use IO::Select;
|
|
||||||
|
|
||||||
use vars qw//;
|
|
||||||
use Device::Firmata::Base
|
|
||||||
ISA => 'Device::Firmata::Base',
|
|
||||||
FIRMATA_ATTRIBS => {
|
|
||||||
};
|
|
||||||
|
|
||||||
sub listen {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my ( $pkg, $ip, $port, $opts ) = @_;
|
|
||||||
|
|
||||||
my $self = ref $pkg ? $pkg : $pkg->new($opts);
|
|
||||||
|
|
||||||
# flush after every write
|
|
||||||
$| = 1;
|
|
||||||
|
|
||||||
my $socket;
|
|
||||||
|
|
||||||
# creating object interface of IO::Socket::INET modules which internally does
|
|
||||||
# socket creation, binding and listening at the specified port address.
|
|
||||||
$socket = new IO::Socket::INET (
|
|
||||||
LocalHost => $ip,
|
|
||||||
LocalPort => $port,
|
|
||||||
Proto => 'tcp',
|
|
||||||
Listen => 5,
|
|
||||||
Reuse => 1
|
|
||||||
) or die "ERROR in Socket Creation : $!\n";
|
|
||||||
|
|
||||||
$self->{'socket'} = $socket;
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub accept {
|
|
||||||
|
|
||||||
my ($self,$timeout) = @_;
|
|
||||||
# waiting for new client connection.
|
|
||||||
my $s = $self->{'select'};
|
|
||||||
if (!($s)) {
|
|
||||||
$s = IO::Select->new();
|
|
||||||
$s->add($self->{'socket'});
|
|
||||||
$self->{'select'} = $s;
|
|
||||||
}
|
|
||||||
if(my @ready = $s->can_read($timeout)) {
|
|
||||||
my $socket = $self->{'socket'};
|
|
||||||
foreach my $fh (@ready) {
|
|
||||||
if ($fh == $socket) {
|
|
||||||
if (my $client_socket = $socket->accept()) {
|
|
||||||
return $self->attach($client_socket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub close {
|
|
||||||
my $self = shift;
|
|
||||||
if ($self->{'select'} && $self->{'socket'}) {
|
|
||||||
$self->{'select'}->remove($self->{'socket'});
|
|
||||||
delete $self->{'select'};
|
|
||||||
}
|
|
||||||
if ($self->{'socket'}) {
|
|
||||||
$self->{'socket'}->close();
|
|
||||||
delete $self->{'socket'};
|
|
||||||
}
|
|
||||||
if ($self->{clients}) {
|
|
||||||
foreach my $client (@{$self->{clients}}) {
|
|
||||||
$client->close();
|
|
||||||
}
|
|
||||||
delete $self->{clients};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub attach {
|
|
||||||
my ( $pkg, $client_socket, $opts ) = @_;
|
|
||||||
|
|
||||||
my $self = ref $pkg ? $pkg : $pkg->new($opts);
|
|
||||||
|
|
||||||
my $clientpackage = "Device::Firmata::IO::NetIO::Client";
|
|
||||||
eval "require $clientpackage";
|
|
||||||
|
|
||||||
my $clientio = $clientpackage->attach($client_socket);
|
|
||||||
|
|
||||||
my $package = "Device::Firmata::Platform";
|
|
||||||
eval "require $package";
|
|
||||||
my $platform = $package->attach( $clientio, $opts ) or die "Could not connect to Firmata Server";
|
|
||||||
|
|
||||||
my $s = $self->{'select'};
|
|
||||||
if (!($s)) {
|
|
||||||
$s = IO::Select->new();
|
|
||||||
$self->{'select'} = $s;
|
|
||||||
}
|
|
||||||
$s->add($client_socket);
|
|
||||||
my $clients = $self->{clients};
|
|
||||||
if (!($clients)) {
|
|
||||||
$clients = [];
|
|
||||||
$self->{clients} = $clients;
|
|
||||||
}
|
|
||||||
push $clients, $platform;
|
|
||||||
|
|
||||||
# Figure out what platform we're running on
|
|
||||||
$platform->probe();
|
|
||||||
|
|
||||||
return $platform;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub poll {
|
|
||||||
my ($self,$timeout) = @_;
|
|
||||||
my $s = $self->{'select'};
|
|
||||||
return unless $s;
|
|
||||||
if(my @ready = $s->can_read($timeout)) {
|
|
||||||
my $socket = $self->{'socket'};
|
|
||||||
my $clients = $self->{clients};
|
|
||||||
if (! defined($clients)) {
|
|
||||||
$clients = [];
|
|
||||||
$self->{clients} = $clients;
|
|
||||||
}
|
|
||||||
my @readyclients = ();
|
|
||||||
foreach my $fh (@ready) {
|
|
||||||
if ($fh != $socket) {
|
|
||||||
push @readyclients, grep { $fh == $_->{io}->{client}; } @$clients;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach my $readyclient (@readyclients) {
|
|
||||||
$readyclient->poll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
package Device::Firmata::IO::NetIO::Client;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
use IO::Socket::INET;
|
|
||||||
|
|
||||||
use vars qw//;
|
|
||||||
use Device::Firmata::Base
|
|
||||||
ISA => 'Device::Firmata::Base',
|
|
||||||
FIRMATA_ATTRIBS => {
|
|
||||||
};
|
|
||||||
|
|
||||||
sub attach {
|
|
||||||
my ( $pkg, $client_socket, $opts ) = @_;
|
|
||||||
|
|
||||||
my $self = ref $pkg ? $pkg : $pkg->new($opts);
|
|
||||||
|
|
||||||
$self->{client} = $client_socket;
|
|
||||||
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 data_write
|
|
||||||
|
|
||||||
Dump a bunch of data into the comm port
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub data_write {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my ( $self, $buf ) = @_;
|
|
||||||
$Device::Firmata::DEBUG and print ">".join(",",map{sprintf"%02x",ord$_}split//,$buf)."\n";
|
|
||||||
return $self->{client}->write( $buf );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
=head2 data_read
|
|
||||||
|
|
||||||
We fetch up to $bytes from the comm port
|
|
||||||
This function is non-blocking
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub data_read {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my ( $self, $bytes ) = @_;
|
|
||||||
my ($buf, $res);
|
|
||||||
$res = $self->{client}->sysread($buf, 512);
|
|
||||||
$buf = "" if(!defined($res));
|
|
||||||
|
|
||||||
if ( $Device::Firmata::DEBUG and $buf ) {
|
|
||||||
print "<".join(",",map{sprintf"%02x",ord$_}split//,$buf)."\n";
|
|
||||||
}
|
|
||||||
return $buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 close
|
|
||||||
|
|
||||||
close the underlying connection
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub close {
|
|
||||||
my $self = shift;
|
|
||||||
$self->{client}->close() if (($self->{client}) and $self->{client}->connected());
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,77 +0,0 @@
|
|||||||
package Device::Firmata::IO::SerialIO;
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
Device::Firmata::IO::SerialIO - implement the low level serial IO
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
use vars qw/ $SERIAL_CLASS /;
|
|
||||||
use Device::Firmata::Base
|
|
||||||
ISA => 'Device::Firmata::Base',
|
|
||||||
FIRMATA_ATTRIBS => {
|
|
||||||
handle => undef,
|
|
||||||
baudrate => 57600,
|
|
||||||
};
|
|
||||||
|
|
||||||
$SERIAL_CLASS = $^O eq 'MSWin32' ? 'Win32::SerialPort'
|
|
||||||
: 'Device::SerialPort';
|
|
||||||
eval "require $SERIAL_CLASS";
|
|
||||||
|
|
||||||
|
|
||||||
=head2 open
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub open {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my ( $pkg, $serial_port, $opts ) = @_;
|
|
||||||
my $self = ref $pkg ? $pkg : $pkg->new($opts);
|
|
||||||
my $serial_obj = $SERIAL_CLASS->new( $serial_port, 1, 0 ) or return;
|
|
||||||
$self->attach($serial_obj,$opts);
|
|
||||||
$self->{handle}->baudrate($self->{baudrate});
|
|
||||||
$self->{handle}->databits(8);
|
|
||||||
$self->{handle}->stopbits(1);
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub attach {
|
|
||||||
my ( $pkg, $serial_obj, $opts ) = @_;
|
|
||||||
my $self = ref $pkg ? $pkg : $pkg->new($opts);
|
|
||||||
$self->{handle} = $serial_obj;
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
=head2 data_write
|
|
||||||
|
|
||||||
Dump a bunch of data into the comm port
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub data_write {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my ( $self, $buf ) = @_;
|
|
||||||
$Device::Firmata::DEBUG and print ">".join(",",map{sprintf"%02x",ord$_}split//,$buf)."\n";
|
|
||||||
return $self->{handle}->write( $buf );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
=head2 data_read
|
|
||||||
|
|
||||||
We fetch up to $bytes from the comm port
|
|
||||||
This function is non-blocking
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub data_read {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my ( $self, $bytes ) = @_;
|
|
||||||
my ( $count, $string ) = $self->{handle}->read($bytes);
|
|
||||||
print "<".join(",",map{sprintf"%02x",ord$_}split//,$string)."\n" if ( $Device::Firmata::DEBUG and $string );
|
|
||||||
return $string;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@ -1,106 +0,0 @@
|
|||||||
package Device::Firmata::Language;
|
|
||||||
# ==================================================================
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
Device::Firmata::Language - Localization
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use vars qw/
|
|
||||||
$FIRMATA_LOCALE
|
|
||||||
$FIRMATA_LOCALE_PATH
|
|
||||||
$FIRMATA_LOCALE_MESSAGES
|
|
||||||
/;
|
|
||||||
use Device::Firmata::Base
|
|
||||||
ISA => 'Device::Firmata::Base',
|
|
||||||
FIRMATA_ATTRIBS => {
|
|
||||||
messages => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
$FIRMATA_LOCALE_MESSAGES = {
|
|
||||||
};
|
|
||||||
$FIRMATA_LOCALE = 'en';
|
|
||||||
$FIRMATA_LOCALE_PATH = '.';
|
|
||||||
|
|
||||||
|
|
||||||
=head2 numbers
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub numbers {
|
|
||||||
# --------------------------------------------------
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
=head2 date
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub date {
|
|
||||||
# --------------------------------------------------
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
=head2 language
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
sub language {
|
|
||||||
# --------------------------------------------------
|
|
||||||
my $self = shift;
|
|
||||||
|
|
||||||
my $messages = $FIRMATA_LOCALE_MESSAGES->{$FIRMATA_LOCALE} ||= do {
|
|
||||||
my $target_fpath = "$FIRMATA_LOCALE_PATH/$FIRMATA_LOCALE.txt";
|
|
||||||
|
|
||||||
my $m;
|
|
||||||
require Symbol;
|
|
||||||
my $fh = Symbol::gensym();
|
|
||||||
|
|
||||||
if ( -f $target_fpath ) {
|
|
||||||
open $fh, "<$target_fpath" or die $!;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$fh = \*DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ( my $l = <$fh> ) {
|
|
||||||
next if $l =~ /^\s*$/;
|
|
||||||
$l =~ /([^\s]*)\s+(.*)/;
|
|
||||||
( $m ||= {} )->{$1} = $2;
|
|
||||||
}
|
|
||||||
close $fh;
|
|
||||||
$m;
|
|
||||||
};
|
|
||||||
|
|
||||||
# This will parse messages coming through such that it will
|
|
||||||
# be possible to encode a language string with a code in the
|
|
||||||
# following formats:
|
|
||||||
#
|
|
||||||
# ->language( "CODE", $parametrs ... )
|
|
||||||
# ->language( "CODE:Default Message %s", $parametrs ... )
|
|
||||||
#
|
|
||||||
my $message = shift or return;
|
|
||||||
$message =~ s/^([\w_]+)\s*:?\s*//;
|
|
||||||
my $key = $1;
|
|
||||||
my $message_template;
|
|
||||||
|
|
||||||
# Get the message template in the following order:
|
|
||||||
# 1. The local object if available
|
|
||||||
# 2. The global message object
|
|
||||||
# 3. The provided default message
|
|
||||||
#
|
|
||||||
ref $self and $message_template = $self->{messages}{$key};
|
|
||||||
$message_template ||= $messages->{$key} || $message;
|
|
||||||
return sprintf( $message_template, @_ );
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
||||||
|
|
||||||
__DATA__
|
|
||||||
FIRMATA__unhandled Unhandled attribute '%s' called
|
|
||||||
FIRMATA__unknown Unknown/Unhandled error encountered: %s
|
|
||||||
|
|
||||||
FIRMATA__separator ,
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -1,19 +0,0 @@
|
|||||||
package Device::Firmata::Platform::Arduino;
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
Device::Firmata::Platform::Arduino - subclass for the arduino itself
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
No customization requried at this time so this is just a specification of the
|
|
||||||
Device::Firmata::Platform class
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use Device::Firmata::Platform;
|
|
||||||
use Device::Firmata::Base
|
|
||||||
ISA => 'Device::Firmata::Platform';
|
|
||||||
|
|
||||||
1;
|
|
File diff suppressed because it is too large
Load Diff
@ -1,47 +0,0 @@
|
|||||||
Device-Firmata
|
|
||||||
|
|
||||||
Device::Firmata - Perl interface to the Firmata protocol for talking to the arduino microcontroler platform. See http://firmata.org/wiki/Main_Page for more details.
|
|
||||||
|
|
||||||
INSTALLATION
|
|
||||||
|
|
||||||
To install this module, run the following commands:
|
|
||||||
|
|
||||||
perl Makefile.PL
|
|
||||||
make
|
|
||||||
make test
|
|
||||||
make install
|
|
||||||
|
|
||||||
SUPPORT AND DOCUMENTATION
|
|
||||||
|
|
||||||
After installing, you can find documentation for this module with the
|
|
||||||
perldoc command.
|
|
||||||
|
|
||||||
perldoc Device::Firmata
|
|
||||||
|
|
||||||
You can also look for information at:
|
|
||||||
|
|
||||||
RT, CPAN's request tracker
|
|
||||||
http://rt.cpan.org/NoAuth/Bugs.html?Dist=Device-Firmata
|
|
||||||
|
|
||||||
AnnoCPAN, Annotated CPAN documentation
|
|
||||||
http://annocpan.org/dist/Device-Firmata
|
|
||||||
|
|
||||||
CPAN Ratings
|
|
||||||
http://cpanratings.perl.org/d/Device-Firmata
|
|
||||||
|
|
||||||
Search CPAN
|
|
||||||
http://search.cpan.org/dist/Device-Firmata/
|
|
||||||
|
|
||||||
|
|
||||||
LICENSE AND COPYRIGHT
|
|
||||||
|
|
||||||
Copyright (C) 2011 amimato
|
|
||||||
Copyright (C) 2012 ntruchsess
|
|
||||||
Copyright (C) 2016 jnsbyr
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it
|
|
||||||
under the terms of either: the GNU General Public License as published
|
|
||||||
by the Free Software Foundation; or the Artistic License.
|
|
||||||
|
|
||||||
See http://dev.perl.org/licenses/ for more information.
|
|
||||||
|
|
@ -1 +0,0 @@
|
|||||||
perl-firmata is distributed under the same terms as perl itself
|
|
Loading…
x
Reference in New Issue
Block a user