package POEDaemon::WheelRun::GPIOChange; use strict; use warnings FATAL => 'all'; no warnings 'redefine'; use POE; use POEDaemon; sub states { return $_[0], [qw( gpiochange_start gpiochange_stop gpiochange_init gpiochange_restart gpiochange_childexit gpiochange_stderr_line gpiochange_set gpiochange_toggle gpiochange_aliveled )]; } sub gpiochange_start { my ($kernel, $heap) = @_[KERNEL, HEAP]; #if (cfg->{poesession_mode} eq 'client') #{ # log_enabled && logline "ignored: delayed, poeserver-configured start is used in poesession mode '%s'", cfg->{poesession_mode}; # # return; #} #$heap->{gpiochange_start_executed} = 1; $kernel->yield('gpiochange_init'); $kernel->yield('gpiochange_aliveled'); } sub gpiochange_stop { my $kernel = $_[KERNEL]; $kernel->yield(wheelrun_kill => { wheel_name => 'gpiochange' }); } sub gpiochange_init { my ($kernel, $heap, $args) = @_[KERNEL, HEAP, ARG0]; log_enabled && logline 'event fired'; my @pins = (); if (cfg->{change_gpio_pins} && ref cfg->{change_gpio_pins} eq 'ARRAY') { @pins = @{cfg->{change_gpio_pins}}; } if ($args->{pins} && ref $args->{pins} eq 'ARRAY') { @pins = @{$args->{pins}}; } if (cfg->{change_gpio_pins_extra} && ref cfg->{change_gpio_pins_extra} eq 'ARRAY') { @pins = (@pins, @{cfg->{change_gpio_pins_extra}}); } if (@pins) { log_enabled && logline 'wheelrun_exec'; $kernel->yield(wheelrun_exec => { prog => [ 'util/gpio.pl', 'change', join(',', sort {$a <=> $b} @pins) ], name => 'gpiochange', stderr_event => 'gpiochange_stderr_line', }); } if (cfg->{tcpserver_client_connected_gpio_pin} && $heap->{tcpserver}->{connections} && %{$heap->{tcpserver}->{connections}}) { $kernel->yield(gpiochange_set => { pin => cfg->{tcpserver_client_connected_gpio_pin}, value => GPIO_HIGH }); } } sub gpiochange_restart { my ($kernel, $heap) = @_[KERNEL, HEAP]; log_enabled && logline "event fired, gpiopoll_start_executed = '%s'", $heap->{gpiopoll_start_executed} || 'n/a'; if ($heap->{wheel_run}->{children_by_name}->{gpiochange}) { $heap->{wheelrun_gpiochange_restartmode} = 1; $kernel->yield('gpiochange_stop'); } else { $kernel->yield(gpiochange_init => { pins => [ keys %{$heap->{tcpclient_dynamic_gpio_pins}->{out}} ], }); } } sub gpiochange_childexit { my ($kernel, $heap) = @_[KERNEL, HEAP]; if ($heap->{wheelrun_gpiochange_restartmode}) { delete $heap->{wheelrun_gpiochange_restartmode}; $kernel->yield(gpiochange_init => { pins => [ keys %{$heap->{tcpclient_dynamic_gpio_pins}->{out}} ], }); } else { unless ($heap->{shutdown}) { $kernel->yield(shutdown => 'gpiochange child abnormally terminated'); } } } sub gpiochange_stderr_line { my ($kernel, $session, $heap, $line) = @_[KERNEL, SESSION, HEAP, ARG0]; log_enabled && logline "line = '%s'", $line; return unless $line =~ /^ready$/i; $line = lc $line; my $output_per_target; $output_per_target->{tcpserver} = sprintf "GPIOCHANGE %s", $line; $output_per_target->{tcpclient} = sprintf "%s gpiochange %s", POECLIENT_CMD_PREFIX, $line; #my $output = sprintf "%s gpiochange %s", # POECLIENT_CMD_PREFIX, # lc $line; # # #foreach my $wheel_id (keys %{$heap->{tcpclient}->{connections}}) #{ # my $client = $heap->{tcpclient}->{connections}->{$wheel_id}; # # # next unless $client; # # # next unless $client->{wheel}; # # # $kernel->yield(tcpclient_output => # { # wheel_id => $wheel_id, # output => $output, # }); #} $kernel->call($session => wheelrun_send_network_reply => { output_per_target => $output_per_target, }); } sub gpiochange_set { my ($heap, $args) = @_[HEAP, ARG0]; my $pin = $args->{pin}; my $value = $args->{value}; unless (cfg->{poesession_mode} && cfg->{poesession_mode} eq 'client') { my $valid_pins = { map { $_ => 1 } @{cfg->{all_valid_out_pins_internal} || []} }; unless ($valid_pins->{$pin}) { log_enabled && logline 'invalid pin'; return; } } unless ($value == GPIO_HIGH || $value == GPIO_LOW) { log_enabled && logline "pin %s, invalid value", $pin; return; } $heap->{gpiochange}->{pinstatus}->{$pin} = { value => $value, last_change => time_hires, }; my $line = sprintf "%s=%s", $pin, $value; #foreach my $id (keys %{$heap->{wheel_run}->{children_by_wid}}) #{ # my $name = $heap->{wheel_run}->{children_by_wid}->{$id}->{args}->{name}; # # # next unless $name && $name eq 'gpiochange'; # # # $heap->{wheel_run}->{children_by_wid}->{$id}->{wheel}->put($line); #} my $wheel = $heap->{wheel_run}->{children_by_name}->{gpiochange}->{wheel}; return unless $wheel; #log_enabled && logline "put '%s'", $line; $wheel->put($line); } sub gpiochange_toggle { my ($kernel, $session, $heap, $args) = @_[KERNEL, SESSION, HEAP, ARG0]; my $pin = $args->{pin}; my $new_value; if (!$heap->{gpiochange}->{pinstatus}->{$pin}->{value} || $heap->{gpiochange}->{pinstatus}->{$pin}->{value} == GPIO_LOW) { $new_value = GPIO_HIGH; } elsif ($heap->{gpiochange}->{pinstatus}->{$pin}->{value} == GPIO_HIGH) { $new_value = GPIO_LOW; } $kernel->call($session => gpiochange_set => { pin => $pin, value => $new_value, }); } sub gpiochange_aliveled { my ($kernel, $heap, $state, $args) = @_[KERNEL, HEAP, STATE, ARG0]; my $led_pin = cfg->{aliveled_gpio_pin}; unless ($led_pin) { log_enabled && logline 'ignored, no led_pin'; return; } if (defined $args && $args eq 'off') { unless ($heap->{wheelrun_gpiochange_restartmode}) { $kernel->yield(gpiochange_set => { pin => $led_pin, value => GPIO_LOW }); } unless ($heap->{shutdown}) { $kernel->delay($state => cfg->{aliveled_off_time} || 1); } } else { unless ($heap->{wheelrun_gpiochange_restartmode}) { $kernel->yield(gpiochange_set => { pin => $led_pin, value => GPIO_HIGH }); } $kernel->delay($state => cfg->{aliveled_on_time} || 0.001 => 'off'); } } 1;