Index: libs/surfaces/tranzport/tranzport_control_protocol.cc
===================================================================
--- libs/surfaces/tranzport/tranzport_control_protocol.cc	(revision 1247)
+++ libs/surfaces/tranzport/tranzport_control_protocol.cc	(working copy)
@@ -18,6 +18,26 @@
     $Id$
 */
 
+/* Design notes: The tranzport is a unique device, basically a 
+   20 lcd gui with 22 shift keys and 8 blinking lights. 
+
+   It might be good one day, to break the gui, keyboard, and blinking light
+   components into separate parts, but for now, this remains monolithic.
+
+   As such it has several unique constraints. The device exerts flow control
+   by having a usb write fail. It is pointless to retry madly at that point,
+   the device is busy, and it's not going to become unbusy very quickly. 
+
+   So writes need to be either "mandatory" or "unreliable", and therein 
+   lies the rub.
+
+   mike.taht@gmail.com
+ */
+
+#define DEFAULT_USB_TIMEOUT 100
+#define MAX_RETRY 0
+#define DEBUG_TRANZPORT 1
+
 #include <iostream>
 #include <algorithm>
 #include <cmath>
@@ -33,6 +53,7 @@
 #include <ardour/route.h>
 #include <ardour/audio_track.h>
 #include <ardour/session.h>
+#include <ardour/tempo.h>
 #include <ardour/location.h>
 #include <ardour/dB.h>
 
@@ -75,7 +96,7 @@
 
 	set_route_table_size (1);
 	
-	timeout = 60000;
+	timeout = 6000;
 	buttonmask = 0;
 	_datawheel = 0;
 	_device_status = STATUS_OFFLINE;
@@ -89,10 +110,24 @@
 	last_track_gain = FLT_MAX;
 	display_mode = DisplayNormal;
 	gain_fraction = 0.0;
+	init_screen();
+	init_lights();
+}
 
-	memset (current_screen, 0, sizeof (current_screen));
-	memset (pending_screen, 0, sizeof (pending_screen));
+void TranzportControlProtocol::invalidate_screen ()
+{
+ 	memset (current_screen, 0x7F, sizeof (current_screen)); // fill cache with a character we otherwise never use
+}
 
+void TranzportControlProtocol::init_screen ()
+{
+ 	memset (current_screen, 0x7F, sizeof (current_screen)); // fill cache with a character we otherwise never use
+ 	memset (pending_screen, ' ', sizeof (pending_screen)); // blank screen
+ 	memset (flash_screen, 0x7E, sizeof (pending_screen)); // fill cache with a character we otherwise never use
+}
+
+void TranzportControlProtocol::init_lights()
+{
 	for (uint32_t i = 0; i < sizeof(lights)/sizeof(lights[0]); ++i) {
 		lights[i] = false;
 	}
@@ -100,6 +135,10 @@
 	for (uint32_t i = 0; i < sizeof(pending_lights)/sizeof(pending_lights[0]); ++i) {
 		pending_lights[i] = false;
 	}
+
+	for (uint32_t i = 0; i < sizeof(flash_lights)/sizeof(flash_lights[0]); ++i) {
+		flash_lights[i] = false;
+	}
 }
 
 TranzportControlProtocol::~TranzportControlProtocol ()
@@ -149,9 +188,9 @@
 		} else {
 			cerr << "Begin tranzport shutdown\n";
 			pthread_cancel_one (thread);
-			cerr << "Thread dead\n";
-			// lcd_clear ();
-			// lights_off ();
+			cerr << "Tranzport Thread dead\n";
+			lcd_clear ();
+			lights_off ();
 			// cerr << "dev reset\n";
 			close ();
 			_active = false;
@@ -168,7 +207,7 @@
 	if (route_table[0]) {
 		gain_t g = route_get_gain (0);
 		if (g != last_track_gain) {
-			char buf[16];
+			char buf[9];
 			snprintf (buf, sizeof (buf), "%6.1fdB", coefficient_to_dB (route_get_effective_gain (0)));
 			print (0, 9, buf); 
 			last_track_gain = g;
@@ -208,6 +247,7 @@
 	lights_off ();
 	last_meter_fill = 0;
 	display_mode = DisplayBigMeter;
+	flush();
 }
 
 void
@@ -215,14 +255,14 @@
 {
 	last_where += 1; /* force time redisplay */
 	last_track_gain = FLT_MAX; /* force gain redisplay */
-
 	lcd_clear ();
 	lights_off ();
 	show_current_track ();
+	show_transport_time ();
+	show_track_gain ();
 	show_wheel_mode ();
-	show_wheel_mode ();
-	show_transport_time ();
 	display_mode = DisplayNormal;
+	flush();
 }
 
 
@@ -230,10 +270,11 @@
 log_meter (float db)
 {
 	float def = 0.0f; /* Meter deflection %age */
- 
-	if (db < -70.0f) {
-		def = 0.0f;
-	} else if (db < -60.0f) {
+
+	if (db < -70.0f) return 0.0f;
+ 	if (db > 6.0f) return 1.0f;
+
+	if (db < -60.0f) {
 		def = (db + 70.0f) * 0.25f;
 	} else if (db < -50.0f) {
 		def = (db + 60.0f) * 0.5f + 2.5f;
@@ -245,8 +286,6 @@
 		def = (db + 30.0f) * 2.0f + 30.0f;
 	} else if (db < 6.0f) {
 		def = (db + 20.0f) * 2.5f + 50.0f;
-	} else {
-		def = 115.0f;
 	}
 	
 	/* 115 is the deflection %age that would be 
@@ -267,6 +306,8 @@
 	float level = route_get_peak_input_power (0, 0);
 	float fraction = log_meter (level);
 
+	/* Someday add a peak bar*/
+
 	/* we draw using a choice of a sort of double colon-like character ("::") or a single, left-aligned ":".
 	   the screen is 20 chars wide, so we can display 40 different levels. compute the level,
 	   then figure out how many "::" to fill. if the answer is odd, make the last one a ":"
@@ -288,7 +329,7 @@
 	
 	if (fraction > 0.98) {
 		light_on (LightAnysolo);
-	}
+}
 
 	/* add all full steps */
 
@@ -318,10 +359,36 @@
 }
 
 void
+TranzportControlProtocol::show_bbt (nframes_t where)
+{ 
+	if (where != last_where) {
+	  char buf[16];
+	  BBT_Time bbt;
+	  session->tempo_map().bbt_time (where, bbt);
+	  sprintf (buf, "%03" PRIu32 "|%02" PRIu32 "|%04" PRIu32, bbt.bars,bbt.beats,bbt.ticks);
+	  print (1, 9, buf);
+	  last_where = where;
+
+	  //        if (bbt_upper_info_label) {
+	  //     TempoMap::Metric m (session->tempo_map().metric_at (when));
+	  //     sprintf (buf, "%-5.2f", m.tempo().beats_per_minute());
+          //      bbt_lower_info_label->set_text (buf);
+          //      sprintf (buf, "%g|%g", m.meter().beats_per_bar(), m.meter().note_divisor());
+          //      bbt_upper_info_label->set_text (buf);
+        }
+}
+
+
+void
 TranzportControlProtocol::show_transport_time ()
 {
 	nframes_t where = session->transport_frame();
-	
+	show_bbt(where);
+}	
+
+void
+TranzportControlProtocol::show_smpte (nframes_t where)
+{
 	if (where != last_where) {
 
 		char buf[5];
@@ -343,7 +410,7 @@
 		print (1, 15, buf);
 
 		sprintf (buf, "%02" PRIu32, smpte.frames);
-		print (1, 18, buf);
+		print_noretry (1, 18, buf); 
 
 		last_where = where;
 	}
@@ -426,45 +493,233 @@
 }
 	
 int
-TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override)
+TranzportControlProtocol::write_noretry (uint8_t* cmd, uint32_t timeout_override)
 {
 	int val;
 
 	val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout);
 
-	if (val < 0)
+	if (val < 0) {
+#if DEBUG_TRANZPORT
+		printf("usb_interrupt_write failed: %d\n", val);
+#endif
 		return val;
-	if (val != 8)
+		}
+
+	if (val != 8) {
+#if DEBUG_TRANZPORT
+		printf("usb_interrupt_write failed: %d\n", val);
+#endif
 		return -1;
+		}
+
 	return 0;
 
 }	
 
-void
-TranzportControlProtocol::lcd_clear ()
+int
+TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override)
 {
-	/* special case this for speed and atomicity */
+#if MAX_RETRY > 0
+	int val;
+	int retry = 0;
+	while((val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout))!=8 && retry++ < MAX_RETRY) {
+		printf("usb_interrupt_write failed, retrying: %d\n", val);
+	}
 
-	uint8_t cmd[8];
+	if (retry == MAX_RETRY) {
+		printf("Too many retries on a tranzport write, aborting\n");
+		}
+
+	if (val < 0) {
+		printf("usb_interrupt_write failed: %d\n", val);
+		return val;
+		}
+	if (val != 8) {
+		printf("usb_interrupt_write failed: %d\n", val);
+		return -1;
+		}
+	return 0;
+#else
+	return (write_noretry(cmd,timeout_override));
+#endif
+
+}	
+
+
+// We have a state "Unknown" - STOP USING SPACES FOR IT - switching to arrow character
+// We have another state - no_retry. Misleading, as we still retry on the next pass
+// We have an "displayed" screen
+// We always draw into the pending screen
+// We have an active screen
+// Print arg - we have 
+// setactive
+// so someday I think we need a screen object.
+
+/*
+flash_screen.clear();
+flash_screen.print(0,0,"Undone:"); // Someday pull the undo stack from somewhere
+flash_screen.print(1,0,"Nextup:"); 
+
+if(flash_messages && lcd.getactive() != flash_screen) lcd.setactive(flash_screen,2000);
+
+screen::setactive(screen_name,duration); // duration in ms
+screen::getactive();
+*/
+
+
+int
+TranzportControlProtocol::flush ()
+{
+    return flush_lights() || flush_screen(); 
+}
+ 
+int
+TranzportControlProtocol::flush_lights ()
+{
+  int pending = 0;
+	/* flush changed light change */
+
+	if (pending_lights[LightRecord] != lights[LightRecord]) {
+		if (pending_lights[LightRecord]) {
+			light_on (LightRecord);
+		} else {
+			light_off (LightRecord);
+		}
+	}
+
+	if (pending_lights[LightTracksolo] != lights[LightTracksolo]) {
+		if (pending_lights[LightTracksolo]) {
+			light_on (LightTracksolo);
+		} else {
+			light_off (LightTracksolo);
+		}
+	}
+
+	if (pending_lights[LightTrackrec] != lights[LightTrackrec]) {
+		if (pending_lights[LightTrackrec]) {
+			light_on (LightTrackrec);
+		} else {
+			light_off (LightTrackrec);
+		}
+	}
+
+	if (pending_lights[LightTrackmute] != lights[LightTrackmute]) {
+		if (pending_lights[LightTrackmute]) {
+			light_on (LightTrackmute);
+		} else {
+			light_off (LightTrackmute);
+		}
+	}
+
+	if (pending_lights[LightTracksolo] != lights[LightTracksolo]) {
+		if (pending_lights[LightTracksolo]) {
+			light_on (LightTracksolo);
+		} else {
+			light_off (LightTracksolo);
+		}
+	}
+
+	if (pending_lights[LightAnysolo] != lights[LightAnysolo]) {
+		if (pending_lights[LightAnysolo]) {
+			light_on (LightAnysolo);
+		} else {
+			light_off (LightAnysolo);
+		}
+	}
+
+	if (pending_lights[LightLoop] != lights[LightLoop]) {
+		if (pending_lights[LightLoop]) {
+			light_on (LightLoop);
+		} else {
+			light_off (LightLoop);
+		}
+	}
+
+	if (pending_lights[LightPunch] != lights[LightPunch]) {
+		if (pending_lights[LightPunch]) {
+			light_on (LightPunch);
+		} else {
+			light_off (LightPunch);
+		}
+	}
+
+	return pending;
+}
+
+
+int
+TranzportControlProtocol::flush_screen ()
+{
+	/* next: flush LCD */
+  int cell, row, col_base, col, pending;
+  pending = 0;
+  cell = 0;
 	
-	cmd[0] = 0x00;
-	cmd[1] = 0x01;
-	cmd[3] = ' ';
-	cmd[4] = ' ';
-	cmd[5] = ' ';
-	cmd[6] = ' ';
-	cmd[7] = 0x00;
+	for (row = 0; row < 2 && pending == 0; ++row) {
+		for (col_base = 0, col = 0; col < 20 && pending == 0; ) {
+			if (pending_screen[row][col] != current_screen[row][col]) {
 
-	for (uint8_t i = 0; i < 10; ++i) {
-		cmd[2] = i;
-		usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, 1000);
+				/* something in this cell is different, so dump the cell
+				   to the device.
+				*/
+
+				uint8_t cmd[8];
+				
+				cmd[0] = 0x00;
+				cmd[1] = 0x01;
+				cmd[2] = cell;
+				cmd[3] = pending_screen[row][col_base];
+				cmd[4] = pending_screen[row][col_base+1];
+				cmd[5] = pending_screen[row][col_base+2];
+				cmd[6] = pending_screen[row][col_base+3];
+				cmd[7] = 0x00;
+				if(write(cmd,DEFAULT_USB_TIMEOUT) != 0) {
+				  /* try to update this cell on the next go-round */
+#if DEBUG_TRANZPORT
+					printf("usb screen update failed for some reason... why? cmd and data were %02x %02x %02x %02x %02x %02x %02x %02x\n", cmd[0],cmd[1],cmd[2], cmd[3], cmd[4], cmd[5],cmd[6],cmd[7]); 
+#endif
+					pending += 1;
+				} else {
+					/* successful write: copy to current */
+				  memcpy (&current_screen[row][col_base], &pending_screen[row][col_base], 4);
+				}
+
+				/* skip the rest of the 4 character cell since we wrote+copied it already */
+				
+				col_base += 4;
+				col = col_base;
+				cell++;
+
+			} else {
+
+				col++;
+				
+				if (col && col % 4 == 0) {
+					cell++;
+					col_base += 4;
+				}
+			}
+		}
 	}
-	
-	memset (current_screen, ' ', sizeof (current_screen));
-	memset (pending_screen, ' ', sizeof (pending_screen));
+
+
+  return pending;
 }
 
+
 void
+TranzportControlProtocol::lcd_clear ()
+{
+	const char *blank = "                    ";
+	invalidate_screen();
+	print(0,0,blank); // and rewrite the pending_screen
+	print(1,0,blank);
+}
+
+// Next up - buffering the lights more appropriately
+
+void
 TranzportControlProtocol::lights_off ()
 {
 	uint8_t cmd[8];
@@ -478,31 +733,31 @@
 	cmd[7] = 0x00;
 
 	cmd[2] = LightRecord;
-	if (write (cmd, 1000) == 0) {
+	if (write (cmd, DEFAULT_USB_TIMEOUT) == 0) {
 		lights[LightRecord] = false;
 	}
 	cmd[2] = LightTrackrec;
-	if (write (cmd, 1000) == 0) {
+	if (write (cmd, DEFAULT_USB_TIMEOUT) == 0) {
 		lights[LightTrackrec] = false;
 	}
 	cmd[2] = LightTrackmute;
-	if (write (cmd, 1000) == 0) {
+	if (write (cmd, DEFAULT_USB_TIMEOUT) == 0) {
 		lights[LightTrackmute] = false;
 	}
 	cmd[2] = LightTracksolo;
-	if (write (cmd, 1000) == 0) {
+	if (write (cmd, DEFAULT_USB_TIMEOUT) == 0) {
 		lights[LightTracksolo] = false;
 	}
 	cmd[2] = LightAnysolo;
-	if (write (cmd, 1000) == 0) {
+	if (write (cmd, DEFAULT_USB_TIMEOUT) == 0) {
 		lights[LightAnysolo] = false;
 	}
 	cmd[2] = LightLoop;
-	if (write (cmd, 1000) == 0) {
+	if (write (cmd, DEFAULT_USB_TIMEOUT) == 0) {
 		lights[LightLoop] = false;
 	}
 	cmd[2] = LightPunch;
-	if (write (cmd, 1000) == 0) {
+	if (write (cmd, DEFAULT_USB_TIMEOUT) == 0) {
 		lights[LightPunch] = false;
 	}
 }
@@ -523,7 +778,7 @@
 		cmd[6] = 0x00;
 		cmd[7] = 0x00;
 
-		if (write (cmd, 1000) == 0) {
+		if (write (cmd, DEFAULT_USB_TIMEOUT) == 0) {
 			lights[light] = true;
 			return 0;
 		} else {
@@ -551,7 +806,7 @@
 		cmd[6] = 0x00;
 		cmd[7] = 0x00;
 
-		if (write (cmd, 1000) == 0) {
+		if (write (cmd, DEFAULT_USB_TIMEOUT) == 0) {
 			lights[light] = false;
 			return 0;
 		} else {
@@ -571,11 +826,13 @@
 	uint8_t buf[8];
 	int val;
 	bool first_time = true;
+	int pending = 0;
+	uint8_t offline = 0;
 
 	PBD::ThreadCreated (pthread_self(), X_("Tranzport"));
 
 	memset (&rtparam, 0, sizeof (rtparam));
-	rtparam.sched_priority = 3; /* XXX should be relative to audio (JACK) thread */
+	rtparam.sched_priority = 52; /* XXX should be relative to audio (JACK) thread */
 	
 	if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
 		// do we care? not particularly.
@@ -593,13 +850,17 @@
 
 		/* anything to read ? */
 
-		if (_device_status == STATUS_OFFLINE) {
-			light_off (LightRecord);
-			first_time = true;
-		}
+	  if (_device_status == STATUS_OFFLINE) {
+	    if(offline++ == 1) { 
+	      cerr << "Transport has gone offline\n";
+	    }
+	    first_time = true;
+	  } else { 
+	    offline = 0; 
+	  }
 
 		pthread_testcancel();
-		val = usb_interrupt_read (udev, READ_ENDPOINT, (char*) buf, 8, 10);
+		val = usb_interrupt_read (udev, READ_ENDPOINT, (char*) buf, 8, 20);
 		pthread_testcancel();
 
 		if (val == 8) {
@@ -611,204 +872,96 @@
 				lcd_clear ();
 				lights_off ();
 				first_time = false;
+				offline = 0;
 			}
 			/* update whatever needs updating */
-			update_state ();
-		}
+			pending = update_state ();
+		} 
 	}
 
 	return (void*) 0;
 }
 
+
+int TranzportControlProtocol::set_lights_normal() 
+{
+  if (route_table[0]) {
+    boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack> (route_table[0]);
+    if (at && at->record_enabled()) {
+      pending_lights[LightTrackrec] = true;
+    } else {
+      pending_lights[LightTrackrec] = false;
+    }
+    if (route_get_muted (0)) {
+      pending_lights[LightTrackmute] = true;
+    } else {
+      pending_lights[LightTrackmute] = false;
+    }
+    if (route_get_soloed (0)) {
+      pending_lights[LightTracksolo] = true;
+    } else {
+      pending_lights[LightTracksolo] = false;
+    }
+    
+  } else {
+    pending_lights[LightTrackrec] = false;
+    pending_lights[LightTracksolo] = false;
+    pending_lights[LightTrackmute] = false;
+  }
+  
+  /* global */
+  
+  if (session->get_play_loop()) {
+    pending_lights[LightLoop] = true;
+  } else {
+    pending_lights[LightLoop] = false;
+  }
+  
+  if (Config->get_punch_in() || Config->get_punch_out()) {
+    pending_lights[LightPunch] = true;
+  } else {
+    pending_lights[LightPunch] = false;
+  }
+  
+  if (session->get_record_enabled()) {
+    pending_lights[LightRecord] = true;
+  } else {
+    pending_lights[LightRecord] = false;
+  }
+  
+  if (session->soloing ()) {
+    pending_lights[LightAnysolo] = true;
+  } else {
+    pending_lights[LightAnysolo] = false;
+  }
+  
+  return 0;
+}
+
+int TranzportControlProtocol::set_lights_tempo() 
+{
+  return set_lights_normal();
+  // someday soon fiddle with the lights based on the tempo 
+}
+
 int
 TranzportControlProtocol::update_state ()
 {
-	int row;
-	int col_base;
-	int col;
-	int cell;
+	/* do the text and light updates */
 
-	/* do the text updates */
-
 	switch (display_mode) {
 	case DisplayBigMeter:
-		show_meter ();
-		break;
+	  set_lights_tempo();
+	  show_meter ();
+	  break;
 
 	case DisplayNormal:
-		normal_update ();
-		break;
+	  set_lights_normal();
+	  normal_update ();
+	  break;
 	}
 
-	/* next: flush LCD */
-
-	cell = 0;
-	
-	for (row = 0; row < 2; ++row) {
-
-		for (col_base = 0, col = 0; col < 20; ) {
-			
-			if (pending_screen[row][col] != current_screen[row][col]) {
-
-				/* something in this cell is different, so dump the cell
-				   to the device.
-				*/
-
-				uint8_t cmd[8];
-				
-				cmd[0] = 0x00;
-				cmd[1] = 0x01;
-				cmd[2] = cell;
-				cmd[3] = pending_screen[row][col_base];
-				cmd[4] = pending_screen[row][col_base+1];
-				cmd[5] = pending_screen[row][col_base+2];
-				cmd[6] = pending_screen[row][col_base+3];
-				cmd[7] = 0x00;
-
-				if (usb_interrupt_write (udev, WRITE_ENDPOINT, (char *) cmd, 8, 1000) == 8) {
-					/* successful write: copy to current */
-					memcpy (&current_screen[row][col_base], &pending_screen[row][col_base], 4);
-				}
-
-				/* skip the rest of the 4 character cell since we wrote+copied it already */
-				
-				col_base += 4;
-				col = col_base;
-				cell++;
-
-			} else {
-
-				col++;
-				
-				if (col && col % 4 == 0) {
-					cell++;
-					col_base += 4;
-				}
-			}
-		}
-	}
-
-	/* now update LED's */
-
-	/* per track */
-
-	if (route_table[0]) {
-		boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack> (route_table[0]);
-		if (at && at->record_enabled()) {
-			pending_lights[LightTrackrec] = true;
-		} else {
-			pending_lights[LightTrackrec] = false;
-		}
-		if (route_get_muted (0)) {
-			pending_lights[LightTrackmute] = true;
-		} else {
-			pending_lights[LightTrackmute] = false;
-		}
-		if (route_get_soloed (0)) {
-			pending_lights[LightTracksolo] = true;
-		} else {
-			pending_lights[LightTracksolo] = false;
-		}
-
-	} else {
-		pending_lights[LightTrackrec] = false;
-		pending_lights[LightTracksolo] = false;
-		pending_lights[LightTrackmute] = false;
-	}
-
-	/* global */
-
-	if (session->get_play_loop()) {
-		pending_lights[LightLoop] = true;
-	} else {
-		pending_lights[LightLoop] = false;
-	}
-
-	if (Config->get_punch_in() || Config->get_punch_out()) {
-		pending_lights[LightPunch] = true;
-	} else {
-		pending_lights[LightPunch] = false;
-	}
-
-	if (session->get_record_enabled()) {
-		pending_lights[LightRecord] = true;
-	} else {
-		pending_lights[LightRecord] = false;
-	}
-
-	if (session->soloing ()) {
-		pending_lights[LightAnysolo] = true;
-	} else {
-		pending_lights[LightAnysolo] = false;
-	}
-
-	/* flush changed light change */
-
-	if (pending_lights[LightRecord] != lights[LightRecord]) {
-		if (pending_lights[LightRecord]) {
-			light_on (LightRecord);
-		} else {
-			light_off (LightRecord);
-		}
-	}
-
-	if (pending_lights[LightTracksolo] != lights[LightTracksolo]) {
-		if (pending_lights[LightTracksolo]) {
-			light_on (LightTracksolo);
-		} else {
-			light_off (LightTracksolo);
-		}
-	}
-
-	if (pending_lights[LightTrackrec] != lights[LightTrackrec]) {
-		if (pending_lights[LightTrackrec]) {
-			light_on (LightTrackrec);
-		} else {
-			light_off (LightTrackrec);
-		}
-	}
-
-	if (pending_lights[LightTrackmute] != lights[LightTrackmute]) {
-		if (pending_lights[LightTrackmute]) {
-			light_on (LightTrackmute);
-		} else {
-			light_off (LightTrackmute);
-		}
-	}
-
-	if (pending_lights[LightTracksolo] != lights[LightTracksolo]) {
-		if (pending_lights[LightTracksolo]) {
-			light_on (LightTracksolo);
-		} else {
-			light_off (LightTracksolo);
-		}
-	}
-
-	if (pending_lights[LightAnysolo] != lights[LightAnysolo]) {
-		if (pending_lights[LightAnysolo]) {
-			light_on (LightAnysolo);
-		} else {
-			light_off (LightAnysolo);
-		}
-	}
-
-	if (pending_lights[LightLoop] != lights[LightLoop]) {
-		if (pending_lights[LightLoop]) {
-			light_on (LightLoop);
-		} else {
-			light_off (LightLoop);
-		}
-	}
-
-	if (pending_lights[LightPunch] != lights[LightPunch]) {
-		if (pending_lights[LightPunch]) {
-			light_on (LightPunch);
-		} else {
-			light_off (LightPunch);
-		}
-	}
-
-	return 0;
+	return flush();
 }
 
 int
@@ -981,11 +1134,20 @@
 void
 TranzportControlProtocol::show_current_track ()
 {
-	if (route_table[0] == 0) {
-		print (0, 0, "--------");
-	} else {
-		print (0, 0, route_get_name (0).substr (0, 8).c_str());
-	}
+  char pad[11];
+  char *v;
+  int len;
+  if (route_table[0] == 0) {
+    print (0, 0, "----------");
+    last_track_gain = FLT_MAX;
+  } else {
+    strcpy(pad,"          ");
+    v =  (char *)route_get_name (0).substr (0, 10).c_str();
+    if((len = strlen(v)) > 0) {
+      strncpy(pad,(char *)v,len);
+    }
+    print (0, 0, pad);
+  }
 }
 
 void
@@ -1006,6 +1168,12 @@
 void
 TranzportControlProtocol::button_event_backlight_release (bool shifted)
 {
+	if (shifted) {
+		lcd_clear();
+		last_where += 1; /* force time redisplay */
+		last_track_gain = FLT_MAX;
+		normal_update(); //  redraw_screen();  
+	}
 }
 
 void
@@ -1080,9 +1248,9 @@
 TranzportControlProtocol::button_event_undo_press (bool shifted)
 {
 	if (shifted) {
-		redo ();
+	  redo (); // someday flash the screen with what was redone
 	} else {
-		undo ();
+	  undo (); // someday flash the screen with what was undone
 	}
 }
 
@@ -1235,7 +1403,11 @@
 void
 TranzportControlProtocol::button_event_play_press (bool shifted)
 {
-	transport_play ();
+	if (shifted) {
+	  set_transport_speed (1.0f);
+	} else {
+	  transport_play ();
+	}
 }
 
 void
@@ -1304,8 +1476,11 @@
 				}
 				break;
 
+			case WheelShiftMarker:
+			        break;
 			case WheelShiftMaster:
 				break;
+
 			}
 		}
 
@@ -1453,6 +1628,8 @@
 		break;
 	case WheelShiftMaster:
 		wheel_shift_mode = WheelShiftGain;
+	case WheelShiftMarker: // Not done yet, disabled
+	  wheel_shift_mode = WheelShiftGain;
 	}
 
 	show_wheel_mode ();
@@ -1512,19 +1689,31 @@
 		break;
 
 	case WheelShiftPan:
-		text += ":Pan";
+		text += ":Pan ";
 		break;
 
 	case WheelShiftMaster:
 		text += ":Mstr";
 		break;
+
+	case WheelShiftMarker:
+   	        text += ":Mrkr";
+		break;
 	}
 	
 	print (1, 0, text.c_str());
 }
 
+// Was going to keep state around saying to retry or not
+// haven't got to it yet.
+
+	void
+TranzportControlProtocol::print (int row, int col, const char *text) {
+	print_noretry(row,col,text);
+}
+
 void
-TranzportControlProtocol::print (int row, int col, const char *text)
+TranzportControlProtocol::print_noretry (int row, int col, const char *text)
 {
 	int cell;
 	uint32_t left = strlen (text);
Index: libs/surfaces/tranzport/tranzport_control_protocol.h
===================================================================
--- libs/surfaces/tranzport/tranzport_control_protocol.h	(revision 1247)
+++ libs/surfaces/tranzport/tranzport_control_protocol.h	(working copy)
@@ -1,3 +1,4 @@
+
 #ifndef ardour_tranzport_control_protocol_h
 #define ardour_tranzport_control_protocol_h
 
@@ -72,7 +73,8 @@
 	enum WheelShiftMode {
 		WheelShiftGain,
 		WheelShiftPan,
-		WheelShiftMaster
+		WheelShiftMaster,
+		WheelShiftMarker
 	};
 		
 	enum WheelMode {
@@ -102,8 +104,10 @@
 	Glib::Mutex update_lock;
 	char current_screen[2][20];
 	char pending_screen[2][20];
+	char flash_screen[2][20];
 	bool lights[7];
 	bool pending_lights[7];
+	bool flash_lights[7];
 
 	bool           last_negative;
 	uint32_t       last_hrs;
@@ -121,12 +125,14 @@
 	int open ();
 	int read (uint32_t timeout_override = 0);
 	int write (uint8_t* cmd, uint32_t timeout_override = 0);
+	int write_noretry (uint8_t* cmd, uint32_t timeout_override = 0);
 	int close ();
 
 	int open_core (struct usb_device*);
 
 	void lcd_clear ();
 	void print (int row, int col, const char* text);
+	void print_noretry (int row, int col, const char* text);
 	int  light_on (LightID);
 	int  light_off (LightID);
 	void lights_off ();
@@ -141,6 +147,8 @@
 	void show_current_track ();
 	void show_track_gain ();
 	void show_transport_time ();
+	void show_bbt (nframes_t where);
+	void show_smpte (nframes_t where);
 	void show_wheel_mode ();
 	void show_gain ();
 	void show_pan ();
@@ -208,6 +216,14 @@
 
 	int process (uint8_t *);
 	int update_state();
+	int flush();
+	int flush_lights();
+	int flush_screen();
+	void init_lights();
+	int set_lights_normal();
+	int set_lights_tempo();
+	void init_screen();
+	void invalidate_screen();
 };
 
 
