mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-17 17:36:01 +00:00
FRM: new module FRM_ROTENC for rotary-encoders attached to arduino
git-svn-id: https://svn.fhem.de/fhem/trunk@5074 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
1d874e81b8
commit
5ac7bd694e
@ -323,6 +323,8 @@ sub FRM_DoInit($) {
|
|||||||
$main::defs{$name}{i2c_pins} = join(",", sort{$a<=>$b}(@$i2cpins)) if (defined $i2cpins and scalar @$i2cpins);
|
$main::defs{$name}{i2c_pins} = join(",", sort{$a<=>$b}(@$i2cpins)) if (defined $i2cpins and scalar @$i2cpins);
|
||||||
my $onewirepins = $device->{metadata}{onewire_pins};
|
my $onewirepins = $device->{metadata}{onewire_pins};
|
||||||
$main::defs{$name}{onewire_pins} = join(",", sort{$a<=>$b}(@$onewirepins)) if (defined $onewirepins and scalar @$onewirepins);
|
$main::defs{$name}{onewire_pins} = join(",", sort{$a<=>$b}(@$onewirepins)) if (defined $onewirepins and scalar @$onewirepins);
|
||||||
|
my $encoderpins = $device->{metadata}{encoder_pins};
|
||||||
|
$main::defs{$name}{encoder_pins} = join(",", sort{$a<=>$b}(@$encoderpins)) if (defined $encoderpins and scalar @$encoderpins);
|
||||||
if (defined $device->{metadata}{analog_resolutions}) {
|
if (defined $device->{metadata}{analog_resolutions}) {
|
||||||
my @analog_resolutions;
|
my @analog_resolutions;
|
||||||
foreach my $pin (sort{$a<=>$b}(keys %{$device->{metadata}{analog_resolutions}})) {
|
foreach my $pin (sort{$a<=>$b}(keys %{$device->{metadata}{analog_resolutions}})) {
|
||||||
@ -344,6 +346,13 @@ sub FRM_DoInit($) {
|
|||||||
}
|
}
|
||||||
$main::defs{$name}{servo_resolutions} = join(",",@servo_resolutions) if (scalar @servo_resolutions);
|
$main::defs{$name}{servo_resolutions} = join(",",@servo_resolutions) if (scalar @servo_resolutions);
|
||||||
}
|
}
|
||||||
|
if (defined $device->{metadata}{encoder_resolutions}) {
|
||||||
|
my @encoder_resolutions;
|
||||||
|
foreach my $pin (sort{$a<=>$b}(keys %{$device->{metadata}{encoder_resolutions}})) {
|
||||||
|
push @encoder_resolutions,$pin.":".$device->{metadata}{encoder_resolutions}{$pin};
|
||||||
|
}
|
||||||
|
$main::defs{$name}{encoder_resolutions} = join(",",@encoder_resolutions) if (scalar @encoder_resolutions);
|
||||||
|
}
|
||||||
$found = 1;
|
$found = 1;
|
||||||
} else {
|
} else {
|
||||||
select (undef,undef,undef,0.01);
|
select (undef,undef,undef,0.01);
|
||||||
|
224
fhem/FHEM/20_FRM_ROTENC.pm
Executable file
224
fhem/FHEM/20_FRM_ROTENC.pm
Executable file
@ -0,0 +1,224 @@
|
|||||||
|
#############################################
|
||||||
|
package main;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
#add FHEM/lib to @INC if it's not allready included. Should rather be in fhem.pl than here though...
|
||||||
|
BEGIN {
|
||||||
|
if (!grep(/FHEM\/lib$/,@INC)) {
|
||||||
|
foreach my $inc (grep(/FHEM$/,@INC)) {
|
||||||
|
push @INC,$inc."/lib";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
use Device::Firmata::Constants qw/ :all /;
|
||||||
|
|
||||||
|
#####################################
|
||||||
|
|
||||||
|
my %sets = (
|
||||||
|
"reset" => "noArg",
|
||||||
|
);
|
||||||
|
|
||||||
|
my %gets = (
|
||||||
|
"position" => "noArg",
|
||||||
|
);
|
||||||
|
|
||||||
|
sub
|
||||||
|
FRM_ROTENC_Initialize($)
|
||||||
|
{
|
||||||
|
my ($hash) = @_;
|
||||||
|
|
||||||
|
$hash->{SetFn} = "FRM_ROTENC_Set";
|
||||||
|
$hash->{GetFn} = "FRM_ROTENC_Get";
|
||||||
|
$hash->{AttrFn} = "FRM_ROTENC_Attr";
|
||||||
|
$hash->{DefFn} = "FRM_Client_Define";
|
||||||
|
$hash->{InitFn} = "FRM_ROTENC_Init";
|
||||||
|
$hash->{UndefFn} = "FRM_ROTENC_Undef";
|
||||||
|
|
||||||
|
$hash->{AttrList} = "IODev $main::readingFnAttributes";
|
||||||
|
main::LoadModule("FRM");
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
FRM_ROTENC_Init($$)
|
||||||
|
{
|
||||||
|
my ($hash,$args) = @_;
|
||||||
|
|
||||||
|
my $u = "wrong syntax: define <name> FRM_ROTENC pinA pinB [id]";
|
||||||
|
return $u unless defined $args and int(@$args) > 1;
|
||||||
|
my $pinA = @$args[0];
|
||||||
|
my $pinB = @$args[1];
|
||||||
|
my $encoder = defined @$args[2] ? @$args[2] : 0;
|
||||||
|
|
||||||
|
$hash->{PINA} = $pinA;
|
||||||
|
$hash->{PINB} = $pinB;
|
||||||
|
|
||||||
|
$hash->{ENCODERNUM} = $encoder;
|
||||||
|
|
||||||
|
eval {
|
||||||
|
FRM_Client_AssignIOPort($hash);
|
||||||
|
my $firmata = FRM_Client_FirmataDevice($hash);
|
||||||
|
$firmata->encoder_attach($encoder,$pinA,$pinB);
|
||||||
|
$firmata->observe_encoder($encoder, \&FRM_ROTENC_observer, $hash );
|
||||||
|
};
|
||||||
|
if ($@) {
|
||||||
|
$@ =~ /^(.*)( at.*FHEM.*)$/;
|
||||||
|
$hash->{STATE} = "error initializing: ".$1;
|
||||||
|
return "error initializing '".$hash->{NAME}."': ".$1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! (defined AttrVal($hash->{NAME},"stateFormat",undef))) {
|
||||||
|
$main::attr{$hash->{NAME}}{"stateFormat"} = "position";
|
||||||
|
}
|
||||||
|
main::readingsSingleUpdate($hash,"state","Initialized",1);
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
FRM_ROTENC_observer
|
||||||
|
{
|
||||||
|
my ( $data, $hash ) = @_;
|
||||||
|
my $name = $hash->{NAME};
|
||||||
|
Log3 $name,5,"onEncoderMessage for pins ".$hash->{PINA}.",".$hash->{PINB}." encoder: ".$data->{encoderNum}." position: ".$data->{value}."\n";
|
||||||
|
main::readingsBeginUpdate($hash);
|
||||||
|
main::readingsBulkUpdate($hash,"position",$data->{value}, 1);
|
||||||
|
main::readingsEndUpdate($hash,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
FRM_ROTENC_Set
|
||||||
|
{
|
||||||
|
my ($hash, @a) = @_;
|
||||||
|
return "Need at least one parameters" if(@a < 2);
|
||||||
|
my $command = $a[1];
|
||||||
|
my $value = $a[2];
|
||||||
|
if(!defined($sets{$command})) {
|
||||||
|
my @commands = ();
|
||||||
|
foreach my $key (sort keys %sets) {
|
||||||
|
push @commands, $sets{$key} ? $key.":".join(",",$sets{$key}) : $key;
|
||||||
|
}
|
||||||
|
return "Unknown argument $a[1], choose one of " . join(" ", @commands);
|
||||||
|
}
|
||||||
|
COMMAND_HANDLER: {
|
||||||
|
$command eq "reset" and do {
|
||||||
|
eval {
|
||||||
|
FRM_Client_FirmataDevice($hash)->encoder_reset_position($hash->{ENCODERNUM});
|
||||||
|
};
|
||||||
|
last;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
FRM_ROTENC_Get($)
|
||||||
|
{
|
||||||
|
my ($hash, @a) = @_;
|
||||||
|
return "Need at least one parameters" if(@a < 2);
|
||||||
|
my $command = $a[1];
|
||||||
|
my $value = $a[2];
|
||||||
|
if(!defined($gets{$command})) {
|
||||||
|
my @commands = ();
|
||||||
|
foreach my $key (sort keys %gets) {
|
||||||
|
push @commands, $gets{$key} ? $key.":".join(",",$gets{$key}) : $key;
|
||||||
|
}
|
||||||
|
return "Unknown argument $a[1], choose one of " . join(" ", @commands);
|
||||||
|
}
|
||||||
|
my $name = shift @a;
|
||||||
|
my $cmd = shift @a;
|
||||||
|
ARGUMENT_HANDLER: {
|
||||||
|
$cmd eq "position" and do {
|
||||||
|
return ReadingsVal($hash->{NAME},"position","0");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
FRM_ROTENC_Attr($$$$) {
|
||||||
|
my ($command,$name,$attribute,$value) = @_;
|
||||||
|
my $hash = $main::defs{$name};
|
||||||
|
my $pin = $hash->{PIN};
|
||||||
|
if ($command eq "set") {
|
||||||
|
ARGUMENT_HANDLER: {
|
||||||
|
$attribute eq "IODev" and do {
|
||||||
|
if (!defined ($hash->{IODev}) or $hash->{IODev}->{NAME} ne $value) {
|
||||||
|
$hash->{IODev} = $defs{$value};
|
||||||
|
FRM_Init_Client($hash) if (defined ($hash->{IODev}));
|
||||||
|
}
|
||||||
|
last;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub
|
||||||
|
FRM_ROTENC_Undef($$)
|
||||||
|
{
|
||||||
|
my ($hash, $name) = @_;
|
||||||
|
my $pinA = $hash->{PINA};
|
||||||
|
my $pinB = $hash->{PINB};
|
||||||
|
eval {
|
||||||
|
my $firmata = FRM_Client_FirmataDevice($hash);
|
||||||
|
$firmata->encoder_detach($hash->{ENCODERNUM});
|
||||||
|
$firmata->pin_mode($pinA,PIN_ANALOG);
|
||||||
|
$firmata->pin_mode($pinB,PIN_ANALOG);
|
||||||
|
};
|
||||||
|
if ($@) {
|
||||||
|
eval {
|
||||||
|
my $firmata = FRM_Client_FirmataDevice($hash);
|
||||||
|
$firmata->pin_mode($pinA,PIN_INPUT);
|
||||||
|
$firmata->digital_write($pinA,0);
|
||||||
|
$firmata->pin_mode($pinB,PIN_INPUT);
|
||||||
|
$firmata->digital_write($pinB,0);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
=pod
|
||||||
|
=begin html
|
||||||
|
|
||||||
|
<a name="FRM_ROTENC"></a>
|
||||||
|
<h3>FRM_ROTENC</h3>
|
||||||
|
<ul>
|
||||||
|
represents a rotary-encoder attached to two pins of an <a href="http://www.arduino.cc">Arduino</a> running <a href="http://www.firmata.org">Firmata</a><br>
|
||||||
|
Requires a defined <a href="#FRM">FRM</a>-device to work.<br><br>
|
||||||
|
|
||||||
|
<a name="FRM_ROTENCdefine"></a>
|
||||||
|
<b>Define</b>
|
||||||
|
<ul>
|
||||||
|
<code>define <name> FRM_ROTENC <pinA> <pinB> [id]</code> <br>
|
||||||
|
Defines the FRM_ROTENC device. <pinA>> and <pinA>> are the arduino-pins to use.<br>
|
||||||
|
[id] is the instance-id of the encoder. Must be a unique number per FRM-device (rages from 0-4 depending on Firmata being used, optional if a single encoder is attached to the arduino).<br>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<a name="FRM_ROTENCset"></a>
|
||||||
|
<b>Set</b><br>
|
||||||
|
<li>reset<br>
|
||||||
|
resets to value of 'position' to 0<br></li>
|
||||||
|
<a name="FRM_ROTENCget"></a>
|
||||||
|
<b>Get</b>
|
||||||
|
<ul>
|
||||||
|
<li>position<br>
|
||||||
|
returns the position of the rotary-encoder attached to pinA and pinB of the arduino<br></li>
|
||||||
|
</ul><br>
|
||||||
|
<a name="FRM_ROTENCattr"></a>
|
||||||
|
<b>Attributes</b><br>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#IODev">IODev</a><br>
|
||||||
|
Specify which <a href="#FRM">FRM</a> to use. (Optional, only required if there is more
|
||||||
|
than one FRM-device defined.)
|
||||||
|
</li>
|
||||||
|
<li><a href="#eventMap">eventMap</a><br></li>
|
||||||
|
<li><a href="#readingFnAttributes">readingFnAttributes</a><br></li>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
=end html
|
||||||
|
=cut
|
@ -19,7 +19,7 @@ Version 0.50
|
|||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
our $VERSION = '0.52';
|
our $VERSION = '0.53';
|
||||||
our $DEBUG = 0;
|
our $DEBUG = 0;
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ use constant (
|
|||||||
PIN_I2C => 6,
|
PIN_I2C => 6,
|
||||||
PIN_ONEWIRE => 7,
|
PIN_ONEWIRE => 7,
|
||||||
PIN_STEPPER => 8,
|
PIN_STEPPER => 8,
|
||||||
|
PIN_ENCODER => 9,
|
||||||
PIN_LOW => 0,
|
PIN_LOW => 0,
|
||||||
PIN_HIGH => 1,
|
PIN_HIGH => 1,
|
||||||
}
|
}
|
||||||
@ -293,6 +294,65 @@ use constant (
|
|||||||
],
|
],
|
||||||
|
|
||||||
}, # /Constants for Version 2.5
|
}, # /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).
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
# Deprecated entries
|
||||||
|
deprecated => [
|
||||||
|
qw( FIRMATA_STRING SYSEX_I2C_REQUEST SYSEX_I2C_REPLY SYSEX_SAMPLING_INTERVAL )
|
||||||
|
],
|
||||||
|
|
||||||
|
}, # /Constants for Version 2.6
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ use Device::Firmata::Base
|
|||||||
ports => [],
|
ports => [],
|
||||||
pins => {},
|
pins => {},
|
||||||
pin_modes => {},
|
pin_modes => {},
|
||||||
|
encoders => [],
|
||||||
|
|
||||||
# To notify on events
|
# To notify on events
|
||||||
digital_observer => [],
|
digital_observer => [],
|
||||||
@ -38,6 +39,8 @@ use Device::Firmata::Base
|
|||||||
sysex_observer => undef,
|
sysex_observer => undef,
|
||||||
i2c_observer => undef,
|
i2c_observer => undef,
|
||||||
onewire_observer => [],
|
onewire_observer => [],
|
||||||
|
stepper_observer => [],
|
||||||
|
encoder_observer => [],
|
||||||
scheduler_observer => undef,
|
scheduler_observer => undef,
|
||||||
string_observer => undef,
|
string_observer => undef,
|
||||||
|
|
||||||
@ -242,6 +245,9 @@ sub sysex_handle {
|
|||||||
my @shiftpins;
|
my @shiftpins;
|
||||||
my @i2cpins;
|
my @i2cpins;
|
||||||
my @onewirepins;
|
my @onewirepins;
|
||||||
|
my @stepperpins;
|
||||||
|
my @encoderpins;
|
||||||
|
|
||||||
foreach my $pin (keys %$capabilities) {
|
foreach my $pin (keys %$capabilities) {
|
||||||
if (defined $capabilities->{$pin}) {
|
if (defined $capabilities->{$pin}) {
|
||||||
if ($capabilities->{$pin}->{PIN_INPUT+0}) {
|
if ($capabilities->{$pin}->{PIN_INPUT+0}) {
|
||||||
@ -271,6 +277,12 @@ sub sysex_handle {
|
|||||||
if ($capabilities->{$pin}->{PIN_ONEWIRE+0}) {
|
if ($capabilities->{$pin}->{PIN_ONEWIRE+0}) {
|
||||||
push @onewirepins, $pin;
|
push @onewirepins, $pin;
|
||||||
}
|
}
|
||||||
|
if ($capabilities->{$pin}->{PIN_STEPPER+0}) {
|
||||||
|
push @stepperpins, $pin;
|
||||||
|
}
|
||||||
|
if ($capabilities->{$pin}->{PIN_ENCODER+0}) {
|
||||||
|
push @encoderpins, $pin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$self->{metadata}{input_pins} = \@inputpins;
|
$self->{metadata}{input_pins} = \@inputpins;
|
||||||
@ -281,6 +293,8 @@ sub sysex_handle {
|
|||||||
$self->{metadata}{shift_pins} = \@shiftpins;
|
$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;
|
||||||
|
$self->{metadata}{stepper_pins} = \@stepperpins;
|
||||||
|
$self->{metadata}{encoder_pins} = \@encoderpins;
|
||||||
last;
|
last;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -332,7 +346,23 @@ sub sysex_handle {
|
|||||||
$observer->{method}( $data->{string}, $observer->{context} );
|
$observer->{method}( $data->{string}, $observer->{context} );
|
||||||
}
|
}
|
||||||
last;
|
last;
|
||||||
|
};
|
||||||
|
|
||||||
|
$sysex_message->{command_str} eq 'STEPPER_DATA' and do {
|
||||||
|
#TODO implement handling of STEPPER_DATA and call observer.
|
||||||
|
last;
|
||||||
|
};
|
||||||
|
|
||||||
|
$sysex_message->{command_str} eq 'ENCODER_DATA' and do {
|
||||||
|
foreach my $encoder_data ( @$data ) {
|
||||||
|
my $encoderNum = $encoder_data->{encoderNum};
|
||||||
|
my $observer = $self->{encoder_observer}[$encoderNum];
|
||||||
|
if (defined $observer) {
|
||||||
|
$observer->{method}( $encoder_data, $observer->{context} );
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
last;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -739,6 +769,38 @@ sub onewire_command_series {
|
|||||||
return $self->{io}->data_write($self->{protocol}->packet_onewire_request( $pin, $args ));
|
return $self->{io}->data_write($self->{protocol}->packet_onewire_request( $pin, $args ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub encoder_attach {
|
||||||
|
my ( $self, $encoderNum, $pinA, $pinB ) = @_;
|
||||||
|
die "unsupported mode 'ENCODER' for pin '".$pinA."'" unless $self->is_supported_mode($pinA,PIN_ENCODER);
|
||||||
|
die "unsupported mode 'ENCODER' for pin '".$pinB."'" unless $self->is_supported_mode($pinB,PIN_ENCODER);
|
||||||
|
return $self->{io}->data_write($self->{protocol}->packet_encoder_attach( $encoderNum, $pinA, $pinB ));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub encoder_report_position {
|
||||||
|
my ( $self, $encoderNum ) = @_;
|
||||||
|
return $self->{io}->data_write($self->{protocol}->packet_encoder_report_position( $encoderNum ));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub encoder_report_positions {
|
||||||
|
my ( $self ) = @_;
|
||||||
|
return $self->{io}->data_write($self->{protocol}->packet_encoder_report_positions());
|
||||||
|
}
|
||||||
|
|
||||||
|
sub encoder_reset_position {
|
||||||
|
my ( $self, $encoderNum ) = @_;
|
||||||
|
return $self->{io}->data_write($self->{protocol}->packet_encoder_reset_position( $encoderNum ));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub encoder_report_auto {
|
||||||
|
my ( $self, $enable ) = @_;
|
||||||
|
return $self->{io}->data_write($self->{protocol}->packet_encoder_report_auto( $enable ));
|
||||||
|
}
|
||||||
|
|
||||||
|
sub encoder_detach {
|
||||||
|
my ( $self, $encoderNum ) = @_;
|
||||||
|
return $self->{io}->data_write($self->{protocol}->packet_encoder_detach( $encoderNum ));
|
||||||
|
}
|
||||||
|
|
||||||
=head2 poll
|
=head2 poll
|
||||||
|
|
||||||
Call this function every once in a while to
|
Call this function every once in a while to
|
||||||
@ -809,6 +871,21 @@ sub observe_onewire {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub observe_stepper {
|
||||||
|
#TODO implement observe_stepper
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub observe_encoder {
|
||||||
|
my ( $self, $encoderNum, $observer, $context ) = @_;
|
||||||
|
#TODO validation? die "unsupported mode 'ENCODER' for pin '".$pin."'" unless ($self->is_supported_mode($pin,PIN_ENCODER));
|
||||||
|
$self->{encoder_observer}[$encoderNum] = {
|
||||||
|
method => $observer,
|
||||||
|
context => $context,
|
||||||
|
};
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
sub observe_scheduler {
|
sub observe_scheduler {
|
||||||
my ( $self, $observer, $context ) = @_;
|
my ( $self, $observer, $context ) = @_;
|
||||||
$self->{scheduler_observer} = {
|
$self->{scheduler_observer} = {
|
||||||
|
@ -73,6 +73,20 @@ our $SCHEDULER_COMMANDS = {
|
|||||||
QUERY_TASK_REPLY => 10,
|
QUERY_TASK_REPLY => 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
our $STEPPER_COMMANDS = {
|
||||||
|
STEPPER_CONFIG => 0,
|
||||||
|
STEPPER_STEP => 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
our $ENCODER_COMMANDS = {
|
||||||
|
ENCODER_ATTACH => 0,
|
||||||
|
ENCODER_REPORT_POSITION => 1,
|
||||||
|
ENCODER_REPORT_POSITIONS => 2,
|
||||||
|
ENCODER_RESET_POSITION => 3,
|
||||||
|
ENCODER_REPORT_AUTO => 4,
|
||||||
|
ENCODER_DETACH => 5,
|
||||||
|
};
|
||||||
|
|
||||||
our $MODENAMES = {
|
our $MODENAMES = {
|
||||||
0 => 'INPUT',
|
0 => 'INPUT',
|
||||||
1 => 'OUTPUT',
|
1 => 'OUTPUT',
|
||||||
@ -82,6 +96,8 @@ our $MODENAMES = {
|
|||||||
5 => 'SHIFT',
|
5 => 'SHIFT',
|
||||||
6 => 'I2C',
|
6 => 'I2C',
|
||||||
7 => 'ONEWIRE',
|
7 => 'ONEWIRE',
|
||||||
|
8 => 'STEPPER',
|
||||||
|
9 => 'ENCODER',
|
||||||
};
|
};
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
@ -290,6 +306,16 @@ sub sysex_parse {
|
|||||||
last;
|
last;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$command == $protocol_commands->{STEPPER_DATA} and do {
|
||||||
|
#TODO implement and call handle_stepper_response
|
||||||
|
last;
|
||||||
|
};
|
||||||
|
|
||||||
|
$command == $protocol_commands->{ENCODER_DATA} and do {
|
||||||
|
$return_data = $self->handle_encoder_response($sysex_data);
|
||||||
|
last;
|
||||||
|
};
|
||||||
|
|
||||||
$command == $protocol_commands->{RESERVED_COMMAND} and do {
|
$command == $protocol_commands->{RESERVED_COMMAND} and do {
|
||||||
$return_data = $sysex_data;
|
$return_data = $sysex_data;
|
||||||
last;
|
last;
|
||||||
@ -841,6 +867,75 @@ sub handle_scheduler_response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#TODO packet_stepper_config
|
||||||
|
sub packet_stepper_config {
|
||||||
|
my ( $self ) = @_;
|
||||||
|
my $packet = $self->packet_sysex_command('STEPPER_DATA', $STEPPER_COMMANDS->{STEPPER_CONFIG});
|
||||||
|
}
|
||||||
|
|
||||||
|
#TODO packet_stepper_step
|
||||||
|
sub packet_stepper_step {
|
||||||
|
my ( $self ) = @_;
|
||||||
|
my $packet = $self->packet_sysex_command('STEPPER_DATA', $STEPPER_COMMANDS->{STEPPER_STEP});
|
||||||
|
}
|
||||||
|
|
||||||
|
sub packet_encoder_attach {
|
||||||
|
my ( $self,$encoderNum, $pinA, $pinB ) = @_;
|
||||||
|
my $packet = $self->packet_sysex_command('ENCODER_DATA', $ENCODER_COMMANDS->{ENCODER_ATTACH}, $encoderNum, $pinA, $pinB);
|
||||||
|
return $packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub packet_encoder_report_position {
|
||||||
|
my ( $self,$encoderNum ) = @_;
|
||||||
|
my $packet = $self->packet_sysex_command('ENCODER_DATA', $ENCODER_COMMANDS->{ENCODER_REPORT_POSITION}, $encoderNum);
|
||||||
|
return $packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub packet_encoder_report_positions {
|
||||||
|
my ( $self ) = @_;
|
||||||
|
my $packet = $self->packet_sysex_command('ENCODER_DATA', $ENCODER_COMMANDS->{ENCODER_REPORT_POSITIONS});
|
||||||
|
return $packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub packet_encoder_reset_position {
|
||||||
|
my ( $self,$encoderNum ) = @_;
|
||||||
|
my $packet = $self->packet_sysex_command('ENCODER_DATA', $ENCODER_COMMANDS->{ENCODER_RESET_POSITION}, $encoderNum);
|
||||||
|
return $packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub packet_encoder_report_auto {
|
||||||
|
my ( $self,$arg ) = @_; #TODO clarify encoder_report_auto $arg
|
||||||
|
my $packet = $self->packet_sysex_command('ENCODER_DATA', $ENCODER_COMMANDS->{ENCODER_REPORT_AUTO}, $arg);
|
||||||
|
return $packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub packet_encoder_detach {
|
||||||
|
my ( $self,$encoderNum ) = @_;
|
||||||
|
my $packet = $self->packet_sysex_command('ENCODER_DATA', $ENCODER_COMMANDS->{ENCODER_DETACH}, $encoderNum);
|
||||||
|
return $packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub handle_encoder_response {
|
||||||
|
my ( $self, $sysex_data ) = @_;
|
||||||
|
|
||||||
|
my @retval = ();
|
||||||
|
|
||||||
|
while (@$sysex_data) {
|
||||||
|
|
||||||
|
my $command = shift @$sysex_data;
|
||||||
|
my $direction = ($command & 0x40) >> 6;
|
||||||
|
my $encoderNum = $command & 0x3f;
|
||||||
|
my $value = shift14bit($sysex_data) + (shift14bit($sysex_data) << 14);
|
||||||
|
|
||||||
|
push @retval,{
|
||||||
|
encoderNum => $encoderNum,
|
||||||
|
value => $direction ? -1 * $value : $value,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return \@retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
sub shift14bit {
|
sub shift14bit {
|
||||||
my $data = shift;
|
my $data = shift;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user