bbabble
changeset 12 5e67754f6457
parent 5 f41d45fe7ae9
--- a/bbabble	Thu Nov 21 14:01:21 2013 +0000
+++ b/bbabble	Fri Jul 03 10:25:08 2020 -0400
@@ -2,12 +2,12 @@
 #======================================================================
 #                    B B A B B L E 
 #                    doc: Thu Mar 11 01:00:51 2004
-#                    dlm: Wed Dec  1 14:31:14 2010
+#                    dlm: Fri Jul  3 10:12:51 2020
 #                    (c) 2004 A.M. Thurnherr
-#                    uE-Info: 49 73 NIL 0 0 72 10 2 8 NIL ofnI
+#                    uE-Info: 58 0 NIL 0 0 72 10 2 8 NIL ofnI
 #======================================================================
 
-# Broad Band Babble --- talk to 1--2 RDI ADCPs
+# Broad Band Babble --- talk to 1--2 RDI ADCPs or other serial instruments
 
 # HISTORY:
 #  Mar  5, 2004: - written first, one-page-long proof-of-concept version
@@ -47,6 +47,14 @@
 #  Aug 26, 2010: - added -y)modem receive
 #  Oct 18, 2010: - added -u option to default ymodem receive call
 #  Dec  1, 2010: - BUG: -y with empty-string option argument did not work
+#  Jun 18, 2018: - explicitly implemented code to disable download on -y ""
+#		 - BUG: one debug message had -s wrong way round
+#		 - added state-change test required when Arduino closes USB connection
+#		 - BUG: non-existing ttys had stupid error messages
+#		 - made -s default and added -a to show async output, which is for debugging only
+#		 - changed default to use -m unless 2 devices are chosen
+#		 - begin implementing non-R)DI mode (currently, upload only)
+#  Jul  3, 2020: - expunged master/slave terminology
 
 #----------------------------------------------------------------------
 # USAGE
@@ -54,33 +62,25 @@
 
 use Getopt::Std;
 
-$USAGE = "Usage: $0 [-m)onochrome] [-s)uppress async output] " .
-		   "[-y)modem receive <cmd>] " .
+$USAGE = "Usage: $0 [-m)onochrome] [-s)uppress async output(default)] [produce -a)sync ouput]" .
+		   "[-y)modem receive <cmd[\"\" for none]>] [non-R)DI mode]" .
 		    "<tty0_device> [tty1_device]\n";
 
-die($USAGE) unless (getopts("msy:"));
+die($USAGE) unless (getopts("amRsy:"));
+$opt_s = 1 unless ($opt_a);
+$opt_m = 1 unless (@ARGV > 1);
+
+#============================== USER MANUAL ==============================
 
 # bbabble is started with 1 or 2 arguments, which are tty special files.
 # On LINUX, /dev/ttyS0 is com1: /dev/ttyS1 is com2: /dev/ttyUSB0 is the
 # first USB tty port, /dev/ttyUSB1 is the 2nd, &c. If two ttys are
 # specified bbabble can talk to two instruments in parallel. Communication
 # with The first (second) port is shown in red (blue). For consistency
-# with the color scheme used by the LDEO expect scripts, the master
-# (downlooker) should be connected to the first tty given on the command
-# line.
-
-# On some (especially BSD-based) systems there are separate tty
-# device files for dialin and dialout operations. Only the latter work
-# with bbabble. They traditionally have names matching /dev/cu* (e.g.
-# /dev/cuad0 for the first serial # port in FreeBSD).
-
-# In order to have read/write access to the device files, the user
-# that is to run bbabble should be added to the group that owns
-# the tty device files (e.g. dialer on FreeBSD).
-
-# The -m option suppresses color ouput and -s suppresses the asynchronous
-# messages generated by bbabble and printed in curly braces. Both
-# options should be used if bbabble is run within expect(1).
+# with the color scheme used by the LDEO expect scripts, the instrument
+# sending the sync pulses (downlooker) should be connected to the first
+# tty given on the command line. When only one port is specified, the
+# -m)onochrome option is assumed.
 
 # Upon startup, bbabble prints a help message showing the current
 # "foreground" instrument as well as a list of legal keyboard commands.
@@ -115,6 +115,17 @@
 # instrument. The command file may contain any valid RDI command, empty
 # lines, as well as comments beginning with a semicolon (;).
 
+#====================== USAGE NOTES ==============================
+
+# On some (especially BSD-based) systems there are separate tty
+# device files for dialin and dialout operations. Only the latter work
+# with bbabble. They traditionally have names matching /dev/cu* (e.g.
+# /dev/cuad0 for the first serial # port in FreeBSD).
+
+# In order to have read/write access to the device files, the user
+# that is to run bbabble should be added to the group that owns
+# the tty device files (e.g. dialer on FreeBSD).
+
 # Upon startup, bbabble expects to communicate with the ADCPs at 9600bps
 # (baud). If the user sends a BREAK (^C) and garbage is produced the
 # instrument's default baud rate is probably set to a different value.
@@ -247,15 +258,17 @@
 # If -y is not given, bbabble trys to find one of the standard ymodem
 # executables. Using -y allows options to be set.
 
-if (length($opt_y) > 0) {
-	$receive_ymodem = $opt_y;
+if (defined($opt_y)) {
+  if (length($opt_y) > 0) {
+    $receive_ymodem = $opt_y;
+  }
 } else {
-	chomp($receive_ymodem = `which lrb 2>/dev/null`);
-	chomp($receive_ymodem = `which	rb 2>/dev/null`)
-		if ($receive_ymodem eq '');
-	die("$0: cannot find rb or lrb\n")
-		if ($receive_ymodem eq '');
-	$receive_ymodem .= ' -u';		# keep upper-case filenames
+  chomp($receive_ymodem = `which lrb 2>/dev/null`);
+  chomp($receive_ymodem = `which  rb 2>/dev/null`)
+    if ($receive_ymodem eq '');
+  die("$0: cannot find rb or lrb\n")
+    if ($receive_ymodem eq '');
+  $receive_ymodem .= ' -u';		  # keep upper-case filenames
 }
 
 # When uploading command files, each command is sent after a prompt
@@ -330,10 +343,12 @@
 }
 
 my(@sfd);					# TTYs
+-c $TTY0 || die("$TTY0: no such file or directory\n");
 open(TTY0,'+>',$TTY0) || die("$TTY0: $!\n");
 $sfd[0] = fileno(TTY0);
 if (defined($TTY1)) {
   select(undef,undef,undef,$naptime);		# KEYSPAN 49W requires this
+  -c $TTY1 || die("$TTY1: no such file or directory\n");
   open(TTY1,'+>',$TTY1) || die("$TTY1: $!\n");
   $sfd[1] = fileno(TTY1);
 }
@@ -386,7 +401,7 @@
  			      | POSIX::CS8());
   $t->setcc(POSIX::VMIN,1); $t->setcc(POSIX::VTIME,0);
   set_speed($t,$id,$DEFAULT_SPEED[$id]);
-  if ($opt_s) {
+  unless ($opt_s) {
     print($COLOR[$id]) unless ($opt_m);
     print("{TTY $id READY}");
   }
@@ -402,7 +417,9 @@
              	   $rcv_state[$id] == $BUFFER);
       vec($rin,$sfd[$id],1) = 1;
     }
-    
+    last unless ($rcv_state[$id] == $ECHO ||		# needed when Arduino USB interface is closed at other end
+                 $rcv_state[$id] == $BUFFER);
+
     #------------------------------
     # DOWNLOAD DATA FROM INSTRUMENT
     #------------------------------
@@ -807,7 +824,9 @@
     if ($rcv_state[$cid]&$DOWNLOAD){
       print(STDERR "$COLOR[$cid]\{DOWNLOAD IN PROGRESS --- ^C TO ABORT}\n");
     } else {
-      $tmp = $rcv_state[$cid]&~$ECHO; $rcv_state[$cid] = $tmp|$BUFFER;
+      unless ($opt_R) {
+        $tmp = $rcv_state[$cid]&~$ECHO; $rcv_state[$cid] = $tmp|$BUFFER;
+      }
       print($RESET);
       cookedmode();
       do {
@@ -815,8 +834,10 @@
 	if ($_ eq '') {				# no file name given
 	  print("{upload canceled}\n");
 	  rawmode();
-      	  $tmp = $rcv_state[$cid]&~$BUFFER; $rcv_state[$cid] = $tmp|$FLUSH;
-      	  wait_for_bit_cleared($cid,$FLUSH);
+	  unless ($opt_R) {
+       	    $tmp = $rcv_state[$cid]&~$BUFFER; $rcv_state[$cid] = $tmp|$FLUSH;
+      	    wait_for_bit_cleared($cid,$FLUSH);
+      	  }
       	  next KEYSTROKE;
 	}
 	unless (open(CF,$_)) {
@@ -825,28 +846,33 @@
         } 
       } while (0);
       rawmode();
-      $tmp = $rcv_state[$cid]&~$BUFFER; $rcv_state[$cid] = $tmp|$FLUSH;
-      wait_for_bit_cleared($cid,$FLUSH);
 
-      my($cmd) = next_cmd(CF);			# read ahead (last cmd may ...
-      my($next_cmd);				# ... not generate prompt)
-      while (defined($next_cmd = next_cmd(CF))) {
-      	$rcv_state[$cid] = $UPLOAD;
-      	if ($cmd eq '<BREAK>') {
-      	  send_BREAK($cid);
-      	} else {
-	  POSIX::write($sfd[$cid],"$cmd\r",length($cmd)+1);
+      if ($opt_R) {				# non-RDI mode: dump entire file contents raw
+      	my($buf,$nread);
+      	while (($nread = read(CF,$buf,1)) > 0) {	# nice small chunks
+      	  POSIX::write($sfd[$cid],$buf,$nread);
+      	}
+      } else {					# RDI mode: parse command file and send command by command
+        $tmp = $rcv_state[$cid]&~$BUFFER; $rcv_state[$cid] = $tmp|$FLUSH;
+        wait_for_bit_cleared($cid,$FLUSH);
+	my($cmd) = next_cmd(CF);		  # read ahead (last cmd may ...
+	my($next_cmd);				  # ... not generate prompt)
+	while (defined($next_cmd = next_cmd(CF))) {
+	  $rcv_state[$cid] = $UPLOAD;
+	  if ($cmd eq '<BREAK>') {
+	    send_BREAK($cid);
+	  } else {
+	    POSIX::write($sfd[$cid],"$cmd\r",length($cmd)+1);
+	  }
+	  $cmd = $next_cmd;
+	  wait_for_bit_set($cid,$ECHO); # NOT SURE!!!
+	  $tmp = $rcv_state[$cid]&~$ECHO; $rcv_state[$cid] = $tmp|$BUFFER;
+	  print("\n${RESET}{upload finished}\n");
+          $tmp = $rcv_state[$cid]&~$BUFFER; $rcv_state[$cid] = $tmp|$FLUSH;
+	  wait_for_bit_cleared($cid,$FLUSH);
 	}
-      	$cmd = $next_cmd;
-        wait_for_bit_set($cid,$ECHO); # NOT SURE!!!
       }
       close(CF);
-      POSIX::write($sfd[$cid],"$cmd\r",length($cmd)+1); # last cmd
-
-      $tmp = $rcv_state[$cid]&~$ECHO; $rcv_state[$cid] = $tmp|$BUFFER;
-      print("\n${RESET}{upload finished}\n");
-      $tmp = $rcv_state[$cid]&~$BUFFER; $rcv_state[$cid] = $tmp|$FLUSH;
-      wait_for_bit_cleared($cid,$FLUSH);
     }
   }
 
@@ -855,15 +881,19 @@
   #--------------------------
 
   elsif ($char == 24) {
-    if ($rcv_state[$cid]&$DOWNLOAD){
-      print(STDERR "$COLOR[$cid]\{DOWNLOAD IN PROGRESS --- ^C TO ABORT}\n");
+    if (defined($receive_ymodem)) {
+      if ($rcv_state[$cid]&$DOWNLOAD){
+	print(STDERR "$COLOR[$cid]\{DOWNLOAD IN PROGRESS --- ^C TO ABORT}\n");
+      } else {
+	$rcv_state[$cid] = $SET_DOWNLOAD_SPEED;
+	wait_for_bit_set($cid,$ECHO);
+	$rcv_state[$cid] = $DOWNLOAD;		  # start waiting for instr. ready
+	POSIX::write($sfd[$cid],"$START_DOWNLOAD_RDI_COMMAND\r",
+				length($START_DOWNLOAD_RDI_COMMAND)+1);
+	wait_for_bit_set($cid,$ECHO);
+      }
     } else {
-      $rcv_state[$cid] = $SET_DOWNLOAD_SPEED;
-      wait_for_bit_set($cid,$ECHO);
-      $rcv_state[$cid] = $DOWNLOAD;		# start waiting for instr. ready
-      POSIX::write($sfd[$cid],"$START_DOWNLOAD_RDI_COMMAND\r",
-			      length($START_DOWNLOAD_RDI_COMMAND)+1);
-      wait_for_bit_set($cid,$ECHO);
+    	print(STDERR "$COLOR[$cid]\{NO YMODEM RECEIVER PROGRAM SPECIFIED}\n");
     }
   }