Device::SerialPort provides a tied filehandle interface that works reasonably well with POE. Version 1.000_002 of the library has some syswrite() problems that have been reported to the author. Please note the workaround in this example.
#!/usr/bin/perl
use warnings;
use strict;
use POE;
use POE::Wheel::ReadWrite;
use POE::Wheel::ReadLine;
use Symbol qw(gensym);
use Device::SerialPort;
use POE::Filter::Line;
POE::Session->create(
inline_states => {
_start => \&setup_device,
got_port => \&display_port_data,
got_console => \&transmit_console_data,
got_error => \&handle_errors,
},
);
POE::Kernel->run();
exit 0;
sub setup_device {
my ($kernel, $heap) = @_[KERNEL, HEAP];
# Open a serial port, and tie it to a file handle for POE.
my $handle = gensym();
my $port = tie(*$handle, "Device::SerialPort", "/dev/cu.modem");
die "can't open port: $!" unless $port;
$port->datatype('raw');
$port->baudrate(4800);
$port->databits(8);
$port->parity("none");
$port->stopbits(1);
$port->handshake("rts");
$port->write_settings();
# Start interacting with the GPS.
$heap->{port} = $port;
$heap->{port_wheel} = POE::Wheel::ReadWrite->new(
Handle => $handle,
Filter => POE::Filter::Line->new(
InputLiteral => "\x0D\x0A", # Received line endings.
OutputLiteral => "\x0D", # Sent line endings.
),
InputEvent => "got_port",
ErrorEvent => "got_error",
);
# Start a wheel to interact with the console, and prompt the user.
$heap->{console} = POE::Wheel::ReadLine->new(InputEvent => "got_console",);
$heap->{console}->put("Press ^D to stop.");
$heap->{console}->get("Ready: ");
}
# Port data (lines, separated by CRLF) are displayed on the console.
sub display_port_data {
my ($heap, $data) = @_[HEAP, ARG0];
$heap->{console}->put($data);
}
# Console input is sent to the device.
sub transmit_console_data {
my ($heap, $input) = @_[HEAP, ARG0];
if (defined $input) {
$heap->{console}->addhistory($input);
$heap->{port_wheel}->put($input);
$heap->{console}->get("Ready: ");
# Clearing $! after $serial_port_wheel->put() seems to work around
# an issue in Device::SerialPort 1.000_002.
$! = 0;
return;
}
$heap->{console}->put("Bye!");
delete $heap->{port_wheel};
delete $heap->{console};
}
# Error on the serial port. Shut down.
sub handle_errors {
my $heap = $_[HEAP];
$heap->{console}->put("$_[ARG0] error $_[ARG1]: $_[ARG2]");
$heap->{console}->put("bye!");
delete $heap->{console};
delete $heap->{port_wheel};
}