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.

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;
  inline_states => {
    _start      => \&setup_device,
    got_port    => \&display_port_data,
    got_console => \&transmit_console_data,
    got_error   => \&handle_errors,
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;

  # 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];

# Console input is sent to the device.
sub transmit_console_data {
  my ($heap, $input) = @_[HEAP, ARG0];
  if (defined $input) {
    $heap->{console}->get("Ready: ");

    # Clearing $! after $serial_port_wheel->put() seems to work around
    # an issue in Device::SerialPort 1.000_002.
    $! = 0;
  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]");
  delete $heap->{console};
  delete $heap->{port_wheel};