Cat ttyUSB

From Wirespeed

(Redirected from Cat ttyUSB0)
Jump to: navigation, search

A simple little PERL script that just outputs all data that is available on /dev/ttyUSB0 from the command line. Combines very well with Plot real time data using Gnuplot to draw real time plots. And of course you want some udev rules.

Contents

Command line options

--device=...        Full path name to the device file. Eg. /dev/ttyUSB0 (default)
--(no-)flush        Flush the serial buffer. This is useful after resetting Arduino, it usually sends a lot of NUL bytes to facilitate reprogramming.
--(no-)reset        Resets the Arduino after succesful (re)connect.
--reset-once        Resets the Arduino at start of the script. If the USB bus receives a reset, the Arduino will not be reset and connection will be restored.
--(no-)restart      Tries to reconnect after a USB bus reset. Default is '--restart'.

Script

 #!/usr/bin/perl

#
# (c) J.P. Hendrix
# http://wirespeed.xs4all.nl/mediawiki
#
# Script to echo all data sent from Arduino to PC
# To set up proper udev rules, refer to http://wirespeed.xs4all.nl/mediawiki/index.php/Udev_rules_file_for_Arduino_boards
# 

use warnings;
use strict;
use Device::SerialPort;
use Getopt::Long;

my $PortObj;
$| = 1;				# make the output line bufferend

my %parameters;
GetOptions (\%parameters , 'device=s' , 'flush!' , 'reset!' , 'reset-once!' , 'restart!' );
my $PortName = $parameters{ 'device' } || "/dev/ttyUSB0";
my $restart  = $parameters{ 'restart' } || 1;

if ( ! -e $PortName ) { die "Device '$PortName' does not exist." }

###
### This sub is to be called when the program exits so the lockfile is removed
### and memory is freed.
###
sub finalize {
	print STDERR "Finalize: ";
	if ( defined( $PortObj ) ) {
		$PortObj->close || die "failed to close";
		undef $PortObj;
		print STDERR "done.";
	}
	print STDERR "\n";
};

###
### When a Ctrl-C is received, clean up after us.
###
$SIG{ INT } = sub { finalize; die "\nSIGINT received. Quitting"; };
$SIG{ KILL } = sub { finalize; die "\nSIGINT received. Quitting"; };

my $lockfile = $PortName;
$lockfile =~ s/dev/tmp/;
# my $file_exists = "";
if ( -e "$lockfile" ) {
	# $file_exists = "Manually remove $lockfile when sure the device is not in use.\n";
	die "Manually remove $lockfile when sure the device is not in use.\n";
}


my $restartRequired = 0;
do {
	print STDERR "Initializing serial port $PortName (115200, 8N1) ...\n";
	my $quiet = 'false';
	my $data;
	my $count;
	
	###
	### Open the serial port device to the Arduino
	###
	if ( $PortObj = new Device::SerialPort ($PortName, $quiet, $lockfile) ) {
		$restartRequired = 0
	} else {
		$restartRequired = 1;
	}
	if ( not $restartRequired ) {
		$PortObj->databits( 8 );
		$PortObj->baudrate( 115200 );
		$PortObj->parity( "none" );
		$PortObj->stopbits( 1 );
		$PortObj->handshake( "none" );
		$PortObj->read_char_time( 0 );
		# $PortObj->read_const_time( 60000 );
		$PortObj->read_const_time( 20 );
	
		###
		### Reset Arduino
		###
		if ( ! defined( $parameters{ 'reset' } ) or $parameters{ 'reset' } ) {
			print STDERR "Resetting Arduino ...\n";
			$PortObj->pulse_dtr_on( 200 );	# Reset Arduino
			if ( $parameters{ 'reset-once' } ) { $parameters{ 'reset' } = 0; }
		}
	
		###
		### Flush serial buffer
		###
		if ( ! defined( $parameters{ 'flush' } ) or $parameters{ 'flush' } ) {
			print STDERR "Flushing serial buffer ...\n";
			#$PortObj->lookclear;	# Doesn't work!
			my ( $count, $data ) = $PortObj->read( 1 );
			while ( $count != 0 ) {
				( $count, $data ) = $PortObj->read( $count );
			}
		}
	
	
		print STDERR "Receiving serial data ...\n";
		( $count, $data ) = $PortObj->read( 1 );
		while ( ord( $data ) == 0x00 ) {
			( $count, $data ) = $PortObj->read( 1 );
		}
	}

	while ( not $restartRequired ) {
	 	if ( ( $data ne  ) ) { printf $data; };
	        ( $count, $data ) = $PortObj->read( 1 ) or $restartRequired = $restart;
	}
	finalize;
	sleep 1;
} until ( not $restartRequired );

Use case 1

Arduino sketch

A simple interrupt driven clock counting days, hours, minutes and seconds.

// timer example from electronicsblog.net
#define LED 13
#define TimerInit 3036
// 1 sec 65536 - 16000000 /256 = 3036, with CLKPR=0
// 10Hz => 65536 - 16000000 / (256 * 10 ) = 59286

boolean x = false;
int d = 0;
int h = 0;
int m = 0;
int s = 0;

ISR( TIMER1_OVF_vect ) {
  TCNT1 = TimerInit; // set initial value to remove time error (16bit counter register)
  digitalWrite( LED , x );
  x = !x;
  s += 1;
  if ( s > 59 ) { s = 0; m += 1; }
  if ( m > 59 ) { m = 0; h += 1; }
  if ( h > 24 ) { h = 0; d += 1; }
  Serial.print( d );
  Serial.print( "-" );
  Serial.print( h );
  Serial.print( ":" );
  Serial.print( m );
  Serial.print( ":" );
  Serial.println( s );
}

void setup() {
  pinMode( LED , OUTPUT );
  CLKPR = _BV( CLKPCE );
  CLKPR = 0;             // prescaler 2**n
  TIMSK1 = 0x01;         // enabled global and timer overflow interrupt;
  TCCR1A = 0x00;         // normal operation page 148 (mode0);
  TCNT1 = TimerInit;     // set initial value to remove time error (16bit counter register)
  TCCR1B = 0x04;         // start timer/ set clock
  Serial.begin( 115200 );
};

void loop () {
  // Do nothing
};// timer example from electronicsblog.net
#define LED 13
#define TimerInit 3036
// 1 sec 65536 - 16000000 /256 = 3036, with CLKPR=0
// 10Hz => 65536 - 16000000 / (256 * 10 ) = 59286

boolean x = false;
int d = 0;
int h = 0;
int m = 0;
int s = 0;

ISR( TIMER1_OVF_vect ) {
  TCNT1 = TimerInit; // set initial value to remove time error (16bit counter register)
  digitalWrite( LED , x );
  x = !x;
  s += 1;
  if ( s > 59 ) { s = 0; m += 1; }
  if ( m > 59 ) { m = 0; h += 1; }
  if ( h > 24 ) { h = 0; d += 1; }
  Serial.print( d );
  Serial.print( "-" );
  Serial.print( h );
  Serial.print( ":" );
  Serial.print( m );
  Serial.print( ":" );
  Serial.println( s );
}

void setup() {
  pinMode( LED , OUTPUT );
  CLKPR = _BV( CLKPCE );
  CLKPR = 0;             // prescaler 2**n
  TIMSK1 = 0x01;         // enabled global and timer overflow interrupt;
  TCCR1A = 0x00;         // normal operation page 148 (mode0);
  TCNT1 = TimerInit;     // set initial value to remove time error (16bit counter register)
  TCCR1B = 0x04;         // start timer/ set clock
  Serial.begin( 115200 );
};

void loop () {
  // Do nothing
};

In action

while [ `date +%S` -ne 57 ]; do true; done; ./cat_ttyUSB.pl --device=/dev/ttyUSB002 --reset-once --flush | awk '{now=strftime("%d-%T "); print now $0}'
Initializing serial port /dev/ttyUSB002 (115200, 8N1) ...
Resetting Arduino ...
Flushing serial buffer ...
Receiving serial data ...
09-10:26:01 0-0:0:1
09-10:26:02 0-0:0:2
09-10:26:03 0-0:0:3
09-10:26:04 0-0:0:4
...
09-10:48:13 0-0:22:13
09-10:48:14 0-0:22:14
09-10:48:15 0-0:22:15
Finalize: done.
Initializing serial port /dev/ttyUSB002 (115200, 8N1) ...
Flushing serial buffer ...
Receiving serial data ...
09-10:48:22 0-0:22:22
09-10:48:23 0-0:22:23
09-10:48:24 0-0:22:24
09-10:48:25 0-0:22:25

Use case 2

Receive data from Arduino during 10 seconds, then kill the program. Dump STDOUT as hexadecimal. More verbose information is printed to STDOUT.

$ { /usr/bin/timeout -s SIGINT 10 /home/jhendrix/bin/cat_ttyUSB0.pl --device=/dev/arduinoMega1280-001; } | hexdump -C
Initializing serial port /dev/arduinoMega1280-001 (115200, 8N1) ...
Resetting Arduino ...
Flushing serial buffer ...
Receiving serial data ...

SIGINT received. Quitting at /home/jhendrix/bin/cat_ttyUSB0.pl line 41.
00000000  4c 44 52 0d 0a 35 32 0d  0a                       |LDR..52..|
00000009
Personal tools