2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 09:16:53 +00:00

update perl-firmata, new module FRM_SERVO

git-svn-id: https://svn.fhem.de/fhem/trunk@2627 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
ntruchsess 2013-02-02 11:50:06 +00:00
parent 3e6460c3df
commit 0adde9b35d
9 changed files with 285 additions and 99 deletions

View File

@ -199,10 +199,29 @@ sub FRM_DoInit($) {
$main::defs{$name}{output_pins} = join(",", sort{$a<=>$b}(@$outputpins)); $main::defs{$name}{output_pins} = join(",", sort{$a<=>$b}(@$outputpins));
my $analogpins = $device->{metadata}{analog_pins}; my $analogpins = $device->{metadata}{analog_pins};
$main::defs{$name}{analog_pins} = join(",", sort{$a<=>$b}(@$analogpins)); $main::defs{$name}{analog_pins} = join(",", sort{$a<=>$b}(@$analogpins));
my $pwmpins = $device->{metadata}{pwm_pins};
$main::defs{$name}{pwm_pins} = join(",", sort{$a<=>$b}(@$pwmpins));
my $servopins = $device->{metadata}{servo_pins};
$main::defs{$name}{servo_pins} = join(",", sort{$a<=>$b}(@$servopins));
my $i2cpins = $device->{metadata}{i2c_pins}; my $i2cpins = $device->{metadata}{i2c_pins};
$main::defs{$name}{i2c_pins} = join(",", sort{$a<=>$b}(@$i2cpins)); $main::defs{$name}{i2c_pins} = join(",", sort{$a<=>$b}(@$i2cpins));
my $onewirepins = $device->{metadata}{onewire_pins}; my $onewirepins = $device->{metadata}{onewire_pins};
$main::defs{$name}{onewire_pins} = join(",", sort{$a<=>$b}(@$onewirepins)); $main::defs{$name}{onewire_pins} = join(",", sort{$a<=>$b}(@$onewirepins));
my @analog_resolutions;
foreach my $pin (sort{$a<=>$b}(keys $device->{metadata}{analog_resolutions})) {
push @analog_resolutions,$pin.":".$device->{metadata}{analog_resolutions}{$pin};
}
$main::defs{$name}{analog_resolutions} = join(",",@analog_resolutions);
my @pwm_resolutions;
foreach my $pin (sort{$a<=>$b}(keys $device->{metadata}{pwm_resolutions})) {
push @pwm_resolutions,$pin.":".$device->{metadata}{pwm_resolutions}{$pin};
}
$main::defs{$name}{pwm_resolutions} = join(",",@pwm_resolutions);
my @servo_resolutions;
foreach my $pin (sort{$a<=>$b}(keys $device->{metadata}{servo_resolutions})) {
push @servo_resolutions,$pin.":".$device->{metadata}{servo_resolutions}{$pin};
}
$main::defs{$name}{servo_resolutions} = join(",",@servo_resolutions);
$found = 1; $found = 1;
last; last;
} }
@ -248,11 +267,17 @@ FRM_Init_Client($$) {
} }
sub sub
FRM_Init_Pin_Client($$) { FRM_Init_Pin_Client($$$) {
my ($hash,$args) = @_; my ($hash,$args,$mode) = @_;
my $u = "wrong syntax: define <name> FRM_XXX pin"; my $u = "wrong syntax: define <name> FRM_XXX pin";
return $u if(int(@$args) < 3); return $u if(int(@$args) < 3);
$hash->{PIN} = @$args[2]; my $pin = @$args[2];
$hash->{PIN} = $pin;
if (defined $hash->{IODev} and defined $hash->{IODev}->{FirmataDevice}) {
$hash->{IODev}->{FirmataDevice}->pin_mode($pin,$mode);
return 1;
}
return undef;
} }
sub sub
@ -356,14 +381,11 @@ sub
FRM_OWX_Init($$) FRM_OWX_Init($$)
{ {
my ($hash,$args) = @_; my ($hash,$args) = @_;
FRM_Init_Pin_Client($hash,$args); if (FRM_Init_Pin_Client($hash,$args,PIN_ONEWIRE)) {
$hash->{INTERFACE} = "firmata"; $hash->{INTERFACE} = "firmata";
if (defined $hash->{IODev}) {
my $firmata = $hash->{IODev}->{FirmataDevice}; my $firmata = $hash->{IODev}->{FirmataDevice};
if (defined $firmata and defined $hash->{PIN}) {
my $pin = $hash->{PIN}; my $pin = $hash->{PIN};
$firmata->observe_onewire($pin,\&FRM_OWX_observer,$hash); $firmata->observe_onewire($pin,\&FRM_OWX_observer,$hash);
$firmata->pin_mode($pin,PIN_ONEWIRE);
$hash->{FRM_OWX_REPLIES} = {}; $hash->{FRM_OWX_REPLIES} = {};
$hash->{DEVS} = []; $hash->{DEVS} = [];
if ( main::AttrVal($hash->{NAME},"buspower","") eq "parasitic" ) { if ( main::AttrVal($hash->{NAME},"buspower","") eq "parasitic" ) {
@ -371,8 +393,9 @@ FRM_OWX_Init($$)
} }
main::readingsSingleUpdate($hash,"state","Initialized",1); main::readingsSingleUpdate($hash,"state","Initialized",1);
$firmata->onewire_search($pin); $firmata->onewire_search($pin);
return undef;
} }
} return 1;
} }
sub FRM_OWX_observer sub FRM_OWX_observer

View File

@ -16,7 +16,6 @@ FRM_AD_Initialize($)
$hash->{DefFn} = "FRM_Client_Define"; $hash->{DefFn} = "FRM_Client_Define";
$hash->{InitFn} = "FRM_AD_Init"; $hash->{InitFn} = "FRM_AD_Init";
$hash->{UndefFn} = "FRM_AD_Undef"; $hash->{UndefFn} = "FRM_AD_Undef";
$hash->{AttrFn} = "FRM_Attr";
$hash->{AttrList} = "IODev loglevel:0,1,2,3,4,5 $main::readingFnAttributes"; $hash->{AttrList} = "IODev loglevel:0,1,2,3,4,5 $main::readingFnAttributes";
} }
@ -25,16 +24,13 @@ sub
FRM_AD_Init($$) FRM_AD_Init($$)
{ {
my ($hash,$args) = @_; my ($hash,$args) = @_;
FRM_Init_Pin_Client($hash,$args); if (FRM_Init_Pin_Client($hash,$args,PIN_ANALOG)) {
if (defined $hash->{IODev}) {
my $firmata = $hash->{IODev}->{FirmataDevice}; my $firmata = $hash->{IODev}->{FirmataDevice};
if (defined $firmata and defined $hash->{PIN}) {
$firmata->pin_mode($hash->{PIN},PIN_ANALOG);
$firmata->observe_analog($hash->{PIN},\&FRM_AD_observer,$hash); $firmata->observe_analog($hash->{PIN},\&FRM_AD_observer,$hash);
main::readingsSingleUpdate($hash,"state","initialized",1); $main::defs{$hash->{NAME}}{resolution}=$firmata->{metadata}{analog_resolutions}{$hash->{PIN}} if (defined $firmata->{metadata}{analog_resolutions});
main::readingsSingleUpdate($hash,"state","Initialized",1);
return undef; return undef;
} }
}
return 1; return 1;
} }
@ -49,15 +45,21 @@ FRM_AD_observer
sub sub
FRM_AD_Get($) FRM_AD_Get($)
{ {
my ($hash) = @_; my ($hash,@a) = @_;
my $iodev = $hash->{IODev}; my $iodev = $hash->{IODev};
if (defined $iodev and defined $iodev->{FirmataDevice} and defined $iodev->{FD}) { my $name = shift @a;
my $ret = $iodev->{FirmataDevice}->analog_read($hash->{PIN}); return $name." no IODev assigned" if (!defined $iodev);
return $ret; return $name.", ".$iodev->{NAME}." is not connected" if (!(defined $iodev->{FirmataDevice} and defined $iodev->{FD}));
} else { my $cmd = shift @a;
return $hash->{NAME}." no IODev assigned" if (!defined $iodev); my $ret;
return $hash->{NAME}.", ".$iodev->{NAME}." is not connected"; ARGUMENT_HANDLER: {
$cmd eq "reading" and do {
$ret = $iodev->{FirmataDevice}->analog_read($hash->{PIN});
last;
};
$ret = "unknown command ".$cmd;
} }
return $ret;
} }
sub sub
@ -76,14 +78,14 @@ FRM_AD_Undef($$)
<ul> <ul>
represents a pin of an <a href="http://www.arduino.cc">Arduino</a> running <a href="http://www.firmata.org">Firmata</a> represents a pin of an <a href="http://www.arduino.cc">Arduino</a> running <a href="http://www.firmata.org">Firmata</a>
configured for analog input.<br> configured for analog input.<br>
The value read is stored in reading 'state'. Range is from 0 to 1.<br> The value read is stored in reading 'state'. Range is from 0 to 1023 (10 Bit)<br>
Requires a defined <a href="#FRM">FRM</a>-device to work.<br><br> Requires a defined <a href="#FRM">FRM</a>-device to work.<br><br>
<a name="FRM_ADdefine"></a> <a name="FRM_ADdefine"></a>
<b>Define</b> <b>Define</b>
<ul> <ul>
<code>define &lt;name&gt; FRM_AD &lt;pin&gt;</code> <br> <code>define &lt;name&gt; FRM_AD &lt;pin&gt;</code> <br>
Specifies the FRM_AD device. Defines the FRM_AD device. &lt;pin&gt; is the arduino-pin to use.
</ul> </ul>
<br> <br>
@ -95,7 +97,8 @@ FRM_AD_Undef($$)
<a name="FRM_ADget"></a> <a name="FRM_ADget"></a>
<b>Get</b><br> <b>Get</b><br>
<ul> <ul>
N/A<br> <li>reading<br>
returns the voltage-level read on the arduino-pin. Values range from 0 to 1023.<br></li>
</ul><br> </ul><br>
<a name="FRM_ADattr"></a> <a name="FRM_ADattr"></a>
<b>Attributes</b><br> <b>Attributes</b><br>

View File

@ -16,7 +16,6 @@ FRM_IN_Initialize($)
$hash->{DefFn} = "FRM_Client_Define"; $hash->{DefFn} = "FRM_Client_Define";
$hash->{InitFn} = "FRM_IN_Init"; $hash->{InitFn} = "FRM_IN_Init";
$hash->{UndefFn} = "FRM_IN_Undef"; $hash->{UndefFn} = "FRM_IN_Undef";
$hash->{AttrFn} = "FRM_Attr";
$hash->{AttrList} = "IODev loglevel:0,1,2,3,4,5 $main::readingFnAttributes"; $hash->{AttrList} = "IODev loglevel:0,1,2,3,4,5 $main::readingFnAttributes";
} }
@ -25,17 +24,14 @@ sub
FRM_IN_Init($$) FRM_IN_Init($$)
{ {
my ($hash,$args) = @_; my ($hash,$args) = @_;
FRM_Init_Pin_Client($hash,$args); if (FRM_Init_Pin_Client($hash,$args,PIN_INPUT)) {
if (defined $hash->{IODev}) {
my $firmata = $hash->{IODev}->{FirmataDevice}; my $firmata = $hash->{IODev}->{FirmataDevice};
if (defined $firmata and defined $hash->{PIN}) {
$firmata->pin_mode($hash->{PIN},PIN_INPUT);
$firmata->observe_digital($hash->{PIN},\&FRM_IN_observer,$hash); $firmata->observe_digital($hash->{PIN},\&FRM_IN_observer,$hash);
main::readingsSingleUpdate($hash,"state","initialized",1); main::readingsSingleUpdate($hash,"state","Initialized",1);
return undef; return undef;
} }
}
return 1; return 1;
} }
sub sub
@ -49,15 +45,21 @@ FRM_IN_observer
sub sub
FRM_IN_Get($) FRM_IN_Get($)
{ {
my ($hash) = @_; my ($hash,@a) = @_;
my $iodev = $hash->{IODev}; my $iodev = $hash->{IODev};
if (defined $iodev and defined $iodev->{FirmataDevice} and defined $iodev->{FD}) { my $name = shift @a;
return $name." no IODev assigned" if (!defined $iodev);
return $name.", ".$iodev->{NAME}." is not connected" if (!(defined $iodev->{FirmataDevice} and defined $iodev->{FD}));
my $cmd = shift @a;
my $ret;
ARGUMENT_HANDLER: {
$cmd eq "reading" and do {
my $ret = $iodev->{FirmataDevice}->digital_read($hash->{PIN}); my $ret = $iodev->{FirmataDevice}->digital_read($hash->{PIN});
return $ret == PIN_HIGH ? "on" : "off"; return $ret == PIN_HIGH ? "on" : "off";
} else { };
return $hash->{NAME}." no IODev assigned" if (!defined $iodev); $ret = "unknown command ".$cmd;
return $hash->{NAME}.", ".$iodev->{NAME}." is not connected";
} }
return $ret;
} }
sub sub
@ -83,7 +85,7 @@ FRM_IN_Undef($$)
<b>Define</b> <b>Define</b>
<ul> <ul>
<code>define &lt;name&gt; FRM_IN &lt;pin&gt;</code> <br> <code>define &lt;name&gt; FRM_IN &lt;pin&gt;</code> <br>
Specifies the FRM_IN device. Defines the FRM_IN device. &lt;pin&gt> is the arduino-pin to use.
</ul> </ul>
<br> <br>
@ -93,9 +95,10 @@ FRM_IN_Undef($$)
N/A<br> N/A<br>
</ul> </ul>
<a name="FRM_INget"></a> <a name="FRM_INget"></a>
<b>Get</b><br> <b>Get</b>
<ul> <ul>
N/A<br> <li>reading<br>
returns the state of the arduino-pin. Values are 'on' and 'off'.<br></li>
</ul><br> </ul><br>
<a name="FRM_INattr"></a> <a name="FRM_INattr"></a>
<b>Attributes</b><br> <b>Attributes</b><br>

View File

@ -17,7 +17,6 @@ FRM_OUT_Initialize($)
$hash->{DefFn} = "FRM_Client_Define"; $hash->{DefFn} = "FRM_Client_Define";
$hash->{InitFn} = "FRM_OUT_Init"; $hash->{InitFn} = "FRM_OUT_Init";
$hash->{UndefFn} = "FRM_OUT_Undef"; $hash->{UndefFn} = "FRM_OUT_Undef";
$hash->{AttrFn} = "FRM_Attr";
$hash->{AttrList} = "IODev loglevel:0,1,2,3,4,5 $main::readingFnAttributes"; $hash->{AttrList} = "IODev loglevel:0,1,2,3,4,5 $main::readingFnAttributes";
} }
@ -26,14 +25,11 @@ sub
FRM_OUT_Init($$) FRM_OUT_Init($$)
{ {
my ($hash,$args) = @_; my ($hash,$args) = @_;
FRM_Init_Pin_Client($hash,$args); if (FRM_Init_Pin_Client($hash,$args,PIN_OUTPUT)) {
if (defined $hash->{IODev}) { main::readingsSingleUpdate($hash,"state","Initialized",1);
my $firmata = $hash->{IODev}->{FirmataDevice}; return undef;
if (defined $firmata and defined $hash->{PIN}) {
$firmata->pin_mode($hash->{PIN},PIN_OUTPUT);
main::readingsSingleUpdate($hash,"state","initialized",1);
}
} }
return 1;
} }
sub sub
@ -85,7 +81,7 @@ FRM_OUT_Undef($$)
<b>Define</b> <b>Define</b>
<ul> <ul>
<code>define &lt;name&gt; FRM_OUT &lt;pin&gt;</code> <br> <code>define &lt;name&gt; FRM_OUT &lt;pin&gt;</code> <br>
Specifies the FRM_OUT device. Defines the FRM_OUT device. &lt;pin&gt> is the arduino-pin to use.
</ul> </ul>
<br> <br>

View File

@ -16,7 +16,6 @@ FRM_PWM_Initialize($)
$hash->{DefFn} = "FRM_Client_Define"; $hash->{DefFn} = "FRM_Client_Define";
$hash->{InitFn} = "FRM_PWM_Init"; $hash->{InitFn} = "FRM_PWM_Init";
$hash->{UndefFn} = "FRM_PWM_Undef"; $hash->{UndefFn} = "FRM_PWM_Undef";
$hash->{AttrFn} = "FIR_Attr";
$hash->{AttrList} = "IODev loglevel:0,1,2,3,4,5 $main::readingFnAttributes"; $hash->{AttrList} = "IODev loglevel:0,1,2,3,4,5 $main::readingFnAttributes";
} }
@ -25,14 +24,13 @@ sub
FRM_PWM_Init($$) FRM_PWM_Init($$)
{ {
my ($hash,$args) = @_; my ($hash,$args) = @_;
FRM_Init_Pin_Client($hash,$args); if (FRM_Init_Pin_Client($hash,$args,PIN_PWM)) {
if (defined $hash->{IODev}) {
my $firmata = $hash->{IODev}->{FirmataDevice}; my $firmata = $hash->{IODev}->{FirmataDevice};
if (defined $firmata and defined $hash->{PIN}) { $main::defs{$hash->{NAME}}{resolution}=$firmata->{metadata}{pwm_resolutions}{$hash->{PIN}} if (defined $firmata->{metadata}{pwm_resolutions});
$firmata->pin_mode($hash->{PIN},PIN_PWM); main::readingsSingleUpdate($hash,"state","Initialized",1);
main::readingsSingleUpdate($hash,"state","initialized",1); return undef;
}
} }
return 1;
} }
sub sub
@ -74,14 +72,16 @@ FRM_PWM_Undef($$)
<b>Define</b> <b>Define</b>
<ul> <ul>
<code>define &lt;name&gt; FRM_PWM &lt;pin&gt;</code> <br> <code>define &lt;name&gt; FRM_PWM &lt;pin&gt;</code> <br>
Specifies the FRM_PWM device. Defines the FRM_PWM device. &lt;pin&gt> is the arduino-pin to use.
</ul> </ul>
<br> <br>
<a name="FRM_PWMset"></a> <a name="FRM_PWMset"></a>
<b>Set</b><br> <b>Set</b><br>
<ul> <ul>
<code>set &lt;name&gt; &lt;value&gt;</code><br><br> <code>set &lt;name&gt; &lt;value&gt;</code><br>
sets the pulse-width of the signal that is output on the configured arduino pin<br>
Range is from 0 to 255 (see <a href="http://arduino.cc/en/Reference/AnalogWrite">analogWrite()</a> for details)
</ul> </ul>
<a name="FRM_PWMget"></a> <a name="FRM_PWMget"></a>
<b>Get</b><br> <b>Get</b><br>

130
fhem/FHEM/20_FRM_SERVO.pm Executable file
View File

@ -0,0 +1,130 @@
#############################################
package main;
use strict;
use warnings;
use Device::Firmata;
use Device::Firmata::Constants qw/ :all /;
#####################################
sub
FRM_SERVO_Initialize($)
{
my ($hash) = @_;
$hash->{SetFn} = "FRM_SERVO_Set";
$hash->{DefFn} = "FRM_Client_Define";
$hash->{InitFn} = "FRM_SERVO_Init";
$hash->{UndefFn} = "FRM_SERVO_Undef";
$hash->{AttrFn} = "FRM_SERVO_Attr";
$hash->{AttrList} = "min-pulse max-pulse IODev loglevel:0,1,2,3,4,5 $main::readingFnAttributes";
}
sub
FRM_SERVO_Init($$)
{
my ($hash,$args) = @_;
if (FRM_Init_Pin_Client($hash,$args,PIN_SERVO)) {
my $firmata = $hash->{IODev}->{FirmataDevice};
$main::defs{$hash->{NAME}}{resolution}=$firmata->{metadata}{servo_resolutions}{$hash->{PIN}} if (defined $firmata->{metadata}{servo_resolutions});
FRM_SERVO_apply_attribute($hash,"max-pulse"); #sets min-pulse as well
main::readingsSingleUpdate($hash,"state","Initialized",1);
return undef;
}
return 1;
}
sub FRM_SERVO_Attr(@) {
my ($command,$name,$attribute,$value) = @_;
if ($command eq "set") {
$main::attr{$name}{$attribute}=$value;
if ( $attribute eq "min-pulse" || $attribute eq "max-pulse" ) {
FRM_SERVO_apply_attribute($main::defs{$name},$attribute);
}
}
}
sub FRM_SERVO_apply_attribute {
my ($hash,$attribute) = @_;
return unless (defined $hash->{IODev} and defined $hash->{IODev}->{FirmataDevice});
my $firmata = $hash->{IODev}->{FirmataDevice};
my $name = $hash->{NAME};
if ( $attribute eq "min-pulse" || $attribute eq "max-pulse" ) {
# defaults are taken from: http://arduino.cc/en/Reference/ServoAttach
$firmata->servo_config($hash->{PIN},{min_pulse => main::AttrVal($name,"min-pulse",544), max_pulse => main::AttrVal($name,"max-pulse",2400)});
}
}
sub
FRM_SERVO_Set($@)
{
my ($hash, @a) = @_;
my $value = $a[1];
my $iodev = $hash->{IODev};
if (defined $iodev and defined $iodev->{FirmataDevice} and defined $iodev->{FD}) {
$iodev->{FirmataDevice}->servo_write($hash->{PIN},$value);
main::readingsSingleUpdate($hash,"state",$a[1], 1);
} else {
return $hash->{NAME}." no IODev assigned" if (!defined $iodev);
return $hash->{NAME}.", ".$iodev->{NAME}." is not connected";
}
return undef;
}
sub
FRM_SERVO_Undef($$)
{
my ($hash, $name) = @_;
}
1;
=pod
=begin html
<a name="FRM_SERVO"></a>
<h3>FRM_SERVO</h3>
<ul>
represents a pin of an <a href="http://www.arduino.cc">Arduino</a> running <a href="http://www.firmata.org">Firmata</a>
configured to drive a pwm-controlled servo-motor.<br>
The value set will be drive the shaft of the servo to the specified angle. see <a href="http://arduino.cc/en/Reference/ServoWrite">Servo.write</a> for values and range<br>
Requires a defined <a href="#FRM">FRM</a>-device to work.<br><br>
<a name="FRM_SERVOdefine"></a>
<b>Define</b>
<ul>
<code>define &lt;name&gt; FRM_SERVO &lt;pin&gt;</code> <br>
Defines the FRM_SERVO device. &lt;pin&gt> is the arduino-pin to use.
</ul>
<br>
<a name="FRM_SERVOset"></a>
<b>Set</b><br>
<ul>
<code>set &lt;name&gt; &lt;value&gt;</code><br>sets the angle of the servo-motors shaft to the value specified (in degrees).<br>
</ul>
<a name="FRM_SERVOget"></a>
<b>Get</b><br>
<ul>
N/A
</ul><br>
<a name="FRM_SERVOattr"></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>min-pulse<br>
sets the minimum puls-width to use. Defaults to 544. For most servos this translates into a rotation of 180° counterclockwise.</li>
<li>max-pulse<br>
sets the maximum puls-width to use. Defaults to 2400. For most servos this translates into a rotation of 180° clockwise</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

@ -220,16 +220,14 @@ use constant (
EXTENDED_ANALOG => 0x6F, # analog write (PWM, Servo, etc) to any pin EXTENDED_ANALOG => 0x6F, # analog write (PWM, Servo, etc) to any pin
SERVO_CONFIG => 0x70, # set max angle, minPulse, maxPulse, freq SERVO_CONFIG => 0x70, # set max angle, minPulse, maxPulse, freq
STRING_DATA => 0x71, # a string message with 14-bits per char STRING_DATA => 0x71, # a string message with 14-bits per char
ONEWIRE_REQUEST => 0x73, # send an OneWire read/write/reset/select/skip/search request ONEWIRE_DATA => 0x73, # OneWire read/write/reset/select/skip/search request + read/search reply
ONEWIRE_REPLY => 0x7D, # reply to a OneWire read/search request
SHIFT_DATA => 0x75, # shiftOut config/data message (34 bits) SHIFT_DATA => 0x75, # shiftOut config/data message (34 bits)
I2C_REQUEST => 0x76, # send an I2C read/write request I2C_REQUEST => 0x76, # send an I2C read/write request
I2C_REPLY => 0x77, # a reply to an I2C read request I2C_REPLY => 0x77, # a reply to an I2C read request
I2C_CONFIG => 0x78, # config I2C settings such as delay times and power pins I2C_CONFIG => 0x78, # config I2C settings such as delay times and power pins
REPORT_FIRMWARE => 0x79, # report name and version of the firmware REPORT_FIRMWARE => 0x79, # report name and version of the firmware
SAMPLING_INTERVAL => 0x7A, # set the poll rate of the main loop SAMPLING_INTERVAL => 0x7A, # set the poll rate of the main loop
SCHEDULER_REQUEST => 0x7B, # send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler SCHEDULER_DATA => 0x7B, # createtask/deletetask/addtotask/schedule/querytasks/querytask request and querytasks/querytask reply
SCHEDULER_REPLY => 0x7C, # a reply to a querytasks/querytask-request from the scheduler
SYSEX_NON_REALTIME => 0x7E, # MIDI Reserved for non-realtime messages SYSEX_NON_REALTIME => 0x7E, # MIDI Reserved for non-realtime messages
SYSEX_REALTIME => 0x7F, # MIDI Reserved for realtime messages SYSEX_REALTIME => 0x7F, # MIDI Reserved for realtime messages

View File

@ -26,6 +26,9 @@ use Device::Firmata::Base
# To track internal status # To track internal status
analog_pins => [], analog_pins => [],
analog_resolutions => {},
pwm_resolutions => {},
servo_resolutions => {},
ports => [], ports => [],
pins => {}, pins => {},
pin_modes => {}, pin_modes => {},
@ -167,7 +170,7 @@ sub messages_handle {
# Handle analog pin messages # Handle analog pin messages
$command eq 'ANALOG_MESSAGE' and do { $command eq 'ANALOG_MESSAGE' and do {
my $pin_number = $message->{command} & 0x0f; my $pin_number = $message->{command} & 0x0f;
my $pin_value = ( $data->[0] | ( $data->[1] << 7 ) ) / 1023; my $pin_value = ( $data->[0] | ( $data->[1] << 7 ) );
if (defined $self->{metadata}{analog_mappings}) { if (defined $self->{metadata}{analog_mappings}) {
$pin_number = $self->{metadata}{analog_mappings}{$pin_number}; $pin_number = $self->{metadata}{analog_mappings}{$pin_number};
} }
@ -247,6 +250,9 @@ sub sysex_handle {
my @analogpins; my @analogpins;
my @inputpins; my @inputpins;
my @outputpins; my @outputpins;
my @pwmpins;
my @servopins;
my @shiftpins;
my @i2cpins; my @i2cpins;
my @onewirepins; my @onewirepins;
foreach my $pin (keys %$capabilities) { foreach my $pin (keys %$capabilities) {
@ -259,6 +265,18 @@ sub sysex_handle {
} }
if ($capabilities->{$pin}->{PIN_ANALOG+0}) { if ($capabilities->{$pin}->{PIN_ANALOG+0}) {
push @analogpins, $pin; push @analogpins, $pin;
$self->{metadata}{analog_resolutions}{$pin} = $capabilities->{$pin}->{PIN_ANALOG+0}->{resolution};
}
if ($capabilities->{$pin}->{PIN_PWM+0}) {
push @pwmpins, $pin;
$self->{metadata}{pwm_resolutions}{$pin} = $capabilities->{$pin}->{PIN_PWM+0}->{resolution};
}
if ($capabilities->{$pin}->{PIN_SERVO+0}) {
push @analogpins, $pin;
$self->{metadata}{servo_resolutions}{$pin} = $capabilities->{$pin}->{PIN_SERVO+0}->{resolution};
}
if ($capabilities->{$pin}->{PIN_SHIFT+0}) {
push @shiftpins, $pin;
} }
if ($capabilities->{$pin}->{PIN_I2C+0}) { if ($capabilities->{$pin}->{PIN_I2C+0}) {
push @i2cpins, $pin; push @i2cpins, $pin;
@ -271,6 +289,9 @@ sub sysex_handle {
$self->{metadata}{input_pins} = \@inputpins; $self->{metadata}{input_pins} = \@inputpins;
$self->{metadata}{output_pins} = \@outputpins; $self->{metadata}{output_pins} = \@outputpins;
$self->{metadata}{analog_pins} = \@analogpins; $self->{metadata}{analog_pins} = \@analogpins;
$self->{metadata}{pwm_pins} = \@pwmpins;
$self->{metadata}{servo_pins} = \@servopins;
$self->{metadata}{shift_pins} = \@shiftpins;
$self->{metadata}{i2c_pins} = \@i2cpins; $self->{metadata}{i2c_pins} = \@i2cpins;
$self->{metadata}{onewire_pins} = \@onewirepins; $self->{metadata}{onewire_pins} = \@onewirepins;
last; last;
@ -300,7 +321,7 @@ sub sysex_handle {
last; last;
}; };
$sysex_message->{command_str} eq 'ONEWIRE_REPLY' and do { $sysex_message->{command_str} eq 'ONEWIRE_DATA' and do {
my $pin = $data->{pin}; my $pin = $data->{pin};
my $observer = $self->{onewire_observer}[$pin]; my $observer = $self->{onewire_observer}[$pin];
if (defined $observer) { if (defined $observer) {
@ -309,7 +330,7 @@ sub sysex_handle {
last; last;
}; };
$sysex_message->{command_str} eq 'SCHEDULER_REPLY' and do { $sysex_message->{command_str} eq 'SCHEDULER_DATA' and do {
my $observer = $self->{scheduler_observer}; my $observer = $self->{scheduler_observer};
if (defined $observer) { if (defined $observer) {
$observer->{method}( $data, $observer->{context} ); $observer->{method}( $data, $observer->{context} );
@ -572,6 +593,18 @@ sub i2c_config {
return $self->{io}->data_write($self->{protocol}->packet_i2c_config($delay,@data)); return $self->{io}->data_write($self->{protocol}->packet_i2c_config($delay,@data));
} }
sub servo_write {
my ( $self, $pin, $value ) = @_;
return undef unless $self->is_configured_mode($pin,PIN_SERVO);
return analog_write( $self, $pin, $value );
}
sub servo_config {
my ( $self, $pin, $args ) = @_;
return undef unless $self->is_configured_mode($pin,PIN_SERVO);
return $self->{io}->data_write($self->{protocol}->packet_servo_config_request($pin,$args));
}
sub scheduler_create_task { sub scheduler_create_task {
my $self = shift; my $self = shift;
my $id=-1; my $id=-1;

View File

@ -296,13 +296,13 @@ sub sysex_parse {
last; last;
}; };
$command == $protocol_commands->{ONEWIRE_REPLY} and do { $command == $protocol_commands->{ONEWIRE_DATA} and do {
$return_data = $self->handle_onewire_reply($sysex_data); $return_data = $self->handle_onewire_reply($sysex_data);
last; last;
}; };
$command == $protocol_commands->{SCHEDULER_REPLY} and do { $command == $protocol_commands->{SCHEDULER_DATA} and do {
$return_data = $self->handle_scheduler_reply($sysex_data); $return_data = $self->handle_scheduler_response($sysex_data);
last; last;
}; };
@ -657,15 +657,15 @@ sub packet_i2c_config {
# * 7 END_SYSEX (0xF7) # * 7 END_SYSEX (0xF7)
# */ # */
sub packet_servo_config { sub packet_servo_config_request {
my ( $self, $data ) = @_; my ( $self, $pin, $data ) = @_;
my $min_pulse = $data->{min_pulse}; my $min_pulse = $data->{min_pulse};
my $max_pulse = $data->{max_pulse}; my $max_pulse = $data->{max_pulse};
return $self->packet_sysex_command( SERVO_CONFIG, return $self->packet_sysex_command( SERVO_CONFIG,
$data->{pin} & 0x7f, $pin & 0x7f,
$min_pulse & 0x7f, $min_pulse & 0x7f,
$min_pulse >> 7, $min_pulse >> 7,
$max_pulse & 0x7f, $max_pulse & 0x7f,
@ -693,17 +693,17 @@ sub packet_servo_config {
sub packet_onewire_search_request { sub packet_onewire_search_request {
my ( $self, $pin ) = @_; my ( $self, $pin ) = @_;
return $self->packet_sysex_command( ONEWIRE_REQUEST,$ONE_WIRE_COMMANDS->{SEARCH_REQUEST},$pin); return $self->packet_sysex_command( ONEWIRE_DATA,$ONE_WIRE_COMMANDS->{SEARCH_REQUEST},$pin);
}; };
sub packet_onewire_search_alarms_request { sub packet_onewire_search_alarms_request {
my ( $self, $pin ) = @_; my ( $self, $pin ) = @_;
return $self->packet_sysex_command( ONEWIRE_REQUEST,$ONE_WIRE_COMMANDS->{SEARCH_ALARMS_REQUEST},$pin); return $self->packet_sysex_command( ONEWIRE_DATA,$ONE_WIRE_COMMANDS->{SEARCH_ALARMS_REQUEST},$pin);
}; };
sub packet_onewire_config_request { sub packet_onewire_config_request {
my ( $self, $pin, $power ) = @_; my ( $self, $pin, $power ) = @_;
return $self->packet_sysex_command( ONEWIRE_REQUEST, $ONE_WIRE_COMMANDS->{CONFIG_REQUEST},$pin, return $self->packet_sysex_command( ONEWIRE_DATA, $ONE_WIRE_COMMANDS->{CONFIG_REQUEST},$pin,
( defined $power ) ? $power : 1 ( defined $power ) ? $power : 1
); );
}; };
@ -748,7 +748,7 @@ sub packet_onewire_request {
my $writeBytes=$args->{write}; my $writeBytes=$args->{write};
push @data,@$writeBytes; push @data,@$writeBytes;
} }
return $self->packet_sysex_command( ONEWIRE_REQUEST, $subcommand, $pin, pack_as_7bit(@data)); return $self->packet_sysex_command( ONEWIRE_DATA, $subcommand, $pin, pack_as_7bit(@data));
}; };
sub handle_onewire_reply { sub handle_onewire_reply {
@ -797,49 +797,49 @@ sub handle_onewire_reply {
sub packet_create_task { sub packet_create_task {
my ($self,$id,$len) = @_; my ($self,$id,$len) = @_;
my $packet = $self->packet_sysex_command('SCHEDULER_REQUEST', $SCHEDULER_COMMANDS->{CREATE_FIRMATA_TASK}, $id, $len & 0x7F, $len>>7); my $packet = $self->packet_sysex_command('SCHEDULER_DATA', $SCHEDULER_COMMANDS->{CREATE_FIRMATA_TASK}, $id, $len & 0x7F, $len>>7);
return $packet; return $packet;
} }
sub packet_delete_task { sub packet_delete_task {
my ($self,$id) = @_; my ($self,$id) = @_;
return $self->packet_sysex_command('SCHEDULER_REQUEST', $SCHEDULER_COMMANDS->{DELETE_FIRMATA_TASK}, $id); return $self->packet_sysex_command('SCHEDULER_DATA', $SCHEDULER_COMMANDS->{DELETE_FIRMATA_TASK}, $id);
} }
sub packet_add_to_task { sub packet_add_to_task {
my ($self,$id,@data) = @_; my ($self,$id,@data) = @_;
my $packet = $self->packet_sysex_command('SCHEDULER_REQUEST', $SCHEDULER_COMMANDS->{ADD_TO_FIRMATA_TASK}, $id, pack_as_7bit(@data)); my $packet = $self->packet_sysex_command('SCHEDULER_DATA', $SCHEDULER_COMMANDS->{ADD_TO_FIRMATA_TASK}, $id, pack_as_7bit(@data));
return $packet; return $packet;
} }
sub packet_delay_task { sub packet_delay_task {
my ($self,$time_ms) = @_; my ($self,$time_ms) = @_;
my $packet = $self->packet_sysex_command('SCHEDULER_REQUEST', $SCHEDULER_COMMANDS->{DELAY_FIRMATA_TASK}, pack_as_7bit($time_ms & 0xFF, ($time_ms & 0xFF00)>>8, ($time_ms & 0xFF0000)>>16,($time_ms & 0xFF000000)>>24)); my $packet = $self->packet_sysex_command('SCHEDULER_DATA', $SCHEDULER_COMMANDS->{DELAY_FIRMATA_TASK}, pack_as_7bit($time_ms & 0xFF, ($time_ms & 0xFF00)>>8, ($time_ms & 0xFF0000)>>16,($time_ms & 0xFF000000)>>24));
return $packet; return $packet;
} }
sub packet_schedule_task { sub packet_schedule_task {
my ($self,$id,$time_ms) = @_; my ($self,$id,$time_ms) = @_;
my $packet = $self->packet_sysex_command('SCHEDULER_REQUEST', $SCHEDULER_COMMANDS->{SCHEDULE_FIRMATA_TASK}, $id, pack_as_7bit($time_ms & 0xFF, ($time_ms & 0xFF00)>>8, ($time_ms & 0xFF0000)>>16,($time_ms & 0xFF000000)>>24)); my $packet = $self->packet_sysex_command('SCHEDULER_DATA', $SCHEDULER_COMMANDS->{SCHEDULE_FIRMATA_TASK}, $id, pack_as_7bit($time_ms & 0xFF, ($time_ms & 0xFF00)>>8, ($time_ms & 0xFF0000)>>16,($time_ms & 0xFF000000)>>24));
return $packet; return $packet;
} }
sub packet_query_all_tasks { sub packet_query_all_tasks {
my $self = shift; my $self = shift;
return $self->packet_sysex_command('SCHEDULER_REQUEST', $SCHEDULER_COMMANDS->{QUERY_ALL_FIRMATA_TASKS}); return $self->packet_sysex_command('SCHEDULER_DATA', $SCHEDULER_COMMANDS->{QUERY_ALL_FIRMATA_TASKS});
} }
sub packet_query_task { sub packet_query_task {
my ($self,$id) = @_; my ($self,$id) = @_;
return $self->packet_sysex_command('SCHEDULER_REQUEST', $SCHEDULER_COMMANDS->{QUERY_FIRMATA_TASK},$id); return $self->packet_sysex_command('SCHEDULER_DATA', $SCHEDULER_COMMANDS->{QUERY_FIRMATA_TASK},$id);
} }
sub packet_reset_scheduler { sub packet_reset_scheduler {
my $self = shift; my $self = shift;
return $self->packet_sysex_command('SCHEDULER_REQUEST', $SCHEDULER_COMMANDS->{RESET_FIRMATA_TASKS}); return $self->packet_sysex_command('SCHEDULER_DATA', $SCHEDULER_COMMANDS->{RESET_FIRMATA_TASKS});
} }
sub handle_scheduler_reply { sub handle_scheduler_response {
my ( $self, $sysex_data ) = @_; my ( $self, $sysex_data ) = @_;
my $command = shift @$sysex_data; my $command = shift @$sysex_data;