use POSIX qw(:termios_h);
use FileHandle;

# usage: $serial=init_serial("/dev/modem",38400,"8n1");
# you can then use sysread/write on $serial, which is a file handle.

sub init_serial {
    my($port,$baud,$pref)=@_;
    my($termios,$cflag,$lflag,$iflag,$oflag);
    my($voice);
 
 my $serial=new FileHandle("+>$port") || die "Could not open $port: $!\n";
    
    $termios = POSIX::Termios->new();
    $termios->getattr($serial->fileno()) || die "getattr: $!\n";
    $cflag= 0 | CS8 | HUPCL | CREAD | CLOCAL;
    $lflag= 0;
    $iflag= 0 | IGNBRK | IGNPAR | IXON | IXOFF;
    $oflag= 0;
        
    $termios->setcflag($cflag);
    $termios->setlflag($lflag);
    $termios->setiflag($iflag);
    $termios->setoflag($oflag);
    $termios->setattr($serial->fileno(),TCSANOW) || die "setattr: $!\n";
    eval qq[
      \$termios->setospeed(POSIX::B$baud) || die "setospeed: \$!\n";
      \$termios->setispeed(POSIX::B$baud) || die "setispeed: \$!\n";
    ];
    
    die $@ if $@;
    
    $termios->setattr($serial->fileno(),TCSANOW) || die "setattr: $!\n";

    if ($pref =~ /7e1/) {
        print "Switching to 7e1 mode\n";
	$termios->getattr($serial->fileno()) || die "getattr: $!\n";
	$cflag= 0 | CS7 | HUPCL | CREAD | CLOCAL | PARENB;
	$iflag= 0 | IGNBRK | IGNPAR | IXON | IXOFF;
	$oflag= 0;
	$lflag= 0;
	$termios->setcflag($cflag);
	$termios->setlflag($lflag);
	$termios->setiflag($iflag);
	$termios->setoflag($oflag);
	$termios->setattr($serial->fileno(),TCSANOW) || die "setattr: $!\n";
	eval qq[
	  \$termios->setospeed(POSIX::B$baud) || die "setospeed: \$!\n";
	  \$termios->setispeed(POSIX::B$baud) || die "setispeed: \$!\n";
	];
	die $@ if $@;
	$termios->setattr($serial->fileno(),TCSANOW) || die "setattr: $!\n";
    }

    # This gets rid of all the special characters..
    $termios->getattr($serial->fileno()) || die "getattr: $!\n";	
    for (0..NCCS) {	
	if ($_ == NCCS) { last; }

	# Dont mess up XON/XOFF..
	if ($_ == VSTART || $_ == VSTOP) { next; }

	$termios->setcc($_,0);	
    }
    $termios->setattr($serial->fileno(),TCSANOW) || die "setattr: $!\n";
    
    return $serial;
}

1;
