I did something like this several years ago, before
Device::SerialPort existed. Are you sure you can't alter the NEAX's output? I'm pretty sure I was working with LF-separated lines. I'll see if I can dig up my old code.
Update: found it
I
did have to replace the ctrl-c, and I got around the buffering issue by using
Term::ReadKey to poll the serial port directly (which pushed the load average to 1.0, but worked fine on a dedicated box).
#!/usr/local/bin/perl
# calldata.pl
# a program to collect call records from a NEAX2400IMS PBX
# via the serial interface. Breaks records into individual
# lines, stored in timestamped logfiles in $LOGDIR.
# SIGHUP forces a logfile cycle.
# SIGINT and SIGTERM force a nice, clean exit, closing files.
# File output is done with as little buffering as possible to
# protect logs from clobbering when power goes "blip".
#
# (c) 1999-2000 Spectral Systems/Brett T Warden
# (c) 1999-2000 University of Portland, Computer Services
fork && exit; # Background immediately
$0 = "calldata.pl";
use Term::ReadKey; # This makes reading serial data easier
print STDERR "Starting calldata.pl at " . `/bin/date`;
# USER DEFINITIONS
my $BASEDIR = "/home/calldata/";
my $PORT = "/dev/ttyS0";
my $LOGDIR = $BASEDIR . "calldata/";
# Internal variables - do not modify!
# Data buffer
my $data;
# Signal handling flags
my $SHUTDOWN = 0;
my $CYCLE_LOGS = 0;
# Signal handling routines: acknowledge signal and set a flag
# to be handled at a more convenient place.
$SIG{HUP} = sub {
# SIGHUP means re-exec, cycling logs
print STDERR "Caught SIGHUP -- Re-exec'ing\n";
$CYCLE_LOGS = 1; # Raise a flag
};
$SIG{INT} = sub {
# SIGINT is equivalent to ^C
print STDERR "Caught SIGINT -- Closing logfile and exiting\n";
$SHUTDOWN = 1; # Raise a flag
};
$SIG{TERM} = sub {
# SIGTERM is the default signal sent by kill(1) and is used on hal
+t
print STDERR "Caught SIGTERM -- Closing logfile and exiting\n";
$SHUTDOWN = 1; # Raise a flag
};
open(PORT, $PORT) || die "$!: Can't open serial port";
ReadMode 4, PORT;
open(LOG, "> " . $LOGDIR . "calldata." . time())
|| die "$!: Can't open logfile";
select(LOG);
$| = 1;
select(STDOUT);
while(1) {
$data = ReadLine(5,PORT); # Get some data, move on when there's a
+pause
$data =~ s/\002//g; # Eliminate that pesky ^B
$data =~ s/\003/\n/g; # ^C means end of record, so replace wit
+h \n
print LOG $data; # Put cooked data in logfile
# Okay, we're done with input for a moment or two,
# so let's handle some signal flags
if($CYCLE_LOGS) {
# Close the current logfile and the port, then re-exec
# myself to make everyone happy or something
close(LOG);
close(PORT);
exec($BASEDIR . $0) || die "$!: exec failed";
$CYCLE_LOGS = 0; # Reset flag... good idea
}
if($SHUTDOWN) {
# Close the open file descriptors and exit nicely
close(LOG);
close(PORT);
print STDERR "Shutting down at " . `/bin/date`;
$SHUTDOWN = 0; # Reset the flag, not really necessary here
exit(0);
}
}
# This will never be executed (unless you break from the while loop),
# but it's good form
close(LOG);
close(PORT);
exit(0);