2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-13 17:26:34 +00:00

lib/Device/Firmata: bump driver vesion to 0.63 (Forum #81815)

git-svn-id: https://svn.fhem.de/fhem/trunk@15744 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
jensb 2018-01-01 10:42:43 +00:00
parent b99a628149
commit 119c9a3885
8 changed files with 376 additions and 31 deletions

View File

@ -8,18 +8,18 @@ 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.59
Version 0.63
=cut
our $VERSION = '0.59';
our $VERSION = '0.63';
our $DEBUG = 0;
@ -58,34 +58,32 @@ sub open {
# --------------------------------------------------
# Establish a connection to Arduino via the serial port
#
my ( $self, $serial_port, $opts ) = @_;
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";
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;
$platform->probe;
return $platform;
}
sub listen {
# --------------------------------------------------
# Listen on socket and wait for Arduino to establish a connection
#
my ( $pkg, $ip, $port, $opts ) = @_;
my ( $pkg, $ip, $port, $opts ) = @_;
my $netio = "Device::Firmata::IO::NetIO";
eval "require $netio";
return $netio->listen( $ip, $port, $opts ) or die "Could not bind to socket";
my $netio = "Device::Firmata::IO::NetIO";
eval "require $netio";
return $netio->listen( $ip, $port, $opts ) || die "Could not bind to socket";
}
1;

View File

@ -0,0 +1,59 @@
Revision history for Device-Firmata
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

View File

@ -29,6 +29,7 @@ use constant (
PIN_ONEWIRE => 7,
PIN_STEPPER => 8,
PIN_ENCODER => 9,
PIN_SERIAL => 10,
PIN_LOW => 0,
PIN_HIGH => 1,
}
@ -260,6 +261,8 @@ use constant (
# 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
@ -291,6 +294,8 @@ use constant (
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
# Deprecated entries
deprecated => [
qw( FIRMATA_STRING SYSEX_I2C_REQUEST SYSEX_I2C_REPLY SYSEX_SAMPLING_INTERVAL )
@ -315,6 +320,7 @@ use constant (
# 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
@ -348,14 +354,14 @@ use constant (
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
# Deprecated entries
deprecated => [
qw( FIRMATA_STRING SYSEX_I2C_REQUEST SYSEX_I2C_REPLY SYSEX_SAMPLING_INTERVAL )
],
}, # /Constants for Version 2.6
}, # /Constants for Version 2.6
}
);

View File

@ -30,6 +30,7 @@ use Device::Firmata::Base
servo_resolutions => {},
stepper_resolutions => {},
encoder_resolutions => {},
serial_resolutions => {},
ports => [],
input_ports => [],
pins => {},
@ -44,6 +45,7 @@ use Device::Firmata::Base
onewire_observer => [],
stepper_observer => [],
encoder_observer => [],
serial_observer => [],
scheduler_observer => undef,
string_observer => undef,
@ -93,6 +95,7 @@ sub detach {
$self->{onewire_observer} = [];
$self->{stepper_observer} = [];
$self->{encoder_observer} = [];
$self->{serial_observer} = [];
$self->{scheduler_observer} = undef;
$self->{tasks} = [];
$self->{metadata} = {};
@ -119,6 +122,7 @@ sub system_reset {
$self->{onewire_observer} = [];
$self->{stepper_observer} = [];
$self->{encoder_observer} = [];
$self->{serial_observer} = [];
$self->{scheduler_observer} = undef;
$self->{tasks} = [];
$self->{metadata} = {};
@ -186,7 +190,7 @@ sub messages_handle {
# Handle metadata information
$command eq 'REPORT_VERSION' and do {
$self->{metadata}{firmware_version} = sprintf "V_%i_%02i",
$self->{metadata}{protocol_version} = sprintf "V_%i_%02i",
@$data;
last;
};
@ -251,6 +255,7 @@ sub sysex_handle {
my @onewirepins;
my @stepperpins;
my @encoderpins;
my @serialpins;
foreach my $pin (keys %$capabilities) {
if (defined $capabilities->{$pin}) {
@ -289,6 +294,10 @@ sub sysex_handle {
push @encoderpins, $pin;
$self->{metadata}{encoder_resolutions}{$pin} = $capabilities->{$pin}->{PIN_ENCODER+0}->{resolution};
}
if ($capabilities->{$pin}->{PIN_SERIAL+0}) {
push @serialpins, $pin;
$self->{metadata}{serial_resolutions}{$pin} = $capabilities->{$pin}->{PIN_SERIAL+0}->{resolution};
}
}
}
$self->{metadata}{input_pins} = \@inputpins;
@ -301,6 +310,7 @@ sub sysex_handle {
$self->{metadata}{onewire_pins} = \@onewirepins;
$self->{metadata}{stepper_pins} = \@stepperpins;
$self->{metadata}{encoder_pins} = \@encoderpins;
$self->{metadata}{serial_pins} = \@serialpins;
last;
};
@ -373,6 +383,15 @@ sub sysex_handle {
};
last;
};
$sysex_message->{command_str} eq 'SERIAL_DATA' and do {
my $serialPort = $data->{port};
my $observer = $self->{serial_observer}[$serialPort];
if (defined $observer) {
$observer->{method}( $data, $observer->{context} );
}
last;
};
}
}
@ -392,14 +411,16 @@ sub probe {
my ($self) = @_;
$self->{metadata}{firmware} = '';
$self->{metadata}{firmware_version} = '';
$self->{metadata}{protocol_version} = '';
# Wait for 5 seconds only
my $end_tics = time + 5;
$self->firmware_version_query();
$self->protocol_version_query();
while ( $end_tics >= time ) {
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};
select( undef, undef, undef, 0.2 ); # wait for responses
if ( $self->poll && $self->{metadata}{firmware} && $self->{metadata}{firmware_version} && $self->{metadata}{protocol_version} ) {
$self->{protocol}->{protocol_version} = $self->{protocol}->get_max_supported_protocol_version($self->{metadata}{protocol_version});
if ( $self->{metadata}{capabilities} ) {
if ( $self->{metadata}{analog_mappings} ) {
return 1;
@ -409,8 +430,10 @@ sub probe {
} else {
$self->capability_query();
}
} else {
$self->firmware_version_query() unless $end_tics - 2 >= time; # version query on last 2 sec only
} elsif ($end_tics - 2 < time) {
# version query on last 2 sec only
$self->firmware_version_query();
$self->protocol_version_query();
}
}
return;
@ -540,6 +563,12 @@ pmw_write is an alias for analog_write
*pwm_write = *analog_write;
sub protocol_version_query {
my $self = shift;
my $protocol_version_query_packet = $self->{protocol}->packet_query_version;
return $self->{io}->data_write($protocol_version_query_packet);
}
sub firmware_version_query {
my $self = shift;
my $firmware_version_query_packet = $self->{protocol}->packet_query_firmware;
@ -831,6 +860,29 @@ sub encoder_detach {
return $self->{io}->data_write($self->{protocol}->packet_encoder_detach( $encoderNum ));
}
sub serial_write {
my ( $self, $port, @data ) = @_;
return $self->{io}->data_write($self->{protocol}->packet_serial_write( $port, @data ));
}
sub serial_read {
my ( $self, $port, $numbytes ) = @_;
if ($port >= 8) {
$self->{io}->data_write($self->{protocol}->packet_serial_listen( $port ));
}
return $self->{io}->data_write($self->{protocol}->packet_serial_read( $port, 0x00, $numbytes ));
}
sub serial_stopreading {
my ( $self, $port) = @_;
return $self->{io}->data_write($self->{protocol}->packet_serial_read( $port, 0x01, 0 ));
}
sub serial_config {
my ( $self, $port, $baud, $rxPin, $txPin ) = @_;
return $self->{io}->data_write($self->{protocol}->packet_serial_config( $port, $baud, $rxPin, $txPin ));
}
=head2 poll
Call this function every once in a while to
@ -921,6 +973,16 @@ sub observe_encoder {
return 1;
}
sub observe_serial {
my ( $self, $port, $observer, $context ) = @_;
return undef if (defined $self->{metadata}->{serialpins} && @$self->{metadata}->{serialpins} == 0 );
$self->{serial_observer}[$port] = {
method => $observer,
context => $context,
};
return 1;
}
sub observe_scheduler {
my ( $self, $observer, $context ) = @_;
$self->{scheduler_observer} = {

View File

@ -16,6 +16,7 @@ use constant {
MIDI_PARSE_SYSEX => 1,
MIDI_START_SYSEX => 0xf0,
MIDI_END_SYSEX => 0xf7,
MAX_PROTOCOL_VERSION => 'V_2_05', # highest Firmata protocol version currently implemented
};
use Device::Firmata::Constants qw/ :all /;
@ -24,7 +25,7 @@ use Device::Firmata::Base
FIRMATA_ATTRIBS => {
buffer => [],
parse_status => MIDI_PARSE_NORMAL,
protocol_version => 'V_2_04', # We are starting with the highest protocol
protocol_version => MAX_PROTOCOL_VERSION, # We are starting with the highest protocol
};
$MIDI_DATA_SIZES = {
@ -93,6 +94,14 @@ our $ENCODER_COMMANDS = {
ENCODER_DETACH => 5,
};
our $SERIAL_COMMANDS = {
SERIAL_CONFIG => 0x10, # config serial port stetting such as baud rate and pins
SERIAL_WRITE => 0x20, # write to serial port
SERIAL_READ => 0x30, # read request to serial port
SERIAL_REPLY => 0x40, # read reply from serial port
SERIAL_LISTEN => 0x70, # start listening on software serial port
};
our $MODENAMES = {
0 => 'INPUT',
1 => 'OUTPUT',
@ -104,6 +113,7 @@ our $MODENAMES = {
7 => 'ONEWIRE',
8 => 'STEPPER',
9 => 'ENCODER',
10 => 'SERIAL',
};
=head1 DESCRIPTION
@ -322,6 +332,11 @@ sub sysex_parse {
last;
};
$command == $protocol_commands->{SERIAL_DATA} and do {
$return_data = $self->handle_serial_reply($sysex_data);
last;
};
$command == $protocol_commands->{RESERVED_COMMAND} and do {
$return_data = $sysex_data;
last;
@ -421,7 +436,11 @@ sub packet_query_version {
}
sub handle_query_version_response {
my ( $self, $data ) = @_;
return {
major_version => shift @$data,
minor_version => shift @$data,
};
}
sub handle_string_data {
@ -1012,6 +1031,138 @@ sub handle_encoder_response {
return \@retval;
}
#/* serial config
# * -------------------------------
# * 0 START_SYSEX (0xF0)
# * 1 SERIAL_DATA (0x60) // command byte
# * 2 SERIAL_CONFIG (0x10) // OR with port (0x11 = SERIAL_CONFIG | HW_SERIAL1)
# * 3 baud (bits 0 - 6)
# * 4 baud (bits 7 - 13)
# * 5 baud (bits 14 - 20) // need to send 3 bytes for baud even if value is < 14 bits
# * 6 rxPin (0-127) [optional] // only set if platform requires RX pin number
# * 7 txPin (0-127) [optional] // only set if platform requires TX pin number
# * 6|8 END_SYSEX (0xF7)
# */
sub packet_serial_config {
my ( $self, $port, $baud, $rxPin, $txPin ) = @_;
if (defined($rxPin) && defined($txPin)) {
return $self->packet_sysex_command( SERIAL_DATA,
$SERIAL_COMMANDS->{SERIAL_CONFIG} | $port,
$baud & 0x7f,
($baud >> 7) & 0x7f,
($baud >> 14) & 0x7f,
$rxPin & 0x7f,
$txPin & 0x7f
);
} else {
return $self->packet_sysex_command( SERIAL_DATA,
$SERIAL_COMMANDS->{SERIAL_CONFIG} | $port,
$baud & 0x7f,
($baud >> 7) & 0x7f,
($baud >> 14) & 0x7f
);
}
}
#/* serial listen
# * -------------------------------
# * 0 START_SYSEX (0xF0)
# * 1 SERIAL_DATA (0x60) // command byte
# * 2 SERIAL_LISTEN (0x70) // OR with port to switch to (0x79 = switch to SW_SERIAL1)
# * 3 END_SYSEX (0xF7)
# */
sub packet_serial_listen {
my ( $self, $port ) = @_;
return $self->packet_sysex_command( SERIAL_DATA,
$SERIAL_COMMANDS->{SERIAL_LISTEN} | $port
);
}
#/* serial write
# * -------------------------------
# * 0 START_SYSEX (0xF0)
# * 1 SERIAL_DATA (0x60)
# * 2 SERIAL_WRITE (0x20) // OR with port (0x21 = SERIAL_WRITE | HW_SERIAL1)
# * 3 data 0 (LSB)
# * 4 data 0 (MSB)
# * 5 data 1 (LSB)
# * 6 data 1 (MSB)
# * ... // up to max buffer - 5
# * n END_SYSEX (0xF7)
# */
sub packet_serial_write {
my ( $self, $port, @serialdata ) = @_;
if (scalar @serialdata) {
my @data;
push_array_as_two_7bit(\@serialdata,\@data);
return $self->packet_sysex_command( SERIAL_DATA,
$SERIAL_COMMANDS->{SERIAL_WRITE} | $port,
@data
);
} else {
return $self->packet_sysex_command( SERIAL_DATA,
$SERIAL_COMMANDS->{SERIAL_WRITE} | $port
);
}
}
#/* serial read
# * -------------------------------
# * 0 START_SYSEX (0xF0)
# * 1 SERIAL_DATA (0x60)
# * 2 SERIAL_READ (0x30) // OR with port (0x31 = SERIAL_READ | HW_SERIAL1)
# * 3 SERIAL_READ_MODE (0x00) // 0x00 => read continuously, 0x01 => stop reading
# * 4 maxBytesToRead (lsb) // 0x00 for all bytes available [optional]
# * 5 maxBytesToRead (msb) // 0x00 for all bytes available [optional]
# * 4|6 END_SYSEX (0xF7)
# */
sub packet_serial_read {
my ( $self, $port, $command, $maxBytes ) = @_;
if ($maxBytes > 0) {
return $self->packet_sysex_command( SERIAL_DATA,
$SERIAL_COMMANDS->{SERIAL_READ} | $port,
$command,
$maxBytes & 0x7f,
($maxBytes >> 7) & 0x7f
);
} else {
return $self->packet_sysex_command( SERIAL_DATA,
$SERIAL_COMMANDS->{SERIAL_READ} | $port,
$command
);
}
}
#/* serial reply
# * -------------------------------
# * 0 START_SYSEX (0xF0)
# * 1 SERIAL_DATA (0x60)
# * 2 SERIAL_REPLY (0x40) // OR with port (0x41 = SERIAL_REPLY | HW_SERIAL1)
# * 3 data 0 (LSB)
# * 4 data 0 (MSB)
# * 3 data 1 (LSB)
# * 4 data 1 (MSB)
# * ... // up to max buffer - 5
# * n END_SYSEX (0xF7)
# */
sub handle_serial_reply {
my ( $self, $sysex_data ) = @_;
my $command = shift @$sysex_data;
my $port = $command & 0xF;
my @data = double_7bit_to_array($sysex_data);
return {
port => $port,
data => \@data,
};
}
sub shift14bit {
my $data = shift;
@ -1133,4 +1284,25 @@ sub unpack_from_7bit {
return @outdata;
}
=head2 get_max_compatible_protocol_version
Search list of implemented protocols for identical or next lower version.
=cut
sub get_max_supported_protocol_version {
my ( $self, $deviceProtcolVersion ) = @_;
return "V_2_01" unless (defined($deviceProtcolVersion)); # min. supported protocol version if undefined
return $deviceProtcolVersion if (defined($COMMANDS->{$deviceProtcolVersion})); # requested version if known
my $maxSupportedProtocolVersion = undef;
foreach my $protocolVersion (sort keys %{$COMMANDS}) {
if ($protocolVersion lt $deviceProtcolVersion) {
$maxSupportedProtocolVersion = $protocolVersion; # nearest lower version if not known
}
}
return $maxSupportedProtocolVersion;
}
1;

View File

@ -0,0 +1,47 @@
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.

View File

@ -0,0 +1 @@
perl-firmata is distributed under the same terms as perl itself

View File

@ -504,7 +504,7 @@ FHEM/TR064Utils.pm rudolfkoenig Automatisierung
FHEM/UConv.pm loredo FHEM Development
FHEM/Unit.pm loredo FHEM Development
FHEM/YahooWeatherAPI.pm neubert Unterstuetzende Dienste/Wettermodule
FHEM/lib/Device/Firmata/* ntruchsess Sonstige Systeme
FHEM/lib/Device/Firmata/* jensb Sonstige Systeme
FHEM/lib/Device/MySensors/* Hauswart Sonstige Systeme
FHEM/lib/MP3/* Reinerlein Multimedia
FHEM/lib/Net/MQTT.pod eisler MQTT